< prev index next >
src/java.base/share/classes/com/sun/crypto/provider/JceKeyStore.java
Print this page
rev 52903 : 8234027: Better JCEKS key support
Reviewed-by: ahgross, mullan, rriggs, rhalade
*** 77,86 ****
--- 77,92 ----
// Secret key
private static final class SecretKeyEntry {
Date date; // the creation date of this entry
SealedObject sealedKey;
+
+ // Maximum possible length of sealedKey. Used to detect malicious
+ // input data. This field is set to the file length of the keystore
+ // at loading. It is useless when creating a new SecretKeyEntry
+ // to be store in a keystore.
+ int maxLength;
}
// Trusted certificate
private static final class TrustedCertEntry {
Date date; // the creation date of this entry
*** 132,143 ****
+ "as PKCS #8 " +
"EncryptedPrivateKeyInfo");
}
key = keyProtector.recover(encrInfo);
} else {
! key =
! keyProtector.unseal(((SecretKeyEntry)entry).sealedKey);
}
return key;
}
--- 138,149 ----
+ "as PKCS #8 " +
"EncryptedPrivateKeyInfo");
}
key = keyProtector.recover(encrInfo);
} else {
! SecretKeyEntry ske = ((SecretKeyEntry)entry);
! key = keyProtector.unseal(ske.sealedKey, ske.maxLength);
}
return key;
}
*** 278,287 ****
--- 284,294 ----
SecretKeyEntry entry = new SecretKeyEntry();
entry.date = new Date();
// seal and store the key
entry.sealedKey = keyProtector.seal(key);
+ entry.maxLength = Integer.MAX_VALUE;
entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
}
} catch (Exception e) {
throw new KeyStoreException(e.getMessage());
*** 687,696 ****
--- 694,707 ----
int trustedKeyCount = 0, privateKeyCount = 0, secretKeyCount = 0;
if (stream == null)
return;
+ byte[] allData = stream.readAllBytes();
+ int fullLength = allData.length;
+
+ stream = new ByteArrayInputStream(allData);
if (password != null) {
md = getPreKeyedHash(password);
dis = new DataInputStream(new DigestInputStream(stream, md));
} else {
dis = new DataInputStream(stream);
*** 825,838 ****
final ObjectInputStream ois2 = ois;
// Set a deserialization checker
AccessController.doPrivileged(
(PrivilegedAction<Void>)() -> {
ois2.setObjectInputFilter(
! new DeserializationChecker());
return null;
});
entry.sealedKey = (SealedObject)ois.readObject();
// NOTE: don't close ois here since we are still
// using dis!!!
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe.getMessage());
} catch (InvalidClassException ice) {
--- 836,850 ----
final ObjectInputStream ois2 = ois;
// Set a deserialization checker
AccessController.doPrivileged(
(PrivilegedAction<Void>)() -> {
ois2.setObjectInputFilter(
! new DeserializationChecker(fullLength));
return null;
});
entry.sealedKey = (SealedObject)ois.readObject();
+ entry.maxLength = fullLength;
// NOTE: don't close ois here since we are still
// using dis!!!
} catch (ClassNotFoundException cnfe) {
throw new IOException(cnfe.getMessage());
} catch (InvalidClassException ice) {
*** 921,940 ****
--- 933,962 ----
/*
* An ObjectInputFilter that checks the format of the secret key being
* deserialized.
*/
private static class DeserializationChecker implements ObjectInputFilter {
+
private static final int MAX_NESTED_DEPTH = 2;
+ // Full length of keystore, anything inside a SecretKeyEntry should not
+ // be bigger. Otherwise, must be illegal.
+ private final int fullLength;
+
+ public DeserializationChecker(int fullLength) {
+ this.fullLength = fullLength;
+ }
+
@Override
public ObjectInputFilter.Status
checkInput(ObjectInputFilter.FilterInfo info) {
// First run a custom filter
long nestedDepth = info.depth();
if ((nestedDepth == 1 &&
info.serialClass() != SealedObjectForKeyProtector.class) ||
+ info.arrayLength() > fullLength ||
(nestedDepth > MAX_NESTED_DEPTH &&
info.serialClass() != null &&
info.serialClass() != Object.class)) {
return Status.REJECTED;
}
< prev index next >