提交 7e7b76aa 编写于 作者: Y yan

8234027: Better JCEKS key support

Reviewed-by: andrew
上级 1503a09b
...@@ -81,6 +81,12 @@ public final class JceKeyStore extends KeyStoreSpi { ...@@ -81,6 +81,12 @@ public final class JceKeyStore extends KeyStoreSpi {
private static final class SecretKeyEntry { private static final class SecretKeyEntry {
Date date; // the creation date of this entry Date date; // the creation date of this entry
SealedObject sealedKey; 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 // Trusted certificate
...@@ -136,8 +142,8 @@ public final class JceKeyStore extends KeyStoreSpi { ...@@ -136,8 +142,8 @@ public final class JceKeyStore extends KeyStoreSpi {
} }
key = keyProtector.recover(encrInfo); key = keyProtector.recover(encrInfo);
} else { } else {
key = SecretKeyEntry ske = ((SecretKeyEntry)entry);
keyProtector.unseal(((SecretKeyEntry)entry).sealedKey); key = keyProtector.unseal(ske.sealedKey, ske.maxLength);
} }
return key; return key;
...@@ -282,6 +288,7 @@ public final class JceKeyStore extends KeyStoreSpi { ...@@ -282,6 +288,7 @@ public final class JceKeyStore extends KeyStoreSpi {
// seal and store the key // seal and store the key
entry.sealedKey = keyProtector.seal(key); entry.sealedKey = keyProtector.seal(key);
entry.maxLength = Integer.MAX_VALUE;
entries.put(alias.toLowerCase(Locale.ENGLISH), entry); entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
} }
...@@ -691,6 +698,10 @@ public final class JceKeyStore extends KeyStoreSpi { ...@@ -691,6 +698,10 @@ public final class JceKeyStore extends KeyStoreSpi {
if (stream == null) if (stream == null)
return; return;
byte[] allData = IOUtils.readAllBytes(stream);
int fullLength = allData.length;
stream = new ByteArrayInputStream(allData);
if (password != null) { if (password != null) {
md = getPreKeyedHash(password); md = getPreKeyedHash(password);
dis = new DataInputStream(new DigestInputStream(stream, md)); dis = new DataInputStream(new DigestInputStream(stream, md));
...@@ -829,10 +840,11 @@ public final class JceKeyStore extends KeyStoreSpi { ...@@ -829,10 +840,11 @@ public final class JceKeyStore extends KeyStoreSpi {
AccessController.doPrivileged( AccessController.doPrivileged(
(PrivilegedAction<Void>)() -> { (PrivilegedAction<Void>)() -> {
ObjectInputFilter.Config.setObjectInputFilter( ObjectInputFilter.Config.setObjectInputFilter(
ois2, new DeserializationChecker()); ois2, new DeserializationChecker(fullLength));
return null; return null;
}); });
entry.sealedKey = (SealedObject)ois.readObject(); entry.sealedKey = (SealedObject)ois.readObject();
entry.maxLength = fullLength;
// NOTE: don't close ois here since we are still // NOTE: don't close ois here since we are still
// using dis!!! // using dis!!!
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
...@@ -909,8 +921,17 @@ public final class JceKeyStore extends KeyStoreSpi { ...@@ -909,8 +921,17 @@ public final class JceKeyStore extends KeyStoreSpi {
* deserialized. * deserialized.
*/ */
private static class DeserializationChecker implements ObjectInputFilter { private static class DeserializationChecker implements ObjectInputFilter {
private static final int MAX_NESTED_DEPTH = 2; 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 @Override
public ObjectInputFilter.Status public ObjectInputFilter.Status
checkInput(ObjectInputFilter.FilterInfo info) { checkInput(ObjectInputFilter.FilterInfo info) {
...@@ -919,6 +940,7 @@ public final class JceKeyStore extends KeyStoreSpi { ...@@ -919,6 +940,7 @@ public final class JceKeyStore extends KeyStoreSpi {
long nestedDepth = info.depth(); long nestedDepth = info.depth();
if ((nestedDepth == 1 && if ((nestedDepth == 1 &&
info.serialClass() != SealedObjectForKeyProtector.class) || info.serialClass() != SealedObjectForKeyProtector.class) ||
info.arrayLength() > fullLength ||
(nestedDepth > MAX_NESTED_DEPTH && (nestedDepth > MAX_NESTED_DEPTH &&
info.serialClass() != null && info.serialClass() != null &&
info.serialClass() != Object.class)) { info.serialClass() != Object.class)) {
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -352,8 +352,11 @@ final class KeyProtector { ...@@ -352,8 +352,11 @@ final class KeyProtector {
/** /**
* Unseals the sealed key. * 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 { throws NoSuchAlgorithmException, UnrecoverableKeyException {
SecretKey sKey = null; SecretKey sKey = null;
try { try {
...@@ -388,7 +391,7 @@ final class KeyProtector { ...@@ -388,7 +391,7 @@ final class KeyProtector {
SunJCE.getInstance(), SunJCE.getInstance(),
"PBEWithMD5AndTripleDES"); "PBEWithMD5AndTripleDES");
cipher.init(Cipher.DECRYPT_MODE, sKey, params); cipher.init(Cipher.DECRYPT_MODE, sKey, params);
return soForKeyProtector.getKey(cipher); return soForKeyProtector.getKey(cipher, maxLength);
} catch (NoSuchAlgorithmException ex) { } catch (NoSuchAlgorithmException ex) {
// Note: this catch needed to be here because of the // Note: this catch needed to be here because of the
// later catch of GeneralSecurityException // later catch of GeneralSecurityException
......
...@@ -73,7 +73,7 @@ final class SealedObjectForKeyProtector extends SealedObject { ...@@ -73,7 +73,7 @@ final class SealedObjectForKeyProtector extends SealedObject {
return params; return params;
} }
final Key getKey(Cipher c) final Key getKey(Cipher c, int maxLength)
throws IOException, ClassNotFoundException, IllegalBlockSizeException, throws IOException, ClassNotFoundException, IllegalBlockSizeException,
BadPaddingException { BadPaddingException {
...@@ -82,7 +82,7 @@ final class SealedObjectForKeyProtector extends SealedObject { ...@@ -82,7 +82,7 @@ final class SealedObjectForKeyProtector extends SealedObject {
AccessController.doPrivileged( AccessController.doPrivileged(
(PrivilegedAction<Void>) () -> { (PrivilegedAction<Void>) () -> {
ObjectInputFilter.Config.setObjectInputFilter(ois, ObjectInputFilter.Config.setObjectInputFilter(ois,
DeserializationChecker.ONE_FILTER); new DeserializationChecker(maxLength));
return null; return null;
}); });
try { try {
...@@ -110,7 +110,7 @@ final class SealedObjectForKeyProtector extends SealedObject { ...@@ -110,7 +110,7 @@ final class SealedObjectForKeyProtector extends SealedObject {
*/ */
private static class DeserializationChecker implements ObjectInputFilter { private static class DeserializationChecker implements ObjectInputFilter {
private static final ObjectInputFilter ONE_FILTER; private static final ObjectInputFilter OWN_FILTER;
static { static {
String prop = AccessController.doPrivileged( String prop = AccessController.doPrivileged(
...@@ -122,26 +122,32 @@ final class SealedObjectForKeyProtector extends SealedObject { ...@@ -122,26 +122,32 @@ final class SealedObjectForKeyProtector extends SealedObject {
return Security.getProperty(KEY_SERIAL_FILTER); return Security.getProperty(KEY_SERIAL_FILTER);
} }
}); });
ONE_FILTER = new DeserializationChecker(prop == null ? null OWN_FILTER = prop == null
: ObjectInputFilter.Config.createFilter(prop)); ? null
: ObjectInputFilter.Config.createFilter(prop);
} }
private final ObjectInputFilter base; // Maximum possible length of anything inside
private final int maxLength;
private DeserializationChecker(ObjectInputFilter base) { private DeserializationChecker(int maxLength) {
this.base = base; this.maxLength = maxLength;
} }
@Override @Override
public ObjectInputFilter.Status checkInput( public ObjectInputFilter.Status checkInput(
ObjectInputFilter.FilterInfo info) { ObjectInputFilter.FilterInfo info) {
if (info.arrayLength() > maxLength) {
return Status.REJECTED;
}
if (info.serialClass() == Object.class) { if (info.serialClass() == Object.class) {
return Status.UNDECIDED; return Status.UNDECIDED;
} }
if (base != null) { if (OWN_FILTER != null) {
Status result = base.checkInput(info); Status result = OWN_FILTER.checkInput(info);
if (result != Status.UNDECIDED) { if (result != Status.UNDECIDED) {
return result; return result;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册