< 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 >