8258915: Temporary buffer cleanup

Reviewed-by: valeriep
This commit is contained in:
Weijun Wang 2021-04-22 18:11:43 +00:00
parent 31d8a19e47
commit f834557ae0
79 changed files with 1517 additions and 1039 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -37,6 +37,7 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import jdk.internal.access.SharedSecrets;
import sun.security.x509.*;
import sun.security.util.*;
@ -95,8 +96,9 @@ public class PKCS8Key implements PrivateKey {
}
private void decode(InputStream is) throws InvalidKeyException {
DerValue val = null;
try {
DerValue val = new DerValue(is);
val = new DerValue(is);
if (val.tag != DerValue.tag_Sequence) {
throw new InvalidKeyException("invalid key format");
}
@ -106,7 +108,7 @@ public class PKCS8Key implements PrivateKey {
throw new InvalidKeyException("unknown version: " + version);
}
algid = AlgorithmId.parse (val.data.getDerValue ());
key = val.data.getOctetString ();
key = val.data.getOctetString();
DerValue next;
if (val.data.available() == 0) {
@ -131,11 +133,15 @@ public class PKCS8Key implements PrivateKey {
throw new InvalidKeyException("Extra bytes");
} catch (IOException e) {
throw new InvalidKeyException("IOException : " + e.getMessage());
} finally {
if (val != null) {
val.clear();
}
}
}
/**
* Construct PKCS#8 subject public key from a DER value. If a
* Construct PKCS#8 subject public key from a DER encoding. If a
* security provider supports the key algorithm with a specific class,
* a PrivateKey from the provider is returned. Otherwise, a raw
* PKCS8Key object is returned.
@ -145,21 +151,29 @@ public class PKCS8Key implements PrivateKey {
* information. Also, when a key (or algorithm) needs some special
* handling, that specific need can be accommodated.
*
* @param in the DER-encoded SubjectPublicKeyInfo value
* @param encoded the DER-encoded SubjectPublicKeyInfo value
* @exception IOException on data format errors
*/
public static PrivateKey parseKey(DerValue in) throws IOException {
public static PrivateKey parseKey(byte[] encoded) throws IOException {
try {
PKCS8Key rawKey = new PKCS8Key(in.toByteArray());
PKCS8EncodedKeySpec pkcs8KeySpec
= new PKCS8EncodedKeySpec(rawKey.getEncoded());
PKCS8Key rawKey = new PKCS8Key(encoded);
byte[] internal = rawKey.getEncodedInternal();
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(internal);
PrivateKey result = null;
try {
return KeyFactory.getInstance(rawKey.algid.getName())
result = KeyFactory.getInstance(rawKey.algid.getName())
.generatePrivate(pkcs8KeySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
// Ignore and return raw key
return rawKey;
result = rawKey;
} finally {
if (result != rawKey) {
rawKey.clear();
}
SharedSecrets.getJavaSecuritySpecAccess()
.clearEncodedKeySpec(pkcs8KeySpec);
}
return result;
} catch (InvalidKeyException e) {
throw new IOException("corrupt private key", e);
}
@ -183,14 +197,9 @@ public class PKCS8Key implements PrivateKey {
* Returns the DER-encoded form of the key as a byte array,
* or {@code null} if an encoding error occurs.
*/
public synchronized byte[] getEncoded() {
try {
encode();
return encodedKey.clone();
} catch (InvalidKeyException e) {
// ignored and return null
}
return null;
public byte[] getEncoded() {
byte[] b = getEncodedInternal();
return (b == null) ? null : b.clone();
}
/**
@ -201,34 +210,34 @@ public class PKCS8Key implements PrivateKey {
}
/**
* DER-encodes this key as a byte array that can be retrieved
* by the {@link #getEncoded()} method.
* DER-encodes this key as a byte array stored inside this object
* and return it.
*
* @exception InvalidKeyException if an encoding error occurs.
* @return the encoding, or null if there is an I/O error.
*/
private void encode() throws InvalidKeyException {
private synchronized byte[] getEncodedInternal() {
if (encodedKey == null) {
try {
DerOutputStream out = new DerOutputStream ();
DerOutputStream tmp = new DerOutputStream();
tmp.putInteger(V1);
algid.encode(tmp);
tmp.putOctetString(key);
out.write(DerValue.tag_Sequence, tmp);
DerValue out = DerValue.wrap(DerValue.tag_Sequence, tmp);
encodedKey = out.toByteArray();
out.clear();
} catch (IOException e) {
throw new InvalidKeyException ("IOException : " +
e.getMessage());
// encodedKey is still null
}
}
return encodedKey;
}
@java.io.Serial
protected Object writeReplace() throws java.io.ObjectStreamException {
return new KeyRep(KeyRep.Type.PRIVATE,
getAlgorithm(),
getFormat(),
getEncoded());
getAlgorithm(),
getFormat(),
getEncodedInternal());
}
/**
@ -258,11 +267,23 @@ public class PKCS8Key implements PrivateKey {
if (this == object) {
return true;
}
if (object instanceof Key) {
if (object instanceof PKCS8Key) {
// time-constant comparison
return MessageDigest.isEqual(
getEncoded(),
((Key)object).getEncoded());
getEncodedInternal(),
((PKCS8Key)object).getEncodedInternal());
} else if (object instanceof Key) {
// time-constant comparison
byte[] otherEncoded = ((Key)object).getEncoded();
try {
return MessageDigest.isEqual(
getEncodedInternal(),
otherEncoded);
} finally {
if (otherEncoded != null) {
Arrays.fill(otherEncoded, (byte) 0);
}
}
}
return false;
}
@ -272,6 +293,13 @@ public class PKCS8Key implements PrivateKey {
* which are equal will also have the same hashcode.
*/
public int hashCode() {
return Arrays.hashCode(getEncoded());
return Arrays.hashCode(getEncodedInternal());
}
public void clear() {
if (encodedKey != null) {
Arrays.fill(encodedKey, (byte)0);
}
Arrays.fill(key, (byte)0);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -65,6 +65,7 @@ import javax.crypto.Mac;
import javax.security.auth.DestroyFailedException;
import javax.security.auth.x500.X500Principal;
import jdk.internal.access.SharedSecrets;
import sun.security.action.GetPropertyAction;
import sun.security.tools.KeyStoreUtil;
import sun.security.util.*;
@ -359,63 +360,87 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
key = RetryWithZero.run(pass -> {
// Use JCE
SecretKey skey = getPBEKey(pass);
Cipher cipher = Cipher.getInstance(
mapPBEParamsToAlgorithm(algOid, algParams));
cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
SecretKey skey = getPBEKey(pass);
try {
cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
} finally {
destroyPBEKey(skey);
}
byte[] keyInfo = cipher.doFinal(encryptedKey);
/*
* Parse the key algorithm and then use a JCA key factory
* to re-create the key.
*/
DerValue val = new DerValue(keyInfo);
DerInputStream in = val.toDerInputStream();
int i = in.getInteger();
DerValue[] value = in.getSequence(2);
if (value.length < 1 || value.length > 2) {
throw new IOException("Invalid length for AlgorithmIdentifier");
}
AlgorithmId algId = new AlgorithmId(value[0].getOID());
String keyAlgo = algId.getName();
// decode private key
if (entry instanceof PrivateKeyEntry) {
KeyFactory kfac = KeyFactory.getInstance(keyAlgo);
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo);
Key tmp = kfac.generatePrivate(kspec);
if (debug != null) {
debug.println("Retrieved a protected private key at alias" +
" '" + alias + "' (" +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
try {
DerInputStream in = val.toDerInputStream();
int i = in.getInteger();
DerValue[] value = in.getSequence(2);
if (value.length < 1 || value.length > 2) {
throw new IOException("Invalid length for AlgorithmIdentifier");
}
return tmp;
// decode secret key
} else {
byte[] keyBytes = in.getOctetString();
SecretKeySpec secretKeySpec =
new SecretKeySpec(keyBytes, keyAlgo);
AlgorithmId algId = new AlgorithmId(value[0].getOID());
String keyAlgo = algId.getName();
// Special handling required for PBE: needs a PBEKeySpec
Key tmp;
if (keyAlgo.startsWith("PBE")) {
SecretKeyFactory sKeyFactory =
SecretKeyFactory.getInstance(keyAlgo);
KeySpec pbeKeySpec =
sKeyFactory.getKeySpec(secretKeySpec, PBEKeySpec.class);
tmp = sKeyFactory.generateSecret(pbeKeySpec);
// decode private key
if (entry instanceof PrivateKeyEntry) {
KeyFactory kfac = KeyFactory.getInstance(keyAlgo);
PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(keyInfo);
try {
Key tmp = kfac.generatePrivate(kspec);
if (debug != null) {
debug.println("Retrieved a protected private key at alias" +
" '" + alias + "' (" +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
} finally {
SharedSecrets.getJavaSecuritySpecAccess()
.clearEncodedKeySpec(kspec);
}
// decode secret key
} else {
tmp = secretKeySpec;
}
byte[] keyBytes = in.getOctetString();
SecretKeySpec secretKeySpec =
new SecretKeySpec(keyBytes, keyAlgo);
if (debug != null) {
debug.println("Retrieved a protected secret key at alias " +
"'" + alias + "' (" +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
try {
// Special handling required for PBE: needs a PBEKeySpec
Key tmp;
if (keyAlgo.startsWith("PBE")) {
SecretKeyFactory sKeyFactory =
SecretKeyFactory.getInstance(keyAlgo);
KeySpec pbeKeySpec =
sKeyFactory.getKeySpec(secretKeySpec, PBEKeySpec.class);
try {
tmp = sKeyFactory.generateSecret(pbeKeySpec);
} finally {
((PBEKeySpec)pbeKeySpec).clearPassword();
SharedSecrets.getJavaxCryptoSpecAccess()
.clearSecretKeySpec(secretKeySpec);
}
} else {
tmp = secretKeySpec;
}
if (debug != null) {
debug.println("Retrieved a protected secret key at alias " +
"'" + alias + "' (" +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
} finally {
Arrays.fill(keyBytes, (byte)0);
}
}
return tmp;
} finally {
val.clear();
Arrays.fill(keyInfo, (byte) 0);
}
}, password);
@ -600,8 +625,15 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
// Encrypt the private key
keyEntry.protectedPrivKey =
encryptPrivateKey(key.getEncoded(), passwordProtection);
byte[] encoded = key.getEncoded();
try {
keyEntry.protectedPrivKey =
encryptPrivateKey(encoded, passwordProtection);
} finally {
if (encoded != null) {
Arrays.fill(encoded, (byte) 0);
}
}
} else {
throw new KeyStoreException("Private key is not encoded" +
"as PKCS#8");
@ -629,17 +661,25 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
keyEntry.date = new Date();
// Encode secret key in a PKCS#8
DerOutputStream pkcs8 = new DerOutputStream();
DerOutputStream secretKeyInfo = new DerOutputStream();
secretKeyInfo.putInteger(0);
AlgorithmId algId = AlgorithmId.get(key.getAlgorithm());
algId.encode(secretKeyInfo);
secretKeyInfo.putOctetString(key.getEncoded());
pkcs8.write(DerValue.tag_Sequence, secretKeyInfo);
// Encrypt the secret key (using same PBE as for private keys)
keyEntry.protectedSecretKey =
encryptPrivateKey(pkcs8.toByteArray(), passwordProtection);
byte[] encoded = key.getEncoded();
secretKeyInfo.putOctetString(encoded);
Arrays.fill(encoded, (byte)0);
DerValue pkcs8 = DerValue.wrap(DerValue.tag_Sequence, secretKeyInfo);
byte[] p8Array = pkcs8.toByteArray();
pkcs8.clear();
try {
// Encrypt the secret key (using same PBE as for private keys)
keyEntry.protectedSecretKey =
encryptPrivateKey(p8Array, passwordProtection);
} finally {
Arrays.fill(p8Array, (byte)0);
}
if (debug != null) {
debug.println("Setting a protected secret key at alias '" +
@ -830,6 +870,17 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
return skey;
}
/*
* Destroy the key obtained from getPBEKey().
*/
private void destroyPBEKey(SecretKey key) {
try {
key.destroy();
} catch (DestroyFailedException e) {
// Accept this
}
}
/*
* Encrypt private key or secret key using Password-based encryption (PBE)
* as defined in PKCS#5.
@ -874,9 +925,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
// Use JCE
SecretKey skey = getPBEKey(passwordProtection.getPassword());
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
SecretKey skey = getPBEKey(passwordProtection.getPassword());
try {
cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
} finally {
destroyPBEKey(skey);
}
byte[] encryptedKey = cipher.doFinal(data);
algid = new AlgorithmId(pbeOID, cipher.getParameters());
@ -1462,7 +1517,11 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
PBEParameterSpec params =
new PBEParameterSpec(salt, macIterationCount);
SecretKey key = getPBEKey(passwd);
m.init(key, params);
try {
m.init(key, params);
} finally {
destroyPBEKey(key);
}
m.update(data);
byte[] macResult = m.doFinal();
@ -1867,9 +1926,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
DerOutputStream bytes = new DerOutputStream();
// Use JCE
SecretKey skey = getPBEKey(password);
Cipher cipher = Cipher.getInstance(certProtectionAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
SecretKey skey = getPBEKey(password);
try {
cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
} finally {
destroyPBEKey(skey);
}
encryptedData = cipher.doFinal(data);
AlgorithmId algId = new AlgorithmId(
@ -2075,10 +2138,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
try {
RetryWithZero.run(pass -> {
// Use JCE
SecretKey skey = getPBEKey(pass);
Cipher cipher = Cipher.getInstance(
mapPBEParamsToAlgorithm(algOid, algParams));
cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
SecretKey skey = getPBEKey(pass);
try {
cipher.init(Cipher.DECRYPT_MODE, skey, algParams);
} finally {
destroyPBEKey(skey);
}
loadSafeContents(new DerInputStream(cipher.doFinal(rawData)));
return null;
}, password);
@ -2128,7 +2195,11 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
RetryWithZero.run(pass -> {
SecretKey key = getPBEKey(pass);
m.init(key, params);
try {
m.init(key, params);
} finally {
destroyPBEKey(key);
}
m.update(authSafeData);
byte[] macResult = m.doFinal();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -495,13 +495,16 @@ public class CtrDrbg extends AbstractDrbg {
// Step 4.1. Increment
addOne(v, ctrLen);
try {
// Step 4.2. Encrypt
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(k, keyAlg));
byte[] out = cipher.doFinal(v);
// Step 4.2. Encrypt
// Step 4.3 and 5. Cat bytes and leftmost
System.arraycopy(out, 0, result, pos,
(len > blockLen) ? blockLen : len);
if (len > blockLen) {
cipher.doFinal(v, 0, blockLen, result, pos);
} else {
byte[] out = cipher.doFinal(v);
System.arraycopy(out, 0, result, pos, len);
Arrays.fill(out, (byte)0);
}
} catch (GeneralSecurityException e) {
throw new InternalError(e);
}

View file

@ -37,6 +37,7 @@ import java.security.spec.KeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
/**
* This class implements the DSA key factory of the Sun provider.
@ -93,7 +94,7 @@ public class DSAKeyFactory extends KeyFactorySpi {
* is inappropriate for this key factory to produce a private key.
*/
protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
throws InvalidKeySpecException {
throws InvalidKeySpecException {
try {
if (keySpec instanceof DSAPrivateKeySpec) {
DSAPrivateKeySpec dsaPrivKeySpec = (DSAPrivateKeySpec)keySpec;
@ -103,9 +104,12 @@ public class DSAKeyFactory extends KeyFactorySpi {
dsaPrivKeySpec.getG());
} else if (keySpec instanceof PKCS8EncodedKeySpec) {
return new DSAPrivateKey
(((PKCS8EncodedKeySpec)keySpec).getEncoded());
byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
try {
return new DSAPrivateKey(encoded);
} finally {
Arrays.fill(encoded, (byte) 0);
}
} else {
throw new InvalidKeySpecException
("Inappropriate key specification");
@ -183,8 +187,12 @@ public class DSAKeyFactory extends KeyFactorySpi {
params.getG()));
} else if (keySpec.isAssignableFrom(pkcs8KeySpec)) {
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
byte[] encoded = key.getEncoded();
try {
return keySpec.cast(new PKCS8EncodedKeySpec(encoded));
} finally {
Arrays.fill(encoded, (byte)0);
}
} else {
throw new InvalidKeySpecException
("Inappropriate key specification");

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,7 @@ import java.security.AlgorithmParameters;
import java.security.spec.DSAParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.security.interfaces.DSAParams;
import java.util.Arrays;
import sun.security.x509.AlgIdDSA;
import sun.security.pkcs.PKCS8Key;
@ -68,8 +69,11 @@ public final class DSAPrivateKey extends PKCS8Key
algid = new AlgIdDSA(p, q, g);
try {
key = new DerValue(DerValue.tag_Integer,
x.toByteArray()).toByteArray();
byte[] xbytes = x.toByteArray();
DerValue val = new DerValue(DerValue.tag_Integer, xbytes);
key = val.toByteArray();
val.clear();
Arrays.fill(xbytes, (byte)0);
} catch (IOException e) {
throw new AssertionError("Should not happen", e);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -254,15 +254,15 @@ public class HashDrbg extends AbstractHashDrbg {
int len = output.length;
while (len > 0) {
// Step 4.1 w = Hash (data).
digest.update(data);
if (len < outLen) {
// Step 4.1 w = Hash (data).
// Step 4.2 W = W || w.
System.arraycopy(digest.digest(data), 0, output, pos,
len);
byte[] out = digest.digest();
System.arraycopy(out, 0, output, pos, len);
Arrays.fill(out, (byte)0);
} else {
try {
// Step 4.1 w = Hash (data).
digest.update(data);
// Step 4.2 digest into right position, no need to cat
digest.digest(output, pos, outLen);
} catch (DigestException e) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -206,6 +206,7 @@ final class KeyProtector {
digest = md.digest();
md.reset();
System.arraycopy(digest, 0, encrKey, encrKeyOffset, digest.length);
Arrays.fill(plainKey, (byte)0);
// wrap the protected private key in a PKCS#8-style
// EncryptedPrivateKeyInfo, and returns its encoding
@ -308,9 +309,11 @@ final class KeyProtector {
// algorithm and instantiates the appropriate key factory,
// which in turn parses the key material.
try {
return PKCS8Key.parseKey(new DerValue(plainKey));
return PKCS8Key.parseKey(plainKey);
} catch (IOException ioe) {
throw new UnrecoverableKeyException(ioe.getMessage());
} finally {
Arrays.fill(plainKey, (byte)0);
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -42,4 +42,8 @@ public final class SHAKE256 extends SHA3 {
public byte[] digest() {
return engineDigest();
}
public void reset() {
engineReset();
}
}

View file

@ -30,6 +30,7 @@ import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import java.util.Arrays;
import sun.security.action.GetPropertyAction;
import sun.security.rsa.RSAUtil.KeyType;
@ -308,8 +309,14 @@ public class RSAKeyFactory extends KeyFactorySpi {
throw new InvalidKeyException("Invalid key", e);
}
} else {
return RSAPrivateCrtKeyImpl.newKey(type, key.getFormat(),
key.getEncoded());
byte[] encoded = key.getEncoded();
try {
return RSAPrivateCrtKeyImpl.newKey(type, key.getFormat(), encoded);
} finally {
if (encoded != null) {
Arrays.fill(encoded, (byte)0);
}
}
}
}
@ -340,8 +347,12 @@ public class RSAKeyFactory extends KeyFactorySpi {
private PrivateKey generatePrivate(KeySpec keySpec)
throws GeneralSecurityException {
if (keySpec instanceof PKCS8EncodedKeySpec) {
return RSAPrivateCrtKeyImpl.newKey(type, "PKCS#8",
((PKCS8EncodedKeySpec)keySpec).getEncoded());
byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
try {
return RSAPrivateCrtKeyImpl.newKey(type, "PKCS#8", encoded);
} finally {
Arrays.fill(encoded, (byte)0);
}
} else if (keySpec instanceof RSAPrivateCrtKeySpec) {
RSAPrivateCrtKeySpec rsaSpec = (RSAPrivateCrtKeySpec)keySpec;
try {
@ -404,7 +415,12 @@ public class RSAKeyFactory extends KeyFactorySpi {
}
} else if (key instanceof RSAPrivateKey) {
if (keySpec.isAssignableFrom(PKCS8_KEYSPEC_CLS)) {
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
byte[] encoded = key.getEncoded();
try {
return keySpec.cast(new PKCS8EncodedKeySpec(encoded));
} finally {
Arrays.fill(encoded, (byte)0);
}
} else if (keySpec.isAssignableFrom(RSA_PRIVCRT_KEYSPEC_CLS)) {
// All supported keyspecs (other than PKCS8_KEYSPEC_CLS) descend from RSA_PRIVCRT_KEYSPEC_CLS
if (key instanceof RSAPrivateCrtKey) {

View file

@ -31,6 +31,7 @@ import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import java.util.Arrays;
import sun.security.util.*;
@ -192,20 +193,44 @@ public final class RSAPrivateCrtKeyImpl
this.keyParams = keyParams;
try {
// generate the key encoding
DerOutputStream out = new DerOutputStream();
byte[][] nbytes = new byte[8][];
nbytes[0] = n.toByteArray();
nbytes[1] = e.toByteArray();
nbytes[2] = d.toByteArray();
nbytes[3] = p.toByteArray();
nbytes[4] = q.toByteArray();
nbytes[5] = pe.toByteArray();
nbytes[6] = qe.toByteArray();
nbytes[7] = coeff.toByteArray();
// Initiate with a big enough size so there's no need to
// reallocate memory later and thus can be cleaned up
// reliably.
DerOutputStream out = new DerOutputStream(
nbytes[0].length + nbytes[1].length +
nbytes[2].length + nbytes[3].length +
nbytes[4].length + nbytes[5].length +
nbytes[6].length + nbytes[7].length +
100); // Enough for version(3) and 8 tag+length(3 or 4)
out.putInteger(0); // version must be 0
out.putInteger(n);
out.putInteger(e);
out.putInteger(d);
out.putInteger(p);
out.putInteger(q);
out.putInteger(pe);
out.putInteger(qe);
out.putInteger(coeff);
DerValue val =
new DerValue(DerValue.tag_Sequence, out.toByteArray());
out.putInteger(nbytes[0]);
out.putInteger(nbytes[1]);
out.putInteger(nbytes[2]);
out.putInteger(nbytes[3]);
out.putInteger(nbytes[4]);
out.putInteger(nbytes[5]);
out.putInteger(nbytes[6]);
out.putInteger(nbytes[7]);
// Private values from [2] on.
Arrays.fill(nbytes[2], (byte)0);
Arrays.fill(nbytes[3], (byte)0);
Arrays.fill(nbytes[4], (byte)0);
Arrays.fill(nbytes[5], (byte)0);
Arrays.fill(nbytes[6], (byte)0);
Arrays.fill(nbytes[7], (byte)0);
DerValue val = DerValue.wrap(DerValue.tag_Sequence, out);
key = val.toByteArray();
val.clear();
} catch (IOException exc) {
// should never occur
throw new InvalidKeyException(exc);
@ -285,29 +310,33 @@ public final class RSAPrivateCrtKeyImpl
// e, d, p, q, pe, qe, and coeff, and return the parsed components.
private static BigInteger[] parseASN1(byte[] raw) throws IOException {
DerValue derValue = new DerValue(raw);
if (derValue.tag != DerValue.tag_Sequence) {
throw new IOException("Not a SEQUENCE");
}
int version = derValue.data.getInteger();
if (version != 0) {
throw new IOException("Version must be 0");
}
try {
if (derValue.tag != DerValue.tag_Sequence) {
throw new IOException("Not a SEQUENCE");
}
int version = derValue.data.getInteger();
if (version != 0) {
throw new IOException("Version must be 0");
}
BigInteger[] result = new BigInteger[8]; // n, e, d, p, q, pe, qe, coeff
/*
* Some implementations do not correctly encode ASN.1 INTEGER values
* in 2's complement format, resulting in a negative integer when
* decoded. Correct the error by converting it to a positive integer.
*
* See CR 6255949
*/
for (int i = 0; i < result.length; i++) {
result[i] = derValue.data.getPositiveBigInteger();
BigInteger[] result = new BigInteger[8]; // n, e, d, p, q, pe, qe, coeff
/*
* Some implementations do not correctly encode ASN.1 INTEGER values
* in 2's complement format, resulting in a negative integer when
* decoded. Correct the error by converting it to a positive integer.
*
* See CR 6255949
*/
for (int i = 0; i < result.length; i++) {
result[i] = derValue.data.getPositiveBigInteger();
}
if (derValue.data.available() != 0) {
throw new IOException("Extra data available");
}
return result;
} finally {
derValue.clear();
}
if (derValue.data.available() != 0) {
throw new IOException("Extra data available");
}
return result;
}
private void parseKeyBits() throws InvalidKeyException {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,6 +31,7 @@ import java.math.BigInteger;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.security.interfaces.*;
import java.util.Arrays;
import sun.security.util.*;
import sun.security.pkcs.PKCS8Key;
@ -90,19 +91,25 @@ public final class RSAPrivateKeyImpl extends PKCS8Key implements RSAPrivateKey {
try {
// generate the key encoding
DerOutputStream out = new DerOutputStream();
byte[] nbytes = n.toByteArray();
byte[] dbytes = d.toByteArray();
DerOutputStream out = new DerOutputStream(
nbytes.length + dbytes.length + 50);
// Enough for 7 zeroes (21) and 2 tag+length(4)
out.putInteger(0); // version must be 0
out.putInteger(n);
out.putInteger(nbytes);
Arrays.fill(nbytes, (byte)0);
out.putInteger(0);
out.putInteger(d);
out.putInteger(dbytes);
Arrays.fill(dbytes, (byte)0);
out.putInteger(0);
out.putInteger(0);
out.putInteger(0);
out.putInteger(0);
out.putInteger(0);
DerValue val =
new DerValue(DerValue.tag_Sequence, out.toByteArray());
DerValue val = DerValue.wrap(DerValue.tag_Sequence, out);
key = val.toByteArray();
val.clear();
} catch (IOException exc) {
// should never occur
throw new InvalidKeyException(exc);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -169,6 +169,17 @@ extends ByteArrayOutputStream implements DerEncoder {
write(buf, 0, buf.length);
}
/**
* Marshals a DER integer on the output stream.
*
* @param i the integer in bytes, equivalent to BigInteger::toByteArray.
*/
public void putInteger(byte[] buf) throws IOException {
write(DerValue.tag_Integer);
putLength(buf.length);
write(buf, 0, buf.length);
}
/**
* Marshals a DER integer on the output stream.
* @param i the integer in the form of an Integer.
@ -575,4 +586,8 @@ extends ByteArrayOutputStream implements DerEncoder {
public void derEncode(OutputStream out) throws IOException {
out.write(toByteArray());
}
byte[] buf() {
return buf;
}
}

View file

@ -286,6 +286,22 @@ public class DerValue {
this(tag, buffer.clone(), true);
}
/**
* Wraps an DerOutputStream. All bytes currently written
* into the stream will become the content of the newly
* created DerValue.
*
* Attention: do not reset the DerOutputStream after this call.
* No array copying is made.
*
* @param tag the tag
* @param out the DerOutputStream
* @returns a new DerValue using out as its content
*/
public static DerValue wrap(byte tag, DerOutputStream out) {
return new DerValue(tag, out.buf(), 0, out.size(), false);
}
/**
* Parse an ASN.1/BER encoded datum. The entire encoding must hold exactly
* one datum, including its tag and length.
@ -1072,10 +1088,15 @@ public class DerValue {
* @return DER-encoded value, including tag and length.
*/
public byte[] toByteArray() throws IOException {
data.pos = data.start; // Compatibility. At head.
// Minimize content duplication by writing out tag and length only
DerOutputStream out = new DerOutputStream();
encode(out);
data.pos = data.start; // encode go last, should go back
return out.toByteArray();
out.write(tag);
out.putLength(end - start);
int headLen = out.size();
byte[] result = Arrays.copyOf(out.buf(), end - start + headLen);
System.arraycopy(buffer, start, result, headLen, end - start);
return result;
}
/**
@ -1216,4 +1237,8 @@ public class DerValue {
}
return result.toArray(new DerValue[0]);
}
public void clear() {
Arrays.fill(buffer, start, end, (byte)0);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,8 @@
package sun.security.util;
import jdk.internal.access.SharedSecrets;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
@ -122,8 +124,11 @@ public final class ECUtil {
throws InvalidKeySpecException {
KeyFactory keyFactory = getKeyFactory();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
return (ECPrivateKey)keyFactory.generatePrivate(keySpec);
try {
return (ECPrivateKey) keyFactory.generatePrivate(keySpec);
} finally {
SharedSecrets.getJavaSecuritySpecAccess().clearEncodedKeySpec(keySpec);
}
}
public static ECPrivateKey generateECPrivateKey(BigInteger s,

View file

@ -47,6 +47,7 @@ import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;
import java.math.BigInteger;
import java.security.spec.NamedParameterSpec;
import java.util.Arrays;
import sun.security.jca.JCAUtil;
@ -82,8 +83,12 @@ public final class KeyUtil {
if (key instanceof SecretKey) {
SecretKey sk = (SecretKey)key;
String format = sk.getFormat();
if ("RAW".equals(format) && sk.getEncoded() != null) {
size = (sk.getEncoded().length * 8);
if ("RAW".equals(format)) {
byte[] encoded = sk.getEncoded();
if (encoded != null) {
size = (encoded.length * 8);
Arrays.fill(encoded, (byte)0);
}
} // Otherwise, it may be a unextractable key of PKCS#11, or
// a key we are not able to handle.
} else if (key instanceof RSAKey) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -100,32 +100,6 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
@Deprecated
public AlgIdDSA () {}
AlgIdDSA (DerValue val) throws IOException
{ super(val.getOID()); }
/**
* Construct an AlgIdDSA from an X.509 encoded byte array.
*/
public AlgIdDSA (byte[] encodedAlg) throws IOException
{ super (new DerValue(encodedAlg).getOID()); }
/**
* Constructs a DSS/DSA Algorithm ID from unsigned integers that
* define the algorithm parameters. Those integers are encoded
* as big-endian byte arrays.
*
* @param p the DSS/DSA parameter "P"
* @param q the DSS/DSA parameter "Q"
* @param g the DSS/DSA parameter "G"
*/
public AlgIdDSA (byte[] p, byte[] q, byte[] g)
throws IOException
{
this (new BigInteger (1, p),
new BigInteger (1, q),
new BigInteger (1, g));
}
/**
* Constructs a DSS/DSA Algorithm ID from numeric parameters.
* If all three are null, then the parameters portion of the algorithm id
@ -135,8 +109,7 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
* @param q the DSS/DSA parameter "Q"
* @param g the DSS/DSA parameter "G"
*/
public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g)
{
public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) {
super (DSA_oid);
if (p != null || q != null || g != null) {
@ -168,28 +141,29 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
* For algorithm IDs which haven't been created from a DER encoded
* value, "params" must be created.
*/
private void initializeParams ()
throws IOException
{
DerOutputStream out = new DerOutputStream ();
private void initializeParams () throws IOException {
DerOutputStream out = new DerOutputStream();
out.putInteger(p);
out.putInteger(q);
out.putInteger(g);
params = new DerValue (DerValue.tag_Sequence,out.toByteArray ());
DerOutputStream result = new DerOutputStream();
result.write(DerValue.tag_Sequence, out);
encodedParams = result.toByteArray();
}
/**
* Parses algorithm parameters P, Q, and G. They're found
* in the "params" member, which never needs to be changed.
*/
protected void decodeParams ()
throws IOException
{
if (params == null)
protected void decodeParams () throws IOException {
if (encodedParams == null) {
throw new IOException("DSA alg params are null");
if (params.tag != DerValue.tag_Sequence)
throw new IOException("DSA alg parsing error");
}
DerValue params = new DerValue(encodedParams);
if (params.tag != DerValue.tag_Sequence) {
throw new IOException("DSA alg parsing error");
}
params.data.reset ();
@ -206,21 +180,21 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
/*
* Returns a formatted string describing the parameters.
*/
public String toString ()
{ return paramsToString (); }
public String toString () {
return paramsToString();
}
/*
* Returns a string describing the parameters.
*/
protected String paramsToString ()
{
if (params == null)
protected String paramsToString () {
if (encodedParams == null) {
return " null\n";
else
return
"\n p:\n" + Debug.toHexString(p) +
"\n q:\n" + Debug.toHexString(q) +
"\n g:\n" + Debug.toHexString(g) +
"\n";
} else {
return "\n p:\n" + Debug.toHexString(p) +
"\n q:\n" + Debug.toHexString(q) +
"\n g:\n" + Debug.toHexString(g) +
"\n";
}
}
}

View file

@ -70,17 +70,13 @@ public class AlgorithmId implements Serializable, DerEncoder {
// The (parsed) parameters
@SuppressWarnings("serial") // Not statically typed as Serializable
private AlgorithmParameters algParams;
private boolean constructedFromDer = true;
/**
* Parameters for this algorithm. These are stored in unparsed
* DER-encoded form; subclasses can be made to automaticaly parse
* them so there is fast access to these parameters.
*/
@SuppressWarnings("serial") // Not statically typed as Serializable
protected DerValue params;
private transient byte[] encodedParams;
protected transient byte[] encodedParams;
/**
* Constructs an algorithm ID which will be initialized
@ -107,17 +103,14 @@ public class AlgorithmId implements Serializable, DerEncoder {
*/
public AlgorithmId(ObjectIdentifier oid, AlgorithmParameters algparams) {
algid = oid;
algParams = algparams;
constructedFromDer = false;
this.algParams = algparams;
if (algParams != null) {
try {
encodedParams = algParams.getEncoded();
} catch (IOException ioe) {
// It should be safe to ignore this.
// This exception can occur if AlgorithmParameters was not
// initialized (which should not occur), or if it was
// initialized with bogus parameters, which should have
// been detected when init was called.
// Ignore this at the moment. This exception can occur
// if AlgorithmParameters was not initialized yet. Will
// try to re-getEncoded() again later.
}
}
}
@ -131,8 +124,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
public AlgorithmId(ObjectIdentifier oid, DerValue params)
throws IOException {
this.algid = oid;
this.params = params;
if (this.params != null) {
if (params != null) {
encodedParams = params.toByteArray();
decodeParams();
}
@ -177,20 +169,14 @@ public class AlgorithmId implements Serializable, DerEncoder {
DerOutputStream tmp = new DerOutputStream();
bytes.putOID(algid);
// Setup params from algParams since no DER encoding is given
if (constructedFromDer == false) {
if (algParams != null) {
if (encodedParams == null) {
// call getEncoded again in case algParams were initialized
// after being passed in to ctor.
encodedParams = algParams.getEncoded();
}
params = new DerValue(encodedParams);
} else {
params = null;
}
// Re-getEncoded() from algParams if it was not initialized
if (algParams != null && encodedParams == null) {
encodedParams = algParams.getEncoded();
// If still not initialized. Let the IOE be thrown.
}
if (params == null) {
if (encodedParams == null) {
// Changes backed out for compatibility with Solaris
// Several AlgorithmId should omit the whole parameter part when
@ -242,7 +228,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
bytes.putNull();
}
} else {
bytes.putDerValue(params);
bytes.write(encodedParams);
}
tmp.write(DerValue.tag_Sequence, bytes);
out.write(tmp.toByteArray());
@ -285,7 +271,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
// first check the list of support oids
KnownOIDs o = KnownOIDs.findMatch(oidStr);
if (o == KnownOIDs.SpecifiedSHA2withECDSA) {
if (params != null) {
if (encodedParams != null) {
try {
AlgorithmId digestParams =
AlgorithmId.parse(new DerValue(encodedParams));