mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8189997: Enhance keystore mechanisms
8194259: keytool error: java.io.IOException: Invalid secret key format Reviewed-by: mullan, valeriep, rriggs, ahgross
This commit is contained in:
parent
3d7092e9a2
commit
8fb70c710a
7 changed files with 163 additions and 68 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2018, 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
|
||||
|
@ -943,8 +943,10 @@ public final class JceKeyStore extends KeyStoreSpi {
|
|||
// First run a custom filter
|
||||
long nestedDepth = info.depth();
|
||||
if ((nestedDepth == 1 &&
|
||||
info.serialClass() != SealedObjectForKeyProtector.class) ||
|
||||
nestedDepth > MAX_NESTED_DEPTH) {
|
||||
info.serialClass() != SealedObjectForKeyProtector.class) ||
|
||||
(nestedDepth > MAX_NESTED_DEPTH &&
|
||||
info.serialClass() != null &&
|
||||
info.serialClass() != Object.class)) {
|
||||
return Status.REJECTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2018, 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
|
||||
|
@ -26,8 +26,6 @@
|
|||
package com.sun.crypto.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.security.Security;
|
||||
import java.security.Key;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Provider;
|
||||
|
@ -35,7 +33,6 @@ import java.security.KeyFactory;
|
|||
import java.security.MessageDigest;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
|
@ -44,7 +41,6 @@ import java.security.spec.PKCS8EncodedKeySpec;
|
|||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherSpi;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.SealedObject;
|
||||
import javax.crypto.spec.*;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
|
@ -347,7 +343,7 @@ final class KeyProtector {
|
|||
SunJCE.getInstance(),
|
||||
"PBEWithMD5AndTripleDES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, skey, params);
|
||||
return (Key)soForKeyProtector.getObject(cipher);
|
||||
return soForKeyProtector.getKey(cipher);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
// Note: this catch needed to be here because of the
|
||||
// later catch of GeneralSecurityException
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2018, 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 com.sun.crypto.provider;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.*;
|
||||
import javax.crypto.*;
|
||||
|
@ -33,6 +35,16 @@ final class SealedObjectForKeyProtector extends SealedObject {
|
|||
|
||||
static final long serialVersionUID = -3650226485480866989L;
|
||||
|
||||
/**
|
||||
* The InputStreamFilter for a Key object inside this SealedObject. It can
|
||||
* be either provided as a {@link Security} property or a system property
|
||||
* (when provided as latter, it shadows the former). If the result of this
|
||||
* filter is {@link java.io.ObjectInputFilter.Status.UNDECIDED}, the system
|
||||
* level filter defined by jdk.serialFilter will be consulted. The value
|
||||
* of this property uses the same format of jdk.serialFilter.
|
||||
*/
|
||||
private static final String KEY_SERIAL_FILTER = "jceks.key.serialFilter";
|
||||
|
||||
SealedObjectForKeyProtector(Serializable object, Cipher c)
|
||||
throws IOException, IllegalBlockSizeException {
|
||||
super(object, c);
|
||||
|
@ -59,4 +71,87 @@ final class SealedObjectForKeyProtector extends SealedObject {
|
|||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
final Key getKey(Cipher c)
|
||||
throws IOException, ClassNotFoundException, IllegalBlockSizeException,
|
||||
BadPaddingException {
|
||||
|
||||
try (ObjectInputStream ois = SharedSecrets.getJavaxCryptoSealedObjectAccess()
|
||||
.getExtObjectInputStream(this, c)) {
|
||||
AccessController.doPrivileged(
|
||||
(PrivilegedAction<Void>) () -> {
|
||||
ois.setObjectInputFilter(DeserializationChecker.ONE_FILTER);
|
||||
return null;
|
||||
});
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Key t = (Key) ois.readObject();
|
||||
return t;
|
||||
} catch (InvalidClassException ice) {
|
||||
String msg = ice.getMessage();
|
||||
if (msg.contains("REJECTED")) {
|
||||
throw new IOException("Rejected by the"
|
||||
+ " jceks.key.serialFilter or jdk.serialFilter"
|
||||
+ " property", ice);
|
||||
} else {
|
||||
throw ice;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter for the content of a SealedObjectForKeyProtector.
|
||||
*
|
||||
* First, the jceks.key.serialFilter will be consulted. If the result
|
||||
* is UNDECIDED, the system level jdk.serialFilter will be consulted.
|
||||
*/
|
||||
private static class DeserializationChecker implements ObjectInputFilter {
|
||||
|
||||
private static final ObjectInputFilter ONE_FILTER;
|
||||
|
||||
static {
|
||||
String prop = AccessController.doPrivileged(
|
||||
(PrivilegedAction<String>) () -> {
|
||||
String tmp = System.getProperty(KEY_SERIAL_FILTER);
|
||||
if (tmp != null) {
|
||||
return tmp;
|
||||
} else {
|
||||
return Security.getProperty(KEY_SERIAL_FILTER);
|
||||
}
|
||||
});
|
||||
ONE_FILTER = new DeserializationChecker(prop == null ? null
|
||||
: ObjectInputFilter.Config.createFilter(prop));
|
||||
}
|
||||
|
||||
private final ObjectInputFilter base;
|
||||
|
||||
private DeserializationChecker(ObjectInputFilter base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectInputFilter.Status checkInput(
|
||||
ObjectInputFilter.FilterInfo info) {
|
||||
|
||||
if (info.serialClass() == Object.class) {
|
||||
return Status.UNDECIDED;
|
||||
}
|
||||
|
||||
if (base != null) {
|
||||
Status result = base.checkInput(info);
|
||||
if (result != Status.UNDECIDED) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectInputFilter defaultFilter =
|
||||
ObjectInputFilter.Config.getSerialFilter();
|
||||
if (defaultFilter != null) {
|
||||
return defaultFilter.checkInput(info);
|
||||
}
|
||||
|
||||
return Status.UNDECIDED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2018, 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 javax.crypto;
|
||||
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.Key;
|
||||
|
@ -287,17 +289,7 @@ public class SealedObject implements Serializable {
|
|||
throws IOException, ClassNotFoundException, IllegalBlockSizeException,
|
||||
BadPaddingException
|
||||
{
|
||||
/*
|
||||
* Unseal the object
|
||||
*/
|
||||
byte[] content = c.doFinal(this.encryptedContent);
|
||||
|
||||
/*
|
||||
* De-serialize it
|
||||
*/
|
||||
// creating a stream pipe-line, from b to a
|
||||
ByteArrayInputStream b = new ByteArrayInputStream(content);
|
||||
ObjectInput a = new extObjectInputStream(b);
|
||||
ObjectInput a = getExtObjectInputStream(c);
|
||||
try {
|
||||
Object obj = a.readObject();
|
||||
return obj;
|
||||
|
@ -417,17 +409,7 @@ public class SealedObject implements Serializable {
|
|||
throw new RuntimeException(iape.getMessage());
|
||||
}
|
||||
|
||||
/*
|
||||
* Unseal the object
|
||||
*/
|
||||
byte[] content = c.doFinal(this.encryptedContent);
|
||||
|
||||
/*
|
||||
* De-serialize it
|
||||
*/
|
||||
// creating a stream pipe-line, from b to a
|
||||
ByteArrayInputStream b = new ByteArrayInputStream(content);
|
||||
ObjectInput a = new extObjectInputStream(b);
|
||||
ObjectInput a = getExtObjectInputStream(c);
|
||||
try {
|
||||
Object obj = a.readObject();
|
||||
return obj;
|
||||
|
@ -450,6 +432,19 @@ public class SealedObject implements Serializable {
|
|||
if (encodedParams != null)
|
||||
encodedParams = encodedParams.clone();
|
||||
}
|
||||
|
||||
// This method is also called inside SealedObjectForKeyProtector.java.
|
||||
private ObjectInputStream getExtObjectInputStream(Cipher c)
|
||||
throws BadPaddingException, IllegalBlockSizeException, IOException {
|
||||
|
||||
byte[] content = c.doFinal(this.encryptedContent);
|
||||
ByteArrayInputStream b = new ByteArrayInputStream(content);
|
||||
return new extObjectInputStream(b);
|
||||
}
|
||||
|
||||
static {
|
||||
SharedSecrets.setJavaxCryptoSealedObjectAccess((obj,c) -> obj.getExtObjectInputStream(c));
|
||||
}
|
||||
}
|
||||
|
||||
final class extObjectInputStream extends ObjectInputStream {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 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
|
||||
|
@ -22,43 +22,17 @@
|
|||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.internal.misc;
|
||||
|
||||
package com.sun.crypto.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.SealedObject;
|
||||
import javax.crypto.spec.*;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
/**
|
||||
* This class is introduced to workaround a problem in
|
||||
* the SunJCE provider shipped in JCE 1.2.1: the class
|
||||
* SealedObjectForKeyProtector was obfuscated due to a mistake.
|
||||
*
|
||||
* In order to retrieve secret keys in a JCEKS KeyStore written
|
||||
* by the SunJCE provider in JCE 1.2.1, this class will be used.
|
||||
*
|
||||
* @author Valerie Peng
|
||||
*
|
||||
*
|
||||
* @see JceKeyStore
|
||||
*/
|
||||
|
||||
final class ai extends javax.crypto.SealedObject {
|
||||
|
||||
static final long serialVersionUID = -7051502576727967444L;
|
||||
|
||||
ai(SealedObject so) {
|
||||
super(so);
|
||||
}
|
||||
|
||||
Object readResolve() throws ObjectStreamException {
|
||||
return new SealedObjectForKeyProtector(this);
|
||||
}
|
||||
public interface JavaxCryptoSealedObjectAccess {
|
||||
ObjectInputStream getExtObjectInputStream(
|
||||
SealedObject sealed, Cipher cipher)
|
||||
throws BadPaddingException, IllegalBlockSizeException, IOException;
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package jdk.internal.misc;
|
||||
|
||||
import javax.crypto.SealedObject;
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -71,6 +72,7 @@ public class SharedSecrets {
|
|||
private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
|
||||
private static JavaObjectInputFilterAccess javaObjectInputFilterAccess;
|
||||
private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess;
|
||||
private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;
|
||||
|
||||
public static JavaUtilJarAccess javaUtilJarAccess() {
|
||||
if (javaUtilJarAccess == null) {
|
||||
|
@ -324,4 +326,15 @@ public class SharedSecrets {
|
|||
}
|
||||
return javaIORandomAccessFileAccess;
|
||||
}
|
||||
|
||||
public static void setJavaxCryptoSealedObjectAccess(JavaxCryptoSealedObjectAccess jcsoa) {
|
||||
javaxCryptoSealedObjectAccess = jcsoa;
|
||||
}
|
||||
|
||||
public static JavaxCryptoSealedObjectAccess getJavaxCryptoSealedObjectAccess() {
|
||||
if (javaxCryptoSealedObjectAccess == null) {
|
||||
unsafe.ensureClassInitialized(SealedObject.class);
|
||||
}
|
||||
return javaxCryptoSealedObjectAccess;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue