Mercurial > hg > release > icedtea7-forest-2.6 > jdk
changeset 9929:ff52524db7f5
8234027: Better JCEKS key support
Reviewed-by: andrew
author | yan |
---|---|
date | Sun, 12 Apr 2020 06:25:42 +0100 |
parents | ce46c9dcfd63 |
children | fe2a830bf68a |
files | src/share/classes/com/sun/crypto/provider/JceKeyStore.java src/share/classes/com/sun/crypto/provider/KeyProtector.java src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java |
diffstat | 3 files changed, 47 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java Sun Apr 12 05:14:13 2020 +0100 +++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java Sun Apr 12 06:25:42 2020 +0100 @@ -78,6 +78,12 @@ 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 @@ -133,8 +139,8 @@ } key = keyProtector.recover(encrInfo); } else { - key = - keyProtector.unseal(((SecretKeyEntry)entry).sealedKey); + SecretKeyEntry ske = ((SecretKeyEntry)entry); + key = keyProtector.unseal(ske.sealedKey, ske.maxLength); } return key; @@ -279,6 +285,7 @@ // seal and store the key entry.sealedKey = keyProtector.seal(key); + entry.maxLength = Integer.MAX_VALUE; entries.put(alias.toLowerCase(Locale.ENGLISH), entry); } @@ -687,6 +694,10 @@ if (stream == null) return; + byte[] allData = IOUtils.readAllBytes(stream); + final int fullLength = allData.length; + + stream = new ByteArrayInputStream(allData); if (password != null) { md = getPreKeyedHash(password); dis = new DataInputStream(new DigestInputStream(stream, md)); @@ -826,11 +837,12 @@ @Override public Void run() { ObjectInputFilter.Config.setObjectInputFilter( - ois2, new DeserializationChecker()); + ois2, 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) { @@ -899,8 +911,17 @@ * 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) { @@ -909,6 +930,7 @@ 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)) {
--- a/src/share/classes/com/sun/crypto/provider/KeyProtector.java Sun Apr 12 05:14:13 2020 +0100 +++ b/src/share/classes/com/sun/crypto/provider/KeyProtector.java Sun Apr 12 06:25:42 2020 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -319,8 +319,11 @@ /** * Unseals the sealed key. + * + * @param maxLength Maximum possible length of so. + * If bigger, must be illegal. */ - Key unseal(SealedObject so) + Key unseal(SealedObject so, int maxLength) throws NoSuchAlgorithmException, UnrecoverableKeyException { SecretKey sKey = null; try { @@ -355,7 +358,7 @@ SunJCE.getInstance(), "PBEWithMD5AndTripleDES"); cipher.init(Cipher.DECRYPT_MODE, sKey, params); - return soForKeyProtector.getKey(cipher); + return soForKeyProtector.getKey(cipher, maxLength); } catch (NoSuchAlgorithmException ex) { // Note: this catch needed to be here because of the // later catch of GeneralSecurityException
--- a/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java Sun Apr 12 05:14:13 2020 +0100 +++ b/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java Sun Apr 12 06:25:42 2020 +0100 @@ -73,7 +73,7 @@ return params; } - final Key getKey(Cipher c) + final Key getKey(Cipher c, final int maxLength) throws IOException, ClassNotFoundException, IllegalBlockSizeException, BadPaddingException { @@ -83,7 +83,7 @@ @Override public Void run() { ObjectInputFilter.Config.setObjectInputFilter(ois, - DeserializationChecker.ONE_FILTER); + new DeserializationChecker(maxLength)); return null; } }); @@ -112,7 +112,7 @@ */ private static class DeserializationChecker implements ObjectInputFilter { - private static final ObjectInputFilter ONE_FILTER; + private static final ObjectInputFilter OWN_FILTER; static { String prop = AccessController.doPrivileged(new PrivilegedAction<String>() { @@ -126,26 +126,32 @@ } } }); - ONE_FILTER = new DeserializationChecker(prop == null ? null - : ObjectInputFilter.Config.createFilter(prop)); + OWN_FILTER = prop == null + ? null + : ObjectInputFilter.Config.createFilter(prop); } - private final ObjectInputFilter base; + // Maximum possible length of anything inside + private final int maxLength; - private DeserializationChecker(ObjectInputFilter base) { - this.base = base; + private DeserializationChecker(int maxLength) { + this.maxLength = maxLength; } @Override public ObjectInputFilter.Status checkInput( ObjectInputFilter.FilterInfo info) { + if (info.arrayLength() > maxLength) { + return Status.REJECTED; + } + if (info.serialClass() == Object.class) { return Status.UNDECIDED; } - if (base != null) { - Status result = base.checkInput(info); + if (OWN_FILTER != null) { + Status result = OWN_FILTER.checkInput(info); if (result != Status.UNDECIDED) { return result; }