8076190: Customizing the generation of a PKCS12 keystore

Reviewed-by: mullan
This commit is contained in:
Weijun Wang 2018-12-13 11:16:33 +08:00
parent 0b05ebed2e
commit 9136c7d1d0
19 changed files with 1782 additions and 350 deletions
src/java.base/share
classes
conf/security
test
jdk/sun/security
lib/jdk/test/lib/security

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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,9 +26,7 @@
package com.sun.crypto.provider;
import java.util.Arrays;
import java.nio.ByteBuffer;
import javax.crypto.MacSpi;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.PBEParameterSpec;
@ -36,18 +34,65 @@ import java.security.*;
import java.security.spec.*;
/**
* This is an implementation of the HMAC-PBESHA1 algorithm as defined
* in PKCS#12 v1.0 standard.
* This is an implementation of the HMAC algorithms as defined
* in PKCS#12 v1.1 standard (see RFC 7292 Appendix B.4).
*
* @author Valerie Peng
*/
public final class HmacPKCS12PBESHA1 extends HmacCore {
abstract class HmacPKCS12PBECore extends HmacCore {
public static final class HmacPKCS12PBE_SHA1 extends HmacPKCS12PBECore {
public HmacPKCS12PBE_SHA1() throws NoSuchAlgorithmException {
super("SHA1", 64);
}
}
public static final class HmacPKCS12PBE_SHA224 extends HmacPKCS12PBECore {
public HmacPKCS12PBE_SHA224() throws NoSuchAlgorithmException {
super("SHA-224", 64);
}
}
public static final class HmacPKCS12PBE_SHA256 extends HmacPKCS12PBECore {
public HmacPKCS12PBE_SHA256() throws NoSuchAlgorithmException {
super("SHA-256", 64);
}
}
public static final class HmacPKCS12PBE_SHA384 extends HmacPKCS12PBECore {
public HmacPKCS12PBE_SHA384() throws NoSuchAlgorithmException {
super("SHA-384", 128);
}
}
public static final class HmacPKCS12PBE_SHA512 extends HmacPKCS12PBECore {
public HmacPKCS12PBE_SHA512() throws NoSuchAlgorithmException {
super("SHA-512", 128);
}
}
public static final class HmacPKCS12PBE_SHA512_224 extends HmacPKCS12PBECore {
public HmacPKCS12PBE_SHA512_224() throws NoSuchAlgorithmException {
super("SHA-512/224", 128);
}
}
public static final class HmacPKCS12PBE_SHA512_256 extends HmacPKCS12PBECore {
public HmacPKCS12PBE_SHA512_256() throws NoSuchAlgorithmException {
super("SHA-512/256", 128);
}
}
private final String algorithm;
private final int bl;
/**
* Standard constructor, creates a new HmacSHA1 instance.
*/
public HmacPKCS12PBESHA1() throws NoSuchAlgorithmException {
super("SHA1", 64);
public HmacPKCS12PBECore(String algorithm, int bl) throws NoSuchAlgorithmException {
super(algorithm, bl);
this.algorithm = algorithm;
this.bl = bl;
}
/**
@ -132,7 +177,8 @@ public final class HmacPKCS12PBESHA1 extends HmacCore {
("IterationCount must be a positive number");
}
derivedKey = PKCS12PBECipherCore.derive(passwdChars, salt,
iCount, engineGetMacLength(), PKCS12PBECipherCore.MAC_KEY);
iCount, engineGetMacLength(), PKCS12PBECipherCore.MAC_KEY,
algorithm, bl);
} finally {
Arrays.fill(passwdChars, '\0');
}

@ -314,41 +314,48 @@ abstract class PBES2Parameters extends AlgorithmParametersSpi {
+ "not an ASN.1 OCTET STRING tag");
}
iCount = pBKDF2_params.data.getInteger();
DerValue prf = null;
// keyLength INTEGER (1..MAX) OPTIONAL,
if (pBKDF2_params.data.available() > 0) {
DerValue keyLength = pBKDF2_params.data.getDerValue();
if (keyLength.tag == DerValue.tag_Integer) {
keysize = keyLength.getInteger() * 8; // keysize (in bits)
} else {
// Should be the prf
prf = keyLength;
}
}
// prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
String kdfAlgo = "HmacSHA1";
if (pBKDF2_params.data.available() > 0) {
if (pBKDF2_params.tag == DerValue.tag_Sequence) {
DerValue prf = pBKDF2_params.data.getDerValue();
kdfAlgo_OID = prf.data.getOID();
if (hmacWithSHA1_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA1";
} else if (hmacWithSHA224_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA224";
} else if (hmacWithSHA256_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA256";
} else if (hmacWithSHA384_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA384";
} else if (hmacWithSHA512_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA512";
} else {
if (prf == null) {
if (pBKDF2_params.data.available() > 0) {
prf = pBKDF2_params.data.getDerValue();
}
}
if (prf != null) {
kdfAlgo_OID = prf.data.getOID();
if (hmacWithSHA1_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA1";
} else if (hmacWithSHA224_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA224";
} else if (hmacWithSHA256_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA256";
} else if (hmacWithSHA384_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA384";
} else if (hmacWithSHA512_OID.equals(kdfAlgo_OID)) {
kdfAlgo = "HmacSHA512";
} else {
throw new IOException("PBE parameter parsing error: "
+ "expecting the object identifier for a HmacSHA key "
+ "derivation function");
}
if (prf.data.available() != 0) {
// parameter is 'NULL' for all HmacSHA KDFs
DerValue parameter = prf.data.getDerValue();
if (parameter.tag != DerValue.tag_Null) {
throw new IOException("PBE parameter parsing error: "
+ "expecting the object identifier for a HmacSHA key "
+ "derivation function");
}
if (prf.data.available() != 0) {
// parameter is 'NULL' for all HmacSHA KDFs
DerValue parameter = prf.data.getDerValue();
if (parameter.tag != DerValue.tag_Null) {
throw new IOException("PBE parameter parsing error: "
+ "not an ASN.1 NULL tag");
}
+ "not an ASN.1 NULL tag");
}
}
}

@ -684,8 +684,29 @@ public final class SunJCE extends Provider {
ps("Mac", "HmacSHA512/256",
"com.sun.crypto.provider.HmacCore$HmacSHA512_256",
null, attrs);
ps("Mac", "HmacPBESHA1", "com.sun.crypto.provider.HmacPKCS12PBESHA1",
ps("Mac", "HmacPBESHA1",
"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA1",
null, attrs);
ps("Mac", "HmacPBESHA224",
"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA224",
null, attrs);
ps("Mac", "HmacPBESHA256",
"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA256",
null, attrs);
ps("Mac", "HmacPBESHA384",
"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA384",
null, attrs);
ps("Mac", "HmacPBESHA512",
"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512",
null, attrs);
ps("Mac", "HmacPBESHA512/224",
"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512_224",
null, attrs);
ps("Mac", "HmacPBESHA512/256",
"com.sun.crypto.provider.HmacPKCS12PBECore$HmacPKCS12PBE_SHA512_256",
null, attrs);
// PBMAC1
ps("Mac", "PBEWithHmacSHA1",
"com.sun.crypto.provider.PBMAC1Core$HmacSHA1", null, attrs);

@ -314,14 +314,7 @@ public class KeyStore {
/**
* Gets the name of the protection algorithm.
* If none was set then the keystore provider will use its default
* protection algorithm. The name of the default protection algorithm
* for a given keystore type is set using the
* {@code 'keystore.<type>.keyProtectionAlgorithm'} security property.
* For example, the
* {@code keystore.PKCS12.keyProtectionAlgorithm} property stores the
* name of the default key protection algorithm used for PKCS12
* keystores. If the security property is not set, an
* implementation-specific algorithm will be used.
* protection algorithm.
*
* @return the algorithm name, or {@code null} if none was set
*
@ -1813,8 +1806,8 @@ public class KeyStore {
}
}
throw new KeyStoreException("This keystore does not support probing "
+ "and must be loaded with a specified type");
throw new KeyStoreException("Unrecognized keystore format. "
+ "Please load it with a specified type");
}
/**

@ -53,7 +53,6 @@ import java.util.*;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import javax.crypto.spec.PBEParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
@ -70,6 +69,7 @@ import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
import sun.security.pkcs.ContentInfo;
import sun.security.util.SecurityProperties;
import sun.security.x509.AlgorithmId;
import sun.security.pkcs.EncryptedPrivateKeyInfo;
import sun.security.provider.JavaKeyStore.JKS;
@ -81,9 +81,11 @@ import sun.security.util.KeyStoreDelegator;
* Implements the PKCS#12 PFX protected using the Password privacy mode.
* The contents are protected using Password integrity mode.
*
* Currently we support following PBE algorithms:
* - pbeWithSHAAnd3KeyTripleDESCBC to encrypt private keys
* - pbeWithSHAAnd40BitRC2CBC to encrypt certificates
* Currently these PBE algorithms are used by default:
* - PBEWithSHA1AndDESede to encrypt private keys, iteration count 50000.
* - PBEWithSHA1AndRC2_40 to encrypt certificates, iteration count 50000.
*
* The default Mac algorithm is HmacPBESHA1, iteration count 100000.
*
* Supported encryption of various implementations :
*
@ -126,11 +128,7 @@ import sun.security.util.KeyStoreDelegator;
* @author Jeff Nisewanger
* @author Jan Luehe
*
* @see KeyProtector
* @see java.security.KeyStoreSpi
* @see KeyTool
*
*
*/
public final class PKCS12KeyStore extends KeyStoreSpi {
@ -143,14 +141,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
public static final int VERSION_3 = 3;
private static final String[] KEY_PROTECTION_ALGORITHM = {
"keystore.pkcs12.keyProtectionAlgorithm",
"keystore.PKCS12.keyProtectionAlgorithm"
};
private static final int MAX_ITERATION_COUNT = 5000000;
private static final int PBE_ITERATION_COUNT = 50000; // default
private static final int MAC_ITERATION_COUNT = 100000; // default
private static final int SALT_LEN = 20;
// friendlyName, localKeyId, trustedKeyUsage
@ -171,10 +162,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
private static final int[] pkcs9certType = {1, 2, 840, 113549, 1, 9, 22, 1};
private static final int[] pbeWithSHAAnd40BitRC2CBC =
{1, 2, 840, 113549, 1, 12, 1, 6};
private static final int[] pbeWithSHAAnd3KeyTripleDESCBC =
{1, 2, 840, 113549, 1, 12, 1, 3};
private static final int[] pbes2 = {1, 2, 840, 113549, 1, 5, 13};
// TODO: temporary Oracle OID
/*
@ -185,17 +172,15 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
{2, 16, 840, 1, 113894, 746875, 1, 1};
private static final int[] AnyExtendedKeyUsage = {2, 5, 29, 37, 0};
private static ObjectIdentifier PKCS8ShroudedKeyBag_OID;
private static ObjectIdentifier CertBag_OID;
private static ObjectIdentifier SecretBag_OID;
private static ObjectIdentifier PKCS9FriendlyName_OID;
private static ObjectIdentifier PKCS9LocalKeyId_OID;
private static ObjectIdentifier PKCS9CertType_OID;
private static ObjectIdentifier pbeWithSHAAnd40BitRC2CBC_OID;
private static ObjectIdentifier pbeWithSHAAnd3KeyTripleDESCBC_OID;
private static ObjectIdentifier pbes2_OID;
private static ObjectIdentifier TrustedKeyUsage_OID;
private static ObjectIdentifier[] AnyUsage;
private static final ObjectIdentifier PKCS8ShroudedKeyBag_OID;
private static final ObjectIdentifier CertBag_OID;
private static final ObjectIdentifier SecretBag_OID;
private static final ObjectIdentifier PKCS9FriendlyName_OID;
private static final ObjectIdentifier PKCS9LocalKeyId_OID;
private static final ObjectIdentifier PKCS9CertType_OID;
private static final ObjectIdentifier pbes2_OID;
private static final ObjectIdentifier TrustedKeyUsage_OID;
private static final ObjectIdentifier[] AnyUsage;
private int counter = 0;
@ -210,6 +195,17 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// certificate count
private int certificateCount = 0;
// Alg/params used for *this* keystore. Initialized as -1 for ic and
// null for algorithm names. When an existing file is read, they will be
// assigned inside engineLoad() so storing an existing keystore uses the
// old alg/params. This makes sure if a keystore is created password-less
// it will be password-less forever. Otherwise, engineStore() will read
// the default values. These fields are always reset when load() is called.
private String certProtectionAlgorithm = null;
private int certPbeIterationCount = -1;
private String macAlgorithm = null;
private int macIterationCount = -1;
// the source of randomness
private SecureRandom random;
@ -221,16 +217,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
PKCS9FriendlyName_OID = new ObjectIdentifier(pkcs9Name);
PKCS9LocalKeyId_OID = new ObjectIdentifier(pkcs9KeyId);
PKCS9CertType_OID = new ObjectIdentifier(pkcs9certType);
pbeWithSHAAnd40BitRC2CBC_OID =
new ObjectIdentifier(pbeWithSHAAnd40BitRC2CBC);
pbeWithSHAAnd3KeyTripleDESCBC_OID =
new ObjectIdentifier(pbeWithSHAAnd3KeyTripleDESCBC);
pbes2_OID = new ObjectIdentifier(pbes2);
TrustedKeyUsage_OID = new ObjectIdentifier(TrustedKeyUsage);
AnyUsage = new ObjectIdentifier[]{
new ObjectIdentifier(AnyExtendedKeyUsage)};
} catch (IOException ioe) {
// should not happen
throw new AssertionError("OID not initialized", ioe);
}
}
@ -391,7 +383,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
ic = pbeSpec.getIterationCount();
if (ic > MAX_ITERATION_COUNT) {
throw new IOException("PBE iteration count too large");
throw new IOException("key PBE iteration count too large");
}
} else {
ic = 0;
@ -424,7 +416,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (debug != null) {
debug.println("Retrieved a protected private key at alias" +
" '" + alias + "' (" +
new AlgorithmId(algOid).getName() +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
@ -449,7 +441,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (debug != null) {
debug.println("Retrieved a protected secret key at alias " +
"'" + alias + "' (" +
new AlgorithmId(algOid).getName() +
mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
return tmp;
@ -701,7 +693,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
} catch (Exception nsae) {
throw new KeyStoreException("Key protection " +
throw new KeyStoreException("Key protection" +
" algorithm not found: " + nsae, nsae);
}
}
@ -801,14 +793,13 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
/*
* Generate PBE Algorithm Parameters
*/
private AlgorithmParameters getPBEAlgorithmParameters(String algorithm)
throws IOException
{
private AlgorithmParameters getPBEAlgorithmParameters(
String algorithm, int iterationCount) throws IOException {
AlgorithmParameters algParams = null;
// create PBE parameters from salt and iteration count
PBEParameterSpec paramSpec =
new PBEParameterSpec(getSalt(), PBE_ITERATION_COUNT);
new PBEParameterSpec(getSalt(), iterationCount);
try {
algParams = AlgorithmParameters.getInstance(algorithm);
algParams.init(paramSpec);
@ -871,13 +862,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
/*
* Encrypt private key using Password-based encryption (PBE)
* Encrypt private key or secret key using Password-based encryption (PBE)
* as defined in PKCS#5.
*
* NOTE: By default, pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is
* used to derive the key and IV.
*
* @return encrypted private key encoded as EncryptedPrivateKeyInfo
* @return encrypted private key or secret key encoded as
* EncryptedPrivateKeyInfo
*/
private byte[] encryptPrivateKey(byte[] data,
KeyStore.PasswordProtection passwordProtection)
@ -899,27 +891,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
algParams = AlgorithmParameters.getInstance(algorithm);
algParams.init(algParamSpec);
} else {
algParams = getPBEAlgorithmParameters(algorithm);
algParams = getPBEAlgorithmParameters(algorithm,
defaultKeyPbeIterationCount());
}
} else {
// Check default key protection algorithm for PKCS12 keystores
algorithm = AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
String prop =
Security.getProperty(
KEY_PROTECTION_ALGORITHM[0]);
if (prop == null) {
prop = Security.getProperty(
KEY_PROTECTION_ALGORITHM[1]);
}
return prop;
}
});
if (algorithm == null || algorithm.isEmpty()) {
algorithm = "PBEWithSHA1AndDESede";
}
algParams = getPBEAlgorithmParameters(algorithm);
algorithm = defaultKeyProtectionAlgorithm();
algParams = getPBEAlgorithmParameters(algorithm,
defaultKeyPbeIterationCount());
}
ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm);
@ -977,7 +956,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (algorithm.equals(pbes2_OID) && algParams != null) {
return algParams.toString();
}
return algorithm.toString();
return new AlgorithmId(algorithm).getName();
}
/**
@ -1209,10 +1188,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
public synchronized void engineStore(OutputStream stream, char[] password)
throws IOException, NoSuchAlgorithmException, CertificateException
{
// password is mandatory when storing
if (password == null) {
throw new IllegalArgumentException("password can't be null");
}
// -- Create PFX
DerOutputStream pfx = new DerOutputStream();
@ -1245,16 +1220,28 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// -- create EncryptedContentInfo
if (certificateCount > 0) {
if (certProtectionAlgorithm == null) {
certProtectionAlgorithm = defaultCertProtectionAlgorithm();
}
if (certPbeIterationCount < 0) {
certPbeIterationCount = defaultCertPbeIterationCount();
}
if (debug != null) {
debug.println("Storing " + certificateCount +
" certificate(s) in a PKCS#7 encryptedData");
}
byte[] encrData = createEncryptedData(password);
ContentInfo encrContentInfo =
new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) {
ContentInfo encrContentInfo =
new ContentInfo(ContentInfo.ENCRYPTED_DATA_OID,
new DerValue(encrData));
encrContentInfo.encode(authSafeContentInfo);
encrContentInfo.encode(authSafeContentInfo);
} else {
ContentInfo dataContentInfo = new ContentInfo(encrData);
dataContentInfo.encode(authSafeContentInfo);
}
}
// wrap as SequenceOf ContentInfos
@ -1269,9 +1256,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
pfx.write(authSafeData);
// -- MAC
byte[] macData = calculateMac(password, authenticatedSafe);
pfx.write(macData);
if (macAlgorithm == null) {
macAlgorithm = defaultMacAlgorithm();
}
if (macIterationCount < 0) {
macIterationCount = defaultMacIterationCount();
}
if (!macAlgorithm.equalsIgnoreCase("NONE")) {
byte[] macData = calculateMac(password, authenticatedSafe);
pfx.write(macData);
}
// write PFX to output stream
DerOutputStream pfxout = new DerOutputStream();
pfxout.write(DerValue.tag_Sequence, pfx);
@ -1481,24 +1475,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
return entry.attributes;
}
/*
* Generate Hash.
*/
private byte[] generateHash(byte[] data) throws IOException
{
byte[] digest = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(data);
digest = md.digest();
} catch (Exception e) {
throw new IOException("generateHash failed: " + e, e);
}
return digest;
}
/*
* Calculate MAC using HMAC algorithm (required for password integrity)
*
@ -1509,16 +1485,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
throws IOException
{
byte[] mData = null;
String algName = "SHA1";
String algName = macAlgorithm.substring(7);
try {
// Generate a random salt.
byte[] salt = getSalt();
// generate MAC (MAC key is generated within JCE)
Mac m = Mac.getInstance("HmacPBESHA1");
Mac m = Mac.getInstance(macAlgorithm);
PBEParameterSpec params =
new PBEParameterSpec(salt, MAC_ITERATION_COUNT);
new PBEParameterSpec(salt, macIterationCount);
SecretKey key = getPBEKey(passwd);
m.init(key, params);
m.update(data);
@ -1526,7 +1502,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
// encode as MacData
MacData macData = new MacData(algName, macResult, salt,
MAC_ITERATION_COUNT);
macIterationCount);
DerOutputStream bytes = new DerOutputStream();
bytes.write(macData.getEncoded());
mData = bytes.toByteArray();
@ -1799,15 +1775,19 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
byte[] safeBagData = safeBagValue.toByteArray();
// encrypt the content (EncryptedContentInfo)
byte[] encrContentInfo = encryptContent(safeBagData, password);
if (!certProtectionAlgorithm.equalsIgnoreCase("NONE")) {
byte[] encrContentInfo = encryptContent(safeBagData, password);
// -- SEQUENCE of EncryptedData
DerOutputStream encrData = new DerOutputStream();
DerOutputStream encrDataContent = new DerOutputStream();
encrData.putInteger(0);
encrData.write(encrContentInfo);
encrDataContent.write(DerValue.tag_Sequence, encrData);
return encrDataContent.toByteArray();
// -- SEQUENCE of EncryptedData
DerOutputStream encrData = new DerOutputStream();
DerOutputStream encrDataContent = new DerOutputStream();
encrData.putInteger(0);
encrData.write(encrContentInfo);
encrDataContent.write(DerValue.tag_Sequence, encrData);
return encrDataContent.toByteArray();
} else {
return safeBagData;
}
}
/*
@ -1916,47 +1896,52 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
byte[] encryptedData = null;
// create AlgorithmParameters
AlgorithmParameters algParams =
getPBEAlgorithmParameters("PBEWithSHA1AndRC2_40");
DerOutputStream bytes = new DerOutputStream();
AlgorithmId algId =
new AlgorithmId(pbeWithSHAAnd40BitRC2CBC_OID, algParams);
algId.encode(bytes);
byte[] encodedAlgId = bytes.toByteArray();
try {
// create AlgorithmParameters
AlgorithmParameters algParams = getPBEAlgorithmParameters(
certProtectionAlgorithm, certPbeIterationCount);
DerOutputStream bytes = new DerOutputStream();
// Use JCE
SecretKey skey = getPBEKey(password);
Cipher cipher = Cipher.getInstance("PBEWithSHA1AndRC2_40");
Cipher cipher = Cipher.getInstance(certProtectionAlgorithm);
cipher.init(Cipher.ENCRYPT_MODE, skey, algParams);
encryptedData = cipher.doFinal(data);
AlgorithmId algId = new AlgorithmId(
mapPBEAlgorithmToOID(certProtectionAlgorithm),
cipher.getParameters());
// cipher.getParameters() now has IV
algId.encode(bytes);
byte[] encodedAlgId = bytes.toByteArray();
if (debug != null) {
debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() +
")");
")");
}
// create EncryptedContentInfo
DerOutputStream bytes2 = new DerOutputStream();
bytes2.putOID(ContentInfo.DATA_OID);
bytes2.write(encodedAlgId);
// Wrap encrypted data in a context-specific tag.
DerOutputStream tmpout2 = new DerOutputStream();
tmpout2.putOctetString(encryptedData);
bytes2.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, (byte) 0), tmpout2);
// wrap EncryptedContentInfo in a Sequence
DerOutputStream out = new DerOutputStream();
out.write(DerValue.tag_Sequence, bytes2);
return out.toByteArray();
} catch (IOException ioe) {
throw ioe;
} catch (Exception e) {
throw new IOException("Failed to encrypt" +
" safe contents entry: " + e, e);
}
// create EncryptedContentInfo
DerOutputStream bytes2 = new DerOutputStream();
bytes2.putOID(ContentInfo.DATA_OID);
bytes2.write(encodedAlgId);
// Wrap encrypted data in a context-specific tag.
DerOutputStream tmpout2 = new DerOutputStream();
tmpout2.putOctetString(encryptedData);
bytes2.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT,
false, (byte)0), tmpout2);
// wrap EncryptedContentInfo in a Sequence
DerOutputStream out = new DerOutputStream();
out.write(DerValue.tag_Sequence, bytes2);
return out.toByteArray();
}
/**
@ -1979,10 +1964,12 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
public synchronized void engineLoad(InputStream stream, char[] password)
throws IOException, NoSuchAlgorithmException, CertificateException
{
DataInputStream dis;
CertificateFactory cf = null;
ByteArrayInputStream bais = null;
byte[] encoded = null;
// Reset config when loading a different keystore.
certProtectionAlgorithm = null;
certPbeIterationCount = -1;
macAlgorithm = null;
macIterationCount = -1;
if (stream == null)
return;
@ -2022,6 +2009,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
secretKeyCount = 0;
certificateCount = 0;
boolean seeEncBag = false;
/*
* Spin over the ContentInfos.
*/
@ -2047,6 +2036,21 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
debug.println("Warning: skipping PKCS#7 encryptedData" +
" - no password was supplied");
}
// No password to decrypt ENCRYPTED_DATA_OID. *Skip it*.
// This means user will see a PrivateKeyEntry without
// certificates and a whole TrustedCertificateEntry will
// be lost. This is not a perfect solution but alternative
// solutions are more disruptive:
//
// We cannot just fail, since KeyStore.load(is, null)
// has been known to never fail because of a null password.
//
// We cannot just throw away the whole PrivateKeyEntry,
// this is too silent and no one will notice anything.
//
// We also cannot fail when getCertificate() on such a
// PrivateKeyEntry is called, since the method has not
// specified this behavior.
continue;
}
@ -2084,13 +2088,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
ic = pbeSpec.getIterationCount();
if (ic > MAX_ITERATION_COUNT) {
throw new IOException("PBE iteration count too large");
throw new IOException("cert PBE iteration count too large");
}
certProtectionAlgorithm
= mapPBEParamsToAlgorithm(algOid, algParams);
certPbeIterationCount = ic;
seeEncBag = true;
}
if (debug != null) {
debug.println("Loading PKCS#7 encryptedData " +
"(" + new AlgorithmId(algOid).getName() +
"(" + mapPBEParamsToAlgorithm(algOid, algParams) +
" iterations: " + ic + ")");
}
@ -2115,48 +2124,62 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
}
}
// No ENCRYPTED_DATA_OID but see certificate. Must be passwordless.
if (!seeEncBag && certificateCount > 0) {
certProtectionAlgorithm = "NONE";
}
// The MacData is optional.
if (password != null && s.available() > 0) {
MacData macData = new MacData(s);
int ic = macData.getIterations();
if (s.available() > 0) {
// If there is no password, we cannot fail. KeyStore.load(is, null)
// has been known to never fail because of a null password.
if (password != null) {
MacData macData = new MacData(s);
int ic = macData.getIterations();
try {
if (ic > MAX_ITERATION_COUNT) {
throw new InvalidAlgorithmParameterException(
"MAC iteration count too large: " + ic);
try {
if (ic > MAX_ITERATION_COUNT) {
throw new InvalidAlgorithmParameterException(
"MAC iteration count too large: " + ic);
}
String algName =
macData.getDigestAlgName().toUpperCase(Locale.ENGLISH);
// Change SHA-1 to SHA1
algName = algName.replace("-", "");
macAlgorithm = "HmacPBE" + algName;
macIterationCount = ic;
// generate MAC (MAC key is created within JCE)
Mac m = Mac.getInstance(macAlgorithm);
PBEParameterSpec params =
new PBEParameterSpec(macData.getSalt(), ic);
RetryWithZero.run(pass -> {
SecretKey key = getPBEKey(pass);
m.init(key, params);
m.update(authSafeData);
byte[] macResult = m.doFinal();
if (debug != null) {
debug.println("Checking keystore integrity " +
"(" + m.getAlgorithm() + " iterations: " + ic + ")");
}
if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
throw new UnrecoverableKeyException("Failed PKCS12" +
" integrity checking");
}
return (Void) null;
}, password);
} catch (Exception e) {
throw new IOException("Integrity check failed: " + e, e);
}
String algName =
macData.getDigestAlgName().toUpperCase(Locale.ENGLISH);
// Change SHA-1 to SHA1
algName = algName.replace("-", "");
// generate MAC (MAC key is created within JCE)
Mac m = Mac.getInstance("HmacPBE" + algName);
PBEParameterSpec params =
new PBEParameterSpec(macData.getSalt(), ic);
RetryWithZero.run(pass -> {
SecretKey key = getPBEKey(pass);
m.init(key, params);
m.update(authSafeData);
byte[] macResult = m.doFinal();
if (debug != null) {
debug.println("Checking keystore integrity " +
"(" + m.getAlgorithm() + " iterations: " + ic + ")");
}
if (!MessageDigest.isEqual(macData.getDigest(), macResult)) {
throw new UnrecoverableKeyException("Failed PKCS12" +
" integrity checking");
}
return (Void)null;
}, password);
} catch (Exception e) {
throw new IOException("Integrity check failed: " + e, e);
}
} else {
macAlgorithm = "NONE";
}
/*
@ -2196,8 +2219,14 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
cert = certsMap.get(issuerDN);
}
/* Update existing KeyEntry in entries table */
if (chain.size() > 0)
if (chain.size() > 0) {
entry.chain = chain.toArray(new Certificate[chain.size()]);
} else {
// Remove private key entries where there is no associated
// certs. Most likely the keystore is loaded with a null
// password.
entries.remove(entry);
}
}
}
@ -2221,6 +2250,46 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
keyList.clear();
}
/**
* Returns if a pkcs12 file is password-less. This means no cert is
* encrypted and there is no Mac. Please note that the private key
* can be encrypted.
*
* This is a simplified version of {@link #engineLoad} that only looks
* at the ContentInfo types.
*
* @param f the pkcs12 file
* @return if it's password-less
* @throws IOException
*/
public static boolean isPasswordless(File f) throws IOException {
try (FileInputStream stream = new FileInputStream(f)) {
DerValue val = new DerValue(stream);
DerInputStream s = val.toDerInputStream();
s.getInteger(); // skip version
ContentInfo authSafe = new ContentInfo(s);
DerInputStream as = new DerInputStream(authSafe.getData());
for (DerValue seq : as.getSequence(2)) {
DerInputStream sci = new DerInputStream(seq.toByteArray());
ContentInfo safeContents = new ContentInfo(sci);
if (safeContents.getContentType()
.equals(ContentInfo.ENCRYPTED_DATA_OID)) {
// Certificate encrypted
return false;
}
}
if (s.available() > 0) {
// The MacData exists.
return false;
}
}
return true;
}
/**
* Locates a matched CertEntry from certEntries, and returns its cert.
* @param entry the KeyEntry to match
@ -2368,8 +2437,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
if (bagItem instanceof KeyEntry) {
KeyEntry entry = (KeyEntry)bagItem;
if (bagItem instanceof PrivateKeyEntry) {
if (keyId == null) {
if (keyId == null) {
if (bagItem instanceof PrivateKeyEntry) {
// Insert a localKeyID for the privateKey
// Note: This is a workaround to allow null localKeyID
// attribute in pkcs12 with one private key entry and
@ -2379,6 +2448,9 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
} else {
continue;
}
} else {
// keyId in a SecretKeyEntry is not significant
keyId = "00".getBytes("UTF8");
}
}
entry.keyId = keyId;
@ -2518,4 +2590,83 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
return result;
}
// 8076190: Customizing the generation of a PKCS12 keystore
private static String defaultCertProtectionAlgorithm() {
String result = SecurityProperties.privilegedGetOverridable(
"keystore.pkcs12.certProtectionAlgorithm");
return (result != null && !result.isEmpty())
? result : "PBEWithSHA1AndRC2_40";
}
private static int defaultCertPbeIterationCount() {
String result = SecurityProperties.privilegedGetOverridable(
"keystore.pkcs12.certPbeIterationCount");
return (result != null && !result.isEmpty())
? string2IC("certPbeIterationCount", result) : 50000;
}
// Read both "keystore.pkcs12.keyProtectionAlgorithm" and
// "keystore.PKCS12.keyProtectionAlgorithm" for compatibility.
private static String defaultKeyProtectionAlgorithm() {
String result = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
String result;
String name1 = "keystore.pkcs12.keyProtectionAlgorithm";
String name2 = "keystore.PKCS12.keyProtectionAlgorithm";
result = System.getProperty(name1);
if (result != null) {
return result;
}
result = System.getProperty(name2);
if (result != null) {
return result;
}
result = Security.getProperty(name1);
if (result != null) {
return result;
}
return Security.getProperty(name2);
}
});
return (result != null && !result.isEmpty())
? result : "PBEWithSHA1AndDESede";
}
private static int defaultKeyPbeIterationCount() {
String result = SecurityProperties.privilegedGetOverridable(
"keystore.pkcs12.keyPbeIterationCount");
return (result != null && !result.isEmpty())
? string2IC("keyPbeIterationCount", result) : 50000;
}
private static String defaultMacAlgorithm() {
String result = SecurityProperties.privilegedGetOverridable(
"keystore.pkcs12.macAlgorithm");
return (result != null && !result.isEmpty())
? result : "HmacPBESHA1";
}
private static int defaultMacIterationCount() {
String result = SecurityProperties.privilegedGetOverridable(
"keystore.pkcs12.macIterationCount");
return (result != null && !result.isEmpty())
? string2IC("macIterationCount", result) : 100000;
}
private static int string2IC(String type, String value) {
int number;
try {
number = Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("keystore.pkcs12." + type
+ " is not a number: " + value);
}
if (number <= 0 || number > MAX_ITERATION_COUNT) {
throw new IllegalArgumentException("Invalid keystore.pkcs12."
+ type + ": " + value);
}
return number;
}
}

@ -70,6 +70,7 @@ import java.security.cert.X509CRLSelector;
import javax.security.auth.x500.X500Principal;
import java.util.Base64;
import sun.security.pkcs12.PKCS12KeyStore;
import sun.security.util.ECKeySizeParameterSpec;
import sun.security.util.KeyUtil;
import sun.security.util.NamedCurve;
@ -79,6 +80,7 @@ import sun.security.pkcs10.PKCS10Attribute;
import sun.security.provider.X509Factory;
import sun.security.provider.certpath.ssl.SSLServerCertStore;
import sun.security.util.Password;
import sun.security.util.SecurityProperties;
import sun.security.util.SecurityProviderConstants;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@ -188,6 +190,7 @@ public final class Main {
private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
private boolean isPasswordlessKeyStore = false;
enum Command {
CERTREQ("Generates.a.certificate.request",
@ -919,6 +922,9 @@ public final class Main {
storetype == null && !inplaceImport) {
keyStore = KeyStore.getInstance(ksfile, storePass);
storetype = keyStore.getType();
if (storetype.equalsIgnoreCase("pkcs12")) {
isPasswordlessKeyStore = PKCS12KeyStore.isPasswordless(ksfile);
}
} else {
if (storetype == null) {
storetype = KeyStore.getDefaultType();
@ -928,6 +934,15 @@ public final class Main {
} else {
keyStore = KeyStore.getInstance(storetype, providerName);
}
// When creating a new pkcs12 file, Do not prompt for storepass
// if certProtectionAlgorithm and macAlgorithm are both NONE.
if (storetype.equalsIgnoreCase("pkcs12")) {
isPasswordlessKeyStore =
"NONE".equals(SecurityProperties.privilegedGetOverridable(
"keystore.pkcs12.certProtectionAlgorithm"))
&& "NONE".equals(SecurityProperties.privilegedGetOverridable(
"keystore.pkcs12.macAlgorithm"));
}
/*
* Load the keystore data.
@ -979,11 +994,10 @@ public final class Main {
("Keystore.password.must.be.at.least.6.characters"));
}
} else if (storePass == null) {
// only prompt if (protectedPath == false)
if (!protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype) &&
(command == CERTREQ ||
if (!protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype)
&& isKeyStoreRelated(command)
&& !isPasswordlessKeyStore) {
if (command == CERTREQ ||
command == DELETE ||
command == GENKEYPAIR ||
command == GENSECKEY ||
@ -995,59 +1009,58 @@ public final class Main {
command == SELFCERT ||
command == STOREPASSWD ||
command == KEYPASSWD ||
command == IDENTITYDB)) {
int count = 0;
do {
if (command == IMPORTKEYSTORE) {
System.err.print
(rb.getString("Enter.destination.keystore.password."));
} else {
System.err.print
(rb.getString("Enter.keystore.password."));
}
System.err.flush();
storePass = Password.readPassword(System.in);
passwords.add(storePass);
command == IDENTITYDB) {
int count = 0;
do {
if (command == IMPORTKEYSTORE) {
System.err.print
(rb.getString("Enter.destination.keystore.password."));
} else {
System.err.print
(rb.getString("Enter.keystore.password."));
}
System.err.flush();
storePass = Password.readPassword(System.in);
passwords.add(storePass);
// If we are creating a new non nullStream-based keystore,
// insist that the password be at least 6 characters
if (!nullStream && (storePass == null || storePass.length < 6)) {
System.err.println(rb.getString
("Keystore.password.is.too.short.must.be.at.least.6.characters"));
storePass = null;
}
// If the keystore file does not exist and needs to be
// created, the storepass should be prompted twice.
if (storePass != null && !nullStream && ksStream == null) {
System.err.print(rb.getString("Re.enter.new.password."));
char[] storePassAgain = Password.readPassword(System.in);
passwords.add(storePassAgain);
if (!Arrays.equals(storePass, storePassAgain)) {
System.err.println
(rb.getString("They.don.t.match.Try.again"));
// If we are creating a new non nullStream-based keystore,
// insist that the password be at least 6 characters
if (!nullStream && (storePass == null || storePass.length < 6)) {
System.err.println(rb.getString
("Keystore.password.is.too.short.must.be.at.least.6.characters"));
storePass = null;
}
// If the keystore file does not exist and needs to be
// created, the storepass should be prompted twice.
if (storePass != null && !nullStream && ksStream == null) {
System.err.print(rb.getString("Re.enter.new.password."));
char[] storePassAgain = Password.readPassword(System.in);
passwords.add(storePassAgain);
if (!Arrays.equals(storePass, storePassAgain)) {
System.err.println
(rb.getString("They.don.t.match.Try.again"));
storePass = null;
}
}
count++;
} while ((storePass == null) && count < 3);
if (storePass == null) {
System.err.println
(rb.getString("Too.many.failures.try.later"));
return;
}
} else {
// here we have EXPORTCERT and LIST (info valid until STOREPASSWD)
if (command != PRINTCRL) {
System.err.print(rb.getString("Enter.keystore.password."));
System.err.flush();
storePass = Password.readPassword(System.in);
passwords.add(storePass);
}
count++;
} while ((storePass == null) && count < 3);
if (storePass == null) {
System.err.println
(rb.getString("Too.many.failures.try.later"));
return;
}
} else if (!protectedPath
&& !KeyStoreUtil.isWindowsKeyStore(storetype)
&& isKeyStoreRelated(command)) {
// here we have EXPORTCERT and LIST (info valid until STOREPASSWD)
if (command != PRINTCRL) {
System.err.print(rb.getString("Enter.keystore.password."));
System.err.flush();
storePass = Password.readPassword(System.in);
passwords.add(storePass);
}
}
@ -1233,7 +1246,8 @@ public final class Main {
kssave = true;
} else if (command == LIST) {
if (storePass == null
&& !KeyStoreUtil.isWindowsKeyStore(storetype)) {
&& !KeyStoreUtil.isWindowsKeyStore(storetype)
&& !isPasswordlessKeyStore) {
printNoIntegrityWarning();
}
@ -1602,7 +1616,8 @@ public final class Main {
throws Exception
{
if (storePass == null
&& !KeyStoreUtil.isWindowsKeyStore(storetype)) {
&& !KeyStoreUtil.isWindowsKeyStore(storetype)
&& !isPasswordlessKeyStore) {
printNoIntegrityWarning();
}
if (alias == null) {
@ -1633,7 +1648,7 @@ public final class Main {
* @param origPass the password to copy from if user press ENTER
*/
private char[] promptForKeyPass(String alias, String orig, char[] origPass) throws Exception{
if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
if (origPass != null && P12KEYSTORE.equalsIgnoreCase(storetype)) {
return origPass;
} else if (!token && !protectedPath) {
// Prompt for key password
@ -1642,22 +1657,25 @@ public final class Main {
MessageFormat form = new MessageFormat(rb.getString
("Enter.key.password.for.alias."));
Object[] source = {alias};
System.err.println(form.format(source));
if (orig == null) {
System.err.print(rb.getString
(".RETURN.if.same.as.keystore.password."));
} else {
form = new MessageFormat(rb.getString
(".RETURN.if.same.as.for.otherAlias."));
Object[] src = {orig};
System.err.print(form.format(src));
System.err.print(form.format(source));
if (origPass != null) {
System.err.println();
if (orig == null) {
System.err.print(rb.getString
(".RETURN.if.same.as.keystore.password."));
} else {
form = new MessageFormat(rb.getString
(".RETURN.if.same.as.for.otherAlias."));
Object[] src = {orig};
System.err.print(form.format(src));
}
}
System.err.flush();
char[] entered = Password.readPassword(System.in);
passwords.add(entered);
if (entered == null) {
if (entered == null && origPass != null) {
return origPass;
} else if (entered.length >= 6) {
} else if (entered != null && entered.length >= 6) {
System.err.print(rb.getString("Re.enter.new.password."));
char[] passAgain = Password.readPassword(System.in);
passwords.add(passAgain);
@ -2066,6 +2084,9 @@ public final class Main {
getCertFingerPrint("SHA-256", chain[0]));
checkWeak(label, chain);
}
} else {
out.println(rb.getString
("Certificate.chain.length.") + 0);
}
} else if (keyStore.entryInstanceOf(alias,
KeyStore.TrustedCertificateEntry.class)) {
@ -2130,6 +2151,7 @@ public final class Main {
InputStream is = null;
File srcksfile = null;
boolean srcIsPasswordless = false;
if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
@ -2151,6 +2173,9 @@ public final class Main {
srcstoretype == null) {
store = KeyStore.getInstance(srcksfile, srcstorePass);
srcstoretype = store.getType();
if (srcstoretype.equalsIgnoreCase("pkcs12")) {
srcIsPasswordless = PKCS12KeyStore.isPasswordless(srcksfile);
}
} else {
if (srcstoretype == null) {
srcstoretype = KeyStore.getDefaultType();
@ -2164,7 +2189,8 @@ public final class Main {
if (srcstorePass == null
&& !srcprotectedPath
&& !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
&& !KeyStoreUtil.isWindowsKeyStore(srcstoretype)
&& !srcIsPasswordless) {
System.err.print(rb.getString("Enter.source.keystore.password."));
System.err.flush();
srcstorePass = Password.readPassword(System.in);
@ -2191,6 +2217,7 @@ public final class Main {
}
if (srcstorePass == null
&& !srcIsPasswordless
&& !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
// anti refactoring, copied from printNoIntegrityWarning(),
// but change 2 lines
@ -3537,25 +3564,25 @@ public final class Main {
if (keyPass == null) {
// Try to recover the key using the keystore password
try {
key = keyStore.getKey(alias, storePass);
keyPass = storePass;
passwords.add(keyPass);
} catch (UnrecoverableKeyException e) {
// Did not work out, so prompt user for key password
if (!token) {
keyPass = getKeyPasswd(alias, null, null);
key = keyStore.getKey(alias, keyPass);
} else {
throw e;
if (storePass != null) {
try {
key = keyStore.getKey(alias, storePass);
passwords.add(storePass);
return Pair.of(key, storePass);
} catch (UnrecoverableKeyException e) {
if (token) {
throw e;
}
}
}
// prompt user for key password
keyPass = getKeyPasswd(alias, null, null);
key = keyStore.getKey(alias, keyPass);
return Pair.of(key, keyPass);
} else {
key = keyStore.getKey(alias, keyPass);
return Pair.of(key, keyPass);
}
return Pair.of(key, keyPass);
}
/**
@ -3570,68 +3597,59 @@ public final class Main {
char[] pstore,
char[] pkey) throws Exception {
if (ks.containsAlias(alias) == false) {
MessageFormat form = new MessageFormat
(rb.getString("Alias.alias.does.not.exist"));
if (!ks.containsAlias(alias)) {
MessageFormat form = new MessageFormat(
rb.getString("Alias.alias.does.not.exist"));
Object[] source = {alias};
throw new Exception(form.format(source));
}
PasswordProtection pp = null;
Entry entry;
// Step 1: First attempt to access entry without key password
// (PKCS11 entry or trusted certificate entry, for example).
// If fail, go next.
try {
// First attempt to access entry without key password
// (PKCS11 entry or trusted certificate entry, for example)
entry = ks.getEntry(alias, pp);
pkey = null;
Entry entry = ks.getEntry(alias, null);
return Pair.of(entry, null);
} catch (UnrecoverableEntryException une) {
if(P11KEYSTORE.equalsIgnoreCase(ks.getType()) ||
KeyStoreUtil.isWindowsKeyStore(ks.getType())) {
KeyStoreUtil.isWindowsKeyStore(ks.getType())) {
// should not happen, but a possibility
throw une;
}
}
// entry is protected
// entry is protected
if (pkey != null) {
// Step 2: try pkey if not null. If fail, fail.
if (pkey != null) {
PasswordProtection pp = new PasswordProtection(pkey);
Entry entry = ks.getEntry(alias, pp);
return Pair.of(entry, pkey);
}
// try provided key password
pp = new PasswordProtection(pkey);
entry = ks.getEntry(alias, pp);
} else {
// try store pass
try {
pp = new PasswordProtection(pstore);
entry = ks.getEntry(alias, pp);
pkey = pstore;
} catch (UnrecoverableEntryException une2) {
if (P12KEYSTORE.equalsIgnoreCase(ks.getType())) {
// P12 keystore currently does not support separate
// store and entry passwords
throw une2;
} else {
// prompt for entry password
pkey = getKeyPasswd(alias, null, null);
pp = new PasswordProtection(pkey);
entry = ks.getEntry(alias, pp);
}
// Step 3: try pstore if not null. If fail, go next.
if (pstore != null) {
try {
PasswordProtection pp = new PasswordProtection(pstore);
Entry entry = ks.getEntry(alias, pp);
return Pair.of(entry, pstore);
} catch (UnrecoverableEntryException une) {
if (P12KEYSTORE.equalsIgnoreCase(ks.getType())) {
// P12 keystore currently does not support separate
// store and entry passwords. We will not prompt for
// entry password.
throw une;
}
}
}
// Step 4: prompt for entry password
pkey = getKeyPasswd(alias, null, null);
PasswordProtection pp = new PasswordProtection(pkey);
Entry entry = ks.getEntry(alias, pp);
return Pair.of(entry, pkey);
}
/**
* Gets the requested finger print of the certificate.
*/

@ -771,8 +771,14 @@ public class AlgorithmId implements Serializable, DerEncoder {
ObjectIdentifier.newInternal(new int[] {1, 2, 840, 113549, 1, 5, 10});
public static final ObjectIdentifier pbeWithSHA1AndRC2_oid =
ObjectIdentifier.newInternal(new int[] {1, 2, 840, 113549, 1, 5, 11});
public static ObjectIdentifier pbeWithSHA1AndRC4_128_oid =
ObjectIdentifier.newInternal(new int[] {1, 2, 840, 113549, 1, 12, 1, 1});
public static ObjectIdentifier pbeWithSHA1AndRC4_40_oid =
ObjectIdentifier.newInternal(new int[] {1, 2, 840, 113549, 1, 12, 1, 2});
public static ObjectIdentifier pbeWithSHA1AndDESede_oid =
ObjectIdentifier.newInternal(new int[] {1, 2, 840, 113549, 1, 12, 1, 3});
public static ObjectIdentifier pbeWithSHA1AndRC2_128_oid =
ObjectIdentifier.newInternal(new int[] {1, 2, 840, 113549, 1, 12, 1, 5});
public static ObjectIdentifier pbeWithSHA1AndRC2_40_oid =
ObjectIdentifier.newInternal(new int[] {1, 2, 840, 113549, 1, 12, 1, 6});
@ -961,7 +967,10 @@ public class AlgorithmId implements Serializable, DerEncoder {
nameTable.put(pbeWithMD5AndRC2_oid, "PBEWithMD5AndRC2");
nameTable.put(pbeWithSHA1AndDES_oid, "PBEWithSHA1AndDES");
nameTable.put(pbeWithSHA1AndRC2_oid, "PBEWithSHA1AndRC2");
nameTable.put(pbeWithSHA1AndRC4_128_oid, "PBEWithSHA1AndRC4_128");
nameTable.put(pbeWithSHA1AndRC4_40_oid, "PBEWithSHA1AndRC4_40");
nameTable.put(pbeWithSHA1AndDESede_oid, "PBEWithSHA1AndDESede");
nameTable.put(pbeWithSHA1AndRC2_128_oid, "PBEWithSHA1AndRC2_128");
nameTable.put(pbeWithSHA1AndRC2_40_oid, "PBEWithSHA1AndRC2_40");
}

@ -1060,6 +1060,77 @@ jdk.xml.dsig.secureValidationPolicy=\
jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep;\
java.base/java.security.KeyRep$Type;java.base/javax.crypto.spec.SecretKeySpec;!*
#
# PKCS12 KeyStore properties
#
# The following properties, if configured, are used by the PKCS12 KeyStore
# implementation during the creation of a new keystore. Several of the
# properties may also be used when modifying an existing keystore. The
# properties can be overridden by a KeyStore API that specifies its own
# algorithms and parameters.
#
# If an existing PKCS12 keystore is loaded and then stored, the algorithm and
# parameter used to generate the existing Mac will be reused. If the existing
# keystore does not have a Mac, no Mac will be created while storing. If there
# is at least one certificate in the existing keystore, the algorithm and
# parameters used to encrypt the last certificate in the existing keystore will
# be reused to encrypt all certificates while storing. If the last certificate
# in the existing keystore is not encrypted, all certificates will be stored
# unencrypted. If there is no certificate in the existing keystore, any newly
# added certificate will be encrypted (or stored unencrypted if algorithm
# value is "NONE") using the "keystore.pkcs12.certProtectionAlgorithm" and
# "keystore.pkcs12.certPbeIterationCount" values defined here. Existing private
# and secret key(s) are not changed. Newly set private and secret key(s) will
# be encrypted using the "keystore.pkcs12.keyProtectionAlgorithm" and
# "keystore.pkcs12.keyPbeIterationCount" values defined here.
#
# In order to apply new algorithms and parameters to all entries in an
# existing keystore, one can create a new keystore and add entries in the
# existing keystore into the new keystore. This can be achieved by calling the
# "keytool -importkeystore" command.
#
# If a system property of the same name is also specified, it supersedes the
# security property value defined here.
#
# If the property is set to an illegal value,
# an iteration count that is not a positive integer, or an unknown algorithm
# name, an exception will be thrown when the property is used.
# If the property is not set or empty, a default value will be used.
#
# Note: These properties are currently used by the JDK Reference implementation.
# They are not guaranteed to be examined and used by other implementations.
# The algorithm used to encrypt a certificate. This can be any non-Hmac PBE
# algorithm defined in the Cipher section of the Java Security Standard
# Algorithm Names Specification. When set to "NONE", the certificate
# is not encrypted. The default value is "PBEWithSHA1AndRC2_40".
#keystore.pkcs12.certProtectionAlgorithm = PBEWithSHA1AndRC2_40
# The iteration count used by the PBE algorithm when encrypting a certificate.
# This value must be a positive integer. The default value is 50000.
#keystore.pkcs12.certPbeIterationCount = 50000
# The algorithm used to encrypt a private key or secret key. This can be
# any non-Hmac PBE algorithm defined in the Cipher section of the Java
# Security Standard Algorithm Names Specification. The value must not be "NONE".
# The default value is "PBEWithSHA1AndDESede".
#keystore.pkcs12.keyProtectionAlgorithm = PBEWithSHA1AndDESede
# The iteration count used by the PBE algorithm when encrypting a private key
# or a secret key. This value must be a positive integer. The default value
# is 50000.
#keystore.pkcs12.keyPbeIterationCount = 50000
# The algorithm used to calculate the optional MacData at the end of a PKCS12
# file. This can be any HmacPBE algorithm defined in the Mac section of the
# Java Security Standard Algorithm Names Specification. When set to "NONE",
# no Mac is generated. The default value is "HmacPBESHA1".
#keystore.pkcs12.macAlgorithm = HmacPBESHA1
# The iteration count used by the MacData algorithm. This value must be a
# positive integer. The default value is 100000.
#keystore.pkcs12.macIterationCount = 100000
#
# Enhanced exception message information
#

@ -0,0 +1,234 @@
/*
* 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.test.lib.SecurityTools;
import sun.security.util.ObjectIdentifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static jdk.test.lib.security.DerUtils.*;
import static sun.security.pkcs.ContentInfo.DATA_OID;
import static sun.security.pkcs.ContentInfo.ENCRYPTED_DATA_OID;
import static sun.security.x509.AlgorithmId.*;
/*
* @test
* @bug 8076190
* @library /test/lib
* @modules java.base/sun.security.pkcs
* java.base/sun.security.x509
* java.base/sun.security.util
* @summary Checks the preferences order of pkcs12 params
*/
public class ParamsPreferences {
public static final void main(String[] args) throws Exception {
int c = 0;
// with storepass
test(c++, "-", "-",
pbeWithSHA1AndRC2_40_oid, 50000,
pbeWithSHA1AndDESede_oid, 50000,
SHA_oid, 100000);
// password-less with system property
test(c++, "keystore.pkcs12.certProtectionAlgorithm", "NONE",
"keystore.pkcs12.macAlgorithm", "NONE",
"-", "-",
null, 0,
pbeWithSHA1AndDESede_oid, 50000,
null, 0);
// password-less with security property
test(c++, "-",
"keystore.pkcs12.certProtectionAlgorithm", "NONE",
"keystore.pkcs12.macAlgorithm", "NONE",
"-",
null, 0,
pbeWithSHA1AndDESede_oid, 50000,
null, 0);
// back to with storepass by overriding security property with system property
test(c++, "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede",
"keystore.pkcs12.macAlgorithm", "HmacPBESHA256",
"-",
"keystore.pkcs12.certProtectionAlgorithm", "NONE",
"keystore.pkcs12.macAlgorithm", "NONE",
"-",
pbeWithSHA1AndDESede_oid, 50000,
pbeWithSHA1AndDESede_oid, 50000,
SHA256_oid, 100000);
// back to with storepass by using "" to force hardcoded default
test(c++, "keystore.pkcs12.certProtectionAlgorithm", "",
"keystore.pkcs12.keyProtectionAlgorithm", "",
"keystore.pkcs12.macAlgorithm", "",
"-",
"keystore.pkcs12.certProtectionAlgorithm", "NONE",
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"keystore.pkcs12.macAlgorithm", "NONE",
"-",
pbeWithSHA1AndRC2_40_oid, 50000,
pbeWithSHA1AndDESede_oid, 50000,
SHA_oid, 100000);
// change everything with system property
test(c++, "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede",
"keystore.pkcs12.certPbeIterationCount", 3000,
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"keystore.pkcs12.keyPbeIterationCount", 4000,
"keystore.pkcs12.macAlgorithm", "HmacPBESHA256",
"keystore.pkcs12.macIterationCount", 2000,
"-", "-",
pbeWithSHA1AndDESede_oid, 3000,
pbeWithSHA1AndRC2_40_oid, 4000,
SHA256_oid, 2000);
// change everything with security property
test(c++, "-",
"keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede",
"keystore.pkcs12.certPbeIterationCount", 3000,
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"keystore.pkcs12.keyPbeIterationCount", 4000,
"keystore.pkcs12.macAlgorithm", "HmacPBESHA256",
"keystore.pkcs12.macIterationCount", 2000,
"-",
pbeWithSHA1AndDESede_oid, 3000,
pbeWithSHA1AndRC2_40_oid, 4000,
SHA256_oid, 2000);
// override security property with system property
test(c++, "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede",
"keystore.pkcs12.certPbeIterationCount", 13000,
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"keystore.pkcs12.keyPbeIterationCount", 14000,
"keystore.pkcs12.macAlgorithm", "HmacPBESHA256",
"keystore.pkcs12.macIterationCount", 12000,
"-",
"keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"keystore.pkcs12.certPbeIterationCount", 3000,
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndDESede",
"keystore.pkcs12.keyPbeIterationCount", 4000,
"keystore.pkcs12.macAlgorithm", "HmacPBESHA1",
"keystore.pkcs12.macIterationCount", 2000,
"-",
pbeWithSHA1AndDESede_oid, 13000,
pbeWithSHA1AndRC2_40_oid, 14000,
SHA256_oid, 12000);
// check keyProtectionAlgorithm old behavior. Preferences of
// 4 different settings.
test(c++, "-",
"keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128",
"-",
pbeWithSHA1AndRC2_40_oid, 50000,
pbeWithSHA1AndRC2_128_oid, 50000,
SHA_oid, 100000);
test(c++, "-",
"keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128",
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"-",
pbeWithSHA1AndRC2_40_oid, 50000,
pbeWithSHA1AndRC2_40_oid, 50000,
SHA_oid, 100000);
test(c++,
"keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128",
"-",
"keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128",
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"-",
pbeWithSHA1AndRC2_40_oid, 50000,
pbeWithSHA1AndRC4_128_oid, 50000,
SHA_oid, 100000);
test(c++,
"keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128",
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_40",
"-",
"keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128",
"keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40",
"-",
pbeWithSHA1AndRC2_40_oid, 50000,
pbeWithSHA1AndRC4_40_oid, 50000,
SHA_oid, 100000);
}
/**
* Run once.
*
* @param args an array containing system properties and values, "-",
* security properties and values, "-", expected certPbeAlg,
* certPbeIC, keyPbeAlg, keyPbeIc, macAlg, macIC.
*/
static void test(int n, Object... args) throws Exception {
boolean isSysProp = true;
String cmd = "-keystore ks" + n + " -genkeypair -keyalg EC "
+ "-alias a -dname CN=A -storepass changeit "
+ "-J-Djava.security.properties=" + n + ".conf";
List<String> jsConf = new ArrayList<>();
for (int i = 0; i < args.length; i++) {
if (isSysProp) {
if (args[i].equals("-")) {
isSysProp = false;
} else {
cmd += " -J-D" + args[i] + "=" + args[++i];
}
} else {
if (args[i] == "-") {
Files.write(Path.of(n + ".conf"), jsConf);
System.out.println("--------- test starts ----------");
System.out.println(jsConf);
SecurityTools.keytool(cmd).shouldHaveExitValue(0);
byte[] data = Files.readAllBytes(Path.of("ks" + n));
// cert pbe alg + ic
if (args[i+1] == null) {
checkAlg(data, "110c10", DATA_OID);
} else {
checkAlg(data, "110c10", ENCRYPTED_DATA_OID);
checkAlg(data, "110c110110", (ObjectIdentifier)args[i+1]);
checkInt(data, "110c1101111", (int)args[i+2]);
}
// key pbe alg + ic
checkAlg(data, "110c010c01000", (ObjectIdentifier)args[i+3]);
checkInt(data, "110c010c010011", (int)args[i+4]);
// mac alg + ic
if (args[i+5] == null) {
shouldNotExist(data, "2");
} else {
checkAlg(data, "2000", (ObjectIdentifier)args[i+5]);
checkInt(data, "22", (int)args[i+6]);
}
} else {
jsConf.add(args[i] + "=" + args[++i]);
}
}
}
}
}

@ -0,0 +1,434 @@
/*
* 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8076190
* @library /test/lib
* @modules java.base/sun.security.pkcs
* java.base/sun.security.x509
* java.base/sun.security.util
* @summary Customizing the generation of a PKCS12 keystore
*/
import jdk.test.lib.Asserts;
import jdk.test.lib.SecurityTools;
import jdk.test.lib.process.OutputAnalyzer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import java.util.Base64;
import java.util.Objects;
import static jdk.test.lib.security.DerUtils.*;
import static sun.security.x509.AlgorithmId.*;
import static sun.security.pkcs.ContentInfo.*;
public class ParamsTest {
public static void main(String[] args) throws Throwable {
// De-BASE64 textual files in ./params to `pwd`
Files.newDirectoryStream(Path.of(System.getProperty("test.src"), "params"))
.forEach(p -> {
try (InputStream is = Files.newInputStream(p);
OutputStream os = Files.newOutputStream(p.getFileName())){
Base64.getMimeDecoder().wrap(is).transferTo(os);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
byte[] data;
// openssl -> keytool interop check
// os2. no cert pbe, no mac.
check("os2", "a", null, "changeit", true, true, true);
check("os2", "a", "changeit", "changeit", true, true, true);
// You can even load it with a wrong storepass, controversial
check("os2", "a", "wrongpass", "changeit", true, true, true);
// os3. no cert pbe, has mac. just like JKS
check("os3", "a", null, "changeit", true, true, true);
check("os3", "a", "changeit", "changeit", true, true, true);
// Cannot load with a wrong storepass, same as JKS
check("os3", "a", "wrongpass", "-", IOException.class, "-", "-");
// os4. non default algs
check("os4", "a", "changeit", "changeit", true, true, true);
check("os4", "a", "wrongpass", "-", IOException.class, "-", "-");
// no storepass no cert
check("os4", "a", null, "changeit", true, false, true);
// os5. strong non default algs
check("os5", "a", "changeit", "changeit", true, true, true);
check("os5", "a", "wrongpass", "-", IOException.class, "-", "-");
// no storepass no cert
check("os5", "a", null, "changeit", true, false, true);
// keytool
// Current default pkcs12 setting
keytool("-importkeystore -srckeystore ks -srcstorepass changeit "
+ "-destkeystore ksnormal -deststorepass changeit");
data = Files.readAllBytes(Path.of("ksnormal"));
checkInt(data, "22", 100000); // Mac ic
checkAlg(data, "2000", SHA_oid); // Mac alg
checkAlg(data, "110c010c01000", pbeWithSHA1AndDESede_oid); // key alg
checkInt(data, "110c010c010011", 50000); // key ic
checkAlg(data, "110c10", ENCRYPTED_DATA_OID);
checkAlg(data, "110c110110", pbeWithSHA1AndRC2_40_oid); // cert alg
checkInt(data, "110c1101111", 50000); // cert ic
check("ksnormal", "a", "changeit", "changeit", true, true, true);
check("ksnormal", "a", null, "changeit", true, false, true);
check("ksnormal", "a", "wrongpass", "-", IOException.class, "-", "-");
// Add a new entry with password-less settings, still has a storepass
keytool("-keystore ksnormal -genkeypair -storepass changeit -alias b -dname CN=b "
+ "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE "
+ "-J-Dkeystore.pkcs12.macAlgorithm=NONE");
data = Files.readAllBytes(Path.of("ksnormal"));
checkInt(data, "22", 100000); // Mac ic
checkAlg(data, "2000", SHA_oid); // Mac alg
checkAlg(data, "110c010c01000", pbeWithSHA1AndDESede_oid); // key alg
checkInt(data, "110c010c010011", 50000); // key ic
checkAlg(data, "110c010c11000", pbeWithSHA1AndDESede_oid); // new key alg
checkInt(data, "110c010c110011", 50000); // new key ic
checkAlg(data, "110c10", ENCRYPTED_DATA_OID);
checkAlg(data, "110c110110", pbeWithSHA1AndRC2_40_oid); // cert alg
checkInt(data, "110c1101111", 50000); // cert ic
check("ksnormal", "b", null, "changeit", true, false, true);
check("ksnormal", "b", "changeit", "changeit", true, true, true);
// Different keypbe alg, no cert pbe and no mac
keytool("-importkeystore -srckeystore ks -srcstorepass changeit "
+ "-destkeystore ksnopass -deststorepass changeit "
+ "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithSHA1AndRC4_128 "
+ "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE "
+ "-J-Dkeystore.pkcs12.macAlgorithm=NONE");
data = Files.readAllBytes(Path.of("ksnopass"));
shouldNotExist(data, "2"); // no Mac
checkAlg(data, "110c010c01000", pbeWithSHA1AndRC4_128_oid);
checkInt(data, "110c010c010011", 50000);
checkAlg(data, "110c10", DATA_OID);
check("ksnopass", "a", null, "changeit", true, true, true);
check("ksnopass", "a", "changeit", "changeit", true, true, true);
check("ksnopass", "a", "wrongpass", "changeit", true, true, true);
// Add a new entry with normal settings, still password-less
keytool("-keystore ksnopass -genkeypair -storepass changeit -alias b -dname CN=B");
data = Files.readAllBytes(Path.of("ksnopass"));
shouldNotExist(data, "2"); // no Mac
checkAlg(data, "110c010c01000", pbeWithSHA1AndRC4_128_oid);
checkInt(data, "110c010c010011", 50000);
checkAlg(data, "110c010c11000", pbeWithSHA1AndDESede_oid);
checkInt(data, "110c010c110011", 50000);
checkAlg(data, "110c10", DATA_OID);
check("ksnopass", "a", null, "changeit", true, true, true);
check("ksnopass", "b", null, "changeit", true, true, true);
keytool("-importkeystore -srckeystore ks -srcstorepass changeit "
+ "-destkeystore ksnewic -deststorepass changeit "
+ "-J-Dkeystore.pkcs12.macIterationCount=5555 "
+ "-J-Dkeystore.pkcs12.certPbeIterationCount=6666 "
+ "-J-Dkeystore.pkcs12.keyPbeIterationCount=7777");
data = Files.readAllBytes(Path.of("ksnewic"));
checkInt(data, "22", 5555); // Mac ic
checkAlg(data, "2000", SHA_oid); // Mac alg
checkAlg(data, "110c010c01000", pbeWithSHA1AndDESede_oid); // key alg
checkInt(data, "110c010c010011", 7777); // key ic
checkAlg(data, "110c110110", pbeWithSHA1AndRC2_40_oid); // cert alg
checkInt(data, "110c1101111", 6666); // cert ic
// keypbe alg cannot be NONE
keytool("-keystore ksnewic -genkeypair -storepass changeit -alias b -dname CN=B "
+ "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=NONE")
.shouldContain("NONE AlgorithmParameters not available")
.shouldHaveExitValue(1);
// new entry new keypbe alg (and default ic), else unchanged
keytool("-keystore ksnewic -genkeypair -storepass changeit -alias b -dname CN=B "
+ "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithSHA1AndRC4_128");
data = Files.readAllBytes(Path.of("ksnewic"));
checkInt(data, "22", 5555); // Mac ic
checkAlg(data, "2000", SHA_oid); // Mac alg
checkAlg(data, "110c010c01000", pbeWithSHA1AndDESede_oid); // key alg
checkInt(data, "110c010c010011", 7777); // key ic
checkAlg(data, "110c010c11000", pbeWithSHA1AndRC4_128_oid); // new key alg
checkInt(data, "110c010c110011", 50000); // new key ic
checkAlg(data, "110c110110", pbeWithSHA1AndRC2_40_oid); // cert alg
checkInt(data, "110c1101111", 6666); // cert ic
// Check KeyStore loading multiple keystores
KeyStore ks = KeyStore.getInstance("pkcs12");
try (FileInputStream fis = new FileInputStream("ksnormal");
FileOutputStream fos = new FileOutputStream("ksnormaldup")) {
ks.load(fis, "changeit".toCharArray());
ks.store(fos, "changeit".toCharArray());
}
data = Files.readAllBytes(Path.of("ksnormaldup"));
checkInt(data, "22", 100000); // Mac ic
checkAlg(data, "2000", SHA_oid); // Mac alg
checkAlg(data, "110c010c01000", pbeWithSHA1AndDESede_oid); // key alg
checkInt(data, "110c010c010011", 50000); // key ic
checkAlg(data, "110c010c11000", pbeWithSHA1AndDESede_oid); // new key alg
checkInt(data, "110c010c110011", 50000); // new key ic
checkAlg(data, "110c10", ENCRYPTED_DATA_OID);
checkAlg(data, "110c110110", pbeWithSHA1AndRC2_40_oid); // cert alg
checkInt(data, "110c1101111", 50000); // cert ic
try (FileInputStream fis = new FileInputStream("ksnopass");
FileOutputStream fos = new FileOutputStream("ksnopassdup")) {
ks.load(fis, "changeit".toCharArray());
ks.store(fos, "changeit".toCharArray());
}
data = Files.readAllBytes(Path.of("ksnopassdup"));
shouldNotExist(data, "2"); // no Mac
checkAlg(data, "110c010c01000", pbeWithSHA1AndRC4_128_oid);
checkInt(data, "110c010c010011", 50000);
checkAlg(data, "110c010c11000", pbeWithSHA1AndDESede_oid);
checkInt(data, "110c010c110011", 50000);
checkAlg(data, "110c10", DATA_OID);
try (FileInputStream fis = new FileInputStream("ksnewic");
FileOutputStream fos = new FileOutputStream("ksnewicdup")) {
ks.load(fis, "changeit".toCharArray());
ks.store(fos, "changeit".toCharArray());
}
data = Files.readAllBytes(Path.of("ksnewicdup"));
checkInt(data, "22", 5555); // Mac ic
checkAlg(data, "2000", SHA_oid); // Mac alg
checkAlg(data, "110c010c01000", pbeWithSHA1AndDESede_oid); // key alg
checkInt(data, "110c010c010011", 7777); // key ic
checkAlg(data, "110c010c11000", pbeWithSHA1AndRC4_128_oid); // new key alg
checkInt(data, "110c010c110011", 50000); // new key ic
checkAlg(data, "110c110110", pbeWithSHA1AndRC2_40_oid); // cert alg
checkInt(data, "110c1101111", 6666); // cert ic
// Check keytool behavior
// ksnormal has password
keytool("-list -keystore ksnormal")
.shouldContain("WARNING WARNING WARNING")
.shouldContain("Certificate chain length: 0");
SecurityTools.setResponse("changeit");
keytool("-list -keystore ksnormal")
.shouldNotContain("WARNING WARNING WARNING")
.shouldContain("Certificate fingerprint");
// ksnopass is password-less
keytool("-list -keystore ksnopass")
.shouldNotContain("WARNING WARNING WARNING")
.shouldContain("Certificate fingerprint");
// -certreq prompts for keypass
SecurityTools.setResponse("changeit");
keytool("-certreq -alias a -keystore ksnopass")
.shouldContain("Enter key password for <a>")
.shouldContain("-----BEGIN NEW CERTIFICATE REQUEST-----")
.shouldHaveExitValue(0);
// -certreq -storepass works fine
keytool("-certreq -alias a -keystore ksnopass -storepass changeit")
.shouldNotContain("Enter key password for <a>")
.shouldContain("-----BEGIN NEW CERTIFICATE REQUEST-----")
.shouldHaveExitValue(0);
// -certreq -keypass also works fine
keytool("-certreq -alias a -keystore ksnopass -keypass changeit")
.shouldNotContain("Enter key password for <a>")
.shouldContain("-----BEGIN NEW CERTIFICATE REQUEST-----")
.shouldHaveExitValue(0);
// -importkeystore prompts for srckeypass
SecurityTools.setResponse("changeit", "changeit");
keytool("-importkeystore -srckeystore ksnopass "
+ "-destkeystore jks3 -deststorepass changeit")
.shouldContain("Enter key password for <a>")
.shouldContain("Enter key password for <b>")
.shouldContain("2 entries successfully imported");
// ksnopass2 is ksnopass + 2 cert entries
ks = KeyStore.getInstance(new File("ksnopass"), (char[])null);
ks.setCertificateEntry("aa", ks.getCertificate("a"));
ks.setCertificateEntry("bb", ks.getCertificate("b"));
try (FileOutputStream fos = new FileOutputStream("ksnopass2")) {
ks.store(fos, null);
}
// -importkeystore prompts for srckeypass for private keys
// and no prompt for certs
SecurityTools.setResponse("changeit", "changeit");
keytool("-importkeystore -srckeystore ksnopass2 "
+ "-destkeystore jks5 -deststorepass changeit")
.shouldContain("Enter key password for <a>")
.shouldContain("Enter key password for <b>")
.shouldNotContain("Enter key password for <aa>")
.shouldNotContain("Enter key password for <bb>")
.shouldContain("4 entries successfully imported");
// ksonlycert has only cert entries
ks.deleteEntry("a");
ks.deleteEntry("b");
try (FileOutputStream fos = new FileOutputStream("ksonlycert")) {
ks.store(fos, null);
}
// -importkeystore does not prompt at all
keytool("-importkeystore -srckeystore ksonlycert "
+ "-destkeystore jks6 -deststorepass changeit")
.shouldNotContain("Enter key password for <aa>")
.shouldNotContain("Enter key password for <bb>")
.shouldContain("2 entries successfully imported");
// create a new password-less keystore
keytool("-keystore ksnopass -exportcert -alias a -file a.cert -rfc");
// Normally storepass is prompted for
keytool("-keystore kscert1 -importcert -alias a -file a.cert -noprompt")
.shouldContain("Enter keystore password:");
keytool("-keystore kscert2 -importcert -alias a -file a.cert -noprompt "
+ "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE")
.shouldContain("Enter keystore password:");
keytool("-keystore kscert3 -importcert -alias a -file a.cert -noprompt "
+ "-J-Dkeystore.pkcs12.macAlgorithm=NONE")
.shouldContain("Enter keystore password:");
// ... but not if it's password-less
keytool("-keystore kscert4 -importcert -alias a -file a.cert -noprompt "
+ "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE "
+ "-J-Dkeystore.pkcs12.macAlgorithm=NONE")
.shouldNotContain("Enter keystore password:");
// still prompt for keypass for genkeypair and certreq
SecurityTools.setResponse("changeit", "changeit");
keytool("-keystore ksnopassnew -genkeypair -alias a -dname CN=A "
+ "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE "
+ "-J-Dkeystore.pkcs12.macAlgorithm=NONE")
.shouldNotContain("Enter keystore password:")
.shouldContain("Enter key password for <a>");
keytool("-keystore ksnopassnew -certreq -alias a")
.shouldNotContain("Enter keystore password:")
.shouldContain("Enter key password for <a>");
keytool("-keystore ksnopassnew -list -v -alias a")
.shouldNotContain("Enter keystore password:")
.shouldNotContain("Enter key password for <a>");
// params only read on demand
// keyPbeIterationCount is used by -genkeypair
keytool("-keystore ksgenbadkeyic -genkeypair -alias a -dname CN=A "
+ "-storepass changeit "
+ "-J-Dkeystore.pkcs12.keyPbeIterationCount=abc")
.shouldContain("keyPbeIterationCount is not a number: abc")
.shouldHaveExitValue(1);
keytool("-keystore ksnopassnew -exportcert -alias a -file a.cert");
// but not used by -importcert
keytool("-keystore ksimpbadkeyic -importcert -alias a -file a.cert "
+ "-noprompt -storepass changeit "
+ "-J-Dkeystore.pkcs12.keyPbeIterationCount=abc")
.shouldHaveExitValue(0);
// None is used by -list
keytool("-keystore ksnormal -storepass changeit -list "
+ "-J-Dkeystore.pkcs12.keyPbeIterationCount=abc "
+ "-J-Dkeystore.pkcs12.certPbeIterationCount=abc "
+ "-J-Dkeystore.pkcs12.macIterationCount=abc")
.shouldHaveExitValue(0);
}
/**
* Check keystore loading and key/cert reading.
*
* @param keystore the file name of keystore
* @param alias the key/cert to read
* @param storePass store pass to try out, can be null
* @param keypass key pass to try, can not be null
* @param expectedLoad expected result of keystore loading, true if non
* null, false if null, exception class if exception
* @param expectedCert expected result of cert reading
* @param expectedKey expected result of key reading
*/
private static void check(
String keystore,
String alias,
String storePass,
String keypass,
Object expectedLoad,
Object expectedCert,
Object expectedKey) {
KeyStore ks = null;
Object actualLoad, actualCert, actualKey;
String label = keystore + "-" + alias + "-" + storePass + "-" + keypass;
try {
ks = KeyStore.getInstance(new File(keystore),
storePass == null ? null : storePass.toCharArray());
actualLoad = ks != null;
} catch (Exception e) {
e.printStackTrace(System.out);
actualLoad = e.getClass();
}
Asserts.assertEQ(expectedLoad, actualLoad, label + "-load");
// If not loaded correctly, skip cert/key reading
if (!Objects.equals(actualLoad, true)) {
return;
}
try {
actualCert = (ks.getCertificate(alias) != null);
} catch (Exception e) {
e.printStackTrace(System.out);
actualCert = e.getClass();
}
Asserts.assertEQ(expectedCert, actualCert, label + "-cert");
try {
actualKey = (ks.getKey(alias, keypass.toCharArray()) != null);
} catch (Exception e) {
e.printStackTrace(System.out);
actualKey = e.getClass();
}
Asserts.assertEQ(expectedKey, actualKey, label + "-key");
}
static OutputAnalyzer keytool(String s) throws Throwable {
return SecurityTools.keytool(s);
}
}

@ -0,0 +1,54 @@
1. Preparing data in this directory
mkdir tmp
cd tmp
keytool -keystore ks -genkeypair -storepass changeit -alias a -dname CN=A
openssl pkcs12 -in ks -nodes -out kandc -passin pass:changeit
openssl pkcs12 -export -in kandc -out os2 -name a -passout pass:changeit \
-certpbe NONE -nomac
openssl pkcs12 -export -in kandc -out os3 -name a -passout pass:changeit \
-certpbe NONE
openssl pkcs12 -export -in kandc -out os4 -name a -passout pass:changeit \
-certpbe PBE-SHA1-RC4-128 -keypbe PBE-SHA1-RC4-128 -macalg SHA224
openssl pkcs12 -export -in kandc -out os5 -name a -passout pass:changeit \
-certpbe AES-256-CBC -keypbe AES-256-CBC -macalg SHA512
for a in *; do
openssl base64 -in $a -out ../$a
done
cd ..
rm -rf tmp
2. After running the test, we can go to the scratch directory and run the
following commands to check keytool -> openssl interoperability.
OpenSSL 1.1.0i is used here. Earlier versions might generate different info.
(
openssl pkcs12 -in ks2 -passin pass:changeit -info -nokeys -nocerts 2> t2 || exit 20
grep "MAC:sha1 Iteration 100000" t2 || exit 21
grep "Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 50000" t2 || exit 23
grep "PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 50000" t2 || exit 24
openssl pkcs12 -in ks22 -passin pass:changeit -info -nokeys -nocerts 2> t22 || exit 25
diff t2 t22 || exit 26
openssl pkcs12 -in ks3 -passin pass:changeit -info -nokeys -nocerts && exit 30
openssl pkcs12 -in ks3 -passin pass:changeit -info -nokeys -nocerts -nomacver 2> t3 || exit 31
grep "PKCS7 Encrypted data:" t3 && exit 33
grep "Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 50000" t3 || exit 34
grep "Shrouded Keybag: pbeWithSHA1And128BitRC4, Iteration 50000" t3 || exit 35
openssl pkcs12 -in ks33 -passin pass:changeit -info -nokeys -nocerts -nomacver 2> t33 || exit 36
diff t3 t33 || exit 37
openssl pkcs12 -in ks4 -passin pass:changeit -info -nokeys -nocerts 2> t4 || exit 40
grep "MAC:sha1 Iteration 5555" t4 || exit 41
grep "Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 7777" t4 || exit 43
grep "Shrouded Keybag: pbeWithSHA1And128BitRC4, Iteration 50000" t4 || exit 44
grep "PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 6666" t4 || exit 45
openssl pkcs12 -in ks44 -passin pass:changeit -info -nokeys -nocerts 2> t44 || exit 46
diff t4 t44 || exit 47
echo Succeed
)

@ -0,0 +1,55 @@
QmFnIEF0dHJpYnV0ZXMKICAgIGZyaWVuZGx5TmFtZTogYQogICAgbG9jYWxLZXlJ
RDogNTQgNjkgNkQgNjUgMjAgMzEgMzUgMzMgMzggMzEgMzMgMzQgMzAgMzUgMzkg
MzQgMzMgMzUgCktleSBBdHRyaWJ1dGVzOiA8Tm8gQXR0cmlidXRlcz4KLS0tLS1C
RUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUNYUUlCQURDQ0FqVUdCeXFHU000NEJB
RXdnZ0lvQW9JQkFRQ1BlVFhadWFycHY2dnRpSHJQU1ZHMjh5N0YKbmp1dk54am82
c1NXSHo3OU5nYm5RMUdweEJnek9iZ0o1OEt1SEZPYnAwZGJoZEFScmJpMGVZZDFT
WVJwWEt3TwpqeFN6Tmdnb29pLzZKeEVLUFdLcGswVTBDYUQrYVd4R1dQaEwzU0NC
bkRjSm9CQlhzWld0elFBalBicFVoTFlwCkg1MWtqdmlEUklaM2w1enNCTFEwcHF3
dWRlbVlYZUk5c0NrdndSR01uL3FkZ1lIbk00MjNrcmN3MTdualNWa3YKYUFtWWNo
VTVGZW85YTR0R1U4WXpSWStBT3pLa3d1RHljcEFsYms0L2lqc0lPS0hFVU9UaGpC
b3BvMzNmWHFGRAoza3RtL3dTUVB0WFBGaVBoV05TSHhnanBmeUVjMkIzS0k4dHVP
QWRsK0NMalFyNUlUQVYyT1RsZ0hOWm5BaDBBCnV2YVdwb1Y0OTkvZTUvcG55WGZI
aGU4eXNqTzY1WURBdk5WcFhRS0NBUUFXcGx4WUlFaFFjRTUxQXFPWFZ3UU4KTk5v
Nk5IakJWTlRrcGNBdEpDN2dUNWJtSGt2UWtFcTlySTgzN3JIZ256R0MwanlRUTh0
a0w0Z0FRV0R0K2NvSgpzeUIycDV3eXBpZnlSejZSaDV1aXhPZEV2U0NCVkV5MVc0
QXNObzBmcUQ3VWllbE9ENkJvampKQ2lseDR4SGpHCmpRVW50eHlhT3JzTEMrRXNS
R2lXT2VmVHpuVGJFQnBscWl1SDlreG9KdHMreHk5TFZabURTN1R0c0M5OGtPbWsK
bHRPbFhWTmI2L3hGMVBZWjlqODk3YnVIT1NYQzhpVGdkekVwYmFpSDdCNUhTUGgr
KzEvZXQxU0VNV3NpTXQ3bApVOTJ2QWhFckRSOEMyakNYTWlUK0o2N2FpNTFMS1NM
WnVvdmpudG5oQTZZOFVvRUx4b2kzNHUxREZ1SHZGOXZlCkJCOENIUUMzU0hOSm5u
cjF0TG00aDdKR1RETU02cUJQc2N3cmdMcGZHOW9tCi0tLS0tRU5EIFBSSVZBVEUg
S0VZLS0tLS0KQmFnIEF0dHJpYnV0ZXMKICAgIGZyaWVuZGx5TmFtZTogYQogICAg
bG9jYWxLZXlJRDogNTQgNjkgNkQgNjUgMjAgMzEgMzUgMzMgMzggMzEgMzMgMzQg
MzAgMzUgMzkgMzQgMzMgMzUgCnN1YmplY3Q9L0NOPUEKaXNzdWVyPS9DTj1BCi0t
LS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFRXpDQ0E3K2dBd0lCQWdJRWJ1
OFlOREFOQmdsZ2hrZ0JaUU1FQXdJRkFEQU1NUW93Q0FZRFZRUURFd0ZCCk1CNFhE
VEU0TURreU9ERXhNamN6T1ZvWERURTRNVEl5TnpFeE1qY3pPVm93RERFS01BZ0dB
MVVFQXhNQlFUQ0MKQTBJd2dnSTFCZ2NxaGtqT09BUUJNSUlDS0FLQ0FRRUFqM2sx
MmJtcTZiK3I3WWg2ejBsUnR2TXV4WjQ3cnpjWQo2T3JFbGg4Ky9UWUc1ME5ScWNR
WU16bTRDZWZDcmh4VG02ZEhXNFhRRWEyNHRIbUhkVW1FYVZ5c0RvOFVzellJCktL
SXYraWNSQ2oxaXFaTkZOQW1nL21sc1JsajRTOTBnZ1p3M0NhQVFWN0dWcmMwQUl6
MjZWSVMyS1IrZFpJNzQKZzBTR2Q1ZWM3QVMwTkthc0xuWHBtRjNpUGJBcEw4RVJq
Si82bllHQjV6T050NUszTU5lNTQwbFpMMmdKbUhJVgpPUlhxUFd1TFJsUEdNMFdQ
Z0RzeXBNTGc4bktRSlc1T1A0bzdDRGloeEZEazRZd2FLYU45MzE2aFE5NUxadjhF
CmtEN1Z6eFlqNFZqVWg4WUk2WDhoSE5nZHlpUExiamdIWmZnaTQwSytTRXdGZGpr
NVlCeldad0lkQUxyMmxxYUYKZVBmZjN1ZjZaOGwzeDRYdk1ySXp1dVdBd0x6VmFW
MENnZ0VBRnFaY1dDQklVSEJPZFFLamwxY0VEVFRhT2pSNAp3VlRVNUtYQUxTUXU0
RStXNWg1TDBKQkt2YXlQTis2eDRKOHhndEk4a0VQTFpDK0lBRUZnN2ZuS0NiTWdk
cWVjCk1xWW44a2Mra1llYm9zVG5STDBnZ1ZSTXRWdUFMRGFOSDZnKzFJbnBUZytn
YUk0eVFvcGNlTVI0eG8wRko3Y2MKbWpxN0N3dmhMRVJvbGpubjA4NTAyeEFhWmFv
cmgvWk1hQ2JiUHNjdlMxV1pnMHUwN2JBdmZKRHBwSmJUcFYxVApXK3Y4UmRUMkdm
WS9QZTI3aHprbHd2SWs0SGN4S1cyb2grd2VSMGo0ZnZ0ZjNyZFVoREZySWpMZTVW
UGRyd0lSCkt3MGZBdG93bHpJay9pZXUyb3VkU3lraTJicUw0NTdaNFFPbVBGS0JD
OGFJdCtMdFF4Ymg3eGZiM2dPQ0FRVUEKQW9JQkFEK0syd1RoV3VyRGpZTUNYeGZy
dXJOK0drZFNFeXk5cCtkdkhJUDFrTWhybTcrRXV6LzExUVlGcGI4Vgpic0NhWWUx
ME9qWkF1WjRXSmdTbkl5R0swb2JzbjlKWkZubUdDbGlxRkVoWGJwbnhyOGxhS3Iw
dDRERytPMTF2CjVQRGh4aHd2b1VZb2ZwWTFEYjN0SHlxdytWM3RRWVA3K3RaNDRB
eW1SdTNtbktZTVZzRHd2M0x1UEdaLzJmQ0MKY2lYVEJIU3VFbzdCUDdBbjdFYkZO
K0JaQldlTlgvcjNOZm1nL0tmQjQ1OFNZMmhFYlplRW5kZUh4d204VFRORwpQaXdi
Nkx5ZE5RS0VFS003cmVFTjkwTXVsUVJMZkhVVFBWZXB5dU9QK1ZySEI3WS9lVWhI
K2RNeHp6d3pLOHJ6CjRYaEwxRFBhT1ZMdmxCSUR5VE5QZU4wV2V4bWpJVEFmTUIw
R0ExVWREZ1FXQkJUQThWK01SSXRNU3Yyb283YjgKYzVlQ0tybzdxREFOQmdsZ2hr
Z0JaUU1FQXdJRkFBTS9BREE4QWh3a0dVK2VVR0kvTFFVejMzTUk3cC9BVXd1WAo0
SnZOVGUrUGhQZFZBaHdvUzdNMFIzbjRnSkkxU2FRdnoyTWhuR3Z1T3Q5UzZMdkRR
NWRFCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K

@ -0,0 +1,45 @@
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
AgMBhqA=

@ -0,0 +1,42 @@
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
Cr9m

@ -0,0 +1,43 @@
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
sUUCAggA

@ -0,0 +1,44 @@
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
owQIAiAhw9ZbovsCAggA

@ -0,0 +1,48 @@
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
YOMCAggA

@ -62,7 +62,7 @@ public class ProbingFailure {
kt("-list -keystore mks")
.shouldHaveExitValue(1)
.shouldContain("This keystore does not support probing");
.shouldContain("Unrecognized keystore format");
// importkeystore
kt("-importkeystore -srckeystore mks -srcstoretype MYKS -destkeystore p12")
@ -70,7 +70,7 @@ public class ProbingFailure {
kt("-importkeystore -srckeystore mks -destkeystore p12a")
.shouldHaveExitValue(1)
.shouldContain("This keystore does not support probing");
.shouldContain("Unrecognized keystore format");
// in-place importkeystore
kt("-importkeystore -srckeystore mks -srcstoretype MYKS -destkeystore mks -deststoretype myks")

@ -0,0 +1,117 @@
/*
* 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.test.lib.security;
import jdk.test.lib.Asserts;
import sun.security.util.DerInputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
import java.io.IOException;
public class DerUtils {
/**
* Returns a DerValue (deep) inside another DerValue.
* <p>
* The location of the inner DerValue is expressed as a string, in which
* each character is a step from the outer DerValue into the inner one.
* If it's a number n, the n'th element (starting from 0) of a sequence
* is the next step. If it's 'c', the content of an OctetString parsed
* as a DerValue is the next step. Note that n cannot be bigger than 9.
* <p>
* Attention: do not reuse the return value. DerValue is mutable and
* reading it advances a pointer inside.
* <p>
* For example, here is a PKCS #12 file:
* <pre>
* 0000:0845 [] SEQUENCE
* 0004:0003 [0] INTEGER 3
* 0007:07FE [1] SEQUENCE
* 000B:000B [10] OID 1.2.840.113549.1.7.1 (data)
* 0016:07EF [11] cont [0]
* 001A:07EB [110] OCTET STRING
* ...
* </pre>
* and the content of OCTET string at offset 001A can be parsed as another
* DerValue which is:
* <pre>
* 0000:07E7 [] SEQUENCE
* 0004:0303 [0] SEQUENCE
* 0008:000B [00] OID 1.2.840.113549.1.7.1 (data)
* ....
* </pre>
* Then the OID is {@code innerDerValue(data, "110c00").getOID()}.
*
* @param data the outer DerValue. We choose byte[] instead of DerValue
* because DerValue is mutable and cannot be reused.
* @param location the location of the inner DerValue
* @return the inner DerValue, or null if no DerValue is at the location
* @throws IOException if an I/O error happens
*/
public static DerValue innerDerValue(byte[] data, String location)
throws IOException {
DerValue v = new DerValue(data);
for (char step : location.toCharArray()) {
if (step == 'c') {
v = new DerValue(v.getOctetString());
} else {
DerInputStream ins = v.getData();
// skip n DerValue in the sequence
for (int i = 0; i < step - '0'; i++) {
ins.getDerValue();
}
if (ins.available() > 0) {
v = ins.getDerValue();
} else {
return null;
}
}
}
return v;
}
/**
* Ensures that the inner DerValue is the expected ObjectIdentifier.
*/
public static void checkAlg(byte[] der, String location,
ObjectIdentifier expected) throws Exception {
Asserts.assertEQ(innerDerValue(der, location).getOID(), expected);
}
/**
* Ensures that the inner DerValue is the expected integer.
*/
public static void checkInt(byte[] der, String location, int expected)
throws Exception {
Asserts.assertEQ(innerDerValue(der, location).getInteger(), expected);
}
/**
* Ensures that there is no inner DerValue at the specified location.
*/
public static void shouldNotExist(byte[] der, String location)
throws Exception {
Asserts.assertTrue(innerDerValue(der, location) == null);
}
}