From 93c69925aeeb2b0bf54cdf743a213acfac5510f4 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 3 Apr 2025 13:23:57 -0600 Subject: [PATCH 01/30] checkpoint --- .../sun/crypto/provider/PBMAC1Parameters.java | 451 ++++++++++++++++++ .../com/sun/crypto/provider/SunJCE.java | 8 + .../crypto/spec/PBMAC1ParameterSpec.java | 134 ++++++ .../classes/sun/security/pkcs12/MacData.java | 156 +++++- .../sun/security/pkcs12/PKCS12KeyStore.java | 112 +++-- .../classes/sun/security/util/KnownOIDs.java | 1 + .../sun/security/pkcs12/PBMAC1Encoding.java | 444 +++++++++++++++++ 7 files changed, 1271 insertions(+), 35 deletions(-) create mode 100644 src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java create mode 100644 src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java create mode 100644 test/jdk/sun/security/pkcs12/PBMAC1Encoding.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java new file mode 100644 index 0000000000000..19971170be3a9 --- /dev/null +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 com.sun.crypto.provider; + +import java.io.IOException; +import java.security.AlgorithmParametersSpi; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import javax.crypto.spec.PBMAC1ParameterSpec; + +import sun.security.util.*; + +/** + * This class implements the parameter set used with password-based + * mac scheme 1 (PBMAC1), which is defined in PKCS#5 as follows: + * + *
+ * -- PBMAC1
+ *
+ * PBMAC1Algorithms ALGORITHM-IDENTIFIER ::=
+ *   { {PBMAC1-params IDENTIFIED BY id-PBMAC1}, ...}
+ *
+ * id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14}
+ *
+ * PBMAC1-params ::= SEQUENCE {
+ *   keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}},
+ *   messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} }
+ *
+ * PBMAC1-KDFs ALGORITHM-IDENTIFIER ::=
+ *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+ *
+ * PBMAC1-MACs ALGORITHM-IDENTIFIER ::= { ... }
+ *
+ * -- PBKDF2
+ *
+ * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::=
+ *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...}
+ *
+ * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
+ *
+ * PBKDF2-params ::= SEQUENCE {
+ *     salt CHOICE {
+ *       specified OCTET STRING,
+ *       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ *     },
+ *     iterationCount INTEGER (1..MAX),
+ *     keyLength INTEGER (1..MAX) OPTIONAL,
+ *     prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+ * }
+ *
+ * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... }
+ *
+ * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= {
+ *     {NULL IDENTIFIED BY id-hmacWithSHA1} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA224} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA256} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA384} |
+ *     {NULL IDENTIFIED BY id-hmacWithSHA512}, ... }
+ *
+ * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::=
+ *     {algorithm id-hmacWithSHA1, parameters NULL : NULL}
+ *
+ * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7}
+ *
+ * 
+ */ +abstract class PBMAC1Parameters extends AlgorithmParametersSpi { + + private static final ObjectIdentifier pkcs5PBKDF2_OID = + ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + private static final ObjectIdentifier pkcs5PBMAC1_OID = + ObjectIdentifier.of(KnownOIDs.PBMAC1); + + // the PBMAC1 algorithm name + private String pbmac1AlgorithmName = null; + + // the salt + private byte[] salt = null; + + // the iteration count + private int iCount = 0; + + // the Hmac function (first one) + private String kdfHmac = null; + + // the Hmac function (second one) + private String Hmac = null; + + // the key derivation function (default is HmacSHA1) + private ObjectIdentifier kdfAlgo_OID = + ObjectIdentifier.of(KnownOIDs.HmacSHA1); + + // the cipher keysize (in bits) + private int keysize = -1; + + PBMAC1Parameters() { + // KDF, encryption & keysize values are set later, in engineInit(byte[]) + } + + PBMAC1Parameters(String pbmac1AlgorithmName) throws NoSuchAlgorithmException { + int and; + String kdfAlgo; + + // Extract the KDF name + this.pbmac1AlgorithmName = pbmac1AlgorithmName; +/* + if (pbmac1AlgorithmName.startsWith("PBMACWith") && + (and = pbes2AlgorithmName.indexOf("And", 7 + 1)) > 0) { + kdfAlgo = pbes2AlgorithmName.substring(7, and); + cipherAlgo = pbes2AlgorithmName.substring(and + 3); + + // Check for keysize + int underscore; + if ((underscore = cipherAlgo.indexOf('_')) > 0) { + int slash; + if ((slash = cipherAlgo.indexOf('/', underscore + 1)) > 0) { + keysize = + Integer.parseInt(cipherAlgo.substring(underscore + 1, + slash)); + } else { + keysize = + Integer.parseInt(cipherAlgo.substring(underscore + 1)); + } + cipherAlgo = cipherAlgo.substring(0, underscore); + } + } else { + throw new NoSuchAlgorithmException("No crypto implementation for " + + pbes2AlgorithmName); + } +*/ + kdfAlgo = "HmacSHA256"; + + switch (kdfAlgo) { + case "HmacSHA1": + case "HmacSHA224": + case "HmacSHA256": + case "HmacSHA384": + case "HmacSHA512": + case "HmacSHA512/224": + case "HmacSHA512/256": + kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.findMatch(kdfAlgo)); + break; + default: + throw new NoSuchAlgorithmException( + "No crypto implementation for " + kdfAlgo); + } + + } + + protected void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (!(paramSpec instanceof PBMAC1ParameterSpec)) { + throw new InvalidParameterSpecException + ("Inappropriate parameter specification"); + } + this.salt = ((PBMAC1ParameterSpec)paramSpec).getSalt().clone(); + this.iCount = ((PBMAC1ParameterSpec)paramSpec).getIterationCount(); + } + + @SuppressWarnings("deprecation") + protected void engineInit(byte[] encoded) + throws IOException + { + DerValue pBMAC1_params = new DerValue(encoded); + if (pBMAC1_params.tag != DerValue.tag_Sequence) { + throw new IOException("PMAC1 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerInputStream xxx = new DerInputStream(pBMAC1_params.toByteArray()); + DerValue[] xxxInfo = xxx.getSequence(2); + if (xxxInfo.length != 2) { + throw new IOException("PMAC1 parameter parsing error: " + + "expected length not 2"); + } + ObjectIdentifier OID = xxxInfo[1].data.getOID(); + KnownOIDs o = KnownOIDs.findMatch(OID.toString()); + if (o == null || (!o.stdName().equals("HmacSHA1") && + !o.stdName().equals("HmacSHA224") && + !o.stdName().equals("HmacSHA256") && + !o.stdName().equals("HmacSHA384") && + !o.stdName().equals("HmacSHA512") && + !o.stdName().equals("HmacSHA512/224") && + !o.stdName().equals("HmacSHA512/256"))) { + throw new IOException("PBE parameter parsing error: " + + "expecting the object identifier for a HmacSHA key " + + "derivation function"); + } + this.Hmac = o.stdName(); + + DerValue kdf = pBMAC1_params.data.getDerValue(); + + String kdfAlgo = parseKDF(kdf); + this.kdfHmac = kdfAlgo; + + if (pBMAC1_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBMAC1 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + + this.pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And"; + } + + @SuppressWarnings("deprecation") + private String parseKDF(DerValue keyDerivationFunc) throws IOException { + + if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { + throw new IOException("PBMAC1 parameter parsing error: " + + "expecting the object identifier for PBKDF2"); + } + if (keyDerivationFunc.tag != DerValue.tag_Sequence) { + throw new IOException("PBMAC1 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); + if (pBKDF2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBMAC1 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue specified = pBKDF2_params.data.getDerValue(); + // the 'specified' ASN.1 CHOICE for 'salt' is supported + if (specified.tag == DerValue.tag_OctetString) { + salt = specified.getOctetString(); + } else { + // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported + throw new IOException("PBMAC1 parameter parsing error: " + + "not an ASN.1 OCTET STRING tag"); + } + iCount = pBKDF2_params.data.getInteger(); + + // keyLength INTEGER (1..MAX) OPTIONAL, + var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); + if (ksDer.isPresent()) { + keysize = ksDer.get().getInteger() * 8; // keysize (in bits) + } else { + throw new IOException("PBMAC1 parameter parsing error: " + + "missing keyLength"); + } + + // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + String kdfAlgo; + var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); + if (prfDer.isPresent()) { + DerValue prf = prfDer.get(); + kdfAlgo_OID = prf.data.getOID(); + KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); + if (o == null || (!o.stdName().equals("HmacSHA1") && + !o.stdName().equals("HmacSHA224") && + !o.stdName().equals("HmacSHA256") && + !o.stdName().equals("HmacSHA384") && + !o.stdName().equals("HmacSHA512") && + !o.stdName().equals("HmacSHA512/224") && + !o.stdName().equals("HmacSHA512/256"))) { + throw new IOException("PBMAC1 parameter parsing error: " + + "expecting the object identifier for a HmacSHA key " + + "derivation function"); + } + kdfAlgo = o.stdName(); + prf.data.getOptional(DerValue.tag_Null); + prf.data.atEnd(); + } else { + kdfAlgo = "HmacSHA1"; + } + return kdfAlgo; + } + + protected void engineInit(byte[] encoded, String decodingMethod) + throws IOException + { + engineInit(encoded); + } + + protected + T engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + if (paramSpec.isAssignableFrom(PBMAC1ParameterSpec.class)) { + return paramSpec.cast( + new PBMAC1ParameterSpec(this.salt, this.iCount, this.kdfHmac, + this.Hmac, this.keysize)); + } else { + throw new InvalidParameterSpecException + ("Inappropriate parameter specification"); + } + } + + protected byte[] engineGetEncoded() throws IOException { + DerOutputStream out = new DerOutputStream(); + + DerOutputStream pBMAC1_params = new DerOutputStream(); + + DerOutputStream keyDerivationFunc = new DerOutputStream(); + keyDerivationFunc.putOID(pkcs5PBKDF2_OID); + + DerOutputStream pBKDF2_params = new DerOutputStream(); + pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' + pBKDF2_params.putInteger(iCount); + + if (keysize > 0) { + pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) + } + + DerOutputStream prf = new DerOutputStream(); + // algorithm is id-hmacWith + prf.putOID(kdfAlgo_OID); + // parameters is 'NULL' + prf.putNull(); + pBKDF2_params.write(DerValue.tag_Sequence, prf); + + keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); + pBMAC1_params.write(DerValue.tag_Sequence, keyDerivationFunc); + + out.write(DerValue.tag_Sequence, pBMAC1_params); + + return out.toByteArray(); + } + + protected byte[] engineGetEncoded(String encodingMethod) + throws IOException + { + return engineGetEncoded(); + } + + /* + * Returns a formatted string describing the parameters. + * + * The algorithm name pattern is: "PBEWithAnd" + * where is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, + * HmacSHA512, HmacSHA512/224, or HmacSHA512/256 and is + * AES with a keysize suffix. + */ + protected String engineToString() { + return pbmac1AlgorithmName; + } + + public static final class General extends PBMAC1Parameters { + public General() throws NoSuchAlgorithmException { + super(); + } + } + +/* + public static final class HmacSHA1AndAES_128 extends PBES2Parameters { + public HmacSHA1AndAES_128() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA1AndAES_128"); + } + } + + public static final class HmacSHA224AndAES_128 extends PBES2Parameters { + public HmacSHA224AndAES_128() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA224AndAES_128"); + } + } + + public static final class HmacSHA256AndAES_128 extends PBES2Parameters { + public HmacSHA256AndAES_128() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA256AndAES_128"); + } + } + + public static final class HmacSHA384AndAES_128 extends PBES2Parameters { + public HmacSHA384AndAES_128() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA384AndAES_128"); + } + } + + public static final class HmacSHA512AndAES_128 extends PBES2Parameters { + public HmacSHA512AndAES_128() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA512AndAES_128"); + } + } + + public static final class HmacSHA512_224AndAES_128 extends PBES2Parameters { + public HmacSHA512_224AndAES_128() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA512/224AndAES_128"); + } + } + + public static final class HmacSHA512_256AndAES_128 extends PBES2Parameters { + public HmacSHA512_256AndAES_128() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA512/256AndAES_128"); + } + } + + public static final class HmacSHA1AndAES_256 extends PBES2Parameters { + public HmacSHA1AndAES_256() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA1AndAES_256"); + } + } + + public static final class HmacSHA224AndAES_256 extends PBES2Parameters { + public HmacSHA224AndAES_256() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA224AndAES_256"); + } + } + + public static final class HmacSHA256AndAES_256 extends PBES2Parameters { + public HmacSHA256AndAES_256() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA256AndAES_256"); + } + } + + public static final class HmacSHA384AndAES_256 extends PBES2Parameters { + public HmacSHA384AndAES_256() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA384AndAES_256"); + } + } + + public static final class HmacSHA512AndAES_256 extends PBES2Parameters { + public HmacSHA512AndAES_256() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA512AndAES_256"); + } + } + + public static final class HmacSHA512_224AndAES_256 extends PBES2Parameters { + public HmacSHA512_224AndAES_256() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA512/224AndAES_256"); + } + } + + public static final class HmacSHA512_256AndAES_256 extends PBES2Parameters { + public HmacSHA512_256AndAES_256() throws NoSuchAlgorithmException { + super("PBEWithHmacSHA512/256AndAES_256"); + } + } +*/ +} diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index 9bb1fa7ff8246..381f4d062a632 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -542,6 +542,14 @@ void putEntries() { ps("AlgorithmParameters", "PBEWithHmacSHA512/256AndAES_256", "com.sun.crypto.provider.PBES2Parameters$HmacSHA512_256AndAES_256"); + psA("AlgorithmParameters", "PBMAC1", + "com.sun.crypto.provider.PBMAC1Parameters$General", + null); + + // just a guess + ps("AlgorithmParameters", "PBMACWithHmacSHA256", + "com.sun.crypto.provider.PBMAC1Parameters$HmacSHA256"); + ps("AlgorithmParameters", "Blowfish", "com.sun.crypto.provider.BlowfishParameters"); diff --git a/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java new file mode 100644 index 0000000000000..e12f3bf944883 --- /dev/null +++ b/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 javax.crypto.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * This class specifies the set of parameters used with PBMAC1, + * as defined in the + * PKCS #12 + * standard. + * + * @spec https://www.rfc-editor.org/info/rfc9579 + * RFC 9579: Use of Password-Based Message Authentication Code 1 (PBMAC1) in PKCS #12 + * @author xxxx + * + * @since 25 + */ +public class PBMAC1ParameterSpec implements AlgorithmParameterSpec { + + private final byte[] salt; + private final int iterationCount; + //private AlgorithmParameterSpec paramSpec = null; + private String kdfHmac = null; + private String hmac = null; + private int keysize; + + /** + * Constructs a parameter set for password-based encryption as defined in + * the PKCS #5 standard. + * + * @param salt the salt. The contents of {@code salt} are copied + * to protect against subsequent modification. + * @param iterationCount the iteration count. + * @exception NullPointerException if {@code salt} is null. + */ + public PBMAC1ParameterSpec(byte[] salt, int iterationCount) { + this.salt = salt.clone(); + this.iterationCount = iterationCount; + } + + /** + * Constructs a parameter set for PBMAC1 as defined in + * the PKCS #12 standard. + * + * @param salt the salt. The contents of {@code salt} are copied + * to protect against subsequent modification. + * @param iterationCount the iteration count. + * @param kdfHmac the HMAC used by PBKDF2. + * @param hmac the HMAC that protects the keystore. + * may be null. + * @param keysize bit length of Hmac key + * @exception NullPointerException if {@code salt} is null. + * + * @since 25 + */ + public PBMAC1ParameterSpec(byte[] salt, int iterationCount, + String kdfHmac, String hmac, int keysize) { + this.salt = salt.clone(); + this.iterationCount = iterationCount; + this.kdfHmac = kdfHmac; + this.hmac = hmac; + this.keysize = keysize; + } + + /** + * Returns the salt. + * + * @return the salt. Returns a new array + * each time this method is called. + */ + public byte[] getSalt() { + return this.salt.clone(); + } + + /** + * Returns the iteration count. + * + * @return the iteration count + */ + public int getIterationCount() { + return this.iterationCount; + } + + /** + * Returns Hmac used by PBKDF2. + * + * @return the Hmac used by PBKDF2. + */ + public String getkdfHmac() { + return this.kdfHmac; + } + + /** + * Returns Hmac used to protect the KeyStore. + * + * @return the Hmac + */ + public String getHmac() { + return this.hmac; + } + + /** + * Returns size of key generated by PBKDF2. + * + * @return size of key generated by PBKDF2. + */ + public int getKeySize() { + return this.keysize; + } +} diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 9a712f28ccc58..1f7564fcba4c6 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ -27,13 +27,19 @@ import java.io.*; import java.security.*; +import java.security.spec.InvalidParameterSpecException; +import java.util.Base64; import sun.security.util.DerInputStream; import sun.security.util.DerOutputStream; import sun.security.util.DerValue; +import sun.security.util.KnownOIDs; +import sun.security.util.ObjectIdentifier; import sun.security.x509.AlgorithmId; import sun.security.pkcs.ParsingException; +import javax.crypto.spec.PBMAC1ParameterSpec; + /** * A MacData type, as defined in PKCS#12. @@ -48,12 +54,16 @@ class MacData { private final byte[] digest; private final byte[] macSalt; private final int iterations; + private final String kdfHmac; + private final String Hmac; + private final int keysize; // the ASN.1 encoded contents of this class private byte[] encoded = null; /** * Parses a PKCS#12 MAC data. + * Good for default or PBMAC1 or whatever else ails you. */ MacData(DerInputStream derin) throws IOException { DerValue[] macData = derin.getSequence(2); @@ -72,9 +82,32 @@ class MacData { AlgorithmId digestAlgorithmId = AlgorithmId.parse(digestInfo[0]); this.digestAlgorithmName = digestAlgorithmId.getName(); this.digestAlgorithmParams = digestAlgorithmId.getParameters(); + // Get the digest. this.digest = digestInfo[1].getOctetString(); + if (digestInfo[0].tag != DerValue.tag_Sequence) { + throw new IOException("algid parse error, not a sequence"); + } + if (digestAlgorithmName.equals("PBMAC1")) { + PBMAC1ParameterSpec pbmac1Spec; + + try { + pbmac1Spec = + digestAlgorithmParams.getParameterSpec( + PBMAC1ParameterSpec.class); + } catch (InvalidParameterSpecException ipse) { + throw new IOException( + "Invalid PBMAC1 algorithm parameters"); + } + this.iterations = pbmac1Spec.getIterationCount(); + this.macSalt = pbmac1Spec.getSalt(); + this.kdfHmac = pbmac1Spec.getkdfHmac(); + this.Hmac = pbmac1Spec.getHmac(); + this.keysize = pbmac1Spec.getKeySize(); + return; + } + // Get the salt. this.macSalt = macData[1].getOctetString(); @@ -84,8 +117,12 @@ class MacData { } else { this.iterations = 1; } + this.kdfHmac = null; + this.Hmac = null; + this.keysize = 0; } + // default constructor MacData(String algName, byte[] digest, byte[] salt, int iterations) throws NoSuchAlgorithmException { @@ -109,6 +146,47 @@ class MacData { this.macSalt = salt; this.iterations = iterations; + this.kdfHmac = null; + this.Hmac = null; + this.keysize = 0; + + // delay the generation of ASN.1 encoding until + // getEncoded() is called + this.encoded = null; + + } + + // constructor for PBMAC1 + MacData(String algName, byte[] digest, byte[] salt, int iterations, + String kdfHmac, String Hmac, int keysize) + throws NoSuchAlgorithmException + { +/* + if (algName == null) + throw new NullPointerException("the algName parameter " + + "must be non-null"); + + AlgorithmId algid = AlgorithmId.get(algName); +*/ + AlgorithmId algid = AlgorithmId.get("PBMAC1"); + this.digestAlgorithmName = algid.getName(); + this.digestAlgorithmParams = algid.getParameters(); + + if (digest == null) { + throw new NullPointerException("the digest " + + "parameter must be non-null"); + } else if (digest.length == 0) { + throw new IllegalArgumentException("the digest " + + "parameter must not be empty"); + } else { + this.digest = digest.clone(); + } + + this.macSalt = salt; + this.iterations = iterations; + this.kdfHmac = kdfHmac; + this.Hmac = Hmac; + this.keysize = keysize; // delay the generation of ASN.1 encoding until // getEncoded() is called @@ -132,14 +210,88 @@ byte[] getDigest() { return digest; } + String getkdfHmac() { + return kdfHmac; + } + + String getHmac() { + return Hmac; + } + + int getKeySize() { + return keysize; + } + /** * Returns the ASN.1 encoding of this object. * @return the ASN.1 encoding. * @exception IOException if error occurs when constructing its * ASN.1 encoding. */ - public byte[] getEncoded() throws NoSuchAlgorithmException + public byte[] getEncoded() throws NoSuchAlgorithmException, + IOException { + if (digestAlgorithmName.equals("PBMAC1")) { + byte[] notUsed = { 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }; + ObjectIdentifier pkcs5PBMAC1_OID = ObjectIdentifier.of("1.2.840.113549.1.5.14"); + ObjectIdentifier pkcs5PBKDF2_OID = + ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + AlgorithmId algid = AlgorithmId.get(digestAlgorithmName); + AlgorithmId HmacAlgid = AlgorithmId.get(Hmac); + AlgorithmId kdfHmacAlgid = AlgorithmId.get(kdfHmac); + + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp0 = new DerOutputStream(); + DerOutputStream tmp1 = new DerOutputStream(); + DerOutputStream tmp2 = new DerOutputStream(); + DerOutputStream tmp3 = new DerOutputStream(); + DerOutputStream tmp4 = new DerOutputStream(); + DerOutputStream Hmac = new DerOutputStream(); + DerOutputStream kdfHmac = new DerOutputStream(); + DerOutputStream keyDerivationFunc = new DerOutputStream(); + + // encode kdfHmac algorithm + kdfHmac.putOID(ObjectIdentifier.of(KnownOIDs + .findMatch(this.kdfHmac))); + kdfHmac.putNull(); + + // encode Hmac algorithm + Hmac.putOID(ObjectIdentifier.of(KnownOIDs.findMatch(this.Hmac))); + Hmac.putNull(); + + DerOutputStream pBKDF2_params = new DerOutputStream(); + + pBKDF2_params.putOctetString(macSalt); // choice: 'specified OCTET STRING' + + // encode iterations + pBKDF2_params.putInteger(iterations); + + // encode derived key length + if (keysize > 0) { + pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) + } + pBKDF2_params.write(DerValue.tag_Sequence, kdfHmac); + tmp3.putOID(pkcs5PBKDF2_OID); + tmp3.write(DerValue.tag_Sequence, pBKDF2_params); + tmp4.write(DerValue.tag_Sequence, tmp3); + tmp4.write(DerValue.tag_Sequence, Hmac); + + // PBMAC1 + tmp1.putOID(ObjectIdentifier.of(KnownOIDs + .findMatch(digestAlgorithmName))); + + tmp1.write(DerValue.tag_Sequence, tmp4); + tmp2.write(DerValue.tag_Sequence, tmp1); + tmp2.putOctetString(digest); + tmp0.write(DerValue.tag_Sequence, tmp2); + tmp0.putOctetString(notUsed); + tmp0.putInteger(1); + out.write(DerValue.tag_Sequence, tmp0); + this.encoded = out.toByteArray(); + + return this.encoded.clone(); + } + if (this.encoded != null) return this.encoded.clone(); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 52393f0466aba..14c2831ac3bbe 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ -28,6 +28,7 @@ import java.io.*; import java.security.AccessController; import java.security.MessageDigest; +import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.Key; import java.security.KeyFactory; @@ -869,6 +870,18 @@ private void destroyPBEKey(SecretKey key) { } } + /* + * Invoke the PKCS#5 PBKDF2 algorithm + */ + private static SecretKey PBKDF2(String hmac, char[] secret, byte[] salt, + int count, int keyLength) throws GeneralSecurityException { + + PBEKeySpec keySpec = new PBEKeySpec(secret, salt, count, keyLength); + SecretKeyFactory skf = + SecretKeyFactory.getInstance("PBKDF2With" +hmac, "SunJCE"); + return skf.generateSecret(keySpec); + } + /* * Encrypt private key or secret key using Password-based encryption (PBE) * as defined in PKCS#5. @@ -1495,17 +1508,19 @@ private byte[] calculateMac(char[] passwd, byte[] data) byte[] mData; String algName = macAlgorithm.substring(7); + algName = "PBMAC1"; try { // Generate a random salt. byte[] salt = getSalt(); // generate MAC (MAC key is generated within JCE) - Mac m = Mac.getInstance(macAlgorithm); - PBEParameterSpec params = - new PBEParameterSpec(salt, macIterationCount); + Mac m = Mac.getInstance("HmacSHA256"); SecretKey key = getPBEKey(passwd); + SecretKey derivedKey = PBKDF2("HmacSHA256", + (new String(key.getEncoded(), + UTF_8)).toCharArray(), salt, macIterationCount, 256); try { - m.init(key, params); + m.init(derivedKey); } finally { destroyPBEKey(key); } @@ -1514,7 +1529,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) // encode as MacData MacData macData = new MacData(algName, macResult, salt, - macIterationCount); + macIterationCount, "HmacSHA256", "HmacSHA256", 256); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); mData = bytes.toByteArray(); @@ -2140,39 +2155,70 @@ public synchronized void engineLoad(InputStream stream, char[] password) String algName = macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); + if (algName.equals("PBMAC1")) { - // Change SHA-1 to SHA1 - algName = algName.replace("-", ""); + SecretKey key = getPBEKey(password); + SecretKey derivedKey = PBKDF2(macData.getkdfHmac(), + (new String(key.getEncoded(), + UTF_8)).toCharArray(), macData.getSalt(), + macData.getIterations(), macData.getKeySize()); - macAlgorithm = "HmacPBE" + algName; - macIterationCount = ic; + Mac m = Mac.getInstance(macData.getHmac()); - // generate MAC (MAC key is created within JCE) - Mac m = Mac.getInstance(macAlgorithm); - PBEParameterSpec params = - new PBEParameterSpec(macData.getSalt(), ic); + RetryWithZero.run(pass -> { + try { + m.init(derivedKey); + } finally { + destroyPBEKey(key); + } + m.update(authSafeData); + byte[] macResult = m.doFinal(); - RetryWithZero.run(pass -> { - SecretKey key = getPBEKey(pass); - try { - m.init(key, params); - } finally { - destroyPBEKey(key); - } - m.update(authSafeData); - byte[] macResult = m.doFinal(); + if (debug != null) { + debug.println("Checking keystore integrity " + + "(" + m.getAlgorithm() + " iterations: " + ic + ")"); + } - 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); + } else { - if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { - throw new UnrecoverableKeyException("Failed PKCS12" + - " integrity checking"); - } - return (Void) null; - }, password); + // 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); + try { + m.init(key, params); + } finally { + destroyPBEKey(key); + } + 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); } diff --git a/src/java.base/share/classes/sun/security/util/KnownOIDs.java b/src/java.base/share/classes/sun/security/util/KnownOIDs.java index 8cd0a03a365a8..997fb0569a036 100644 --- a/src/java.base/share/classes/sun/security/util/KnownOIDs.java +++ b/src/java.base/share/classes/sun/security/util/KnownOIDs.java @@ -211,6 +211,7 @@ public enum KnownOIDs { PBEWithSHA1AndRC2("1.2.840.113549.1.5.11"), PBKDF2WithHmacSHA1("1.2.840.113549.1.5.12"), PBES2("1.2.840.113549.1.5.13"), + PBMAC1("1.2.840.113549.1.5.14"), // PKCS7 1.2.840.113549.1.7.* PKCS7("1.2.840.113549.1.7"), diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java new file mode 100644 index 0000000000000..354afda6ce1a9 --- /dev/null +++ b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2025, 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 8343232 + * @summary PKCS#12 KeyStore support for RFC 9579: Use of Password-Based Message Authentication Code 1 (PBMAC1) + */ + +import java.io.ByteArrayInputStream; +import java.security.KeyStore; +import java.util.Base64; + +public class PBMAC1Encoding { + // A.1. Valid PKCS #12 File with SHA-256 HMAC and PRF + static final String A1 = + "MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH" + + "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG" + + "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME" + + "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb" + + "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb" + + "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF" + + "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9" + + "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy" + + "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP" + + "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ" + + "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij" + + "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh" + + "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU" + + "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD" + + "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5" + + "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+" + + "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA" + + "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r" + + "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ" + + "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF" + + "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU" + + "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0" + + "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4" + + "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj" + + "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B" + + "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+" + + "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG" + + "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1" + + "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ" + + "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg" + + "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248" + + "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD" + + "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0" + + "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD" + + "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi" + + "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7" + + "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led" + + "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf" + + "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h" + + "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B" + + "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF" + + "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi" + + "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY" + + "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR" + + "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82" + + "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/" + + "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q" + + "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm" + + "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU" + + "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0" + + "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE" + + "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM" + + "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq" + + "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfDBtMEkGCSqGSIb3DQEF" + + "DjA8MCwGCSqGSIb3DQEFDDAfBAhvRzw4sC4xcwICCAACASAwDAYIKoZIhvcNAgkF" + + "ADAMBggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG" + + "3QQITk9UIFVTRUQCAQE="; + + // A.2. Valid PKCS #12 File with SHA-256 HMAC and SHA-512 PRF + static final String A2 = + "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" + + "6QQITk9UIFVTRUQCAQE="; + + // A.3. Valid PKCS #12 File with SHA-512 HMAC and PRF + static final String A3 = + "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"; + + // Invalid PKCS #12 File with Incorrect Iteration Count + static final String A4 = + "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" + + "3QQITk9UIFVTRUQCAggA"; + + // A.5. Invalid PKCS #12 File with Incorrect Salt + static final String A5 = + "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" + + "3QQIb0c8OLAuMXMCAQE="; + + // A.6. Invalid PKCS #12 File with Missing Key Length + static final String A6 = + "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" + + "b0c8OLAuMXMCAggA"; + + static String password = "1234"; + + public static void main(String[] args) throws Exception { + KeyStore ks; + + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A1)), + password.toCharArray()); + System.out.println("A.1 pass"); + + // Make sure both cert and key can be retrieved + //System.out.println(ks.getCertificate("a")); + //System.out.println(ks.getKey("a", "changeit".toCharArray())); + + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), + password.toCharArray()); + System.out.println("A.2 pass"); + + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A3)), + password.toCharArray()); + System.out.println("A.3 pass"); + + try { + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A4)), + password.toCharArray()); + } catch (Exception e) { + System.out.println("A.4 pass"); + } + + try { + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A5)), + password.toCharArray()); + + } catch (Exception e) { + System.out.println("A.5 pass"); + } + + try { + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A6)), + password.toCharArray()); + } catch (Exception e) { + System.out.println("A.6 pass"); + } + } +} From 60f4c15cea0eac0699d028bace87a55c81851585 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Mon, 7 Apr 2025 08:42:52 -0600 Subject: [PATCH 02/30] separate old from new in calculateMac() --- .../sun/security/pkcs12/PKCS12KeyStore.java | 98 +++++++++++++------ 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index d9616e1a39096..e09d7180e353f 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -189,6 +189,8 @@ public DualFormatPKCS12() { private String certProtectionAlgorithm = null; private int certPbeIterationCount = -1; private String macAlgorithm = null; + private String pbmac1Hmac = null; + private String pbmac1KdfHmac = null; private int macIterationCount = -1; // the source of randomness @@ -869,15 +871,15 @@ private void destroyPBEKey(SecretKey key) { /* * Invoke the PKCS#5 PBKDF2 algorithm - */ + */ private static SecretKey PBKDF2(String hmac, char[] secret, byte[] salt, - int count, int keyLength) throws GeneralSecurityException { - + int count, int keyLength) throws GeneralSecurityException { + PBEKeySpec keySpec = new PBEKeySpec(secret, salt, count, keyLength); SecretKeyFactory skf = - SecretKeyFactory.getInstance("PBKDF2With" +hmac, "SunJCE"); + SecretKeyFactory.getInstance("PBKDF2With" +hmac, "SunJCE"); return skf.generateSecret(keySpec); - } + } /* * Encrypt private key or secret key using Password-based encryption (PBE) @@ -1278,6 +1280,7 @@ public synchronized void engineStore(OutputStream stream, char[] password) macIterationCount = defaultMacIterationCount(); } if (password != null && !macAlgorithm.equalsIgnoreCase("NONE")) { + macAlgorithm = defaultMacAlgorithm(); byte[] macData = calculateMac(password, authenticatedSafe); pfx.write(macData); } @@ -1503,35 +1506,66 @@ private byte[] calculateMac(char[] passwd, byte[] data) throws IOException { byte[] mData; - String algName = macAlgorithm.substring(7); - algName = "PBMAC1"; - try { - // Generate a random salt. - byte[] salt = getSalt(); - - // generate MAC (MAC key is generated within JCE) - Mac m = Mac.getInstance("HmacSHA256"); - SecretKey key = getPBEKey(passwd); - SecretKey derivedKey = PBKDF2("HmacSHA256", - (new String(key.getEncoded(), - UTF_8)).toCharArray(), salt, macIterationCount, 256); + if (macAlgorithm.equals("PBMAC1")) { + // PBMAC1 try { - m.init(derivedKey); - } finally { - destroyPBEKey(key); + // Generate a random salt. + byte[] salt = getSalt(); + + // generate MAC (MAC key is generated within JCE) + Mac m = Mac.getInstance(pbmac1Hmac); + SecretKey key = getPBEKey(passwd); + SecretKey derivedKey = PBKDF2(pbmac1KdfHmac, + (new String(key.getEncoded(), + UTF_8)).toCharArray(), salt, macIterationCount, 256); + try { + m.init(derivedKey); + } finally { + destroyPBEKey(key); + } + m.update(data); + byte[] macResult = m.doFinal(); + + // encode as MacData + MacData macData = new MacData("PBMAC1", macResult, salt, + macIterationCount, pbmac1KdfHmac, pbmac1Hmac, 256); + DerOutputStream bytes = new DerOutputStream(); + bytes.write(macData.getEncoded()); + mData = bytes.toByteArray(); + } catch (Exception e) { + throw new IOException("calculateMac failed: " + e, e); } - m.update(data); - byte[] macResult = m.doFinal(); + } else { + // The old (original) way of computing the MAC. + String algName = macAlgorithm.substring(7); - // encode as MacData - MacData macData = new MacData(algName, macResult, salt, - macIterationCount, "HmacSHA256", "HmacSHA256", 256); - DerOutputStream bytes = new DerOutputStream(); - bytes.write(macData.getEncoded()); - mData = bytes.toByteArray(); - } catch (Exception e) { - throw new IOException("calculateMac failed: " + e, e); + try { + // Generate a random salt. + byte[] salt = getSalt(); + + // generate MAC (MAC key is generated within JCE) + Mac m = Mac.getInstance(macAlgorithm); + PBEParameterSpec params = + new PBEParameterSpec(salt, macIterationCount); + SecretKey key = getPBEKey(passwd); + try { + m.init(key, params); + } finally { + destroyPBEKey(key); + } + m.update(data); + byte[] macResult = m.doFinal(); + + // encode as MacData + MacData macData = new MacData(algName, macResult, salt, + macIterationCount); + DerOutputStream bytes = new DerOutputStream(); + bytes.write(macData.getEncoded()); + mData = bytes.toByteArray(); + } catch (Exception e) { + throw new IOException("calculateMac failed: " + e, e); + } } return mData; } @@ -2182,6 +2216,10 @@ public synchronized void engineLoad(InputStream stream, char[] password) } return (Void) null; }, password); + macAlgorithm = algName; + pbmac1Hmac = macData.getHmac(); + pbmac1KdfHmac = macData.getkdfHmac(); + macIterationCount = macData.getIterations(); } else { // Change SHA-1 to SHA1 From d21040b06be991a4ad082f86f545f8ee6bee01d6 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 11 Apr 2025 14:41:45 -0600 Subject: [PATCH 03/30] test failures and white space --- .../share/classes/com/sun/crypto/provider/SunJCE.java | 4 ---- .../share/classes/sun/security/pkcs12/PKCS12KeyStore.java | 7 +++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index 12d91e671cde9..f486e562e049a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -544,10 +544,6 @@ void putEntries() { "com.sun.crypto.provider.PBMAC1Parameters$General", null); - // just a guess - ps("AlgorithmParameters", "PBMACWithHmacSHA256", - "com.sun.crypto.provider.PBMAC1Parameters$HmacSHA256"); - ps("AlgorithmParameters", "Blowfish", "com.sun.crypto.provider.BlowfishParameters"); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index e09d7180e353f..5c25e711ba10b 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -1280,7 +1280,6 @@ public synchronized void engineStore(OutputStream stream, char[] password) macIterationCount = defaultMacIterationCount(); } if (password != null && !macAlgorithm.equalsIgnoreCase("NONE")) { - macAlgorithm = defaultMacAlgorithm(); byte[] macData = calculateMac(password, authenticatedSafe); pfx.write(macData); } @@ -1543,7 +1542,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) try { // Generate a random salt. byte[] salt = getSalt(); - + // generate MAC (MAC key is generated within JCE) Mac m = Mac.getInstance(macAlgorithm); PBEParameterSpec params = @@ -1556,7 +1555,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) } m.update(data); byte[] macResult = m.doFinal(); - + // encode as MacData MacData macData = new MacData(algName, macResult, salt, macIterationCount); @@ -2205,7 +2204,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) m.update(authSafeData); byte[] macResult = m.doFinal(); - if (debug != null) { + if (debug != null) { debug.println("Checking keystore integrity " + "(" + m.getAlgorithm() + " iterations: " + ic + ")"); } From b5cb457de72c6d61298a5d2fa7a5750e051db6f4 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 22 May 2025 12:20:30 -0600 Subject: [PATCH 04/30] another iteration --- .../com/sun/crypto/provider/PBMAC1Core.java | 43 +++- .../sun/crypto/provider/PBMAC1Parameters.java | 153 +----------- .../crypto/spec/PBMAC1ParameterSpec.java | 40 +-- .../classes/sun/security/pkcs12/MacData.java | 108 +++----- .../sun/security/pkcs12/PKCS12KeyStore.java | 235 +++++++----------- 5 files changed, 175 insertions(+), 404 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index 146999e35ce7d..425459bf91e6b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -33,6 +33,7 @@ import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.PBMAC1ParameterSpec; import java.security.*; import java.security.spec.*; @@ -44,8 +45,7 @@ abstract class PBMAC1Core extends HmacCore { // NOTE: this class inherits the Cloneable interface from HmacCore // Need to override clone() if mutable fields are added. - private final String kdfAlgo; - private final String hashAlgo; + private String kdfAlgo; private final int blockLength; // in octets /** @@ -56,7 +56,6 @@ abstract class PBMAC1Core extends HmacCore { throws NoSuchAlgorithmException { super(hashAlgo, blockLength); this.kdfAlgo = kdfAlgo; - this.hashAlgo = hashAlgo; this.blockLength = blockLength; } @@ -107,9 +106,8 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) char[] passwdChars; byte[] salt = null; int iCount = 0; - if (key instanceof javax.crypto.interfaces.PBEKey) { - javax.crypto.interfaces.PBEKey pbeKey = - (javax.crypto.interfaces.PBEKey) key; + int keyLength = blockLength; + if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) { passwdChars = pbeKey.getPassword(); salt = pbeKey.getSalt(); // maybe null if unspecified iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified @@ -138,11 +136,8 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) throw new InvalidAlgorithmParameterException ("PBEParameterSpec required for salt and iteration count"); } - } else if (!(params instanceof PBEParameterSpec)) { - throw new InvalidAlgorithmParameterException - ("PBEParameterSpec type required"); - } else { - PBEParameterSpec pbeParams = (PBEParameterSpec) params; + //keyLength = blockLength; + } else if ((params instanceof PBEParameterSpec pbeParams)) { // make sure the parameter values are consistent if (salt != null) { if (!Arrays.equals(salt, pbeParams.getSalt())) { @@ -160,7 +155,31 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) } else { iCount = pbeParams.getIterationCount(); } + //keyLength = blockLength; + } else if ((params instanceof PBMAC1ParameterSpec pbmac1Params)) { + if (salt != null) { + if (!Arrays.equals(salt, pbmac1Params.getSalt())) { + throw new InvalidAlgorithmParameterException + ("Inconsistent value of salt between key and params"); + } + } else { + salt = pbmac1Params.getSalt(); + } + if (iCount != 0) { + if (iCount != pbmac1Params.getIterationCount()) { + throw new InvalidAlgorithmParameterException + ("Different iteration count between key and params"); + } + } else { + iCount = pbmac1Params.getIterationCount(); + } + keyLength = pbmac1Params.getKeyLength(); + this.kdfAlgo = pbmac1Params.getkdfHmac(); + } else { + throw new InvalidAlgorithmParameterException + ("PBEParameterSpec or PBMAC1ParameterSpec required"); } + // For security purpose, we need to enforce a minimum length // for salt; just require the minimum salt length to be 8-byte // which is what PKCS#5 recommends and openssl does. @@ -173,7 +192,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) ("IterationCount must be a positive number"); } - pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, blockLength); + pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, keyLength); // password char[] was cloned in PBEKeySpec constructor, // so we can zero it out here } finally { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index 19971170be3a9..d50b1bbc1ebc9 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -121,54 +121,8 @@ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { // KDF, encryption & keysize values are set later, in engineInit(byte[]) } - PBMAC1Parameters(String pbmac1AlgorithmName) throws NoSuchAlgorithmException { - int and; - String kdfAlgo; - - // Extract the KDF name - this.pbmac1AlgorithmName = pbmac1AlgorithmName; -/* - if (pbmac1AlgorithmName.startsWith("PBMACWith") && - (and = pbes2AlgorithmName.indexOf("And", 7 + 1)) > 0) { - kdfAlgo = pbes2AlgorithmName.substring(7, and); - cipherAlgo = pbes2AlgorithmName.substring(and + 3); - - // Check for keysize - int underscore; - if ((underscore = cipherAlgo.indexOf('_')) > 0) { - int slash; - if ((slash = cipherAlgo.indexOf('/', underscore + 1)) > 0) { - keysize = - Integer.parseInt(cipherAlgo.substring(underscore + 1, - slash)); - } else { - keysize = - Integer.parseInt(cipherAlgo.substring(underscore + 1)); - } - cipherAlgo = cipherAlgo.substring(0, underscore); - } - } else { - throw new NoSuchAlgorithmException("No crypto implementation for " + - pbes2AlgorithmName); - } -*/ - kdfAlgo = "HmacSHA256"; - - switch (kdfAlgo) { - case "HmacSHA1": - case "HmacSHA224": - case "HmacSHA256": - case "HmacSHA384": - case "HmacSHA512": - case "HmacSHA512/224": - case "HmacSHA512/256": - kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.findMatch(kdfAlgo)); - break; - default: - throw new NoSuchAlgorithmException( - "No crypto implementation for " + kdfAlgo); - } - + PBMAC1Parameters(String pbmac1AlgorithmName) { + // TBD } protected void engineInit(AlgorithmParameterSpec paramSpec) @@ -191,13 +145,13 @@ protected void engineInit(byte[] encoded) throw new IOException("PMAC1 parameter parsing error: " + "not an ASN.1 SEQUENCE tag"); } - DerInputStream xxx = new DerInputStream(pBMAC1_params.toByteArray()); - DerValue[] xxxInfo = xxx.getSequence(2); - if (xxxInfo.length != 2) { + DerValue[] Info = (new DerInputStream(pBMAC1_params.toByteArray())) + .getSequence(2); + if (Info.length != 2) { throw new IOException("PMAC1 parameter parsing error: " + "expected length not 2"); } - ObjectIdentifier OID = xxxInfo[1].data.getOID(); + ObjectIdentifier OID = Info[1].data.getOID(); KnownOIDs o = KnownOIDs.findMatch(OID.toString()); if (o == null || (!o.stdName().equals("HmacSHA1") && !o.stdName().equals("HmacSHA224") && @@ -206,7 +160,7 @@ protected void engineInit(byte[] encoded) !o.stdName().equals("HmacSHA512") && !o.stdName().equals("HmacSHA512/224") && !o.stdName().equals("HmacSHA512/256"))) { - throw new IOException("PBE parameter parsing error: " + throw new IOException("PBMAC1 parameter parsing error: " + "expecting the object identifier for a HmacSHA key " + "derivation function"); } @@ -222,7 +176,7 @@ protected void engineInit(byte[] encoded) + "not an ASN.1 SEQUENCE tag"); } - this.pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And"; + this.pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" +Hmac; } @SuppressWarnings("deprecation") @@ -347,11 +301,6 @@ protected byte[] engineGetEncoded(String encodingMethod) /* * Returns a formatted string describing the parameters. - * - * The algorithm name pattern is: "PBEWithAnd" - * where is one of: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, - * HmacSHA512, HmacSHA512/224, or HmacSHA512/256 and is - * AES with a keysize suffix. */ protected String engineToString() { return pbmac1AlgorithmName; @@ -362,90 +311,4 @@ public General() throws NoSuchAlgorithmException { super(); } } - -/* - public static final class HmacSHA1AndAES_128 extends PBES2Parameters { - public HmacSHA1AndAES_128() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA1AndAES_128"); - } - } - - public static final class HmacSHA224AndAES_128 extends PBES2Parameters { - public HmacSHA224AndAES_128() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA224AndAES_128"); - } - } - - public static final class HmacSHA256AndAES_128 extends PBES2Parameters { - public HmacSHA256AndAES_128() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA256AndAES_128"); - } - } - - public static final class HmacSHA384AndAES_128 extends PBES2Parameters { - public HmacSHA384AndAES_128() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA384AndAES_128"); - } - } - - public static final class HmacSHA512AndAES_128 extends PBES2Parameters { - public HmacSHA512AndAES_128() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA512AndAES_128"); - } - } - - public static final class HmacSHA512_224AndAES_128 extends PBES2Parameters { - public HmacSHA512_224AndAES_128() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA512/224AndAES_128"); - } - } - - public static final class HmacSHA512_256AndAES_128 extends PBES2Parameters { - public HmacSHA512_256AndAES_128() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA512/256AndAES_128"); - } - } - - public static final class HmacSHA1AndAES_256 extends PBES2Parameters { - public HmacSHA1AndAES_256() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA1AndAES_256"); - } - } - - public static final class HmacSHA224AndAES_256 extends PBES2Parameters { - public HmacSHA224AndAES_256() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA224AndAES_256"); - } - } - - public static final class HmacSHA256AndAES_256 extends PBES2Parameters { - public HmacSHA256AndAES_256() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA256AndAES_256"); - } - } - - public static final class HmacSHA384AndAES_256 extends PBES2Parameters { - public HmacSHA384AndAES_256() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA384AndAES_256"); - } - } - - public static final class HmacSHA512AndAES_256 extends PBES2Parameters { - public HmacSHA512AndAES_256() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA512AndAES_256"); - } - } - - public static final class HmacSHA512_224AndAES_256 extends PBES2Parameters { - public HmacSHA512_224AndAES_256() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA512/224AndAES_256"); - } - } - - public static final class HmacSHA512_256AndAES_256 extends PBES2Parameters { - public HmacSHA512_256AndAES_256() throws NoSuchAlgorithmException { - super("PBEWithHmacSHA512/256AndAES_256"); - } - } -*/ } diff --git a/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java index e12f3bf944883..e650fccd28b0b 100644 --- a/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java @@ -37,30 +37,15 @@ * RFC 9579: Use of Password-Based Message Authentication Code 1 (PBMAC1) in PKCS #12 * @author xxxx * - * @since 25 + * @since 26 */ public class PBMAC1ParameterSpec implements AlgorithmParameterSpec { private final byte[] salt; private final int iterationCount; - //private AlgorithmParameterSpec paramSpec = null; private String kdfHmac = null; private String hmac = null; - private int keysize; - - /** - * Constructs a parameter set for password-based encryption as defined in - * the PKCS #5 standard. - * - * @param salt the salt. The contents of {@code salt} are copied - * to protect against subsequent modification. - * @param iterationCount the iteration count. - * @exception NullPointerException if {@code salt} is null. - */ - public PBMAC1ParameterSpec(byte[] salt, int iterationCount) { - this.salt = salt.clone(); - this.iterationCount = iterationCount; - } + private int keyLength; /** * Constructs a parameter set for PBMAC1 as defined in @@ -68,22 +53,21 @@ public PBMAC1ParameterSpec(byte[] salt, int iterationCount) { * * @param salt the salt. The contents of {@code salt} are copied * to protect against subsequent modification. - * @param iterationCount the iteration count. - * @param kdfHmac the HMAC used by PBKDF2. - * @param hmac the HMAC that protects the keystore. - * may be null. - * @param keysize bit length of Hmac key - * @exception NullPointerException if {@code salt} is null. + * @param iterationCount the iteration count + * @param kdfHmac the HMAC used by PBKDF2 + * @param hmac the HMAC that protects the keystore + * @param keyLength bit length of Hmac key + * @exception NullPointerException if {@code salt} is null * - * @since 25 + * @since 26 */ public PBMAC1ParameterSpec(byte[] salt, int iterationCount, - String kdfHmac, String hmac, int keysize) { + String kdfHmac, String hmac, int keyLength) { this.salt = salt.clone(); this.iterationCount = iterationCount; this.kdfHmac = kdfHmac; this.hmac = hmac; - this.keysize = keysize; + this.keyLength = keyLength; } /** @@ -128,7 +112,7 @@ public String getHmac() { * * @return size of key generated by PBKDF2. */ - public int getKeySize() { - return this.keysize; + public int getKeyLength() { + return this.keyLength; } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 1f7564fcba4c6..6875a28c8f98d 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -25,20 +25,17 @@ package sun.security.pkcs12; -import java.io.*; -import java.security.*; +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; -import java.util.Base64; +import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.PBMAC1ParameterSpec; -import sun.security.util.DerInputStream; -import sun.security.util.DerOutputStream; -import sun.security.util.DerValue; -import sun.security.util.KnownOIDs; -import sun.security.util.ObjectIdentifier; -import sun.security.x509.AlgorithmId; import sun.security.pkcs.ParsingException; - -import javax.crypto.spec.PBMAC1ParameterSpec; +import sun.security.util.*; +import sun.security.x509.AlgorithmId; /** @@ -50,20 +47,19 @@ class MacData { private final String digestAlgorithmName; - private AlgorithmParameters digestAlgorithmParams; + private final AlgorithmParameters digestAlgorithmParams; private final byte[] digest; private final byte[] macSalt; private final int iterations; private final String kdfHmac; private final String Hmac; - private final int keysize; + private final int keyLength; // the ASN.1 encoded contents of this class private byte[] encoded = null; /** * Parses a PKCS#12 MAC data. - * Good for default or PBMAC1 or whatever else ails you. */ MacData(DerInputStream derin) throws IOException { DerValue[] macData = derin.getSequence(2); @@ -104,14 +100,14 @@ class MacData { this.macSalt = pbmac1Spec.getSalt(); this.kdfHmac = pbmac1Spec.getkdfHmac(); this.Hmac = pbmac1Spec.getHmac(); - this.keysize = pbmac1Spec.getKeySize(); + this.keyLength = pbmac1Spec.getKeyLength(); return; } // Get the salt. this.macSalt = macData[1].getOctetString(); - // Iterations is optional. The default value is 1. + // Iterations are optional. The default value is 1. if (macData.length > 2) { this.iterations = macData[2].getInteger(); } else { @@ -119,16 +115,16 @@ class MacData { } this.kdfHmac = null; this.Hmac = null; - this.keysize = 0; + this.keyLength = 0; } - // default constructor - MacData(String algName, byte[] digest, byte[] salt, int iterations) + MacData(String algName, byte[] digest, AlgorithmParameterSpec params) throws NoSuchAlgorithmException { - if (algName == null) + if (algName == null) { throw new NullPointerException("the algName parameter " + "must be non-null"); + } AlgorithmId algid = AlgorithmId.get(algName); this.digestAlgorithmName = algid.getName(); @@ -144,54 +140,25 @@ class MacData { this.digest = digest.clone(); } - this.macSalt = salt; - this.iterations = iterations; - this.kdfHmac = null; - this.Hmac = null; - this.keysize = 0; - - // delay the generation of ASN.1 encoding until - // getEncoded() is called - this.encoded = null; - - } - - // constructor for PBMAC1 - MacData(String algName, byte[] digest, byte[] salt, int iterations, - String kdfHmac, String Hmac, int keysize) - throws NoSuchAlgorithmException - { -/* - if (algName == null) - throw new NullPointerException("the algName parameter " + - "must be non-null"); - - AlgorithmId algid = AlgorithmId.get(algName); -*/ - AlgorithmId algid = AlgorithmId.get("PBMAC1"); - this.digestAlgorithmName = algid.getName(); - this.digestAlgorithmParams = algid.getParameters(); - - if (digest == null) { - throw new NullPointerException("the digest " + - "parameter must be non-null"); - } else if (digest.length == 0) { - throw new IllegalArgumentException("the digest " + - "parameter must not be empty"); + if (params instanceof PBMAC1ParameterSpec p) { + this.macSalt = p.getSalt(); + this.iterations = p.getIterationCount(); + this.kdfHmac = p.getkdfHmac(); + this.Hmac = p.getHmac(); + this.keyLength = p.getKeyLength(); + } else if (params instanceof PBEParameterSpec p) { + this.macSalt = p.getSalt(); + this.iterations = p.getIterationCount(); + this.kdfHmac = null; + this.Hmac = null; + this.keyLength = 0; } else { - this.digest = digest.clone(); + throw new IllegalArgumentException("unsupported parameter spec"); } - this.macSalt = salt; - this.iterations = iterations; - this.kdfHmac = kdfHmac; - this.Hmac = Hmac; - this.keysize = keysize; - // delay the generation of ASN.1 encoding until // getEncoded() is called this.encoded = null; - } String getDigestAlgName() { @@ -218,8 +185,8 @@ String getHmac() { return Hmac; } - int getKeySize() { - return keysize; + int getKeyLength() { + return keyLength; } /** @@ -233,12 +200,8 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, { if (digestAlgorithmName.equals("PBMAC1")) { byte[] notUsed = { 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }; - ObjectIdentifier pkcs5PBMAC1_OID = ObjectIdentifier.of("1.2.840.113549.1.5.14"); - ObjectIdentifier pkcs5PBKDF2_OID = - ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - AlgorithmId algid = AlgorithmId.get(digestAlgorithmName); - AlgorithmId HmacAlgid = AlgorithmId.get(Hmac); - AlgorithmId kdfHmacAlgid = AlgorithmId.get(kdfHmac); + ObjectIdentifier pkcs5PBKDF2_OID = + ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); DerOutputStream out = new DerOutputStream(); DerOutputStream tmp0 = new DerOutputStream(); @@ -248,7 +211,6 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, DerOutputStream tmp4 = new DerOutputStream(); DerOutputStream Hmac = new DerOutputStream(); DerOutputStream kdfHmac = new DerOutputStream(); - DerOutputStream keyDerivationFunc = new DerOutputStream(); // encode kdfHmac algorithm kdfHmac.putOID(ObjectIdentifier.of(KnownOIDs @@ -267,8 +229,8 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, pBKDF2_params.putInteger(iterations); // encode derived key length - if (keysize > 0) { - pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) + if (keyLength > 0) { + pBKDF2_params.putInteger(keyLength / 8); // derived key length (in octets) } pBKDF2_params.write(DerValue.tag_Sequence, kdfHmac); tmp3.putOID(pkcs5PBKDF2_OID); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 5c25e711ba10b..4382838855597 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -26,53 +26,38 @@ package sun.security.pkcs12; import java.io.*; -import java.security.MessageDigest; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.KeyStoreSpi; -import java.security.KeyStoreException; -import java.security.PKCS12Attribute; -import java.security.PrivateKey; -import java.security.UnrecoverableEntryException; -import java.security.UnrecoverableKeyException; -import java.security.SecureRandom; -import java.security.Security; +import java.security.*; import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.security.cert.CertificateException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.util.*; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; -import javax.crypto.SecretKeyFactory; -import javax.crypto.SecretKey; import javax.crypto.Cipher; import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.PBMAC1ParameterSpec; +import javax.crypto.spec.SecretKeySpec; import javax.security.auth.DestroyFailedException; import javax.security.auth.x500.X500Principal; import jdk.internal.access.SharedSecrets; -import sun.security.tools.KeyStoreUtil; -import sun.security.util.*; import sun.security.pkcs.ContentInfo; -import sun.security.x509.AlgorithmId; import sun.security.pkcs.EncryptedPrivateKeyInfo; import sun.security.provider.JavaKeyStore.JKS; +import sun.security.tools.KeyStoreUtil; +import sun.security.util.*; +import sun.security.x509.AlgorithmId; import sun.security.x509.AuthorityKeyIdentifierExtension; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class provides the keystore implementation referred to as "PKCS12". @@ -192,6 +177,8 @@ public DualFormatPKCS12() { private String pbmac1Hmac = null; private String pbmac1KdfHmac = null; private int macIterationCount = -1; + private int macKeyLength = -1; + private int macSaltLength = -1; // the source of randomness private SecureRandom random; @@ -805,7 +792,8 @@ public synchronized void engineSetKeyEntry(String alias, byte[] key, private byte[] getSalt() { // Generate a random salt. - byte[] salt = new byte[SALT_LEN]; + int len = (this.macSaltLength == -1) ? SALT_LEN : this.macSaltLength; + byte[] salt = new byte[len]; if (random == null) { random = new SecureRandom(); } @@ -869,18 +857,6 @@ private void destroyPBEKey(SecretKey key) { } } - /* - * Invoke the PKCS#5 PBKDF2 algorithm - */ - private static SecretKey PBKDF2(String hmac, char[] secret, byte[] salt, - int count, int keyLength) throws GeneralSecurityException { - - PBEKeySpec keySpec = new PBEKeySpec(secret, salt, count, keyLength); - SecretKeyFactory skf = - SecretKeyFactory.getInstance("PBKDF2With" +hmac, "SunJCE"); - return skf.generateSecret(keySpec); - } - /* * Encrypt private key or secret key using Password-based encryption (PBE) * as defined in PKCS#5. @@ -1504,67 +1480,42 @@ private void populateAttributes(Entry entry) { private byte[] calculateMac(char[] passwd, byte[] data) throws IOException { - byte[] mData; + final byte[] mData; + final AlgorithmParameterSpec params; + final String macString; + final String algName; + final MacData macData; if (macAlgorithm.equals("PBMAC1")) { - // PBMAC1 - try { - // Generate a random salt. - byte[] salt = getSalt(); - - // generate MAC (MAC key is generated within JCE) - Mac m = Mac.getInstance(pbmac1Hmac); - SecretKey key = getPBEKey(passwd); - SecretKey derivedKey = PBKDF2(pbmac1KdfHmac, - (new String(key.getEncoded(), - UTF_8)).toCharArray(), salt, macIterationCount, 256); - try { - m.init(derivedKey); - } finally { - destroyPBEKey(key); - } - m.update(data); - byte[] macResult = m.doFinal(); - - // encode as MacData - MacData macData = new MacData("PBMAC1", macResult, salt, - macIterationCount, pbmac1KdfHmac, pbmac1Hmac, 256); - DerOutputStream bytes = new DerOutputStream(); - bytes.write(macData.getEncoded()); - mData = bytes.toByteArray(); - } catch (Exception e) { - throw new IOException("calculateMac failed: " + e, e); - } + params = new PBMAC1ParameterSpec(getSalt(), macIterationCount, + pbmac1KdfHmac, pbmac1Hmac, macKeyLength); + macString = "PBEWith" + pbmac1Hmac; + algName = "PBMAC1"; } else { - // The old (original) way of computing the MAC. - String algName = macAlgorithm.substring(7); + params = new PBEParameterSpec(getSalt(), macIterationCount); + macString = macAlgorithm; + algName = macAlgorithm.substring(7); + } + + try { + SecretKey key = getPBEKey(passwd); + Mac m = Mac.getInstance(macString); try { - // Generate a random salt. - byte[] salt = getSalt(); - - // generate MAC (MAC key is generated within JCE) - Mac m = Mac.getInstance(macAlgorithm); - PBEParameterSpec params = - new PBEParameterSpec(salt, macIterationCount); - SecretKey key = getPBEKey(passwd); - try { - m.init(key, params); - } finally { - destroyPBEKey(key); - } - m.update(data); - byte[] macResult = m.doFinal(); - - // encode as MacData - MacData macData = new MacData(algName, macResult, salt, - macIterationCount); - DerOutputStream bytes = new DerOutputStream(); - bytes.write(macData.getEncoded()); - mData = bytes.toByteArray(); - } catch (Exception e) { - throw new IOException("calculateMac failed: " + e, e); + m.init(key, params); + } finally { + destroyPBEKey(key); } + m.update(data); + byte[] macResult = m.doFinal(); + + // encode as MacData + macData = new MacData(algName, macResult, params); + DerOutputStream bytes = new DerOutputStream(); + bytes.write(macData.getEncoded()); + mData = bytes.toByteArray(); + } catch (Exception e) { + throw new IOException("calculateMac failed: " + e, e); } return mData; } @@ -1977,6 +1928,35 @@ private byte[] encryptContent(byte[] data, char[] password) } } + private void processMacData(AlgorithmParameterSpec params, + MacData macData, char[] password, byte[] data, String macAlgorithm) + throws Exception { + Mac m = Mac.getInstance(macAlgorithm); + + RetryWithZero.run(pass -> { + SecretKey key = getPBEKey(pass); + try { + m.init(key, params); + } finally { + destroyPBEKey(key); + } + m.update(data); + byte[] macResult = m.doFinal(); + + if (debug != null) { + debug.println("Checking keystore integrity " + + "(" + m.getAlgorithm() + " iterations: " + + macData.getIterations() + ")"); + } + + if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { + throw new UnrecoverableKeyException("Failed PKCS12" + + " integrity checking"); + } + return (Void) null; + }, password); + } + /** * Loads the keystore from the given input stream. * @@ -2187,71 +2167,34 @@ public synchronized void engineLoad(InputStream stream, char[] password) macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); if (algName.equals("PBMAC1")) { - SecretKey key = getPBEKey(password); - SecretKey derivedKey = PBKDF2(macData.getkdfHmac(), - (new String(key.getEncoded(), - UTF_8)).toCharArray(), macData.getSalt(), - macData.getIterations(), macData.getKeySize()); - - Mac m = Mac.getInstance(macData.getHmac()); - - RetryWithZero.run(pass -> { - try { - m.init(derivedKey); - } finally { - destroyPBEKey(key); - } - m.update(authSafeData); - byte[] macResult = m.doFinal(); - - if (debug != null) { - debug.println("Checking keystore integrity " + - "(" + m.getAlgorithm() + " iterations: " + ic + ")"); - } + byte[] salt = macData.getSalt(); + PBMAC1ParameterSpec params = + new PBMAC1ParameterSpec(salt, + macData.getIterations(), macData.getkdfHmac(), + macData.getHmac(), macData.getKeyLength()); + processMacData(params, macData, password, authSafeData, + "PBEWith" + macData.getHmac()); - if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { - throw new UnrecoverableKeyException("Failed PKCS12" + - " integrity checking"); - } - return (Void) null; - }, password); macAlgorithm = algName; pbmac1Hmac = macData.getHmac(); pbmac1KdfHmac = macData.getkdfHmac(); macIterationCount = macData.getIterations(); + macKeyLength = macData.getKeyLength(); + // store salt length in macData + macSaltLength = salt.length; } else { // 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); + processMacData(params, macData, password, authSafeData, + macAlgorithm); - RetryWithZero.run(pass -> { - SecretKey key = getPBEKey(pass); - try { - m.init(key, params); - } finally { - destroyPBEKey(key); - } - 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); + macIterationCount = ic; } } catch (Exception e) { throw new IOException("Integrity check failed: " + e, e); From 956ecb670ea1ad82af1b364cc237db987ff49a59 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 6 Jun 2025 13:03:52 -0600 Subject: [PATCH 05/30] final approach --- .../sun/crypto/provider/PBES2Parameters.java | 67 +--------- .../com/sun/crypto/provider/PBMAC1Core.java | 7 +- .../sun/crypto/provider/PBMAC1Parameters.java | 116 +++++------------- .../crypto/spec/PBMAC1ParameterSpec.java | 19 ++- .../classes/sun/security/pkcs12/MacData.java | 78 +++++++----- .../sun/security/pkcs12/PKCS12KeyStore.java | 7 +- .../classes/sun/security/util/KnownOIDs.java | 2 +- .../sun/security/pkcs12/PBMAC1Encoding.java | 4 - 8 files changed, 97 insertions(+), 203 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index 64b276a1c79a3..84e164e7b0145 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -227,7 +227,11 @@ protected void engineInit(byte[] encoded) kdf = pBES2_params.data.getDerValue(); } - String kdfAlgo = parseKDF(kdf); + var kdfParams = new PBKDF2Parameters(); + String kdfAlgo = kdfParams.parseKDF(kdf); + salt = kdfParams.getSalt(); + iCount = kdfParams.getIterationCount(); + keysize = kdfParams.getKeyLength(); if (pBES2_params.tag != DerValue.tag_Sequence) { throw new IOException("PBE parameter parsing error: " @@ -238,65 +242,6 @@ protected void engineInit(byte[] encoded) this.pbes2AlgorithmName = "PBEWith" + kdfAlgo + "And" + cipherAlgo; } - private String parseKDF(DerValue keyDerivationFunc) throws IOException { - - if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { - throw new IOException("PBE parameter parsing error: " - + "expecting the object identifier for PBKDF2"); - } - if (keyDerivationFunc.tag != DerValue.tag_Sequence) { - throw new IOException("PBE parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } - DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); - if (pBKDF2_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBE parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } - DerValue specified = pBKDF2_params.data.getDerValue(); - // the 'specified' ASN.1 CHOICE for 'salt' is supported - if (specified.tag == DerValue.tag_OctetString) { - salt = specified.getOctetString(); - } else { - // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported - throw new IOException("PBE parameter parsing error: " - + "not an ASN.1 OCTET STRING tag"); - } - iCount = pBKDF2_params.data.getInteger(); - - // keyLength INTEGER (1..MAX) OPTIONAL, - var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); - if (ksDer.isPresent()) { - keysize = ksDer.get().getInteger() * 8; // keysize (in bits) - } - - // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 - String kdfAlgo; - var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); - if (prfDer.isPresent()) { - DerValue prf = prfDer.get(); - kdfAlgo_OID = prf.data.getOID(); - KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); - if (o == null || (!o.stdName().equals("HmacSHA1") && - !o.stdName().equals("HmacSHA224") && - !o.stdName().equals("HmacSHA256") && - !o.stdName().equals("HmacSHA384") && - !o.stdName().equals("HmacSHA512") && - !o.stdName().equals("HmacSHA512/224") && - !o.stdName().equals("HmacSHA512/256"))) { - throw new IOException("PBE parameter parsing error: " - + "expecting the object identifier for a HmacSHA key " - + "derivation function"); - } - kdfAlgo = o.stdName(); - prf.data.getOptional(DerValue.tag_Null); - prf.data.atEnd(); - } else { - kdfAlgo = "HmacSHA1"; - } - return kdfAlgo; - } - private String parseES(DerValue encryptionScheme) throws IOException { String cipherAlgo; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index 425459bf91e6b..ce0175b16e492 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, 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 @@ -136,7 +136,6 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) throw new InvalidAlgorithmParameterException ("PBEParameterSpec required for salt and iteration count"); } - //keyLength = blockLength; } else if ((params instanceof PBEParameterSpec pbeParams)) { // make sure the parameter values are consistent if (salt != null) { @@ -155,7 +154,6 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) } else { iCount = pbeParams.getIterationCount(); } - //keyLength = blockLength; } else if ((params instanceof PBMAC1ParameterSpec pbmac1Params)) { if (salt != null) { if (!Arrays.equals(salt, pbmac1Params.getSalt())) { @@ -173,8 +171,9 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) } else { iCount = pbmac1Params.getIterationCount(); } + // Key length SHOULD be same as the HMAC function output size. keyLength = pbmac1Params.getKeyLength(); - this.kdfAlgo = pbmac1Params.getkdfHmac(); + kdfAlgo = pbmac1Params.getkdfHmac(); } else { throw new InvalidAlgorithmParameterException ("PBEParameterSpec or PBMAC1ParameterSpec required"); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index d50b1bbc1ebc9..aa0fa23e83548 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -87,13 +87,13 @@ * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7} * * + * + * @since 26 */ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { private static final ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - private static final ObjectIdentifier pkcs5PBMAC1_OID = - ObjectIdentifier.of(KnownOIDs.PBMAC1); // the PBMAC1 algorithm name private String pbmac1AlgorithmName = null; @@ -104,26 +104,18 @@ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { // the iteration count private int iCount = 0; - // the Hmac function (first one) + // the Hmac function used by the kdf private String kdfHmac = null; - // the Hmac function (second one) + // the Hmac function private String Hmac = null; // the key derivation function (default is HmacSHA1) - private ObjectIdentifier kdfAlgo_OID = + private final ObjectIdentifier kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.HmacSHA1); - // the cipher keysize (in bits) - private int keysize = -1; - - PBMAC1Parameters() { - // KDF, encryption & keysize values are set later, in engineInit(byte[]) - } - - PBMAC1Parameters(String pbmac1AlgorithmName) { - // TBD - } + // length of key generated by the kdf + private int keyLength = -1; protected void engineInit(AlgorithmParameterSpec paramSpec) throws InvalidParameterSpecException @@ -132,11 +124,10 @@ protected void engineInit(AlgorithmParameterSpec paramSpec) throw new InvalidParameterSpecException ("Inappropriate parameter specification"); } - this.salt = ((PBMAC1ParameterSpec)paramSpec).getSalt().clone(); - this.iCount = ((PBMAC1ParameterSpec)paramSpec).getIterationCount(); + salt = ((PBMAC1ParameterSpec)paramSpec).getSalt().clone(); + iCount = ((PBMAC1ParameterSpec)paramSpec).getIterationCount(); } - @SuppressWarnings("deprecation") protected void engineInit(byte[] encoded) throws IOException { @@ -164,82 +155,31 @@ protected void engineInit(byte[] encoded) + "expecting the object identifier for a HmacSHA key " + "derivation function"); } - this.Hmac = o.stdName(); + Hmac = o.stdName(); DerValue kdf = pBMAC1_params.data.getDerValue(); + var kdfParams = new PBKDF2Parameters(); + String kdfAlgo = kdfParams.parseKDF(kdf); + salt = kdfParams.getSalt(); + iCount = kdfParams.getIterationCount(); - String kdfAlgo = parseKDF(kdf); - this.kdfHmac = kdfAlgo; + // Key length SHOULD be the same size as the HMAC function output size. + keyLength = kdfParams.getKeyLength(); - if (pBMAC1_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBMAC1 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); + // Implementations MUST NOT accept PBKDF2 KDF with params that + // omit the keyLength field. + if (keyLength == -1) { + throw new IOException("PMAC1 parameter parsing error: " + + "missing keyLength field"); } + kdfHmac = kdfAlgo; - this.pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" +Hmac; - } - - @SuppressWarnings("deprecation") - private String parseKDF(DerValue keyDerivationFunc) throws IOException { - - if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { - throw new IOException("PBMAC1 parameter parsing error: " - + "expecting the object identifier for PBKDF2"); - } - if (keyDerivationFunc.tag != DerValue.tag_Sequence) { - throw new IOException("PBMAC1 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } - DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); - if (pBKDF2_params.tag != DerValue.tag_Sequence) { + if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PBMAC1 parameter parsing error: " + "not an ASN.1 SEQUENCE tag"); } - DerValue specified = pBKDF2_params.data.getDerValue(); - // the 'specified' ASN.1 CHOICE for 'salt' is supported - if (specified.tag == DerValue.tag_OctetString) { - salt = specified.getOctetString(); - } else { - // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported - throw new IOException("PBMAC1 parameter parsing error: " - + "not an ASN.1 OCTET STRING tag"); - } - iCount = pBKDF2_params.data.getInteger(); - - // keyLength INTEGER (1..MAX) OPTIONAL, - var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); - if (ksDer.isPresent()) { - keysize = ksDer.get().getInteger() * 8; // keysize (in bits) - } else { - throw new IOException("PBMAC1 parameter parsing error: " - + "missing keyLength"); - } - // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 - String kdfAlgo; - var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); - if (prfDer.isPresent()) { - DerValue prf = prfDer.get(); - kdfAlgo_OID = prf.data.getOID(); - KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); - if (o == null || (!o.stdName().equals("HmacSHA1") && - !o.stdName().equals("HmacSHA224") && - !o.stdName().equals("HmacSHA256") && - !o.stdName().equals("HmacSHA384") && - !o.stdName().equals("HmacSHA512") && - !o.stdName().equals("HmacSHA512/224") && - !o.stdName().equals("HmacSHA512/256"))) { - throw new IOException("PBMAC1 parameter parsing error: " - + "expecting the object identifier for a HmacSHA key " - + "derivation function"); - } - kdfAlgo = o.stdName(); - prf.data.getOptional(DerValue.tag_Null); - prf.data.atEnd(); - } else { - kdfAlgo = "HmacSHA1"; - } - return kdfAlgo; + pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" +Hmac; } protected void engineInit(byte[] encoded, String decodingMethod) @@ -254,8 +194,8 @@ T engineGetParameterSpec(Class paramSpec) { if (paramSpec.isAssignableFrom(PBMAC1ParameterSpec.class)) { return paramSpec.cast( - new PBMAC1ParameterSpec(this.salt, this.iCount, this.kdfHmac, - this.Hmac, this.keysize)); + new PBMAC1ParameterSpec(salt, iCount, kdfHmac, + Hmac, keyLength)); } else { throw new InvalidParameterSpecException ("Inappropriate parameter specification"); @@ -274,8 +214,8 @@ protected byte[] engineGetEncoded() throws IOException { pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' pBKDF2_params.putInteger(iCount); - if (keysize > 0) { - pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) + if (keyLength > 0) { + pBKDF2_params.putInteger(keyLength / 8); // derived key length (in octets) } DerOutputStream prf = new DerOutputStream(); diff --git a/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java index e650fccd28b0b..88aa4b39ae46e 100644 --- a/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java @@ -35,7 +35,6 @@ * * @spec https://www.rfc-editor.org/info/rfc9579 * RFC 9579: Use of Password-Based Message Authentication Code 1 (PBMAC1) in PKCS #12 - * @author xxxx * * @since 26 */ @@ -49,7 +48,7 @@ public class PBMAC1ParameterSpec implements AlgorithmParameterSpec { /** * Constructs a parameter set for PBMAC1 as defined in - * the PKCS #12 standard. + * the PKCS #5 standard. * * @param salt the salt. The contents of {@code salt} are copied * to protect against subsequent modification. @@ -58,8 +57,6 @@ public class PBMAC1ParameterSpec implements AlgorithmParameterSpec { * @param hmac the HMAC that protects the keystore * @param keyLength bit length of Hmac key * @exception NullPointerException if {@code salt} is null - * - * @since 26 */ public PBMAC1ParameterSpec(byte[] salt, int iterationCount, String kdfHmac, String hmac, int keyLength) { @@ -77,7 +74,7 @@ public PBMAC1ParameterSpec(byte[] salt, int iterationCount, * each time this method is called. */ public byte[] getSalt() { - return this.salt.clone(); + return salt.clone(); } /** @@ -86,7 +83,7 @@ public byte[] getSalt() { * @return the iteration count */ public int getIterationCount() { - return this.iterationCount; + return iterationCount; } /** @@ -95,7 +92,7 @@ public int getIterationCount() { * @return the Hmac used by PBKDF2. */ public String getkdfHmac() { - return this.kdfHmac; + return kdfHmac; } /** @@ -104,15 +101,15 @@ public String getkdfHmac() { * @return the Hmac */ public String getHmac() { - return this.hmac; + return hmac; } /** - * Returns size of key generated by PBKDF2. + * Returns length of key generated by PBKDF2. * - * @return size of key generated by PBKDF2. + * @return length of key generated by PBKDF2. */ public int getKeyLength() { - return this.keyLength; + return keyLength; } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 6875a28c8f98d..ac2083cdd40a4 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -49,11 +49,13 @@ class MacData { private final String digestAlgorithmName; private final AlgorithmParameters digestAlgorithmParams; private final byte[] digest; - private final byte[] macSalt; - private final int iterations; - private final String kdfHmac; - private final String Hmac; - private final int keyLength; + private byte[] macSalt; + private byte[] extraMacSalt; + private int iterations; + private int extraIterations; + private String kdfHmac; + private String Hmac; + private int keyLength; // the ASN.1 encoded contents of this class private byte[] encoded = null; @@ -96,29 +98,30 @@ class MacData { throw new IOException( "Invalid PBMAC1 algorithm parameters"); } - this.iterations = pbmac1Spec.getIterationCount(); - this.macSalt = pbmac1Spec.getSalt(); - this.kdfHmac = pbmac1Spec.getkdfHmac(); - this.Hmac = pbmac1Spec.getHmac(); - this.keyLength = pbmac1Spec.getKeyLength(); - return; + iterations = pbmac1Spec.getIterationCount(); + macSalt = pbmac1Spec.getSalt(); + kdfHmac = pbmac1Spec.getkdfHmac(); + Hmac = pbmac1Spec.getHmac(); + keyLength = pbmac1Spec.getKeyLength(); } // Get the salt. - this.macSalt = macData[1].getOctetString(); + extraMacSalt = macData[1].getOctetString(); // Iterations are optional. The default value is 1. if (macData.length > 2) { - this.iterations = macData[2].getInteger(); + extraIterations = macData[2].getInteger(); } else { - this.iterations = 1; + extraIterations = 1; + } + if (!digestAlgorithmName.equals("PBMAC1")) { + macSalt = extraMacSalt; + iterations = extraIterations; } - this.kdfHmac = null; - this.Hmac = null; - this.keyLength = 0; } - MacData(String algName, byte[] digest, AlgorithmParameterSpec params) + MacData(String algName, byte[] digest, AlgorithmParameterSpec params, + byte[] extraSalt, int extraIterationCount) throws NoSuchAlgorithmException { if (algName == null) { @@ -141,17 +144,19 @@ class MacData { } if (params instanceof PBMAC1ParameterSpec p) { - this.macSalt = p.getSalt(); - this.iterations = p.getIterationCount(); - this.kdfHmac = p.getkdfHmac(); - this.Hmac = p.getHmac(); - this.keyLength = p.getKeyLength(); + macSalt = p.getSalt(); + iterations = p.getIterationCount(); + kdfHmac = p.getkdfHmac(); + Hmac = p.getHmac(); + keyLength = p.getKeyLength(); + extraMacSalt = extraSalt; + extraIterations = extraIterationCount; } else if (params instanceof PBEParameterSpec p) { - this.macSalt = p.getSalt(); - this.iterations = p.getIterationCount(); - this.kdfHmac = null; - this.Hmac = null; - this.keyLength = 0; + macSalt = p.getSalt(); + iterations = p.getIterationCount(); + kdfHmac = null; + Hmac = null; + keyLength = 0; } else { throw new IllegalArgumentException("unsupported parameter spec"); } @@ -189,6 +194,14 @@ int getKeyLength() { return keyLength; } + byte[] getExtraSalt() { + return extraMacSalt; + } + + int getExtraIterations() { + return extraIterations; + } + /** * Returns the ASN.1 encoding of this object. * @return the ASN.1 encoding. @@ -199,7 +212,6 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { if (digestAlgorithmName.equals("PBMAC1")) { - byte[] notUsed = { 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }; ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); @@ -246,12 +258,12 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, tmp2.write(DerValue.tag_Sequence, tmp1); tmp2.putOctetString(digest); tmp0.write(DerValue.tag_Sequence, tmp2); - tmp0.putOctetString(notUsed); - tmp0.putInteger(1); + tmp0.putOctetString(extraMacSalt); + tmp0.putInteger(extraIterations); out.write(DerValue.tag_Sequence, tmp0); - this.encoded = out.toByteArray(); + encoded = out.toByteArray(); - return this.encoded.clone(); + return encoded.clone(); } if (this.encoded != null) diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 4382838855597..b2d9d6460259b 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -179,6 +179,8 @@ public DualFormatPKCS12() { private int macIterationCount = -1; private int macKeyLength = -1; private int macSaltLength = -1; + private byte[] extraSalt = null; + private int extraIterationCount = -1; // the source of randomness private SecureRandom random; @@ -1510,7 +1512,8 @@ private byte[] calculateMac(char[] passwd, byte[] data) byte[] macResult = m.doFinal(); // encode as MacData - macData = new MacData(algName, macResult, params); + macData = new MacData(algName, macResult, params, extraSalt, + extraIterationCount); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); mData = bytes.toByteArray(); @@ -2182,6 +2185,8 @@ public synchronized void engineLoad(InputStream stream, char[] password) macKeyLength = macData.getKeyLength(); // store salt length in macData macSaltLength = salt.length; + extraSalt = macData.getExtraSalt(); + extraIterationCount = macData.getExtraIterations(); } else { // Change SHA-1 to SHA1 diff --git a/src/java.base/share/classes/sun/security/util/KnownOIDs.java b/src/java.base/share/classes/sun/security/util/KnownOIDs.java index 6b4496d9d94d5..31fcde8c0cd9c 100644 --- a/src/java.base/share/classes/sun/security/util/KnownOIDs.java +++ b/src/java.base/share/classes/sun/security/util/KnownOIDs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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 diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java index 354afda6ce1a9..15176a9f28680 100644 --- a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java +++ b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java @@ -402,10 +402,6 @@ public static void main(String[] args) throws Exception { password.toCharArray()); System.out.println("A.1 pass"); - // Make sure both cert and key can be retrieved - //System.out.println(ks.getCertificate("a")); - //System.out.println(ks.getKey("a", "changeit".toCharArray())); - ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), password.toCharArray()); From e52e229350e709ae58c394cc4d3c4baba883cc25 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 6 Jun 2025 17:26:10 -0600 Subject: [PATCH 06/30] missed this new file --- .../sun/security/util/PBKDF2Parameters.java | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java new file mode 100644 index 0000000000000..a7d26c6b9f619 --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 sun.security.util; + +import java.io.IOException; +import java.security.AlgorithmParametersSpi; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * This class implements the parameter set used with password-based + * mac scheme 1 (PBKDF2), which is defined in PKCS#5 as follows: + * + * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::= + * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...} + * + * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} + * + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} + * }, + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX) OPTIONAL, + * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + * } + * + * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... } + * + * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { + * {NULL IDENTIFIED BY id-hmacWithSHA1} | + * {NULL IDENTIFIED BY id-hmacWithSHA224} | + * {NULL IDENTIFIED BY id-hmacWithSHA256} | + * {NULL IDENTIFIED BY id-hmacWithSHA384} | + * {NULL IDENTIFIED BY id-hmacWithSHA512}, ... } + * + * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::= + * {algorithm id-hmacWithSHA1, parameters NULL : NULL} + * + * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7} + */ +public class PBKDF2Parameters { + + private static final ObjectIdentifier pkcs5PBKDF2_OID = + ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + + // the PBMAC1 algorithm name + private String pbmac1AlgorithmName = null; + + // the salt + private byte[] salt = null; + + // the iteration count + private int iCount = 0; + + // the key derivation function (default is HmacSHA1) + private ObjectIdentifier kdfAlgo_OID = + ObjectIdentifier.of(KnownOIDs.HmacSHA1); + + // the keysize (in bits) + private int keysize = -1; + + @SuppressWarnings("deprecation") + public String parseKDF(DerValue keyDerivationFunc) throws IOException { + + if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { + throw new IOException("PBKDF2 parameter parsing error: " + + "expecting the object identifier for PBKDF2"); + } + if (keyDerivationFunc.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); + if (pBKDF2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue specified = pBKDF2_params.data.getDerValue(); + // the 'specified' ASN.1 CHOICE for 'salt' is supported + if (specified.tag == DerValue.tag_OctetString) { + salt = specified.getOctetString(); + } else { + // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 OCTET STRING tag"); + } + iCount = pBKDF2_params.data.getInteger(); + + // keyLength INTEGER (1..MAX) OPTIONAL, + var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); + if (ksDer.isPresent()) { + keysize = ksDer.get().getInteger() * 8; // keysize (in bits) + } + + // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + String kdfAlgo; + var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); + if (prfDer.isPresent()) { + DerValue prf = prfDer.get(); + kdfAlgo_OID = prf.data.getOID(); + KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); + if (o == null || (!o.stdName().equals("HmacSHA1") && + !o.stdName().equals("HmacSHA224") && + !o.stdName().equals("HmacSHA256") && + !o.stdName().equals("HmacSHA384") && + !o.stdName().equals("HmacSHA512") && + !o.stdName().equals("HmacSHA512/224") && + !o.stdName().equals("HmacSHA512/256"))) { + throw new IOException("PBKDF2 parameter parsing error: " + + "expecting the object identifier for a HmacSHA key " + + "derivation function"); + } + kdfAlgo = o.stdName(); + prf.data.getOptional(DerValue.tag_Null); + prf.data.atEnd(); + } else { + kdfAlgo = "HmacSHA1"; + } + return kdfAlgo; + } + + /** + * Returns the salt. + * + * @return the salt. Returns a new array + * each time this method is called. + */ + public byte[] getSalt() { + return this.salt.clone(); + } + + /** + * Returns the iteration count. + * + * @return the iteration count + */ + public int getIterationCount() { + return this.iCount; + } + + /** + * Returns size of key generated by PBKDF2. + * + * @return size of key generated by PBKDF2. + */ + public int getKeyLength() { + return this.keysize; + } +} From 3ff7625aaf9c391564de9021ef3d608680ed397b Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 11 Jul 2025 11:06:34 -0600 Subject: [PATCH 07/30] comments from Valerie --- .../sun/crypto/provider/PBES2Parameters.java | 2 +- .../sun/crypto/provider/PBMAC1Parameters.java | 39 ++++++++----------- .../sun/security/pkcs12/PKCS12KeyStore.java | 12 +++++- .../sun/security/util/PBKDF2Parameters.java | 35 ++++++++--------- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index 84e164e7b0145..e60e3f3c26321 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -228,7 +228,7 @@ protected void engineInit(byte[] encoded) } var kdfParams = new PBKDF2Parameters(); - String kdfAlgo = kdfParams.parseKDF(kdf); + String kdfAlgo = kdfParams.init(kdf); salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); keysize = kdfParams.getKeyLength(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index aa0fa23e83548..f60f9b4650f5d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -98,17 +98,16 @@ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { // the PBMAC1 algorithm name private String pbmac1AlgorithmName = null; - // the salt private byte[] salt = null; - // the iteration count + // Iteration count private int iCount = 0; - // the Hmac function used by the kdf + // Hmac function used by the kdf private String kdfHmac = null; - // the Hmac function - private String Hmac = null; + // Hmac function used to compute the MAC + private String hmacAlgo = null; // the key derivation function (default is HmacSHA1) private final ObjectIdentifier kdfAlgo_OID = @@ -120,12 +119,12 @@ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { protected void engineInit(AlgorithmParameterSpec paramSpec) throws InvalidParameterSpecException { - if (!(paramSpec instanceof PBMAC1ParameterSpec)) { - throw new InvalidParameterSpecException - ("Inappropriate parameter specification"); - } - salt = ((PBMAC1ParameterSpec)paramSpec).getSalt().clone(); - iCount = ((PBMAC1ParameterSpec)paramSpec).getIterationCount(); + if (!(paramSpec instanceof PBMAC1ParameterSpec)) { + throw new InvalidParameterSpecException + ("Inappropriate parameter specification"); + } + salt = ((PBMAC1ParameterSpec)paramSpec).getSalt().clone(); + iCount = ((PBMAC1ParameterSpec)paramSpec).getIterationCount(); } protected void engineInit(byte[] encoded) @@ -134,7 +133,7 @@ protected void engineInit(byte[] encoded) DerValue pBMAC1_params = new DerValue(encoded); if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PMAC1 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); + + "not an ASN.1 SEQUENCE tag"); } DerValue[] Info = (new DerInputStream(pBMAC1_params.toByteArray())) .getSequence(2); @@ -155,31 +154,25 @@ protected void engineInit(byte[] encoded) + "expecting the object identifier for a HmacSHA key " + "derivation function"); } - Hmac = o.stdName(); + hmacAlgo = o.stdName(); DerValue kdf = pBMAC1_params.data.getDerValue(); var kdfParams = new PBKDF2Parameters(); - String kdfAlgo = kdfParams.parseKDF(kdf); + String kdfAlgo = kdfParams.init(kdf); salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); // Key length SHOULD be the same size as the HMAC function output size. keyLength = kdfParams.getKeyLength(); - // Implementations MUST NOT accept PBKDF2 KDF with params that - // omit the keyLength field. - if (keyLength == -1) { - throw new IOException("PMAC1 parameter parsing error: " - + "missing keyLength field"); - } kdfHmac = kdfAlgo; if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PBMAC1 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); + + "not an ASN.1 SEQUENCE tag"); } - pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" +Hmac; + pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" +hmacAlgo; } protected void engineInit(byte[] encoded, String decodingMethod) @@ -195,7 +188,7 @@ T engineGetParameterSpec(Class paramSpec) if (paramSpec.isAssignableFrom(PBMAC1ParameterSpec.class)) { return paramSpec.cast( new PBMAC1ParameterSpec(salt, iCount, kdfHmac, - Hmac, keyLength)); + hmacAlgo, keyLength)); } else { throw new InvalidParameterSpecException ("Inappropriate parameter specification"); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index b2d9d6460259b..4fc14da9bb945 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -2169,12 +2169,20 @@ public synchronized void engineLoad(InputStream stream, char[] password) String algName = macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); if (algName.equals("PBMAC1")) { - byte[] salt = macData.getSalt(); + int keyLength = macData.getKeyLength(); + + // PKCS12 implementations MUST NOT accept PBKDF2 KDF + // params that omit the keyLength field. + if (keyLength == -1) { + throw new IOException("PMAC1 parameter parsing " + + "error: missing keyLength field"); + } + PBMAC1ParameterSpec params = new PBMAC1ParameterSpec(salt, macData.getIterations(), macData.getkdfHmac(), - macData.getHmac(), macData.getKeyLength()); + macData.getHmac(), keyLength); processMacData(params, macData, password, authSafeData, "PBEWith" + macData.getHmac()); diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index a7d26c6b9f619..f7f111599b85b 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -33,7 +33,7 @@ /** * This class implements the parameter set used with password-based - * mac scheme 1 (PBKDF2), which is defined in PKCS#5 as follows: + * key derivation function 2 (PBKDF2), which is defined in PKCS#5 as follows: * * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::= * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...} @@ -69,24 +69,22 @@ public class PBKDF2Parameters { private static final ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - // the PBMAC1 algorithm name - private String pbmac1AlgorithmName = null; + // AlgorithmIdentifier + private String prf = null; - // the salt private byte[] salt = null; - // the iteration count - private int iCount = 0; + private int iterationCount = 0; - // the key derivation function (default is HmacSHA1) + // the pseudorandom function (default is HmacSHA1) private ObjectIdentifier kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.HmacSHA1); - // the keysize (in bits) - private int keysize = -1; + // keyLength (in bits) + private int keyLength = -1; @SuppressWarnings("deprecation") - public String parseKDF(DerValue keyDerivationFunc) throws IOException { + public String init(DerValue keyDerivationFunc) throws IOException { if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { throw new IOException("PBKDF2 parameter parsing error: " @@ -110,12 +108,12 @@ public String parseKDF(DerValue keyDerivationFunc) throws IOException { throw new IOException("PBKDF2 parameter parsing error: " + "not an ASN.1 OCTET STRING tag"); } - iCount = pBKDF2_params.data.getInteger(); + iterationCount = pBKDF2_params.data.getInteger(); // keyLength INTEGER (1..MAX) OPTIONAL, var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); if (ksDer.isPresent()) { - keysize = ksDer.get().getInteger() * 8; // keysize (in bits) + keyLength = ksDer.get().getInteger() * 8; // keyLength (in bits) } // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 @@ -133,8 +131,8 @@ public String parseKDF(DerValue keyDerivationFunc) throws IOException { !o.stdName().equals("HmacSHA512/224") && !o.stdName().equals("HmacSHA512/256"))) { throw new IOException("PBKDF2 parameter parsing error: " - + "expecting the object identifier for a HmacSHA key " - + "derivation function"); + + "expecting the object identifier for a HmacSHA " + + "pseudorandom function"); } kdfAlgo = o.stdName(); prf.data.getOptional(DerValue.tag_Null); @@ -152,24 +150,25 @@ public String parseKDF(DerValue keyDerivationFunc) throws IOException { * each time this method is called. */ public byte[] getSalt() { - return this.salt.clone(); + return this.salt.clone(); } - + /** * Returns the iteration count. * * @return the iteration count */ public int getIterationCount() { - return this.iCount; + return this.iterationCount; } /** * Returns size of key generated by PBKDF2. + * Set to -1 if not found/set. * * @return size of key generated by PBKDF2. */ public int getKeyLength() { - return this.keysize; + return this.keyLength; } } From 6f15caa2ffc2febf9650eeafa707ed43372bdbb5 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 22 Aug 2025 14:35:52 -0600 Subject: [PATCH 08/30] rework to eliminate PBMAC1ParameterSpec --- .../com/sun/crypto/provider/PBMAC1Core.java | 40 ++++---- .../sun/crypto/provider/PBMAC1Parameters.java | 41 ++++----- .../classes/sun/security/pkcs12/MacData.java | 91 +++++++++++++------ .../sun/security/pkcs12/PKCS12KeyStore.java | 36 +++----- .../share/conf/security/java.security | 1 + .../sun/security/pkcs12/PBMAC1Encoding.java | 2 + 6 files changed, 117 insertions(+), 94 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index ce0175b16e492..123e1452273e0 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -33,7 +33,6 @@ import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.PBMAC1ParameterSpec; import java.security.*; import java.security.spec.*; @@ -45,7 +44,8 @@ abstract class PBMAC1Core extends HmacCore { // NOTE: this class inherits the Cloneable interface from HmacCore // Need to override clone() if mutable fields are added. - private String kdfAlgo; + private final String kdfAlgo; + private final String hashAlgo; private final int blockLength; // in octets /** @@ -56,6 +56,7 @@ abstract class PBMAC1Core extends HmacCore { throws NoSuchAlgorithmException { super(hashAlgo, blockLength); this.kdfAlgo = kdfAlgo; + this.hashAlgo = hashAlgo; this.blockLength = blockLength; } @@ -106,7 +107,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) char[] passwdChars; byte[] salt = null; int iCount = 0; - int keyLength = blockLength; + int keyLength = 0; if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) { passwdChars = pbeKey.getPassword(); salt = pbeKey.getSalt(); // maybe null if unspecified @@ -136,7 +137,10 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) throw new InvalidAlgorithmParameterException ("PBEParameterSpec required for salt and iteration count"); } - } else if ((params instanceof PBEParameterSpec pbeParams)) { + } else if (!(params instanceof PBEParameterSpec pbeParams)) { + throw new InvalidAlgorithmParameterException + ("PBEParameterSpec type required"); + } else { // make sure the parameter values are consistent if (salt != null) { if (!Arrays.equals(salt, pbeParams.getSalt())) { @@ -154,29 +158,17 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) } else { iCount = pbeParams.getIterationCount(); } - } else if ((params instanceof PBMAC1ParameterSpec pbmac1Params)) { - if (salt != null) { - if (!Arrays.equals(salt, pbmac1Params.getSalt())) { - throw new InvalidAlgorithmParameterException - ("Inconsistent value of salt between key and params"); - } + + // Infer key length from algorithm name. + // The PBEParameterSpec doesn't contain a key length. + if (kdfAlgo.equals("HmacSHA512")) { + keyLength = 512; + } else if (kdfAlgo.equals("HmacSHA256")) { + keyLength = 256; } else { - salt = pbmac1Params.getSalt(); - } - if (iCount != 0) { - if (iCount != pbmac1Params.getIterationCount()) { throw new InvalidAlgorithmParameterException - ("Different iteration count between key and params"); - } - } else { - iCount = pbmac1Params.getIterationCount(); + ("Unsupported Mac algorithm"); } - // Key length SHOULD be same as the HMAC function output size. - keyLength = pbmac1Params.getKeyLength(); - kdfAlgo = pbmac1Params.getkdfHmac(); - } else { - throw new InvalidAlgorithmParameterException - ("PBEParameterSpec or PBMAC1ParameterSpec required"); } // For security purpose, we need to enforce a minimum length diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index f60f9b4650f5d..f0b49872862db 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -30,7 +30,7 @@ import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; -import javax.crypto.spec.PBMAC1ParameterSpec; +import javax.crypto.spec.PBEParameterSpec; import sun.security.util.*; @@ -103,12 +103,6 @@ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { // Iteration count private int iCount = 0; - // Hmac function used by the kdf - private String kdfHmac = null; - - // Hmac function used to compute the MAC - private String hmacAlgo = null; - // the key derivation function (default is HmacSHA1) private final ObjectIdentifier kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.HmacSHA1); @@ -119,12 +113,12 @@ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { protected void engineInit(AlgorithmParameterSpec paramSpec) throws InvalidParameterSpecException { - if (!(paramSpec instanceof PBMAC1ParameterSpec)) { + if (!(paramSpec instanceof PBEParameterSpec)) { throw new InvalidParameterSpecException ("Inappropriate parameter specification"); } - salt = ((PBMAC1ParameterSpec)paramSpec).getSalt().clone(); - iCount = ((PBMAC1ParameterSpec)paramSpec).getIterationCount(); + salt = ((PBEParameterSpec)paramSpec).getSalt().clone(); + iCount = ((PBEParameterSpec)paramSpec).getIterationCount(); } protected void engineInit(byte[] encoded) @@ -154,7 +148,8 @@ protected void engineInit(byte[] encoded) + "expecting the object identifier for a HmacSHA key " + "derivation function"); } - hmacAlgo = o.stdName(); + // Hmac function used to compute the MAC + String hmacAlgo = o.stdName(); DerValue kdf = pBMAC1_params.data.getDerValue(); var kdfParams = new PBKDF2Parameters(); @@ -162,17 +157,20 @@ protected void engineInit(byte[] encoded) salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); - // Key length SHOULD be the same size as the HMAC function output size. + // Key length must be present. It is not currently used. keyLength = kdfParams.getKeyLength(); - - kdfHmac = kdfAlgo; - - if (pBMAC1_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBMAC1 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); + if (keyLength == -1) { + throw new IOException("PMAC1 parameter parsing " + + "error: missing keyLength field"); + } + // Key length SHOULD be the same size as HMAC function output size. + if ((kdfAlgo.contains("256") && keyLength != 256) || + (kdfAlgo.contains("512") && keyLength != 512)) { + throw new IOException("PMAC1 parameter parsing " + + "error: keyLength not Hmac output length "); } - pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" +hmacAlgo; + pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" + hmacAlgo; } protected void engineInit(byte[] encoded, String decodingMethod) @@ -185,10 +183,9 @@ protected void engineInit(byte[] encoded, String decodingMethod) T engineGetParameterSpec(Class paramSpec) throws InvalidParameterSpecException { - if (paramSpec.isAssignableFrom(PBMAC1ParameterSpec.class)) { + if (paramSpec.isAssignableFrom(PBEParameterSpec.class)) { return paramSpec.cast( - new PBMAC1ParameterSpec(salt, iCount, kdfHmac, - hmacAlgo, keyLength)); + new PBEParameterSpec(salt, iCount)); } else { throw new InvalidParameterSpecException ("Inappropriate parameter specification"); diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index ac2083cdd40a4..de68e2ae4afce 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -30,8 +30,9 @@ import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.PBMAC1ParameterSpec; import sun.security.pkcs.ParsingException; import sun.security.util.*; @@ -88,21 +89,21 @@ class MacData { throw new IOException("algid parse error, not a sequence"); } if (digestAlgorithmName.equals("PBMAC1")) { - PBMAC1ParameterSpec pbmac1Spec; + PBEParameterSpec pbeSpec; try { - pbmac1Spec = + pbeSpec = digestAlgorithmParams.getParameterSpec( - PBMAC1ParameterSpec.class); + PBEParameterSpec.class); } catch (InvalidParameterSpecException ipse) { throw new IOException( - "Invalid PBMAC1 algorithm parameters"); + "Invalid PBE algorithm parameters"); } - iterations = pbmac1Spec.getIterationCount(); - macSalt = pbmac1Spec.getSalt(); - kdfHmac = pbmac1Spec.getkdfHmac(); - Hmac = pbmac1Spec.getHmac(); - keyLength = pbmac1Spec.getKeyLength(); + iterations = pbeSpec.getIterationCount(); + macSalt = pbeSpec.getSalt(); + String ps = digestAlgorithmParams.toString(); + kdfHmac = getKdfHmac(ps); + Hmac = getHmac(ps); } // Get the salt. @@ -121,7 +122,7 @@ class MacData { } MacData(String algName, byte[] digest, AlgorithmParameterSpec params, - byte[] extraSalt, int extraIterationCount) + String defaultKdfHmac, byte[] extraSalt, int extraIterationCount) throws NoSuchAlgorithmException { if (algName == null) { @@ -143,20 +144,29 @@ class MacData { this.digest = digest.clone(); } - if (params instanceof PBMAC1ParameterSpec p) { - macSalt = p.getSalt(); - iterations = p.getIterationCount(); - kdfHmac = p.getkdfHmac(); - Hmac = p.getHmac(); - keyLength = p.getKeyLength(); - extraMacSalt = extraSalt; - extraIterations = extraIterationCount; - } else if (params instanceof PBEParameterSpec p) { - macSalt = p.getSalt(); - iterations = p.getIterationCount(); - kdfHmac = null; - Hmac = null; - keyLength = 0; + if (params instanceof PBEParameterSpec p) { + if (algName.equals("PBMAC1")) { + macSalt = p.getSalt(); + iterations = p.getIterationCount(); + kdfHmac = defaultKdfHmac; + Hmac = kdfHmac; + + if (defaultKdfHmac.equals("HmacSHA512")) { + keyLength = 512; + } else if (defaultKdfHmac.equals("HmacSHA256")) { + keyLength = 256; + } else { + throw new IllegalArgumentException("unsupported Hmac"); + } + extraMacSalt = extraSalt; + extraIterations = extraIterationCount; + } else { + macSalt = p.getSalt(); + iterations = p.getIterationCount(); + kdfHmac = null; + Hmac = null; + keyLength = 0; + } } else { throw new IllegalArgumentException("unsupported parameter spec"); } @@ -182,7 +192,7 @@ byte[] getDigest() { return digest; } - String getkdfHmac() { + String getKdfHmac() { return kdfHmac; } @@ -260,6 +270,7 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, tmp0.write(DerValue.tag_Sequence, tmp2); tmp0.putOctetString(extraMacSalt); tmp0.putInteger(extraIterations); + out.write(DerValue.tag_Sequence, tmp0); encoded = out.toByteArray(); @@ -295,4 +306,32 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, return this.encoded.clone(); } + public String getKdfHmac(String text) { + final String word1 = "With"; + final String word2 = "And"; + + String regex = Pattern.quote(word1) + "(.*?)" + Pattern.quote(word2); + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(text); + + if (matcher.find()) { + return matcher.group(1); + } else { + return null; + } + } + + public String getHmac(String text) { + final String word2 = "And"; + + String regex = Pattern.quote(word2) + "(.*?)$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(text); + + if (matcher.find()) { + return matcher.group(1); + } else { + return null; + } + } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 4fc14da9bb945..c49083d66bcb0 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -42,7 +42,6 @@ import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; -import javax.crypto.spec.PBMAC1ParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.security.auth.DestroyFailedException; import javax.security.auth.x500.X500Principal; @@ -177,7 +176,6 @@ public DualFormatPKCS12() { private String pbmac1Hmac = null; private String pbmac1KdfHmac = null; private int macIterationCount = -1; - private int macKeyLength = -1; private int macSaltLength = -1; private byte[] extraSalt = null; private int extraIterationCount = -1; @@ -1489,9 +1487,12 @@ private byte[] calculateMac(char[] passwd, byte[] data) final MacData macData; if (macAlgorithm.equals("PBMAC1")) { - params = new PBMAC1ParameterSpec(getSalt(), macIterationCount, - pbmac1KdfHmac, pbmac1Hmac, macKeyLength); - macString = "PBEWith" + pbmac1Hmac; + params = new PBEParameterSpec(getSalt(), macIterationCount); + if (defaultMacAlgorithm().equals("HmacPBESHA512")) { + macString = "PBEWithHmacSHA512"; + } else { + macString = "PBEWithHmacSHA256"; + } algName = "PBMAC1"; } else { params = new PBEParameterSpec(getSalt(), macIterationCount); @@ -1512,8 +1513,9 @@ private byte[] calculateMac(char[] passwd, byte[] data) byte[] macResult = m.doFinal(); // encode as MacData - macData = new MacData(algName, macResult, params, extraSalt, - extraIterationCount); + macData = new MacData(algName, macResult, params, + defaultMacAlgorithm().replace("PBE", ""), + extraSalt, extraIterationCount); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); mData = bytes.toByteArray(); @@ -2170,27 +2172,17 @@ public synchronized void engineLoad(InputStream stream, char[] password) macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); if (algName.equals("PBMAC1")) { byte[] salt = macData.getSalt(); - int keyLength = macData.getKeyLength(); - // PKCS12 implementations MUST NOT accept PBKDF2 KDF - // params that omit the keyLength field. - if (keyLength == -1) { - throw new IOException("PMAC1 parameter parsing " - + "error: missing keyLength field"); - } + pbmac1Hmac = macData.getHmac(); + pbmac1KdfHmac = macData.getKdfHmac(); - PBMAC1ParameterSpec params = - new PBMAC1ParameterSpec(salt, - macData.getIterations(), macData.getkdfHmac(), - macData.getHmac(), keyLength); + PBEParameterSpec params = + new PBEParameterSpec(salt, ic); processMacData(params, macData, password, authSafeData, - "PBEWith" + macData.getHmac()); + "PBEWith" + pbmac1Hmac); macAlgorithm = algName; - pbmac1Hmac = macData.getHmac(); - pbmac1KdfHmac = macData.getkdfHmac(); macIterationCount = macData.getIterations(); - macKeyLength = macData.getKeyLength(); // store salt length in macData macSaltLength = salt.length; extraSalt = macData.getExtraSalt(); diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 5d96d74539e1c..60c7107898534 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1270,6 +1270,7 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep # Java Security Standard Algorithm Names Specification. When set to "NONE", # no Mac is generated. The default value is "HmacPBESHA256". #keystore.pkcs12.macAlgorithm = HmacPBESHA256 +keystore.pkcs12.macAlgorithm = HmacPBESHA256 # The iteration count used by the MacData algorithm. This value must be a # positive integer. The default value is 10000. diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java index 15176a9f28680..9316fe840735a 100644 --- a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java +++ b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java @@ -402,10 +402,12 @@ public static void main(String[] args) throws Exception { password.toCharArray()); System.out.println("A.1 pass"); +/* kdfHash and Hash must have same value, therefore, this test is not supported. ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), password.toCharArray()); System.out.println("A.2 pass"); +*/ ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A3)), From 7880e283476d1b9f191ed693f80e7fc2f90c5f4e Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Sat, 23 Aug 2025 11:22:41 -0600 Subject: [PATCH 09/30] refresh index --- .../share/conf/security/java.security | 1577 +++++++++++++++++ 1 file changed, 1577 insertions(+) create mode 100644 src/java.base/share/conf/security/java.security diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security new file mode 100644 index 0000000000000..5d96d74539e1c --- /dev/null +++ b/src/java.base/share/conf/security/java.security @@ -0,0 +1,1577 @@ +# +# This is the "master security properties file". +# +# An alternate java.security properties file may be specified +# from the command line via the system property +# +# -Djava.security.properties= +# +# This properties file appends to the master security properties file. +# If both properties files specify values for the same key, the value +# from the command-line properties file is selected, as it is the last +# one loaded. +# +# Also, if you specify +# +# -Djava.security.properties== (2 equals), +# +# then that properties file completely overrides the master security +# properties file. +# +# To disable the ability to specify an additional properties file from +# the command line, set the key security.overridePropertiesFile +# to false in the master security properties file. It is set to true +# by default. +# +# If this properties file fails to load, the JDK implementation will throw +# an unspecified error when initializing the java.security.Security class. +# Properties in this file are typically parsed only once. If any of the +# properties are modified, applications should be restarted to ensure the +# changes are properly reflected. +# +# The special "include" property can be defined one or multiple times with +# a filesystem path value. The effect of each definition is to include a +# referred security properties file inline, adding all its properties. +# Security properties defined before an include statement may be overridden +# by properties in the included file, if their names match. Conversely, +# properties defined after an include statement may override properties in +# the included file. +# +# Included files, as well as files pointed to by java.security.properties, +# can include other files recursively. Paths may be absolute or relative. +# Each relative path is resolved against the base file containing its +# "include" definition, if local. Paths may contain system properties for +# expansion in the form of ${system.property}. If a system property does +# not have a value, it expands to the empty string. +# +# An error will be thrown if a file cannot be included. This may happen +# if the file cannot be resolved, does not exist, is a directory, there are +# insufficient permissions to read it, it is recursively included more than +# once, or for any other reason. For a secure JDK configuration, it is +# important to review OS write permissions assigned to any file included. +# +# Examples: +# 1) include ${java.home}/conf/security/extra.security +# 2) include extra.security +# 3) include ${java.home}/conf/security/profile${SecurityProfile}.security +# + +# In this file, various security properties are set for use by +# java.security classes. This is where users can statically register +# Cryptography Package Providers ("providers" for short). The term +# "provider" refers to a package or set of packages that supply a +# concrete implementation of a subset of the cryptography aspects of +# the Java Security API. A provider may, for example, implement one or +# more digital signature algorithms or message digest algorithms. +# +# Each provider must implement a subclass of the Provider class. +# To register a provider in this master security properties file, +# specify the provider and priority in the format +# +# security.provider.= +# +# This declares a provider, and specifies its preference +# order n. The preference order is the order in which providers are +# searched for requested algorithms (when no specific provider is +# requested). The order is 1-based; 1 is the most preferred, followed +# by 2, and so on. +# +# must specify the name of the Provider as passed to its super +# class java.security.Provider constructor. This is for providers loaded +# through the ServiceLoader mechanism. +# +# must specify the subclass of the Provider class whose +# constructor sets the values of various properties that are required +# for the Java Security API to look up the algorithms or other +# facilities implemented by the provider. This is for providers loaded +# through classpath. +# +# Note: Providers can be dynamically registered instead by calls to +# either the addProvider or insertProviderAt method in the Security +# class. + +# +# List of providers and their preference orders (see above): +# +security.provider.tbd=SUN +security.provider.tbd=SunRsaSign +security.provider.tbd=SunEC +security.provider.tbd=SunJSSE +security.provider.tbd=SunJCE +security.provider.tbd=SunJGSS +security.provider.tbd=SunSASL +security.provider.tbd=XMLDSig +security.provider.tbd=SunPCSC +security.provider.tbd=JdkLDAP +security.provider.tbd=JdkSASL +#ifdef windows +security.provider.tbd=SunMSCAPI +#endif +#ifdef macosx +security.provider.tbd=Apple +#endif +security.provider.tbd=SunPKCS11 + +# +# A list of preferred providers for specific algorithms. These providers will +# be searched for matching algorithms before the list of registered providers. +# Entries containing errors (parsing, etc) will be ignored. Use the +# -Djava.security.debug=jca property to debug these errors. +# +# The property is a comma-separated list of serviceType.algorithm:provider +# entries. The serviceType (example: "MessageDigest") is optional, and if +# not specified, the algorithm applies to all service types that support it. +# The algorithm is the standard algorithm name or transformation. +# Transformations can be specified in their full standard name +# (ex: AES/CBC/PKCS5Padding), or as partial matches (ex: AES, AES/CBC). +# The provider is the name of the provider. Any provider that does not +# also appear in the registered list will be ignored. +# +# There is a special serviceType for this property only to group a set of +# algorithms together. The type is "Group" and is followed by an algorithm +# keyword. Groups are to simplify and lessen the entries on the property +# line. Current groups are: +# Group.SHA2 = SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 +# Group.HmacSHA2 = HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512 +# Group.SHA2RSA = SHA224withRSA, SHA256withRSA, SHA384withRSA, SHA512withRSA +# Group.SHA2DSA = SHA224withDSA, SHA256withDSA, SHA384withDSA, SHA512withDSA +# Group.SHA2ECDSA = SHA224withECDSA, SHA256withECDSA, SHA384withECDSA, \ +# SHA512withECDSA +# Group.SHA3 = SHA3-224, SHA3-256, SHA3-384, SHA3-512 +# Group.HmacSHA3 = HmacSHA3-224, HmacSHA3-256, HmacSHA3-384, HmacSHA3-512 +# +# Example: +# jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \ +# MessageDigest.SHA-256:SUN, Group.HmacSHA2:SunJCE +# +#jdk.security.provider.preferred= + + +# +# Sun Provider SecureRandom seed source. +# +# Select the primary source of seed data for the "NativePRNG", "SHA1PRNG" +# and "DRBG" SecureRandom implementations in the "Sun" provider. +# (Other SecureRandom implementations might also use this property.) +# +# On Unix-like systems (for example, Linux/MacOS), the +# "NativePRNG", "SHA1PRNG" and "DRBG" implementations obtains seed data from +# special device files such as file:/dev/random. +# +# On Windows systems, specifying the URLs "file:/dev/random" or +# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding +# mechanism for SHA1PRNG and DRBG. +# +# By default, an attempt is made to use the entropy gathering device +# specified by the "securerandom.source" Security property. If an +# exception occurs while accessing the specified URL: +# +# NativePRNG: +# a default value of /dev/random will be used. If neither +# are available, the implementation will be disabled. +# "file" is the only currently supported protocol type. +# +# SHA1PRNG and DRBG: +# the traditional system/thread activity algorithm will be used. +# +# The entropy gathering device can also be specified with the System +# property "java.security.egd". For example: +# +# % java -Djava.security.egd=file:/dev/random MainClass +# +# Specifying this System property will override the +# "securerandom.source" Security property. +# +# In addition, if "file:/dev/random" or "file:/dev/urandom" is +# specified, the "NativePRNG" implementation will be more preferred than +# DRBG and SHA1PRNG in the Sun provider. +# +securerandom.source=file:/dev/random + +# +# A list of known strong SecureRandom implementations. +# +# To help guide applications in selecting a suitable strong +# java.security.SecureRandom implementation, Java distributions should +# indicate a list of known strong implementations using the property. +# +# This is a comma-separated list of algorithm and/or algorithm:provider +# entries. +# +#ifdef windows +securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,DRBG:SUN +#endif +#ifndef windows +securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN +#endif + +# +# Sun provider DRBG configuration and default instantiation request. +# +# NIST SP 800-90Ar1 lists several DRBG mechanisms. Each can be configured +# with a DRBG algorithm name, and can be instantiated with a security strength, +# prediction resistance support, etc. This property defines the configuration +# and the default instantiation request of "DRBG" SecureRandom implementations +# in the SUN provider. (Other DRBG implementations can also use this property.) +# Applications can request different instantiation parameters like security +# strength, capability, personalization string using one of the +# getInstance(...,SecureRandomParameters,...) methods with a +# DrbgParameters.Instantiation argument, but other settings such as the +# mechanism and DRBG algorithm names are not currently configurable by any API. +# +# Please note that the SUN implementation of DRBG always supports reseeding. +# +# The value of this property is a comma-separated list of all configurable +# aspects. The aspects can appear in any order but the same aspect can only +# appear at most once. Its BNF-style definition is: +# +# Value: +# aspect { "," aspect } +# +# aspect: +# mech_name | algorithm_name | strength | capability | df +# +# // The DRBG mechanism to use. Default "Hash_DRBG" +# mech_name: +# "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG" +# +# // The DRBG algorithm name. The "SHA-***" names are for Hash_DRBG and +# // HMAC_DRBG, default "SHA-256". The "AES-***" names are for CTR_DRBG, +# // default "AES-128" when using the limited cryptographic or "AES-256" +# // when using the unlimited. +# algorithm_name: +# "SHA-224" | "SHA-512/224" | "SHA-256" | +# "SHA-512/256" | "SHA-384" | "SHA-512" | +# "AES-128" | "AES-192" | "AES-256" +# +# // Security strength requested. Default "128" +# strength: +# "112" | "128" | "192" | "256" +# +# // Prediction resistance and reseeding request. Default "none" +# // "pr_and_reseed" - Both prediction resistance and reseeding +# // support requested +# // "reseed_only" - Only reseeding support requested +# // "none" - Neither prediction resistance not reseeding +# // support requested +# pr: +# "pr_and_reseed" | "reseed_only" | "none" +# +# // Whether a derivation function should be used. only applicable +# // to CTR_DRBG. Default "use_df" +# df: +# "use_df" | "no_df" +# +# Examples, +# securerandom.drbg.config=Hash_DRBG,SHA-224,112,none +# securerandom.drbg.config=CTR_DRBG,AES-256,192,pr_and_reseed,use_df +# +# The default value is an empty string, which is equivalent to +# securerandom.drbg.config=Hash_DRBG,SHA-256,128,none +# +securerandom.drbg.config= + +# +# Class to instantiate as the javax.security.auth.login.Configuration +# provider. +# +login.configuration.provider=sun.security.provider.ConfigFile + +# +# Default login configuration file +# +#login.config.url.1=file:${user.home}/.java.login.config + +# Controls whether or not properties are expanded in login configuration files. +# If set to false, properties (${...}) will not be expanded in login +# configuration files. If commented out or set to an empty string, the default +# value is "true" for login configuration files. +# +policy.expandProperties=true + +# Controls whether or not an extra login configuration file is allowed to be +# passed on the command line with -Djava.security.auth.login.config=somefile. +# If commented out or set to an empty string, the default value is "false". +# +policy.allowSystemProperty=true + +# +# Default keystore type. +# +keystore.type=pkcs12 + +# +# Controls compatibility mode for JKS and PKCS12 keystore types. +# +# When set to 'true', both JKS and PKCS12 keystore types support loading +# keystore files in either JKS or PKCS12 format. When set to 'false' the +# JKS keystore type supports loading only JKS keystore files and the PKCS12 +# keystore type supports loading only PKCS12 keystore files. +# +keystore.type.compat=true + +# +# Determines whether this properties file can be appended to +# or overridden on the command line via -Djava.security.properties +# +security.overridePropertiesFile=true + +# +# Determines the default key and trust manager factory algorithms for +# the javax.net.ssl package. +# +ssl.KeyManagerFactory.algorithm=SunX509 +ssl.TrustManagerFactory.algorithm=PKIX + +# +# The Java-level namelookup cache policy for successful lookups: +# +# any negative value: caching forever +# any positive value: the number of seconds to cache an address for +# zero: do not cache +# +# The default behavior in this implementation is to cache for 30 seconds. +# +# NOTE: setting this to anything other than the default value can have +# serious security implications. Do not set it unless +# you are sure you are not exposed to DNS spoofing attack. +# +#networkaddress.cache.ttl=-1 + +# +# The Java-level namelookup cache stale policy: +# +# any positive value: the number of seconds to use the stale names +# zero: do not use stale names +# negative values are ignored +# +# default value is 0 (NEVER). +# +#networkaddress.cache.stale.ttl=0 + +# The Java-level namelookup cache policy for failed lookups: +# +# any negative value: cache forever +# any positive value: the number of seconds to cache negative lookup results +# zero: do not cache +# +# In some Microsoft Windows networking environments that employ +# the WINS name service in addition to DNS, name service lookups +# that fail may take a noticeably long time to return (approx. 5 seconds). +# For this reason the default caching policy is to maintain these +# results for 10 seconds. +# +networkaddress.cache.negative.ttl=10 + +# +# Properties to configure OCSP for certificate revocation checking +# + +# Enable OCSP +# +# By default, OCSP is not used for certificate revocation checking. +# This property enables the use of OCSP when set to the value "true". +# +# NOTE: SocketPermission is required to connect to an OCSP responder. +# +# Example, +# ocsp.enable=true + +# +# Location of the OCSP responder +# +# By default, the location of the OCSP responder is determined implicitly +# from the certificate being validated. This property explicitly specifies +# the location of the OCSP responder. The property is used when the +# Authority Information Access extension (defined in RFC 5280) is absent +# from the certificate or when it requires overriding. +# +# Example, +# ocsp.responderURL=http://ocsp.example.net:80 + +# +# Subject name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. In cases where +# the subject name alone is not sufficient to uniquely identify the certificate +# then both the "ocsp.responderCertIssuerName" and +# "ocsp.responderCertSerialNumber" properties must be used instead. When this +# property is set then those two properties are ignored. +# +# Example, +# ocsp.responderCertSubjectName=CN=OCSP Responder, O=XYZ Corp + +# +# Issuer name of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# distinguished name (defined in RFC 2253) which identifies a certificate in +# the set of certificates supplied during cert path validation. When this +# property is set then the "ocsp.responderCertSerialNumber" property must also +# be set. When the "ocsp.responderCertSubjectName" property is set then this +# property is ignored. +# +# Example, +# ocsp.responderCertIssuerName=CN=Enterprise CA, O=XYZ Corp + +# +# Serial number of the OCSP responder's certificate +# +# By default, the certificate of the OCSP responder is that of the issuer +# of the certificate being validated. This property identifies the certificate +# of the OCSP responder when the default does not apply. Its value is a string +# of hexadecimal digits (colon or space separators may be present) which +# identifies a certificate in the set of certificates supplied during cert path +# validation. When this property is set then the "ocsp.responderCertIssuerName" +# property must also be set. When the "ocsp.responderCertSubjectName" property +# is set then this property is ignored. +# +# Example, +# ocsp.responderCertSerialNumber=2A:FF:00 + +# +# Policy for failed Kerberos KDC lookups: +# +# When a KDC is unavailable (network error, service failure, etc), it is +# put inside a secondary list and accessed less often for future requests. The +# value (case-insensitive) for this policy can be: +# +# tryLast +# KDCs in the secondary list are always tried after those not on the list. +# +# tryLess[:max_retries,timeout] +# KDCs in the secondary list are still tried by their order in the +# configuration, but with smaller max_retries and timeout values. +# max_retries and timeout are optional numerical parameters (default 1 and +# 5000, which means once and 5 seconds). Please note that if any of the +# values defined here are more than what is defined in krb5.conf, it will be +# ignored. +# +# Whenever a KDC is detected as available, it is removed from the secondary +# list. The secondary list is reset when krb5.conf is reloaded. You can add +# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is +# reloaded whenever a JAAS authentication is attempted. +# +# Example, +# krb5.kdc.bad.policy = tryLast +# krb5.kdc.bad.policy = tryLess:2,2000 +# +krb5.kdc.bad.policy = tryLast + +# +# Kerberos cross-realm referrals (RFC 6806) +# +# OpenJDK's Kerberos client supports cross-realm referrals as defined in +# RFC 6806. This allows to setup more dynamic environments in which clients +# do not need to know in advance how to reach the realm of a target principal +# (either a user or service). +# +# When a client issues an AS or a TGS request, the "canonicalize" option +# is set to announce support of this feature. A KDC server may fulfill the +# request or reply referring the client to a different one. If referred, +# the client will issue a new request and the cycle repeats. +# +# In addition to referrals, the "canonicalize" option allows the KDC server +# to change the client name in response to an AS request. For security reasons, +# RFC 6806 (section 11) FAST scheme is enforced. +# +# Disable Kerberos cross-realm referrals. Value may be overwritten with a +# System property (-Dsun.security.krb5.disableReferrals). +sun.security.krb5.disableReferrals=false + +# Maximum number of AS or TGS referrals to avoid infinite loops. Value may +# be overwritten with a System property (-Dsun.security.krb5.maxReferrals). +sun.security.krb5.maxReferrals=5 + +# +# This property contains a list of disabled EC Named Curves that can be included +# in the jdk.[tls|certpath|jar].disabledAlgorithms properties. To include this +# list in any of the disabledAlgorithms properties, add the property name as +# an entry. +#jdk.disabled.namedCurves= + +# +# Algorithm restrictions for certification path (CertPath) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# for certification path building and validation. For example, "MD2" is +# generally no longer considered to be a secure hash algorithm. This section +# describes the mechanism for disabling algorithms based on algorithm name +# and/or key length. This includes algorithms used in certificates, as well +# as revocation information such as CRLs and signed OCSP Responses. +# The syntax of the disabled algorithm string is described as follows: +# DisabledAlgorithms: +# " DisabledAlgorithm { , DisabledAlgorithm } " +# +# DisabledAlgorithm: +# AlgorithmName [Constraint] { '&' Constraint } | IncludeProperty +# +# AlgorithmName: +# (see below) +# +# Constraint: +# KeySizeConstraint | CAConstraint | DenyAfterConstraint | +# UsageConstraint +# +# KeySizeConstraint: +# keySize Operator KeyLength +# +# Operator: +# <= | < | == | != | >= | > +# +# KeyLength: +# Integer value of the algorithm's key length in bits +# +# CAConstraint: +# jdkCA +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# TLSServer | TLSClient | SignedJAR +# +# IncludeProperty: +# include +# +# The "AlgorithmName" is the standard algorithm name of the disabled +# algorithm. See the Java Security Standard Algorithm Names Specification +# for information about Standard Algorithm Names. Matching is +# performed using a case-insensitive sub-element matching rule. (For +# example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and +# "ECDSA" for signatures.) If the assertion "AlgorithmName" is a +# sub-element of the certificate algorithm name, the algorithm will be +# rejected during certification path building and validation. For example, +# the assertion algorithm name "DSA" will disable all certificate algorithms +# that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion +# will not disable algorithms related to "ECDSA". +# +# The "IncludeProperty" allows a implementation-defined security property that +# can be included in the disabledAlgorithms properties. These properties are +# to help manage common actions easier across multiple disabledAlgorithm +# properties. +# There is one defined security property: jdk.disabled.namedCurves +# See the property for more specific details. +# +# +# A "Constraint" defines restrictions on the keys and/or certificates for +# a specified AlgorithmName: +# +# KeySizeConstraint: +# keySize Operator KeyLength +# The constraint requires a key of a valid size range if the +# "AlgorithmName" is of a key algorithm. The "KeyLength" indicates +# the key size specified in number of bits. For example, +# "RSA keySize <= 1024" indicates that any RSA key with key size less +# than or equal to 1024 bits should be disabled, and +# "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key +# with key size less than 1024 or greater than 2048 should be disabled. +# This constraint is only used on algorithms that have a key size. +# +# CAConstraint: +# jdkCA +# This constraint prohibits the specified algorithm only if the +# algorithm is used in a certificate chain that terminates at a marked +# trust anchor in the lib/security/cacerts keystore. If the jdkCA +# constraint is not set, then all chains using the specified algorithm +# are restricted. jdkCA may only be used once in a DisabledAlgorithm +# expression. +# Example: To apply this constraint to SHA-1 certificates, include +# the following: "SHA1 jdkCA" +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# This constraint prohibits a certificate with the specified algorithm +# from being used after the date regardless of the certificate's +# validity. JAR files that are signed and timestamped before the +# constraint date with certificates containing the disabled algorithm +# will not be restricted. The date is processed in the UTC timezone. +# This constraint can only be used once in a DisabledAlgorithm +# expression. +# Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020, +# use the following: "RSA keySize == 2048 & denyAfter 2020-02-03" +# +# UsageConstraint: +# usage UsageType { UsageType } +# This constraint prohibits the specified algorithm for +# a specified UsageType. This should be used when disabling an algorithm +# for all usages is not practical. 'TLSServer' restricts the algorithm +# in TLS server certificate chains when server authentication is +# performed. 'TLSClient' restricts the algorithm in TLS client +# certificate chains when client authentication is performed. +# 'SignedJAR' constrains use of certificates in signed jar files. +# The usage type follows the keyword and more than one usage type can +# be specified with a whitespace delimiter. +# Example: "SHA1 usage TLSServer TLSClient" +# +# When an algorithm must satisfy more than one constraint, it must be +# delimited by an ampersand '&'. For example, to restrict certificates in a +# chain that terminate at a distribution provided trust anchor and contain +# RSA keys that are less than or equal to 1024 bits, add the following +# constraint: "RSA keySize <= 1024 & jdkCA". +# +# All DisabledAlgorithms expressions are processed in the order defined in the +# property. This requires lower keysize constraints to be specified +# before larger keysize constraints of the same algorithm. For example: +# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". +# +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# +# Note: This property is currently used by Oracle's PKIX implementation. It +# is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 +# +# +jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \ + RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224, \ + SHA1 usage SignedJAR & denyAfter 2019-01-01 + +# +# Legacy cryptographic algorithms and key lengths. +# +# In some environments, a certain algorithm or key length may be undesirable. +# +# Tools such as keytool and jarsigner may emit warnings when these legacy +# algorithms are used. See the man pages for those tools for more information. +# +# The syntax is the same as the "jdk.certpath.disabledAlgorithms" and +# "jdk.jar.disabledAlgorithms" security properties. +# +# Note: This property is currently used by the JDK Reference +# implementation. It is not guaranteed to be examined and used by other +# implementations. + +jdk.security.legacyAlgorithms=SHA1, \ + RSA keySize < 2048, DSA keySize < 2048, \ + DES, DESede, MD5, RC2, ARCFOUR + +# +# Algorithm restrictions for signed JAR files +# +# In some environments, certain algorithms or key lengths may be undesirable +# for signed JAR validation. For example, "MD2" is generally no longer +# considered to be a secure hash algorithm. This section describes the +# mechanism for disabling algorithms based on algorithm name and/or key length. +# JARs signed with any of the disabled algorithms or key sizes will be treated +# as unsigned. +# +# The syntax of the disabled algorithm string is described as follows: +# DisabledAlgorithms: +# " DisabledAlgorithm { , DisabledAlgorithm } " +# +# DisabledAlgorithm: +# AlgorithmName [Constraint] { '&' Constraint } +# +# AlgorithmName: +# (see below) +# +# Constraint: +# KeySizeConstraint | DenyAfterConstraint +# +# KeySizeConstraint: +# keySize Operator KeyLength +# +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# +# Operator: +# <= | < | == | != | >= | > +# +# KeyLength: +# Integer value of the algorithm's key length in bits +# +# Note: This property is currently used by the JDK Reference +# implementation. It is not guaranteed to be examined and used by other +# implementations. +# +# See "jdk.certpath.disabledAlgorithms" for syntax descriptions. +# +jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ + DSA keySize < 1024, SHA1 denyAfter 2019-01-01 + +# +# Disabled message digest algorithms for use with plaintext +# HTTP Digest authentication (java.net.HttpURLConnection). +# This includes HTTPS Digest authentication to proxies. +# This may be overridden by setting the networking (or system) +# property "http.auth.digest.reEnabledAlgorithms" to a comma +# separated list of algorithms to be allowed. +# +http.auth.digest.disabledAlgorithms = MD5, SHA-1 + +# +# Algorithm restrictions for Secure Socket Layer/Transport Layer Security +# (SSL/TLS/DTLS) processing +# +# In some environments, certain algorithms or key lengths may be undesirable +# when using SSL/TLS/DTLS. This section describes the mechanism for disabling +# algorithms during SSL/TLS/DTLS security parameters negotiation, including +# protocol version negotiation, cipher suites selection, named groups +# selection, signature schemes selection, peer authentication and key +# exchange mechanisms. +# +# Disabled algorithms will not be negotiated for SSL/TLS connections, even +# if they are enabled explicitly in an application. +# +# For PKI-based peer authentication and key exchange mechanisms, this list +# of disabled algorithms will also be checked during certification path +# building and validation, including algorithms used in certificates, as +# well as revocation information such as CRLs and signed OCSP Responses. +# This is in addition to the jdk.certpath.disabledAlgorithms property above. +# +# See the specification of "jdk.certpath.disabledAlgorithms" for the +# syntax of the disabled algorithm string. +# +# Additional TLS-specific syntax supported by this property: +# +# - TLS cipher suites can be disabled with this property using one or more +# "*" wildcard characters. For example, "TLS_RSA_*" disables all cipher +# suites that start with "TLS_RSA_". Only cipher suites starting with +# "TLS_" are allowed to have wildcard characters. +# +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" +# +# Note: The algorithm restrictions do not apply to trust anchors or +# self-signed certificates. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048, \ +# rsa_pkcs1_sha1, secp224r1, TLS_RSA_* +jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ + MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ + ECDH, TLS_RSA_*, rsa_pkcs1_sha1 usage HandshakeSignature, \ + ecdsa_sha1 usage HandshakeSignature, dsa_sha1 usage HandshakeSignature + +# +# Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) +# processing in JSSE implementation. +# +# In some environments, a certain algorithm may be undesirable but it +# cannot be disabled because of its use in legacy applications. Legacy +# algorithms may still be supported, but applications should not use them +# as the security strength of legacy algorithms are usually not strong enough +# in practice. +# +# During SSL/TLS security parameters negotiation, legacy algorithms will +# not be negotiated unless there are no other candidates. +# +# The syntax of the legacy algorithms string is described as this Java +# BNF-style: +# LegacyAlgorithms: +# " LegacyAlgorithm { , LegacyAlgorithm } " +# +# LegacyAlgorithm: +# AlgorithmName (standard JSSE algorithm name) +# +# See the specification of security property "jdk.certpath.disabledAlgorithms" +# for the syntax and description of the "AlgorithmName" notation. +# +# Per SSL/TLS specifications, cipher suites have the form: +# SSL_KeyExchangeAlg_WITH_CipherAlg_MacAlg +# or +# TLS_KeyExchangeAlg_WITH_CipherAlg_MacAlg +# +# For example, the cipher suite TLS_RSA_WITH_AES_128_CBC_SHA uses RSA as the +# key exchange algorithm, AES_128_CBC (128 bits AES cipher algorithm in CBC +# mode) as the cipher (encryption) algorithm, and SHA-1 as the message digest +# algorithm for HMAC. +# +# The LegacyAlgorithm can be one of the following standard algorithm names: +# 1. JSSE cipher suite name, e.g., TLS_RSA_WITH_AES_128_CBC_SHA +# 2. JSSE key exchange algorithm name, e.g., RSA +# 3. JSSE cipher (encryption) algorithm name, e.g., AES_128_CBC +# 4. JSSE message digest algorithm name, e.g., SHA +# +# See SSL/TLS specifications and the Java Security Standard Algorithm Names +# Specification for information about the algorithm names. +# +# Note: If a legacy algorithm is also restricted through the +# jdk.tls.disabledAlgorithms property or the +# java.security.AlgorithmConstraints API (See +# javax.net.ssl.SSLParameters.setAlgorithmConstraints()), +# then the algorithm is completely disabled and will not be negotiated. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# There is no guarantee the property will continue to exist or be of the +# same syntax in future releases. +# +# Example: +# jdk.tls.legacyAlgorithms=DH_anon, DES_CBC, SSL_RSA_WITH_RC4_128_MD5 +# +jdk.tls.legacyAlgorithms=NULL, anon, RC4, DES, 3DES_EDE_CBC + +# +# The pre-defined default finite field Diffie-Hellman ephemeral (DHE) +# parameters for Transport Layer Security (SSL/TLS/DTLS) processing. +# +# In traditional SSL/TLS/DTLS connections where finite field DHE parameters +# negotiation mechanism is not used, the server offers the client group +# parameters, base generator g and prime modulus p, for DHE key exchange. +# It is recommended to use dynamic group parameters. This property defines +# a mechanism that allows you to specify custom group parameters. +# +# The syntax of this property string is described as this Java BNF-style: +# DefaultDHEParameters: +# DefinedDHEParameters { , DefinedDHEParameters } +# +# DefinedDHEParameters: +# "{" DHEPrimeModulus , DHEBaseGenerator "}" +# +# DHEPrimeModulus: +# HexadecimalDigits +# +# DHEBaseGenerator: +# HexadecimalDigits +# +# HexadecimalDigits: +# HexadecimalDigit { HexadecimalDigit } +# +# HexadecimalDigit: one of +# 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f +# +# Whitespace characters are ignored. +# +# The "DefinedDHEParameters" defines the custom group parameters, prime +# modulus p and base generator g, for a particular size of prime modulus p. +# The "DHEPrimeModulus" defines the hexadecimal prime modulus p, and the +# "DHEBaseGenerator" defines the hexadecimal base generator g of a group +# parameter. It is recommended to use safe primes for the custom group +# parameters. +# +# If this property is not defined or the value is empty, the underlying JSSE +# provider's default group parameter is used for each connection. +# +# If the property value does not follow the grammar, or a particular group +# parameter is not valid, the connection will fall back and use the +# underlying JSSE provider's default group parameter. +# +# Note: This property is currently used by OpenJDK's JSSE implementation. It +# is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.tls.server.defaultDHEParameters= +# { \ +# FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 \ +# 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD \ +# EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 \ +# E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED \ +# EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 \ +# FFFFFFFF FFFFFFFF, 2} + +# +# TLS key limits on symmetric cryptographic algorithms +# +# This security property sets limits on algorithms key usage in TLS 1.3. +# When the amount of data encrypted exceeds the algorithm value listed below, +# a KeyUpdate message will trigger a key change. This is for symmetric ciphers +# with TLS 1.3 only. +# +# The syntax for the property is described below: +# KeyLimits: +# " KeyLimit { , KeyLimit } " +# +# KeyLimit: +# AlgorithmName Action Length +# +# AlgorithmName: +# A full algorithm transformation. +# +# Action: +# KeyUpdate +# +# Length: +# The amount of encrypted data in a session before the Action occurs +# This value may be an integer value in bytes, or as a power of two, 2^29. +# +# KeyUpdate: +# The TLS 1.3 KeyUpdate handshake process begins when the Length amount +# is fulfilled. +# +# Note: This property is currently used by OpenJDK's JSSE implementation. It +# is not guaranteed to be examined and used by other implementations. +# +jdk.tls.keyLimits=AES/GCM/NoPadding KeyUpdate 2^37, \ + ChaCha20-Poly1305 KeyUpdate 2^37 + +# +# Cryptographic Jurisdiction Policy defaults +# +# Import and export control rules on cryptographic software vary from +# country to country. By default, Java provides two different sets of +# cryptographic policy files[1]: +# +# unlimited: These policy files contain no restrictions on cryptographic +# strengths or algorithms +# +# limited: These policy files contain more restricted cryptographic +# strengths +# +# The default setting is determined by the value of the "crypto.policy" +# Security property below. If your country or usage requires the +# traditional restrictive policy, the "limited" Java cryptographic +# policy is still available and may be appropriate for your environment. +# +# If you have restrictions that do not fit either use case mentioned +# above, Java provides the capability to customize these policy files. +# The "crypto.policy" security property points to a subdirectory +# within /conf/security/policy/ which can be customized. +# Please see the /conf/security/policy/README.txt file or consult +# the Java Security Guide/JCA documentation for more information. +# +# YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY +# TO DETERMINE THE EXACT REQUIREMENTS. +# +# [1] Please note that the JCE for Java SE, including the JCE framework, +# cryptographic policy files, and standard JCE providers provided with +# the Java SE, have been reviewed and approved for export as mass market +# encryption item by the US Bureau of Industry and Security. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +crypto.policy=crypto.policydir-tbd + +# +# The policy for the XML Signature secure validation mode. Validation of +# XML Signatures that violate any of these constraints will fail. +# The mode can be enabled or disabled by setting the property +# "org.jcp.xml.dsig.secureValidation" to Boolean.TRUE or Boolean.FALSE with +# the javax.xml.crypto.XMLCryptoContext.setProperty() method, or by setting +# the system property "org.jcp.xml.dsig.secureValidation" to "true" or +# "false". Any other value for the system property is also treated as "false". +# If the system property is set, it supersedes the XMLCryptoContext property +# value. +# +# The secure validation mode is enabled by default. +# +# Policy: +# Constraint {"," Constraint } +# Constraint: +# AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint | +# ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint +# AlgConstraint +# "disallowAlg" Uri +# MaxTransformsConstraint: +# "maxTransforms" Integer +# MaxReferencesConstraint: +# "maxReferences" Integer +# ReferenceUriSchemeConstraint: +# "disallowReferenceUriSchemes" String { String } +# KeySizeConstraint: +# "minKeySize" KeyAlg Integer +# OtherConstraint: +# "noDuplicateIds" | "noRetrievalMethodLoops" +# +# For AlgConstraint, Uri is the algorithm URI String that is not allowed. +# See the XML Signature Recommendation for more information on algorithm +# URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm +# name of the key type (ex: "RSA"). If the MaxTransformsConstraint, +# MaxReferencesConstraint or KeySizeConstraint (for the same key type) is +# specified more than once, only the last entry is enforced. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +jdk.xml.dsig.secureValidationPolicy=\ + disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,\ + disallowAlg http://www.w3.org/2000/09/xmldsig#sha1,\ + disallowAlg http://www.w3.org/2000/09/xmldsig#dsa-sha1,\ + disallowAlg http://www.w3.org/2000/09/xmldsig#rsa-sha1,\ + disallowAlg http://www.w3.org/2007/05/xmldsig-more#sha1-rsa-MGF1,\ + disallowAlg http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1,\ + disallowAlg http://www.w3.org/TR/1999/REC-xpath-19991116,\ + maxTransforms 5,\ + maxReferences 30,\ + disallowReferenceUriSchemes file http https,\ + minKeySize RSA 1024,\ + minKeySize DSA 1024,\ + minKeySize EC 224,\ + noDuplicateIds,\ + noRetrievalMethodLoops + +# +# Support for the here() function +# +# This security property determines whether the here() XPath function is +# supported in XML Signature generation and verification. +# +# If this property is set to false, the here() function is not supported. +# Generating an XML Signature that uses the here() function will throw an +# XMLSignatureException. Validating an existing XML Signature that uses the +# here() function will also throw an XMLSignatureException. +# +# The default value for this property is true. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +#jdk.xml.dsig.hereFunctionSupported=true + +# +# Deserialization JVM-wide filter factory +# +# A filter factory class name is used to configure the JVM-wide filter factory. +# The class must be public, must have a public zero-argument constructor, implement the +# java.util.function.BinaryOperator interface, provide its +# implementation and be accessible via the application class loader. +# A builtin filter factory is used if no filter factory is defined. +# See java.io.ObjectInputFilter.Config for more information. +# +# If the system property jdk.serialFilterFactory is also specified, it supersedes +# the security property value defined here. +# +#jdk.serialFilterFactory= + +# +# Deserialization JVM-wide filter +# +# A filter, if configured, is used by the filter factory to provide the filter used by +# java.io.ObjectInputStream during deserialization to check the contents of the stream. +# A filter is configured as a sequence of patterns, each pattern is either +# matched against the name of a class in the stream or defines a limit. +# Patterns are separated by ";" (semicolon). +# Whitespace is significant and is considered part of the pattern. +# +# If the system property jdk.serialFilter is also specified, it supersedes +# the security property value defined here. +# +# If a pattern includes a "=", it sets a limit. +# If a limit appears more than once the last value is used. +# Limits are checked before classes regardless of the order in the +# sequence of patterns. +# If any of the limits are exceeded, the filter status is REJECTED. +# +# maxdepth=value - the maximum depth of a graph +# maxrefs=value - the maximum number of internal references +# maxbytes=value - the maximum number of bytes in the input stream +# maxarray=value - the maximum array length allowed +# +# Other patterns, from left to right, match the class or package name as +# returned from Class.getName. +# If the class is an array type, the class or package to be matched is the +# element type. +# Arrays of any number of dimensions are treated the same as the element type. +# For example, a pattern of "!example.Foo", rejects creation of any instance or +# array of example.Foo. +# +# If the pattern starts with "!", the status is REJECTED if the remaining +# pattern is matched; otherwise the status is ALLOWED if the pattern matches. +# If the pattern contains "/", the non-empty prefix up to the "/" is the +# module name; +# if the module name matches the module name of the class then +# the remaining pattern is matched with the class name. +# If there is no "/", the module name is not compared. +# If the pattern ends with ".**" it matches any class in the package and all +# subpackages. +# If the pattern ends with ".*" it matches any class in the package. +# If the pattern ends with "*", it matches any class with the pattern as a +# prefix. +# If the pattern is equal to the class name, it matches. +# Otherwise, the status is UNDECIDED. +# +#jdk.serialFilter=pattern;pattern + +# +# RMI Registry Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI Registry or to decrease limits but not +# to increase limits. +# If the limits (maxdepth, maxrefs, or maxbytes) are exceeded, the object is rejected. +# +# Each non-array type is allowed or rejected if it matches one of the patterns, +# evaluated from left to right, and is otherwise allowed. Arrays of any +# component type, including subarrays and arrays of primitives, are allowed. +# +# Array construction of any component type, including subarrays and arrays of +# primitives, are allowed unless the length is greater than the maxarray limit. +# The filter is applied to each array element. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# The built-in filter allows subclasses of allowed classes and +# can approximately be represented as the pattern: +# +#sun.rmi.registry.registryFilter=\ +# maxarray=1000000;\ +# maxdepth=20;\ +# java.lang.String;\ +# java.lang.Number;\ +# java.lang.reflect.Proxy;\ +# java.rmi.Remote;\ +# sun.rmi.server.UnicastRef;\ +# sun.rmi.server.RMIClientSocketFactory;\ +# sun.rmi.server.RMIServerSocketFactory;\ +# java.rmi.server.UID +# +# RMI Distributed Garbage Collector (DGC) Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI DGC. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# The builtin DGC filter can approximately be represented as the filter pattern: +# +#sun.rmi.transport.dgcFilter=\ +# java.rmi.server.ObjID;\ +# java.rmi.server.UID;\ +# java.rmi.dgc.VMID;\ +# java.rmi.dgc.Lease;\ +# maxdepth=5;maxarray=10000 + +# +# JCEKS Encrypted Key Serial Filter +# +# This filter, if configured, is used by the JCEKS KeyStore during the +# deserialization of the encrypted Key object stored inside a key entry. +# If not configured or the filter result is UNDECIDED (i.e. none of the patterns +# matches), the filter configured by jdk.serialFilter will be consulted. +# +# If the system property jceks.key.serialFilter is also specified, it supersedes +# the security property value defined here. +# +# The filter pattern uses the same format as jdk.serialFilter. The default +# pattern allows java.lang.Enum, java.security.KeyRep, java.security.KeyRep$Type, +# and javax.crypto.spec.SecretKeySpec and rejects all the others. +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;!* + +# The iteration count used for password-based encryption (PBE) in JCEKS +# keystores. Values in the range 10000 to 5000000 are considered valid. +# If the value is out of this range, or is not a number, or is unspecified; +# a default of 200000 is used. +# +# If the system property jdk.jceks.iterationCount is also specified, it +# supersedes the security property value defined here. +# +#jdk.jceks.iterationCount = 200000 + +# +# 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. +# +# Some PKCS12 tools and libraries may not support algorithms based on PBES2 +# and AES. To create a PKCS12 keystore which they can load, set the system +# property "keystore.pkcs12.legacy" which overrides the values of the properties +# defined below with legacy algorithms. Setting this system property (which can +# only be enabled and has no value) is equivalent to +# +# -Dkeystore.pkcs12.certProtectionAlgorithm=PBEWithSHA1AndRC2_40 +# -Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithSHA1AndDESede +# -Dkeystore.pkcs12.macAlgorithm=HmacPBESHA1 +# -Dkeystore.pkcs12.certPbeIterationCount=50000 +# -Dkeystore.pkcs12.keyPbeIterationCount=50000 +# -Dkeystore.pkcs12.macIterationCount=100000 +# +# Also, you can downgrade an existing PKCS12 keystore created with stronger +# algorithms to legacy algorithms with +# +# keytool -J-Dkeystore.pkcs12.legacy -importkeystore -srckeystore ks -destkeystore ks +# +# This system property should be used at your own risk. +# +# 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 "PBEWithHmacSHA256AndAES_256". +#keystore.pkcs12.certProtectionAlgorithm = PBEWithHmacSHA256AndAES_256 + +# The iteration count used by the PBE algorithm when encrypting a certificate. +# This value must be a positive integer. The default value is 10000. +#keystore.pkcs12.certPbeIterationCount = 10000 + +# 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 "PBEWithHmacSHA256AndAES_256". +#keystore.pkcs12.keyProtectionAlgorithm = PBEWithHmacSHA256AndAES_256 + +# 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 10000. +#keystore.pkcs12.keyPbeIterationCount = 10000 + +# 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 "HmacPBESHA256". +#keystore.pkcs12.macAlgorithm = HmacPBESHA256 + +# The iteration count used by the MacData algorithm. This value must be a +# positive integer. The default value is 10000. +#keystore.pkcs12.macIterationCount = 10000 + +# +# Enhanced exception message information +# +# Exception messages may include potentially sensitive information such as file +# names, host names, or port numbers. By default, socket related exceptions +# have this information restricted (meaning the sensitive details are removed). +# Exception messages relating to JAR files and exceptions containing user +# identity information are also restricted by default. +# This property can be used to relax this restriction or to place further +# restrictions on other categories, defined below. The property +# accepts one or more comma separated values, each of which represents a +# category of enhanced exception message information to enable. Values are +# case-insensitive. Leading and trailing whitespaces, surrounding each value, +# are ignored. Unknown values are ignored. +# +# NOTE: Use caution before setting this property. Setting this property +# exposes sensitive information in Exceptions, which could, for example, +# propagate to untrusted code or be emitted in stack traces that are +# inadvertently disclosed and made accessible over a public network. +# +# The categories are: +# +# hostInfo - All networking related exceptions will contain enhanced +# exception message information. +# +# hostInfoExclSocket - The hostInfo category defined above, excluding +# IOExceptions thrown by java.net.Socket and the NetworkChannel +# types in the java.nio.channels package, will contain enhanced +# exception message information +# +# jar - enables more detailed information in the IOExceptions thrown +# by classes in the java.util.jar package +# +# userInfo - enables more detailed information in exceptions which may contain +# user identity information +# +# The property setting in this file can be overridden by a system property of +# the same name, with the same syntax and possible values. +# +# If the property is not set or set to an empty string, then this is the most +# restricted setting with all categories disabled. The following is the default +# (out of the box) setting, meaning these categories are not restricted. +# +jdk.includeInExceptions=hostInfoExclSocket + +# +# Disabled mechanisms for the Simple Authentication and Security Layer (SASL) +# +# Disabled mechanisms will not be negotiated by both SASL clients and servers. +# These mechanisms will be ignored if they are specified in the "mechanisms" +# argument of "Sasl.createSaslClient" or the "mechanism" argument of +# "Sasl.createSaslServer". +# +# The value of this property is a comma-separated list of SASL mechanisms. +# The mechanisms are case-sensitive. Whitespaces around the commas are ignored. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.sasl.disabledMechanisms=PLAIN, CRAM-MD5, DIGEST-MD5 +jdk.sasl.disabledMechanisms= + +# +# Policies for distrusting Certificate Authorities (CAs). +# +# This is a comma separated value of one or more case-sensitive strings, each +# of which represents a policy for determining if a CA should be distrusted. +# The supported values are: +# +# SYMANTEC_TLS : Distrust TLS Server certificates anchored by a Symantec +# root CA and issued after April 16, 2019 unless issued by one of the +# following subordinate CAs which have a later distrust date: +# 1. Apple IST CA 2 - G1, SHA-256 fingerprint: +# AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B +# Distrust after December 31, 2019. +# 2. Apple IST CA 8 - G1, SHA-256 fingerprint: +# A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED +# Distrust after December 31, 2019. +# +# ENTRUST_TLS : Distrust TLS Server certificates anchored by +# an Entrust root CA and issued after November 11, 2024. +# +# CAMERFIRMA_TLS : Distrust TLS Server certificates anchored by +# a Camerfirma root CA and issued after April 15, 2025. +# +# Leading and trailing whitespace surrounding each value are ignored. +# Unknown values are ignored. If the property is commented out or set to the +# empty String, no policies are enforced. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be supported by other SE implementations. Also, this +# property does not override other security properties which can restrict +# certificates such as jdk.tls.disabledAlgorithms or +# jdk.certpath.disabledAlgorithms; those restrictions are still enforced even +# if this property is not enabled. +# +jdk.security.caDistrustPolicies=SYMANTEC_TLS,ENTRUST_TLS,CAMERFIRMA_TLS + +# +# FilePermission path canonicalization +# +# This security property dictates how the path argument is processed and stored +# while constructing a FilePermission object. If the value is set to true, the +# path argument is canonicalized and FilePermission methods (such as implies, +# equals, and hashCode) are implemented based on this canonicalized result. +# Otherwise, the path argument is not canonicalized and FilePermission methods are +# implemented based on the original input. See the implementation note of the +# FilePermission class for more details. +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# The default value for this property is false. +# +jdk.io.permissionsUseCanonicalPath=false + + +# +# Policies for the proxy_impersonator Kerberos ccache configuration entry +# +# The proxy_impersonator ccache configuration entry indicates that the ccache +# is a synthetic delegated credential for use with S4U2Proxy by an intermediate +# server. The ccache file should also contain the TGT of this server and +# an evidence ticket from the default principal of the ccache to this server. +# +# This security property determines how Java uses this configuration entry. +# There are 3 possible values: +# +# no-impersonate - Ignore this configuration entry, and always act as +# the owner of the TGT (if it exists). +# +# try-impersonate - Try impersonation when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# fallback to no-impersonate. +# +# always-impersonate - Always impersonate when this configuration entry exists. +# If no matching TGT or evidence ticket is found, +# no initial credential is read from the ccache. +# +# The default value is "always-impersonate". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +#jdk.security.krb5.default.initiate.credential=always-impersonate + +# +# Trust Anchor Certificates - CA Basic Constraint check +# +# X.509 v3 certificates used as Trust Anchors (to validate signed code or TLS +# connections) must have the cA Basic Constraint field set to 'true'. Also, if +# they include a Key Usage extension, the keyCertSign bit must be set. These +# checks, enabled by default, can be disabled for backward-compatibility +# purposes with the jdk.security.allowNonCaAnchor System and Security +# properties. In the case that both properties are simultaneously set, the +# System value prevails. The default value of the property is "false". +# +#jdk.security.allowNonCaAnchor=true + +# +# The default Character set name (java.nio.charset.Charset.forName()) +# for converting TLS ALPN values between byte arrays and Strings. +# Prior versions of the JDK may use UTF-8 as the default charset. If +# you experience interoperability issues, setting this property to UTF-8 +# may help. +# +# jdk.tls.alpnCharset=UTF-8 +jdk.tls.alpnCharset=ISO_8859_1 + +# +# Global JNDI Object Factories Filter +# +# This filter is used by the JNDI runtime to control the set of object factory classes +# which will be allowed to instantiate objects from object references returned by +# naming/directory systems. The factory class named by the reference instance will be +# matched against this filter. The filter property supports pattern-based filter syntax +# with the same format as jdk.serialFilter. Limit patterns specified in the filter property +# are unused. +# +# Each class name pattern is matched against the factory class name to allow or disallow its +# instantiation. The access to a factory class is allowed if the filter returns +# ALLOWED. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# If the system property jdk.jndi.object.factoriesFilter is also specified, it supersedes +# the security property value defined here. The default value of the property is "*". +# +# The default pattern value allows any object factory class specified by the reference +# instance to recreate the referenced object. +#jdk.jndi.object.factoriesFilter=* + +# +# Protocol Specific JNDI/LDAP Object Factories Filter +# +# This filter is used by the JNDI/LDAP provider implementation in the JDK to further control the +# set of object factory classes which will be allowed to instantiate objects from object +# references bound to LDAP contexts. The factory class named by the reference instance will +# be matched against this filter. The filter property supports pattern-based filter syntax +# with the same format as jdk.serialFilter. Limit patterns specified in the filter property +# are unused. +# +# Each class name pattern is matched against the factory class name to allow or disallow its +# instantiation. The access to a factory class is allowed only when it is not rejected by this filter +# or by the global filter defined by "jdk.jndi.object.factoriesFilter", and at least one of these +# two filters returns ALLOWED. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# If the system property jdk.jndi.ldap.object.factoriesFilter is also specified, it supersedes +# the security property value defined here. The default value of the property is +# "java.naming/com.sun.jndi.ldap.**;!*". +# +# The default pattern value allows any object factory class defined in the java.naming module +# to be specified by the reference instance, but rejects any other. +#jdk.jndi.ldap.object.factoriesFilter=java.naming/com.sun.jndi.ldap.**;!* + +# +# Protocol Specific JNDI/RMI Object Factories Filter +# +# This filter is used by the JNDI/RMI provider implementation in the JDK to further control the +# set of object factory classes which will be allowed to instantiate objects from object +# references bound to RMI names. The factory class named by the reference instance will +# be matched against this filter. The filter property supports pattern-based filter syntax +# with the same format as jdk.serialFilter. Limit patterns specified in the filter property +# are unused. +# +# Each class name pattern is matched against the factory class name to allow or disallow its +# instantiation. The access to a factory class is allowed only when it is not rejected by this filter +# or by the global filter defined by "jdk.jndi.object.factoriesFilter", and at least one of these +# two filters returns ALLOWED. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# If the system property jdk.jndi.rmi.object.factoriesFilter is also specified, it supersedes +# the security property value defined here. The default value of the property is +# "jdk.naming.rmi/com.sun.jndi.rmi.**;!*". +# +# The default pattern value allows any object factory class defined in the jdk.naming.rmi module +# to be specified by the reference instance, but rejects any other. +#jdk.jndi.rmi.object.factoriesFilter=jdk.naming.rmi/com.sun.jndi.rmi.**;!* + +# +# Policy for non-forwardable service ticket in a S4U2proxy request +# +# The Service for User to Proxy (S4U2proxy) Kerberos extension enables a middle service +# to obtain a service ticket to another service on behalf of a user. It requires that +# the user's service ticket to the first service has the forwardable flag set [1]. +# However, some KDC implementations ignore this requirement and accept service tickets +# with the flag unset. +# +# If this security property is set to "true", then +# +# 1) The user service ticket, when obtained by the middle service after a S4U2self +# impersonation, is not required to have the forwardable flag set; and, +# +# 2) If a S4U2proxy request receives a KRB_ERROR of the KDC_ERR_BADOPTION error code +# and the ticket to the middle service is not forwardable, OpenJDK will try the same +# request with another KDC instead of treating it as a fatal failure. +# +# The default value is "false". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +# [1] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/bde93b0e-f3c9-4ddf-9f44-e1453be7af5a +#jdk.security.krb5.s4u2proxy.acceptNonForwardableServiceTicket=false + +# +# Policy for name comparison in keytab and ccache entry lookup +# +# When looking up a keytab or credentials cache (ccache) entry for a Kerberos +# principal, the principal name is compared with the name in the entry. +# The comparison is by default case-insensitive. However, many Kerberos +# implementations consider principal names to be case-sensitive. Consequently, +# if two principals have names that differ only in case, there is a risk that +# an incorrect keytab or ccache entry might be selected. +# +# If this security property is set to "true", the comparison of principal +# names at keytab and ccache entry lookup is case-sensitive. +# +# The default value is "false". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +#jdk.security.krb5.name.case.sensitive=false + +# +# Default algorithm for PEMEncoder Encrypted PKCS#8 +# +# This property defines the default password-based encryption algorithm for +# java.security.PEMEncoder when configured for encryption with the +# withEncryption method. +# +jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128 From 1503815ad921f6d4ad8720c660747e08aeb037d4 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Sat, 23 Aug 2025 12:29:01 -0600 Subject: [PATCH 10/30] not used --- .../crypto/spec/PBMAC1ParameterSpec.java | 115 ------------------ 1 file changed, 115 deletions(-) delete mode 100644 src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java diff --git a/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java deleted file mode 100644 index 88aa4b39ae46e..0000000000000 --- a/src/java.base/share/classes/javax/crypto/spec/PBMAC1ParameterSpec.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2025, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 javax.crypto.spec; - -import java.security.spec.AlgorithmParameterSpec; - -/** - * This class specifies the set of parameters used with PBMAC1, - * as defined in the - * PKCS #12 - * standard. - * - * @spec https://www.rfc-editor.org/info/rfc9579 - * RFC 9579: Use of Password-Based Message Authentication Code 1 (PBMAC1) in PKCS #12 - * - * @since 26 - */ -public class PBMAC1ParameterSpec implements AlgorithmParameterSpec { - - private final byte[] salt; - private final int iterationCount; - private String kdfHmac = null; - private String hmac = null; - private int keyLength; - - /** - * Constructs a parameter set for PBMAC1 as defined in - * the PKCS #5 standard. - * - * @param salt the salt. The contents of {@code salt} are copied - * to protect against subsequent modification. - * @param iterationCount the iteration count - * @param kdfHmac the HMAC used by PBKDF2 - * @param hmac the HMAC that protects the keystore - * @param keyLength bit length of Hmac key - * @exception NullPointerException if {@code salt} is null - */ - public PBMAC1ParameterSpec(byte[] salt, int iterationCount, - String kdfHmac, String hmac, int keyLength) { - this.salt = salt.clone(); - this.iterationCount = iterationCount; - this.kdfHmac = kdfHmac; - this.hmac = hmac; - this.keyLength = keyLength; - } - - /** - * Returns the salt. - * - * @return the salt. Returns a new array - * each time this method is called. - */ - public byte[] getSalt() { - return salt.clone(); - } - - /** - * Returns the iteration count. - * - * @return the iteration count - */ - public int getIterationCount() { - return iterationCount; - } - - /** - * Returns Hmac used by PBKDF2. - * - * @return the Hmac used by PBKDF2. - */ - public String getkdfHmac() { - return kdfHmac; - } - - /** - * Returns Hmac used to protect the KeyStore. - * - * @return the Hmac - */ - public String getHmac() { - return hmac; - } - - /** - * Returns length of key generated by PBKDF2. - * - * @return length of key generated by PBKDF2. - */ - public int getKeyLength() { - return keyLength; - } -} From ecda43f557b4f96c9f54287b13e7cf7056fb8e94 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Mon, 25 Aug 2025 12:58:22 -0600 Subject: [PATCH 11/30] small changes --- .../com/sun/crypto/provider/PBMAC1Core.java | 5 ++- .../sun/crypto/provider/PBMAC1Parameters.java | 8 ++-- .../classes/sun/security/pkcs12/MacData.java | 15 ------- .../sun/security/pkcs12/PKCS12KeyStore.java | 3 +- .../sun/security/pkcs12/PBMAC1Encoding.java | 43 +++++++++++++++---- 5 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index 123e1452273e0..b467e35c9176d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -107,7 +107,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) char[] passwdChars; byte[] salt = null; int iCount = 0; - int keyLength = 0; + int keyLength = blockLength; if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) { passwdChars = pbeKey.getPassword(); salt = pbeKey.getSalt(); // maybe null if unspecified @@ -165,10 +165,13 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) keyLength = 512; } else if (kdfAlgo.equals("HmacSHA256")) { keyLength = 256; + } +/* } else { throw new InvalidAlgorithmParameterException ("Unsupported Mac algorithm"); } +*/ } // For security purpose, we need to enforce a minimum length diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index f0b49872862db..523958560705a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -126,13 +126,13 @@ protected void engineInit(byte[] encoded) { DerValue pBMAC1_params = new DerValue(encoded); if (pBMAC1_params.tag != DerValue.tag_Sequence) { - throw new IOException("PMAC1 parameter parsing error: " + throw new IOException("PBMAC1 parameter parsing error: " + "not an ASN.1 SEQUENCE tag"); } DerValue[] Info = (new DerInputStream(pBMAC1_params.toByteArray())) .getSequence(2); if (Info.length != 2) { - throw new IOException("PMAC1 parameter parsing error: " + throw new IOException("PBMAC1 parameter parsing error: " + "expected length not 2"); } ObjectIdentifier OID = Info[1].data.getOID(); @@ -160,13 +160,13 @@ protected void engineInit(byte[] encoded) // Key length must be present. It is not currently used. keyLength = kdfParams.getKeyLength(); if (keyLength == -1) { - throw new IOException("PMAC1 parameter parsing " + throw new IOException("PBMAC1 parameter parsing " + "error: missing keyLength field"); } // Key length SHOULD be the same size as HMAC function output size. if ((kdfAlgo.contains("256") && keyLength != 256) || (kdfAlgo.contains("512") && keyLength != 512)) { - throw new IOException("PMAC1 parameter parsing " + throw new IOException("PBMAC1 parameter parsing " + "error: keyLength not Hmac output length "); } diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index de68e2ae4afce..8153b5497999c 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -103,7 +103,6 @@ class MacData { macSalt = pbeSpec.getSalt(); String ps = digestAlgorithmParams.toString(); kdfHmac = getKdfHmac(ps); - Hmac = getHmac(ps); } // Get the salt. @@ -320,18 +319,4 @@ public String getKdfHmac(String text) { return null; } } - - public String getHmac(String text) { - final String word2 = "And"; - - String regex = Pattern.quote(word2) + "(.*?)$"; - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(text); - - if (matcher.find()) { - return matcher.group(1); - } else { - return null; - } - } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index c49083d66bcb0..448e0f3ae6b74 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -2173,13 +2173,12 @@ public synchronized void engineLoad(InputStream stream, char[] password) if (algName.equals("PBMAC1")) { byte[] salt = macData.getSalt(); - pbmac1Hmac = macData.getHmac(); pbmac1KdfHmac = macData.getKdfHmac(); PBEParameterSpec params = new PBEParameterSpec(salt, ic); processMacData(params, macData, password, authSafeData, - "PBEWith" + pbmac1Hmac); + "PBEWith" + pbmac1KdfHmac); macAlgorithm = algName; macIterationCount = macData.getIterations(); diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java index 9316fe840735a..57f34f58ba417 100644 --- a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java +++ b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java @@ -28,6 +28,9 @@ */ import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.security.KeyStore; import java.util.Base64; @@ -396,29 +399,51 @@ public class PBMAC1Encoding { public static void main(String[] args) throws Exception { KeyStore ks; + FileOutputStream fos; + FileInputStream fis; ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A1)), password.toCharArray()); + + fos = new FileOutputStream("pbmac1KeyStore.p12"); + ks.store(fos, password.toCharArray()); + fos.close(); + + // read keystore we just wrote + fis = new FileInputStream("pbmac1KeyStore.p12"); + ks.load(fis, password.toCharArray()); + fis.close(); System.out.println("A.1 pass"); -/* kdfHash and Hash must have same value, therefore, this test is not supported. - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), - password.toCharArray()); - System.out.println("A.2 pass"); -*/ + // Unsupported: key length must be same as Hmac output length. + try { + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), + password.toCharArray()); + } catch (IOException e) { + System.out.println("A.2 pass"); + } ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A3)), password.toCharArray()); + + fos = new FileOutputStream("pbmac1KeyStore.p12"); + ks.store(fos, password.toCharArray()); + fos.close(); + + // read keystore we just wrote + fis = new FileInputStream("pbmac1KeyStore.p12"); + ks.load(fis, password.toCharArray()); + fis.close(); System.out.println("A.3 pass"); try { ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A4)), password.toCharArray()); - } catch (Exception e) { + } catch (IOException e) { System.out.println("A.4 pass"); } @@ -427,7 +452,7 @@ public static void main(String[] args) throws Exception { ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A5)), password.toCharArray()); - } catch (Exception e) { + } catch (IOException e) { System.out.println("A.5 pass"); } @@ -435,7 +460,7 @@ public static void main(String[] args) throws Exception { ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A6)), password.toCharArray()); - } catch (Exception e) { + } catch (IOException e) { System.out.println("A.6 pass"); } } From 7a010df9b6c75ac151c53979febcda56ec563ab8 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 16 Sep 2025 11:59:06 -0600 Subject: [PATCH 12/30] removed changes to PBMAC1Core and addressed some comments from Valerie --- .../sun/crypto/provider/PBES2Parameters.java | 4 +- .../com/sun/crypto/provider/PBMAC1Core.java | 27 ++---- .../sun/crypto/provider/PBMAC1Parameters.java | 71 ++++---------- .../classes/sun/security/pkcs12/MacData.java | 95 +++++++++++-------- .../sun/security/pkcs12/PKCS12KeyStore.java | 92 +++++++++++------- .../sun/security/util/PBKDF2Parameters.java | 35 +++++-- 6 files changed, 163 insertions(+), 161 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index e60e3f3c26321..624d0d8adffb6 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -227,8 +227,8 @@ protected void engineInit(byte[] encoded) kdf = pBES2_params.data.getDerValue(); } - var kdfParams = new PBKDF2Parameters(); - String kdfAlgo = kdfParams.init(kdf); + var kdfParams = new PBKDF2Parameters(kdf); + String kdfAlgo = kdfParams.getKdfAlgo(); salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); keysize = kdfParams.getKeyLength(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index b467e35c9176d..146999e35ce7d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -107,8 +107,9 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) char[] passwdChars; byte[] salt = null; int iCount = 0; - int keyLength = blockLength; - if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) { + if (key instanceof javax.crypto.interfaces.PBEKey) { + javax.crypto.interfaces.PBEKey pbeKey = + (javax.crypto.interfaces.PBEKey) key; passwdChars = pbeKey.getPassword(); salt = pbeKey.getSalt(); // maybe null if unspecified iCount = pbeKey.getIterationCount(); // maybe 0 if unspecified @@ -137,10 +138,11 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) throw new InvalidAlgorithmParameterException ("PBEParameterSpec required for salt and iteration count"); } - } else if (!(params instanceof PBEParameterSpec pbeParams)) { + } else if (!(params instanceof PBEParameterSpec)) { throw new InvalidAlgorithmParameterException ("PBEParameterSpec type required"); } else { + PBEParameterSpec pbeParams = (PBEParameterSpec) params; // make sure the parameter values are consistent if (salt != null) { if (!Arrays.equals(salt, pbeParams.getSalt())) { @@ -158,22 +160,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) } else { iCount = pbeParams.getIterationCount(); } - - // Infer key length from algorithm name. - // The PBEParameterSpec doesn't contain a key length. - if (kdfAlgo.equals("HmacSHA512")) { - keyLength = 512; - } else if (kdfAlgo.equals("HmacSHA256")) { - keyLength = 256; - } -/* - } else { - throw new InvalidAlgorithmParameterException - ("Unsupported Mac algorithm"); - } -*/ } - // For security purpose, we need to enforce a minimum length // for salt; just require the minimum salt length to be 8-byte // which is what PKCS#5 recommends and openssl does. @@ -186,7 +173,7 @@ protected void engineInit(Key key, AlgorithmParameterSpec params) ("IterationCount must be a positive number"); } - pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, keyLength); + pbeSpec = new PBEKeySpec(passwdChars, salt, iCount, blockLength); // password char[] was cloned in PBEKeySpec constructor, // so we can zero it out here } finally { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index 523958560705a..89efb6aaf6eb8 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -57,34 +57,7 @@ * * -- PBKDF2 * - * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::= - * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...} - * - * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} - * - * PBKDF2-params ::= SEQUENCE { - * salt CHOICE { - * specified OCTET STRING, - * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} - * }, - * iterationCount INTEGER (1..MAX), - * keyLength INTEGER (1..MAX) OPTIONAL, - * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 - * } - * - * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... } - * - * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { - * {NULL IDENTIFIED BY id-hmacWithSHA1} | - * {NULL IDENTIFIED BY id-hmacWithSHA224} | - * {NULL IDENTIFIED BY id-hmacWithSHA256} | - * {NULL IDENTIFIED BY id-hmacWithSHA384} | - * {NULL IDENTIFIED BY id-hmacWithSHA512}, ... } - * - * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::= - * {algorithm id-hmacWithSHA1, parameters NULL : NULL} - * - * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7} + * {@link PBKDF2Parameters} * * * @@ -92,9 +65,6 @@ */ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { - private static final ObjectIdentifier pkcs5PBKDF2_OID = - ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - // the PBMAC1 algorithm name private String pbmac1AlgorithmName = null; @@ -136,39 +106,33 @@ protected void engineInit(byte[] encoded) + "expected length not 2"); } ObjectIdentifier OID = Info[1].data.getOID(); - KnownOIDs o = KnownOIDs.findMatch(OID.toString()); - if (o == null || (!o.stdName().equals("HmacSHA1") && - !o.stdName().equals("HmacSHA224") && - !o.stdName().equals("HmacSHA256") && - !o.stdName().equals("HmacSHA384") && - !o.stdName().equals("HmacSHA512") && - !o.stdName().equals("HmacSHA512/224") && - !o.stdName().equals("HmacSHA512/256"))) { - throw new IOException("PBMAC1 parameter parsing error: " - + "expecting the object identifier for a HmacSHA key " - + "derivation function"); - } + KnownOIDs o = KnownOIDs.findMatch(OID.toString()); + if (o == null || (!o.stdName().equals("HmacSHA1") && + !o.stdName().equals("HmacSHA224") && + !o.stdName().equals("HmacSHA256") && + !o.stdName().equals("HmacSHA384") && + !o.stdName().equals("HmacSHA512") && + !o.stdName().equals("HmacSHA512/224") && + !o.stdName().equals("HmacSHA512/256"))) { + throw new IOException("PBMAC1 parameter parsing error: " + + "expecting the object identifier for a HmacSHA key " + + "derivation function"); + } // Hmac function used to compute the MAC String hmacAlgo = o.stdName(); DerValue kdf = pBMAC1_params.data.getDerValue(); - var kdfParams = new PBKDF2Parameters(); - String kdfAlgo = kdfParams.init(kdf); + var kdfParams = new PBKDF2Parameters(kdf); + String kdfAlgo = kdfParams.getKdfAlgo(); salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); - // Key length must be present. It is not currently used. + // Key length must be present even though it is not used. keyLength = kdfParams.getKeyLength(); if (keyLength == -1) { throw new IOException("PBMAC1 parameter parsing " + "error: missing keyLength field"); } - // Key length SHOULD be the same size as HMAC function output size. - if ((kdfAlgo.contains("256") && keyLength != 256) || - (kdfAlgo.contains("512") && keyLength != 512)) { - throw new IOException("PBMAC1 parameter parsing " - + "error: keyLength not Hmac output length "); - } pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" + hmacAlgo; } @@ -198,7 +162,8 @@ protected byte[] engineGetEncoded() throws IOException { DerOutputStream pBMAC1_params = new DerOutputStream(); DerOutputStream keyDerivationFunc = new DerOutputStream(); - keyDerivationFunc.putOID(pkcs5PBKDF2_OID); + keyDerivationFunc.putOID( + sun.security.util.PBKDF2Parameters.pkcs5PBKDF2_OID); DerOutputStream pBKDF2_params = new DerOutputStream(); pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 8153b5497999c..2ea653de8b2f8 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -47,16 +47,17 @@ class MacData { - private final String digestAlgorithmName; - private final AlgorithmParameters digestAlgorithmParams; + private String digestAlgorithmName; + private AlgorithmParameters digestAlgorithmParams; private final byte[] digest; private byte[] macSalt; - private byte[] extraMacSalt; + private byte[] extraSalt; private int iterations; - private int extraIterations; + private int extraIterations = -1; private String kdfHmac; private String Hmac; private int keyLength; + private boolean pbmac1Keystore = false;; // the ASN.1 encoded contents of this class private byte[] encoded = null; @@ -103,33 +104,42 @@ class MacData { macSalt = pbeSpec.getSalt(); String ps = digestAlgorithmParams.toString(); kdfHmac = getKdfHmac(ps); + Hmac = kdfHmac; } - // Get the salt. - extraMacSalt = macData[1].getOctetString(); + // Get the old salt. + extraSalt = macData[1].getOctetString(); - // Iterations are optional. The default value is 1. + // Old iterations are optional. The default value is 1. if (macData.length > 2) { extraIterations = macData[2].getInteger(); } else { extraIterations = 1; } if (!digestAlgorithmName.equals("PBMAC1")) { - macSalt = extraMacSalt; + macSalt = extraSalt; iterations = extraIterations; } } MacData(String algName, byte[] digest, AlgorithmParameterSpec params, - String defaultKdfHmac, byte[] extraSalt, int extraIterationCount) + boolean writePBMAC1, String kdfHmac, int keyLength, + byte[] extraSalt, int extraIterationCount) throws NoSuchAlgorithmException { + AlgorithmId algid; + if (algName == null) { throw new NullPointerException("the algName parameter " + "must be non-null"); } + if (writePBMAC1) { + pbmac1Keystore = true; + algid = AlgorithmId.get("PBMAC1"); + } else { + algid = AlgorithmId.get(algName); + } - AlgorithmId algid = AlgorithmId.get(algName); this.digestAlgorithmName = algid.getName(); this.digestAlgorithmParams = algid.getParameters(); @@ -143,33 +153,26 @@ class MacData { this.digest = digest.clone(); } - if (params instanceof PBEParameterSpec p) { - if (algName.equals("PBMAC1")) { - macSalt = p.getSalt(); - iterations = p.getIterationCount(); - kdfHmac = defaultKdfHmac; - Hmac = kdfHmac; - - if (defaultKdfHmac.equals("HmacSHA512")) { - keyLength = 512; - } else if (defaultKdfHmac.equals("HmacSHA256")) { - keyLength = 256; - } else { - throw new IllegalArgumentException("unsupported Hmac"); - } - extraMacSalt = extraSalt; - extraIterations = extraIterationCount; - } else { - macSalt = p.getSalt(); - iterations = p.getIterationCount(); - kdfHmac = null; - Hmac = null; - keyLength = 0; - } - } else { + if (!(params instanceof PBEParameterSpec p)) { throw new IllegalArgumentException("unsupported parameter spec"); } + if (pbmac1Keystore) { + this.macSalt = p.getSalt(); + this.iterations = p.getIterationCount(); + this.kdfHmac = kdfHmac; + this.Hmac = kdfHmac; + this.keyLength = keyLength; + this.extraSalt = extraSalt; + this.extraIterations = extraIterationCount; + } else { + this.macSalt = p.getSalt(); + this.iterations = p.getIterationCount(); + this.kdfHmac = null; + this.Hmac = null; + this.keyLength = 0; + } + // delay the generation of ASN.1 encoding until // getEncoded() is called this.encoded = null; @@ -204,7 +207,7 @@ int getKeyLength() { } byte[] getExtraSalt() { - return extraMacSalt; + return extraSalt; } int getExtraIterations() { @@ -220,10 +223,13 @@ int getExtraIterations() { public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { - if (digestAlgorithmName.equals("PBMAC1")) { + if (pbmac1Keystore) { + //digestAlgorithmName = "PBMAC1"; ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + byte[] not_used = { 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }; + DerOutputStream out = new DerOutputStream(); DerOutputStream tmp0 = new DerOutputStream(); DerOutputStream tmp1 = new DerOutputStream(); @@ -259,17 +265,22 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, tmp4.write(DerValue.tag_Sequence, tmp3); tmp4.write(DerValue.tag_Sequence, Hmac); - // PBMAC1 - tmp1.putOID(ObjectIdentifier.of(KnownOIDs - .findMatch(digestAlgorithmName))); + tmp1.putOID(ObjectIdentifier.of(KnownOIDs .findMatch("PBMAC1"))); tmp1.write(DerValue.tag_Sequence, tmp4); tmp2.write(DerValue.tag_Sequence, tmp1); tmp2.putOctetString(digest); tmp0.write(DerValue.tag_Sequence, tmp2); - tmp0.putOctetString(extraMacSalt); - tmp0.putInteger(extraIterations); - + if (extraSalt != null) { + tmp0.putOctetString(extraSalt); + } else { + tmp0.putOctetString(not_used); + } + if (extraIterations != -1) { + tmp0.putInteger(extraIterations); + } else { + tmp0.putInteger(1); + } out.write(DerValue.tag_Sequence, tmp0); encoded = out.toByteArray(); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 448e0f3ae6b74..2dcd3b954e2ed 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -1478,43 +1478,53 @@ private void populateAttributes(Entry entry) { * create a message authentication code (MAC) */ private byte[] calculateMac(char[] passwd, byte[] data) - throws IOException + throws IOException, NoSuchAlgorithmException { final byte[] mData; final AlgorithmParameterSpec params; - final String macString; final String algName; final MacData macData; - - if (macAlgorithm.equals("PBMAC1")) { - params = new PBEParameterSpec(getSalt(), macIterationCount); - if (defaultMacAlgorithm().equals("HmacPBESHA512")) { - macString = "PBEWithHmacSHA512"; - } else { - macString = "PBEWithHmacSHA256"; - } - algName = "PBMAC1"; + final String kdfHmac; + boolean writePBMAC1 = false; + + if (macAlgorithm.equals("PBMAC1") || + defaultMacAlgorithm().contains("PBEWith")) { + if (defaultMacAlgorithm().equals("PBEWithHmacSHA512")) { + kdfHmac = "HmacSHA512"; + } else if (defaultMacAlgorithm().equals("PBEWithHmacSHA256")) { + kdfHmac = "HmacSHA256"; + } else { + // Use value currently associated with this keystore. + kdfHmac = pbmac1Hmac; + } + algName = "PBMAC1"; + writePBMAC1 = true; } else { - params = new PBEParameterSpec(getSalt(), macIterationCount); - macString = macAlgorithm; - algName = macAlgorithm.substring(7); + algName = macAlgorithm.substring(7); + kdfHmac = macAlgorithm; } + params = new PBEParameterSpec(getSalt(), macIterationCount); + + var skf = SecretKeyFactory.getInstance(kdfHmac.equals("HmacSHA512") ? + "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); try { - SecretKey key = getPBEKey(passwd); - Mac m = Mac.getInstance(macString); + SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(passwd, + ((PBEParameterSpec)params).getSalt(), macIterationCount, + kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8)); + Mac m = Mac.getInstance(kdfHmac); try { - m.init(key, params); + m.init(pbeKey); } finally { - destroyPBEKey(key); + destroyPBEKey(pbeKey); } m.update(data); byte[] macResult = m.doFinal(); // encode as MacData - macData = new MacData(algName, macResult, params, - defaultMacAlgorithm().replace("PBE", ""), + macData = new MacData(algName, macResult, params, writePBMAC1, + kdfHmac, kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8, extraSalt, extraIterationCount); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); @@ -1936,14 +1946,30 @@ private byte[] encryptContent(byte[] data, char[] password) private void processMacData(AlgorithmParameterSpec params, MacData macData, char[] password, byte[] data, String macAlgorithm) throws Exception { - Mac m = Mac.getInstance(macAlgorithm); + String kdfHmac; + + if (macAlgorithm.equals("PBEWithHmacSHA256")) { + kdfHmac = "HmacSHA256"; + } else if (macAlgorithm.equals("PBEWithHmacSHA512")) { + kdfHmac = "HmacSHA512"; + } else { + kdfHmac = macAlgorithm; + } + + var skf = SecretKeyFactory.getInstance( + macAlgorithm.contains("HmacSHA512") ? + "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); RetryWithZero.run(pass -> { - SecretKey key = getPBEKey(pass); + SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(pass, + ((PBEParameterSpec)params).getSalt(), + ((PBEParameterSpec)params).getIterationCount(), + kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8)); + Mac m = Mac.getInstance(kdfHmac); try { - m.init(key, params); + m.init(pbeKey); } finally { - destroyPBEKey(key); + destroyPBEKey(pbeKey); } m.update(data); byte[] macResult = m.doFinal(); @@ -2174,31 +2200,27 @@ public synchronized void engineLoad(InputStream stream, char[] password) byte[] salt = macData.getSalt(); pbmac1KdfHmac = macData.getKdfHmac(); - - PBEParameterSpec params = - new PBEParameterSpec(salt, ic); - processMacData(params, macData, password, authSafeData, - "PBEWith" + pbmac1KdfHmac); - + pbmac1Hmac = pbmac1KdfHmac; + macIterationCount = ic; macAlgorithm = algName; - macIterationCount = macData.getIterations(); - // store salt length in macData macSaltLength = salt.length; extraSalt = macData.getExtraSalt(); extraIterationCount = macData.getExtraIterations(); + PBEParameterSpec params = + new PBEParameterSpec(salt, ic); + processMacData(params, macData, password, authSafeData, + "PBEWith" + pbmac1KdfHmac); } else { // Change SHA-1 to SHA1 algName = algName.replace("-", ""); - macAlgorithm = "HmacPBE" + algName; + macIterationCount = ic; PBEParameterSpec params = new PBEParameterSpec(macData.getSalt(), ic); processMacData(params, macData, password, authSafeData, macAlgorithm); - - macIterationCount = ic; } } catch (Exception e) { throw new IOException("Integrity check failed: " + e, e); diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index f7f111599b85b..8fe0f8eb36f1b 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -35,6 +35,8 @@ * This class implements the parameter set used with password-based * key derivation function 2 (PBKDF2), which is defined in PKCS#5 as follows: * + *
+ *
  * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::=
  *   { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...}
  *
@@ -63,13 +65,18 @@
  *     {algorithm id-hmacWithSHA1, parameters NULL : NULL}
  *
  * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7}
+ *
+ * For more information, see
+ * RFC 8018:
+ * PKCS #5: Password-Based Cryptography Specification.
+ *
+ * 
*/ -public class PBKDF2Parameters { +final public class PBKDF2Parameters { - private static final ObjectIdentifier pkcs5PBKDF2_OID = + public static final ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - // AlgorithmIdentifier private String prf = null; private byte[] salt = null; @@ -83,8 +90,10 @@ public class PBKDF2Parameters { // keyLength (in bits) private int keyLength = -1; + private String kdfAlgo; + @SuppressWarnings("deprecation") - public String init(DerValue keyDerivationFunc) throws IOException { + public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { throw new IOException("PBKDF2 parameter parsing error: " @@ -117,7 +126,7 @@ public String init(DerValue keyDerivationFunc) throws IOException { } // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 - String kdfAlgo; + ///String kdfAlgo; var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); if (prfDer.isPresent()) { DerValue prf = prfDer.get(); @@ -140,7 +149,7 @@ public String init(DerValue keyDerivationFunc) throws IOException { } else { kdfAlgo = "HmacSHA1"; } - return kdfAlgo; + //return kdfAlgo; } /** @@ -163,12 +172,20 @@ public int getIterationCount() { } /** - * Returns size of key generated by PBKDF2. - * Set to -1 if not found/set. + * Returns size of key generated by PBKDF2, or -1 if not found/set. * - * @return size of key generated by PBKDF2. + * @return size of key generated by PBKDF2, or -1 if not found/set */ public int getKeyLength() { return this.keyLength; } + + /** + * Returns name of Hmac. + * + * @return name of Hmac + */ + public String getKdfAlgo() { + return this.kdfAlgo; + } } From e13d0dd2c3c5f40aebb7aa47afe942a29e6e87af Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 16 Sep 2025 16:53:55 -0600 Subject: [PATCH 13/30] a few more comments --- .../sun/crypto/provider/PBMAC1Parameters.java | 3 +-- .../classes/sun/security/pkcs12/MacData.java | 26 +++++++------------ .../sun/security/pkcs12/PKCS12KeyStore.java | 15 +++++------ .../sun/security/util/PBKDF2Parameters.java | 21 ++++----------- 4 files changed, 23 insertions(+), 42 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index 89efb6aaf6eb8..a12aed01b884d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -81,8 +81,7 @@ abstract class PBMAC1Parameters extends AlgorithmParametersSpi { private int keyLength = -1; protected void engineInit(AlgorithmParameterSpec paramSpec) - throws InvalidParameterSpecException - { + throws InvalidParameterSpecException { if (!(paramSpec instanceof PBEParameterSpec)) { throw new InvalidParameterSpecException ("Inappropriate parameter specification"); diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 2ea653de8b2f8..9902f2326fec2 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -30,6 +30,7 @@ import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.crypto.spec.PBEParameterSpec; @@ -47,8 +48,8 @@ class MacData { - private String digestAlgorithmName; - private AlgorithmParameters digestAlgorithmParams; + private final String digestAlgorithmName; + private final AlgorithmParameters digestAlgorithmParams; private final byte[] digest; private byte[] macSalt; private byte[] extraSalt; @@ -57,7 +58,7 @@ class MacData { private String kdfHmac; private String Hmac; private int keyLength; - private boolean pbmac1Keystore = false;; + private boolean pbmac1Keystore = false; // the ASN.1 encoded contents of this class private byte[] encoded = null; @@ -104,6 +105,11 @@ class MacData { macSalt = pbeSpec.getSalt(); String ps = digestAlgorithmParams.toString(); kdfHmac = getKdfHmac(ps); + if (!(kdfHmac.equals("HmacSHA512") || + kdfHmac.equals("HmacSHA256"))) { + throw new IllegalArgumentException("unsupported PBMAC1 Hmac"); + } + Hmac = kdfHmac; } @@ -198,14 +204,6 @@ String getKdfHmac() { return kdfHmac; } - String getHmac() { - return Hmac; - } - - int getKeyLength() { - return keyLength; - } - byte[] getExtraSalt() { return extraSalt; } @@ -271,11 +269,7 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, tmp2.write(DerValue.tag_Sequence, tmp1); tmp2.putOctetString(digest); tmp0.write(DerValue.tag_Sequence, tmp2); - if (extraSalt != null) { - tmp0.putOctetString(extraSalt); - } else { - tmp0.putOctetString(not_used); - } + tmp0.putOctetString(Objects.requireNonNullElse(extraSalt, not_used)); if (extraIterations != -1) { tmp0.putInteger(extraIterations); } else { diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 2dcd3b954e2ed..7d1ffb1fd4cf6 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -174,7 +174,6 @@ public DualFormatPKCS12() { private int certPbeIterationCount = -1; private String macAlgorithm = null; private String pbmac1Hmac = null; - private String pbmac1KdfHmac = null; private int macIterationCount = -1; private int macSaltLength = -1; private byte[] extraSalt = null; @@ -1481,14 +1480,14 @@ private byte[] calculateMac(char[] passwd, byte[] data) throws IOException, NoSuchAlgorithmException { final byte[] mData; - final AlgorithmParameterSpec params; + final PBEParameterSpec params; final String algName; final MacData macData; final String kdfHmac; boolean writePBMAC1 = false; if (macAlgorithm.equals("PBMAC1") || - defaultMacAlgorithm().contains("PBEWith")) { + defaultMacAlgorithm().startsWith("PBEWith")) { if (defaultMacAlgorithm().equals("PBEWithHmacSHA512")) { kdfHmac = "HmacSHA512"; } else if (defaultMacAlgorithm().equals("PBEWithHmacSHA256")) { @@ -1509,9 +1508,10 @@ private byte[] calculateMac(char[] passwd, byte[] data) var skf = SecretKeyFactory.getInstance(kdfHmac.equals("HmacSHA512") ? "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); try { + int keyLength = kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8; + SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(passwd, - ((PBEParameterSpec)params).getSalt(), macIterationCount, - kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8)); + params.getSalt(), macIterationCount, keyLength)); Mac m = Mac.getInstance(kdfHmac); try { @@ -1524,8 +1524,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) // encode as MacData macData = new MacData(algName, macResult, params, writePBMAC1, - kdfHmac, kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8, - extraSalt, extraIterationCount); + kdfHmac, keyLength, extraSalt, extraIterationCount); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); mData = bytes.toByteArray(); @@ -2199,7 +2198,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) if (algName.equals("PBMAC1")) { byte[] salt = macData.getSalt(); - pbmac1KdfHmac = macData.getKdfHmac(); + String pbmac1KdfHmac = macData.getKdfHmac(); pbmac1Hmac = pbmac1KdfHmac; macIterationCount = ic; macAlgorithm = algName; diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 8fe0f8eb36f1b..312e9380caa46 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -26,10 +26,6 @@ package sun.security.util; import java.io.IOException; -import java.security.AlgorithmParametersSpi; -import java.security.NoSuchAlgorithmException; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidParameterSpecException; /** * This class implements the parameter set used with password-based @@ -77,22 +73,19 @@ final public class PBKDF2Parameters { public static final ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - private String prf = null; + private final byte[] salt; - private byte[] salt = null; + private final int iterationCount; - private int iterationCount = 0; + // keyLength in bits, or -1 if not present + private int keyLength = -1; // the pseudorandom function (default is HmacSHA1) private ObjectIdentifier kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.HmacSHA1); - // keyLength (in bits) - private int keyLength = -1; - - private String kdfAlgo; + private String kdfAlgo = "HmacSHA1"; - @SuppressWarnings("deprecation") public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { @@ -126,7 +119,6 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { } // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 - ///String kdfAlgo; var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); if (prfDer.isPresent()) { DerValue prf = prfDer.get(); @@ -146,10 +138,7 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { kdfAlgo = o.stdName(); prf.data.getOptional(DerValue.tag_Null); prf.data.atEnd(); - } else { - kdfAlgo = "HmacSHA1"; } - //return kdfAlgo; } /** From bfb8bd227c323e4083eb5749da7a388f109b5fa5 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 18 Sep 2025 12:31:25 -0600 Subject: [PATCH 14/30] comment from Sean --- .../sun/crypto/provider/PBMAC1Parameters.java | 13 ++++--------- .../classes/sun/security/pkcs12/MacData.java | 17 +++++------------ .../sun/security/pkcs12/PKCS12KeyStore.java | 17 ++++++++++++----- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index a12aed01b884d..7dfda709565a3 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -90,9 +90,7 @@ protected void engineInit(AlgorithmParameterSpec paramSpec) iCount = ((PBEParameterSpec)paramSpec).getIterationCount(); } - protected void engineInit(byte[] encoded) - throws IOException - { + protected void engineInit(byte[] encoded) throws IOException { DerValue pBMAC1_params = new DerValue(encoded); if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PBMAC1 parameter parsing error: " @@ -137,15 +135,13 @@ protected void engineInit(byte[] encoded) } protected void engineInit(byte[] encoded, String decodingMethod) - throws IOException - { + throws IOException { engineInit(encoded); } protected T engineGetParameterSpec(Class paramSpec) - throws InvalidParameterSpecException - { + throws InvalidParameterSpecException { if (paramSpec.isAssignableFrom(PBEParameterSpec.class)) { return paramSpec.cast( new PBEParameterSpec(salt, iCount)); @@ -188,8 +184,7 @@ protected byte[] engineGetEncoded() throws IOException { } protected byte[] engineGetEncoded(String encodingMethod) - throws IOException - { + throws IOException { return engineGetEncoded(); } diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 9902f2326fec2..5d6b2b200ae7a 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -129,22 +129,18 @@ class MacData { } MacData(String algName, byte[] digest, AlgorithmParameterSpec params, - boolean writePBMAC1, String kdfHmac, int keyLength, - byte[] extraSalt, int extraIterationCount) - throws NoSuchAlgorithmException - { + String kdfHmac, int keyLength, byte[] extraSalt, + int extraIterationCount) throws NoSuchAlgorithmException { AlgorithmId algid; if (algName == null) { throw new NullPointerException("the algName parameter " + "must be non-null"); } - if (writePBMAC1) { + if (algName.equals("PBMAC1")) { pbmac1Keystore = true; - algid = AlgorithmId.get("PBMAC1"); - } else { - algid = AlgorithmId.get(algName); } + algid = AlgorithmId.get(algName); this.digestAlgorithmName = algid.getName(); this.digestAlgorithmParams = algid.getParameters(); @@ -218,11 +214,8 @@ int getExtraIterations() { * @exception IOException if error occurs when constructing its * ASN.1 encoding. */ - public byte[] getEncoded() throws NoSuchAlgorithmException, - IOException - { + public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { if (pbmac1Keystore) { - //digestAlgorithmName = "PBMAC1"; ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 7d1ffb1fd4cf6..ff2d0dc854682 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -1485,6 +1485,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) final MacData macData; final String kdfHmac; boolean writePBMAC1 = false; + int writeIterationCount = macIterationCount; if (macAlgorithm.equals("PBMAC1") || defaultMacAlgorithm().startsWith("PBEWith")) { @@ -1498,12 +1499,14 @@ private byte[] calculateMac(char[] passwd, byte[] data) } algName = "PBMAC1"; writePBMAC1 = true; + // Override with value of security property. + writeIterationCount = defaultMacIterationCount(); } else { algName = macAlgorithm.substring(7); kdfHmac = macAlgorithm; } - params = new PBEParameterSpec(getSalt(), macIterationCount); + params = new PBEParameterSpec(getSalt(), writeIterationCount); var skf = SecretKeyFactory.getInstance(kdfHmac.equals("HmacSHA512") ? "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); @@ -1511,7 +1514,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) int keyLength = kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8; SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(passwd, - params.getSalt(), macIterationCount, keyLength)); + params.getSalt(), writeIterationCount, keyLength)); Mac m = Mac.getInstance(kdfHmac); try { @@ -1523,7 +1526,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) byte[] macResult = m.doFinal(); // encode as MacData - macData = new MacData(algName, macResult, params, writePBMAC1, + macData = new MacData(algName, macResult, params, kdfHmac, keyLength, extraSalt, extraIterationCount); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); @@ -2186,6 +2189,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) if (password != null) { MacData macData = new MacData(s); int ic = macData.getIterations(); + byte[] salt = macData.getSalt(); try { if (ic > MAX_ITERATION_COUNT) { @@ -2196,7 +2200,6 @@ public synchronized void engineLoad(InputStream stream, char[] password) String algName = macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); if (algName.equals("PBMAC1")) { - byte[] salt = macData.getSalt(); String pbmac1KdfHmac = macData.getKdfHmac(); pbmac1Hmac = pbmac1KdfHmac; @@ -2216,8 +2219,12 @@ public synchronized void engineLoad(InputStream stream, char[] password) macAlgorithm = "HmacPBE" + algName; macIterationCount = ic; + // save in extra in case we write out as PBMAC1 + extraSalt = salt; + extraIterationCount = ic; + PBEParameterSpec params = - new PBEParameterSpec(macData.getSalt(), ic); + new PBEParameterSpec(salt, ic); processMacData(params, macData, password, authSafeData, macAlgorithm); } From 32b56a6cb616024cb4889cace79748a7d2533fb2 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Sat, 20 Sep 2025 15:50:04 -0600 Subject: [PATCH 15/30] a few more comments --- .../sun/crypto/provider/PBES2Parameters.java | 2 +- .../sun/crypto/provider/PBMAC1Parameters.java | 4 +- .../classes/sun/security/pkcs12/MacData.java | 79 +++++++++---------- .../sun/security/util/PBKDF2Parameters.java | 8 +- 4 files changed, 45 insertions(+), 48 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index 624d0d8adffb6..d3ce98a327798 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -228,7 +228,7 @@ protected void engineInit(byte[] encoded) } var kdfParams = new PBKDF2Parameters(kdf); - String kdfAlgo = kdfParams.getKdfAlgo(); + String kdfAlgo = kdfParams.getPrfAlgo(); salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); keysize = kdfParams.getKeyLength(); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index 7dfda709565a3..2a07e4b479a70 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -120,7 +120,7 @@ protected void engineInit(byte[] encoded) throws IOException { DerValue kdf = pBMAC1_params.data.getDerValue(); var kdfParams = new PBKDF2Parameters(kdf); - String kdfAlgo = kdfParams.getKdfAlgo(); + String prfAlgo = kdfParams.getPrfAlgo(); salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); @@ -131,7 +131,7 @@ protected void engineInit(byte[] encoded) throws IOException { + "error: missing keyLength field"); } - pbmac1AlgorithmName = "PBMAC1With" + kdfAlgo + "And" + hmacAlgo; + pbmac1AlgorithmName = "PBMAC1With" + prfAlgo + "And" + hmacAlgo; } protected void engineInit(byte[] encoded, String decodingMethod) diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 5d6b2b200ae7a..67758c2847078 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -87,44 +87,41 @@ class MacData { // Get the digest. this.digest = digestInfo[1].getOctetString(); - if (digestInfo[0].tag != DerValue.tag_Sequence) { - throw new IOException("algid parse error, not a sequence"); - } - if (digestAlgorithmName.equals("PBMAC1")) { + if (this.digestAlgorithmName.equals("PBMAC1")) { PBEParameterSpec pbeSpec; try { pbeSpec = - digestAlgorithmParams.getParameterSpec( + this.digestAlgorithmParams.getParameterSpec( PBEParameterSpec.class); } catch (InvalidParameterSpecException ipse) { throw new IOException( "Invalid PBE algorithm parameters"); } - iterations = pbeSpec.getIterationCount(); - macSalt = pbeSpec.getSalt(); - String ps = digestAlgorithmParams.toString(); - kdfHmac = getKdfHmac(ps); - if (!(kdfHmac.equals("HmacSHA512") || - kdfHmac.equals("HmacSHA256"))) { - throw new IllegalArgumentException("unsupported PBMAC1 Hmac"); + this.iterations = pbeSpec.getIterationCount(); + this.macSalt = pbeSpec.getSalt(); + String ps = this.digestAlgorithmParams.toString(); + this.kdfHmac = getKdfHmac(ps); + if (!(this.kdfHmac.equals("HmacSHA512") || + this.kdfHmac.equals("HmacSHA256"))) { + throw new IOException("unsupported PBMAC1 Hmac"); } - Hmac = kdfHmac; + this.Hmac = this.kdfHmac; } // Get the old salt. - extraSalt = macData[1].getOctetString(); + this.extraSalt = macData[1].getOctetString(); // Old iterations are optional. The default value is 1. if (macData.length > 2) { - extraIterations = macData[2].getInteger(); + this.extraIterations = macData[2].getInteger(); } else { - extraIterations = 1; + this.extraIterations = 1; } - if (!digestAlgorithmName.equals("PBMAC1")) { - macSalt = extraSalt; - iterations = extraIterations; + if (!this.digestAlgorithmName.equals("PBMAC1")) { + this.macSalt = this.extraSalt; + this.iterations = this.extraIterations; } } @@ -138,7 +135,7 @@ class MacData { "must be non-null"); } if (algName.equals("PBMAC1")) { - pbmac1Keystore = true; + this.pbmac1Keystore = true; } algid = AlgorithmId.get(algName); @@ -159,7 +156,7 @@ class MacData { throw new IllegalArgumentException("unsupported parameter spec"); } - if (pbmac1Keystore) { + if (this.pbmac1Keystore) { this.macSalt = p.getSalt(); this.iterations = p.getIterationCount(); this.kdfHmac = kdfHmac; @@ -181,31 +178,31 @@ class MacData { } String getDigestAlgName() { - return digestAlgorithmName; + return this.digestAlgorithmName; } byte[] getSalt() { - return macSalt; + return this.macSalt; } int getIterations() { - return iterations; + return this.iterations; } byte[] getDigest() { - return digest; + return this.digest; } String getKdfHmac() { - return kdfHmac; + return this.kdfHmac; } byte[] getExtraSalt() { - return extraSalt; + return this.extraSalt; } int getExtraIterations() { - return extraIterations; + return this.extraIterations; } /** @@ -215,7 +212,7 @@ int getExtraIterations() { * ASN.1 encoding. */ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { - if (pbmac1Keystore) { + if (this.pbmac1Keystore) { ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); @@ -241,14 +238,14 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { DerOutputStream pBKDF2_params = new DerOutputStream(); - pBKDF2_params.putOctetString(macSalt); // choice: 'specified OCTET STRING' + pBKDF2_params.putOctetString(this.macSalt); // choice: 'specified OCTET STRING' // encode iterations - pBKDF2_params.putInteger(iterations); + pBKDF2_params.putInteger(this.iterations); // encode derived key length - if (keyLength > 0) { - pBKDF2_params.putInteger(keyLength / 8); // derived key length (in octets) + if (this.keyLength > 0) { + pBKDF2_params.putInteger(this.keyLength / 8); // derived key length (in octets) } pBKDF2_params.write(DerValue.tag_Sequence, kdfHmac); tmp3.putOID(pkcs5PBKDF2_OID); @@ -260,11 +257,11 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { tmp1.write(DerValue.tag_Sequence, tmp4); tmp2.write(DerValue.tag_Sequence, tmp1); - tmp2.putOctetString(digest); + tmp2.putOctetString(this.digest); tmp0.write(DerValue.tag_Sequence, tmp2); - tmp0.putOctetString(Objects.requireNonNullElse(extraSalt, not_used)); - if (extraIterations != -1) { - tmp0.putInteger(extraIterations); + tmp0.putOctetString(Objects.requireNonNullElse(this.extraSalt, not_used)); + if (this.extraIterations != -1) { + tmp0.putInteger(this.extraIterations); } else { tmp0.putInteger(1); } @@ -282,19 +279,19 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { DerOutputStream tmp2 = new DerOutputStream(); // encode encryption algorithm - AlgorithmId algid = AlgorithmId.get(digestAlgorithmName); + AlgorithmId algid = AlgorithmId.get(this.digestAlgorithmName); algid.encode(tmp2); // encode digest data - tmp2.putOctetString(digest); + tmp2.putOctetString(this.digest); tmp.write(DerValue.tag_Sequence, tmp2); // encode salt - tmp.putOctetString(macSalt); + tmp.putOctetString(this.macSalt); // encode iterations - tmp.putInteger(iterations); + tmp.putInteger(this.iterations); // wrap everything into a SEQUENCE out.write(DerValue.tag_Sequence, tmp); diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 312e9380caa46..9b1c8b93eb57f 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -84,7 +84,7 @@ final public class PBKDF2Parameters { private ObjectIdentifier kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.HmacSHA1); - private String kdfAlgo = "HmacSHA1"; + private String prfAlgo = "HmacSHA1"; public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { @@ -135,7 +135,7 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { + "expecting the object identifier for a HmacSHA " + "pseudorandom function"); } - kdfAlgo = o.stdName(); + prfAlgo = o.stdName(); prf.data.getOptional(DerValue.tag_Null); prf.data.atEnd(); } @@ -174,7 +174,7 @@ public int getKeyLength() { * * @return name of Hmac */ - public String getKdfAlgo() { - return this.kdfAlgo; + public String getPrfAlgo() { + return this.prfAlgo; } } From e190920c410ccec60d8b5c8c3f76c9bebb631a62 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Sun, 21 Sep 2025 14:10:02 -0600 Subject: [PATCH 16/30] remove the extras --- .../classes/sun/security/pkcs12/MacData.java | 42 ++++--------------- .../sun/security/pkcs12/PKCS12KeyStore.java | 12 +----- 2 files changed, 10 insertions(+), 44 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 67758c2847078..b4f6bc19fd303 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -52,9 +52,7 @@ class MacData { private final AlgorithmParameters digestAlgorithmParams; private final byte[] digest; private byte[] macSalt; - private byte[] extraSalt; private int iterations; - private int extraIterations = -1; private String kdfHmac; private String Hmac; private int keyLength; @@ -108,26 +106,18 @@ class MacData { } this.Hmac = this.kdfHmac; - } - - // Get the old salt. - this.extraSalt = macData[1].getOctetString(); - - // Old iterations are optional. The default value is 1. - if (macData.length > 2) { - this.extraIterations = macData[2].getInteger(); } else { - this.extraIterations = 1; - } - if (!this.digestAlgorithmName.equals("PBMAC1")) { - this.macSalt = this.extraSalt; - this.iterations = this.extraIterations; + this.macSalt = macData[1].getOctetString(); + if (macData.length > 2) { + this.iterations = macData[2].getInteger(); + } else { + this.iterations = 1; + } } } MacData(String algName, byte[] digest, AlgorithmParameterSpec params, - String kdfHmac, int keyLength, byte[] extraSalt, - int extraIterationCount) throws NoSuchAlgorithmException { + String kdfHmac, int keyLength) throws NoSuchAlgorithmException { AlgorithmId algid; if (algName == null) { @@ -162,8 +152,6 @@ class MacData { this.kdfHmac = kdfHmac; this.Hmac = kdfHmac; this.keyLength = keyLength; - this.extraSalt = extraSalt; - this.extraIterations = extraIterationCount; } else { this.macSalt = p.getSalt(); this.iterations = p.getIterationCount(); @@ -197,14 +185,6 @@ String getKdfHmac() { return this.kdfHmac; } - byte[] getExtraSalt() { - return this.extraSalt; - } - - int getExtraIterations() { - return this.extraIterations; - } - /** * Returns the ASN.1 encoding of this object. * @return the ASN.1 encoding. @@ -259,12 +239,8 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { tmp2.write(DerValue.tag_Sequence, tmp1); tmp2.putOctetString(this.digest); tmp0.write(DerValue.tag_Sequence, tmp2); - tmp0.putOctetString(Objects.requireNonNullElse(this.extraSalt, not_used)); - if (this.extraIterations != -1) { - tmp0.putInteger(this.extraIterations); - } else { - tmp0.putInteger(1); - } + tmp0.putOctetString(not_used); + tmp0.putInteger(1); out.write(DerValue.tag_Sequence, tmp0); encoded = out.toByteArray(); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index ff2d0dc854682..2d144d2cb7f13 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -176,8 +176,6 @@ public DualFormatPKCS12() { private String pbmac1Hmac = null; private int macIterationCount = -1; private int macSaltLength = -1; - private byte[] extraSalt = null; - private int extraIterationCount = -1; // the source of randomness private SecureRandom random; @@ -1484,7 +1482,6 @@ private byte[] calculateMac(char[] passwd, byte[] data) final String algName; final MacData macData; final String kdfHmac; - boolean writePBMAC1 = false; int writeIterationCount = macIterationCount; if (macAlgorithm.equals("PBMAC1") || @@ -1498,7 +1495,6 @@ private byte[] calculateMac(char[] passwd, byte[] data) kdfHmac = pbmac1Hmac; } algName = "PBMAC1"; - writePBMAC1 = true; // Override with value of security property. writeIterationCount = defaultMacIterationCount(); } else { @@ -1527,7 +1523,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) // encode as MacData macData = new MacData(algName, macResult, params, - kdfHmac, keyLength, extraSalt, extraIterationCount); + kdfHmac, keyLength); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); mData = bytes.toByteArray(); @@ -2206,8 +2202,6 @@ public synchronized void engineLoad(InputStream stream, char[] password) macIterationCount = ic; macAlgorithm = algName; macSaltLength = salt.length; - extraSalt = macData.getExtraSalt(); - extraIterationCount = macData.getExtraIterations(); PBEParameterSpec params = new PBEParameterSpec(salt, ic); processMacData(params, macData, password, authSafeData, @@ -2219,10 +2213,6 @@ public synchronized void engineLoad(InputStream stream, char[] password) macAlgorithm = "HmacPBE" + algName; macIterationCount = ic; - // save in extra in case we write out as PBMAC1 - extraSalt = salt; - extraIterationCount = ic; - PBEParameterSpec params = new PBEParameterSpec(salt, ic); processMacData(params, macData, password, authSafeData, From 31b4aeafbb6ed06fec3c9d98e670cf98ad72e743 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Mon, 22 Sep 2025 12:34:32 -0600 Subject: [PATCH 17/30] default salt length and one other comment from Weijun --- .../classes/sun/security/pkcs12/PKCS12KeyStore.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 2d144d2cb7f13..1ced8de5562ae 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -175,7 +175,6 @@ public DualFormatPKCS12() { private String macAlgorithm = null; private String pbmac1Hmac = null; private int macIterationCount = -1; - private int macSaltLength = -1; // the source of randomness private SecureRandom random; @@ -789,8 +788,7 @@ public synchronized void engineSetKeyEntry(String alias, byte[] key, private byte[] getSalt() { // Generate a random salt. - int len = (this.macSaltLength == -1) ? SALT_LEN : this.macSaltLength; - byte[] salt = new byte[len]; + byte[] salt = new byte[SALT_LEN]; if (random == null) { random = new SecureRandom(); } @@ -1484,7 +1482,7 @@ private byte[] calculateMac(char[] passwd, byte[] data) final String kdfHmac; int writeIterationCount = macIterationCount; - if (macAlgorithm.equals("PBMAC1") || + if (macAlgorithm.startsWith("PBEWith") || defaultMacAlgorithm().startsWith("PBEWith")) { if (defaultMacAlgorithm().equals("PBEWithHmacSHA512")) { kdfHmac = "HmacSHA512"; @@ -2200,8 +2198,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) String pbmac1KdfHmac = macData.getKdfHmac(); pbmac1Hmac = pbmac1KdfHmac; macIterationCount = ic; - macAlgorithm = algName; - macSaltLength = salt.length; + macAlgorithm = "PBEWith" + pbmac1KdfHmac; PBEParameterSpec params = new PBEParameterSpec(salt, ic); processMacData(params, macData, password, authSafeData, From 069ef25432281cabd71849dd4d4060854c84b0e6 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 23 Sep 2025 20:52:20 -0600 Subject: [PATCH 18/30] fix behavior with keytool --- .../classes/sun/security/pkcs12/MacData.java | 20 ++++++++ .../sun/security/pkcs12/PKCS12KeyStore.java | 51 +++++++++++-------- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index b4f6bc19fd303..30d80be2ae1f2 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -98,8 +98,14 @@ class MacData { } this.iterations = pbeSpec.getIterationCount(); this.macSalt = pbeSpec.getSalt(); + String ps = this.digestAlgorithmParams.toString(); this.kdfHmac = getKdfHmac(ps); + this.Hmac = getHmac(ps); + + if (!this.kdfHmac.equals(this.Hmac)) { + throw new IOException("PRF and Hmac must be same"); + } if (!(this.kdfHmac.equals("HmacSHA512") || this.kdfHmac.equals("HmacSHA256"))) { throw new IOException("unsupported PBMAC1 Hmac"); @@ -290,4 +296,18 @@ public String getKdfHmac(String text) { return null; } } + + public static String getHmac(String text) { + final String word2 = "And"; + + String regex = Pattern.quote(word2) + "(.*?)$"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(text); + + if (matcher.find()) { + return matcher.group(1); + } else { + return null; + } + } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 1ced8de5562ae..bd00a15cc4dcc 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -175,6 +175,7 @@ public DualFormatPKCS12() { private String macAlgorithm = null; private String pbmac1Hmac = null; private int macIterationCount = -1; + private boolean newKeystore; // the source of randomness private SecureRandom random; @@ -1245,6 +1246,7 @@ public synchronized void engineStore(OutputStream stream, char[] password) // -- MAC if (macAlgorithm == null) { + newKeystore = true; macAlgorithm = defaultMacAlgorithm(); } if (macIterationCount < 0) { @@ -1479,25 +1481,32 @@ private byte[] calculateMac(char[] passwd, byte[] data) final PBEParameterSpec params; final String algName; final MacData macData; - final String kdfHmac; + String kdfHmac; int writeIterationCount = macIterationCount; - if (macAlgorithm.startsWith("PBEWith") || - defaultMacAlgorithm().startsWith("PBEWith")) { - if (defaultMacAlgorithm().equals("PBEWithHmacSHA512")) { - kdfHmac = "HmacSHA512"; - } else if (defaultMacAlgorithm().equals("PBEWithHmacSHA256")) { - kdfHmac = "HmacSHA256"; + if (newKeystore) { + if (macAlgorithm.startsWith("PBEWith") || + defaultMacAlgorithm().startsWith("PBEWith")) { + kdfHmac = defaultMacAlgorithm().replace("PBEWith", ""); + if (!(kdfHmac.equals("HmacSHA512") || + kdfHmac.equals("HmacSHA256"))) { + kdfHmac = pbmac1Hmac; // use value associated with keystore + } + algName = "PBMAC1"; + // Override with value of security property. + writeIterationCount = defaultMacIterationCount(); } else { - // Use value currently associated with this keystore. - kdfHmac = pbmac1Hmac; + algName = macAlgorithm.substring(7); + kdfHmac = macAlgorithm; } - algName = "PBMAC1"; - // Override with value of security property. - writeIterationCount = defaultMacIterationCount(); } else { - algName = macAlgorithm.substring(7); - kdfHmac = macAlgorithm; + if (pbmac1Hmac != null) { // have PBMAC1 keystore + kdfHmac = pbmac1Hmac; + algName = "PBMAC1"; + } else { + algName = macAlgorithm.substring(7); + kdfHmac = macAlgorithm; + } } params = new PBEParameterSpec(getSalt(), writeIterationCount); @@ -1942,14 +1951,14 @@ private byte[] encryptContent(byte[] data, char[] password) private void processMacData(AlgorithmParameterSpec params, MacData macData, char[] password, byte[] data, String macAlgorithm) throws Exception { - String kdfHmac; + final String kdfHmac; + String tmp; - if (macAlgorithm.equals("PBEWithHmacSHA256")) { - kdfHmac = "HmacSHA256"; - } else if (macAlgorithm.equals("PBEWithHmacSHA512")) { - kdfHmac = "HmacSHA512"; - } else { + tmp = macAlgorithm.replace("PBEWith", ""); + if (!(tmp.equals("HmacSHA512") || tmp.equals("HmacSHA256"))) { kdfHmac = macAlgorithm; + } else { + kdfHmac = tmp; } var skf = SecretKeyFactory.getInstance( @@ -2202,7 +2211,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) PBEParameterSpec params = new PBEParameterSpec(salt, ic); processMacData(params, macData, password, authSafeData, - "PBEWith" + pbmac1KdfHmac); + macAlgorithm); } else { // Change SHA-1 to SHA1 From 76ccce74e81498d10f5b542dad67a1fcec201379 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 26 Sep 2025 20:34:56 -0600 Subject: [PATCH 19/30] move algorithm-specific code into MacData and no change to SunJCE --- .../sun/crypto/provider/PBMAC1Parameters.java | 17 +- .../com/sun/crypto/provider/SunJCE.java | 4 - .../classes/sun/security/pkcs12/MacData.java | 233 ++++++++++++++---- .../sun/security/pkcs12/PKCS12KeyStore.java | 144 +---------- 4 files changed, 207 insertions(+), 191 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index 2a07e4b479a70..e9cfb37c7894e 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -26,8 +26,6 @@ package com.sun.crypto.provider; import java.io.IOException; -import java.security.AlgorithmParametersSpi; -import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.PBEParameterSpec; @@ -63,7 +61,7 @@ * * @since 26 */ -abstract class PBMAC1Parameters extends AlgorithmParametersSpi { +final public class PBMAC1Parameters { // the PBMAC1 algorithm name private String pbmac1AlgorithmName = null; @@ -90,7 +88,7 @@ protected void engineInit(AlgorithmParameterSpec paramSpec) iCount = ((PBEParameterSpec)paramSpec).getIterationCount(); } - protected void engineInit(byte[] encoded) throws IOException { + public void engineInit(byte[] encoded) throws IOException { DerValue pBMAC1_params = new DerValue(encoded); if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PBMAC1 parameter parsing error: " @@ -191,13 +189,14 @@ protected byte[] engineGetEncoded(String encodingMethod) /* * Returns a formatted string describing the parameters. */ - protected String engineToString() { + public String engineToString() { return pbmac1AlgorithmName; } - public static final class General extends PBMAC1Parameters { - public General() throws NoSuchAlgorithmException { - super(); - } + public byte[] getSalt() { + return salt; + } + public int getIterations() { + return iCount; } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index a8d4cc095a6b2..22d5f17c6e0fb 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -544,10 +544,6 @@ void putEntries() { ps("AlgorithmParameters", "PBEWithHmacSHA512/256AndAES_256", "com.sun.crypto.provider.PBES2Parameters$HmacSHA512_256AndAES_256"); - psA("AlgorithmParameters", "PBMAC1", - "com.sun.crypto.provider.PBMAC1Parameters$General", - null); - ps("AlgorithmParameters", "Blowfish", "com.sun.crypto.provider.BlowfishParameters"); diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 30d80be2ae1f2..13d4f3b97c6a6 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -26,15 +26,20 @@ package sun.security.pkcs12; import java.io.IOException; -import java.security.AlgorithmParameters; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidParameterSpecException; -import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; +import javax.security.auth.DestroyFailedException; +import com.sun.crypto.provider.PBMAC1Parameters; import sun.security.pkcs.ParsingException; import sun.security.util.*; import sun.security.x509.AlgorithmId; @@ -48,11 +53,11 @@ class MacData { + private static final Debug debug = Debug.getInstance("pkcs12"); private final String digestAlgorithmName; - private final AlgorithmParameters digestAlgorithmParams; private final byte[] digest; - private byte[] macSalt; - private int iterations; + private final byte[] macSalt; + private final int iterations; private String kdfHmac; private String Hmac; private int keyLength; @@ -80,38 +85,22 @@ class MacData { // Parse the DigestAlgorithmIdentifier. AlgorithmId digestAlgorithmId = AlgorithmId.parse(digestInfo[0]); this.digestAlgorithmName = digestAlgorithmId.getName(); - this.digestAlgorithmParams = digestAlgorithmId.getParameters(); // Get the digest. this.digest = digestInfo[1].getOctetString(); if (this.digestAlgorithmName.equals("PBMAC1")) { - PBEParameterSpec pbeSpec; + PBMAC1Parameters algParams; - try { - pbeSpec = - this.digestAlgorithmParams.getParameterSpec( - PBEParameterSpec.class); - } catch (InvalidParameterSpecException ipse) { - throw new IOException( - "Invalid PBE algorithm parameters"); - } - this.iterations = pbeSpec.getIterationCount(); - this.macSalt = pbeSpec.getSalt(); + algParams = new PBMAC1Parameters(); + algParams.engineInit(digestAlgorithmId.getEncodedParams()); - String ps = this.digestAlgorithmParams.toString(); - this.kdfHmac = getKdfHmac(ps); - this.Hmac = getHmac(ps); + this.iterations = algParams.getIterations(); + this.macSalt = algParams.getSalt(); - if (!this.kdfHmac.equals(this.Hmac)) { - throw new IOException("PRF and Hmac must be same"); - } - if (!(this.kdfHmac.equals("HmacSHA512") || - this.kdfHmac.equals("HmacSHA256"))) { - throw new IOException("unsupported PBMAC1 Hmac"); - } - - this.Hmac = this.kdfHmac; + String ps = algParams.engineToString(); + this.kdfHmac = parseKdfHmac(ps); + this.Hmac = parseHmac(ps); } else { this.macSalt = macData[1].getOctetString(); if (macData.length > 2) { @@ -123,7 +112,7 @@ class MacData { } MacData(String algName, byte[] digest, AlgorithmParameterSpec params, - String kdfHmac, int keyLength) throws NoSuchAlgorithmException { + String kdfHmac, String Hmac, int keyLength) throws NoSuchAlgorithmException { AlgorithmId algid; if (algName == null) { @@ -136,7 +125,6 @@ class MacData { algid = AlgorithmId.get(algName); this.digestAlgorithmName = algid.getName(); - this.digestAlgorithmParams = algid.getParameters(); if (digest == null) { throw new NullPointerException("the digest " + @@ -156,7 +144,7 @@ class MacData { this.macSalt = p.getSalt(); this.iterations = p.getIterationCount(); this.kdfHmac = kdfHmac; - this.Hmac = kdfHmac; + this.Hmac = Hmac; this.keyLength = keyLength; } else { this.macSalt = p.getSalt(); @@ -171,6 +159,158 @@ class MacData { this.encoded = null; } + /* + * Destroy the key obtained from getPBEKey(). + */ + static void destroyPBEKey(SecretKey key) { + try { + key.destroy(); + } catch (DestroyFailedException e) { + // Accept this + } + } + + /** + * Retries an action with password "\0" if "" fails. + * @param the return type + */ + @FunctionalInterface + private interface RetryWithZero { + + T tryOnce(char[] password) throws Exception; + + static S run(RetryWithZero f, char[] password) throws Exception { + try { + return f.tryOnce(password); + } catch (Exception e) { + if (password.length == 0) { + // Retry using an empty password with a NUL terminator. + if (debug != null) { + debug.println("Retry with a NUL password"); + } + return f.tryOnce(new char[1]); + } + throw e; + } + } + } + + void processMacData(AlgorithmParameterSpec params, + MacData macData, char[] password, byte[] data, String macAlgorithm) + throws Exception { + final String kdfHmac; + final String Hmac; + + if (macAlgorithm.startsWith("PBEWith")) { + kdfHmac = macData.getKdfHmac(); + Hmac = macData.getHmac(); + } else { + kdfHmac = macAlgorithm; + Hmac = macAlgorithm; + } + + var skf = SecretKeyFactory.getInstance( + kdfHmac.equals("HmacSHA512") ? + "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); + + RetryWithZero.run(pass -> { + SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(pass, + ((PBEParameterSpec)params).getSalt(), + ((PBEParameterSpec)params).getIterationCount(), + Hmac.equals("HmacSHA512") ? 64*8 : 32*8)); + Mac m = Mac.getInstance(Hmac); + try { + m.init(pbeKey); + } finally { + destroyPBEKey(pbeKey); + } + m.update(data); + byte[] macResult = m.doFinal(); + + if (debug != null) { + debug.println("Checking keystore integrity " + + "(" + m.getAlgorithm() + " iterations: " + + macData.getIterations() + ")"); + } + + if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { + throw new UnrecoverableKeyException("Failed PKCS12" + + " integrity checking"); + } + return (Void) null; + }, password); + } + + /* + * Calculate MAC using HMAC algorithm (required for password integrity) + * + * Hash-based MAC algorithm combines secret key with message digest to + * create a message authentication code (MAC) + */ + public static byte[] calculateMac(char[] passwd, byte[] data, boolean newKeystore, + String macAlgorithm, int macIterationCount, byte[] salt) + throws IOException, NoSuchAlgorithmException + { + final byte[] mData; + final PBEParameterSpec params; + final MacData macData; + String algName = "PBMAC1"; + String kdfHmac = null; + String Hmac = null; + + if (newKeystore) { + if (macAlgorithm.startsWith("PBEWith")) { + kdfHmac = MacData.parseKdfHmac(macAlgorithm); + Hmac = MacData.parseHmac(macAlgorithm); + if (Hmac == null) { + Hmac = kdfHmac; + } + } + } else { + String tmp = MacData.parseKdfHmac(macAlgorithm); + if (tmp != null) { + kdfHmac = tmp; + Hmac = MacData.parseHmac(macAlgorithm); + } + } + // Fall back to old way of computing MAC + if (kdfHmac == null) { + algName = macAlgorithm.substring(7); + kdfHmac = macAlgorithm; + Hmac = macAlgorithm; + } + + params = new PBEParameterSpec(salt, macIterationCount); + + var skf = SecretKeyFactory.getInstance(kdfHmac.equals("HmacSHA512") ? + "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); + try { + int keyLength = Hmac.equals("HmacSHA512") ? 64*8 : 32*8; + + SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(passwd, + params.getSalt(), macIterationCount, keyLength)); + + Mac m = Mac.getInstance(Hmac); + try { + m.init(pbeKey); + } finally { + destroyPBEKey(pbeKey); + } + m.update(data); + byte[] macResult = m.doFinal(); + + // encode as MacData + macData = new MacData(algName, macResult, params, + kdfHmac, Hmac, keyLength); + DerOutputStream bytes = new DerOutputStream(); + bytes.write(macData.getEncoded()); + mData = bytes.toByteArray(); + } catch (Exception e) { + throw new IOException("calculateMac failed: " + e, e); + } + return mData; + } + String getDigestAlgName() { return this.digestAlgorithmName; } @@ -191,6 +331,10 @@ String getKdfHmac() { return this.kdfHmac; } + String getHmac() { + return this.Hmac; + } + /** * Returns the ASN.1 encoding of this object. * @return the ASN.1 encoding. @@ -282,22 +426,27 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { return this.encoded.clone(); } - public String getKdfHmac(String text) { + public static String parseKdfHmac(String text) { final String word1 = "With"; final String word2 = "And"; - String regex = Pattern.quote(word1) + "(.*?)" + Pattern.quote(word2); - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(text); + String regex1 = Pattern.quote(word1) + "(.*?)" + Pattern.quote(word2); + Pattern pattern1 = Pattern.compile(regex1); + Matcher matcher1 = pattern1.matcher(text); - if (matcher.find()) { - return matcher.group(1); - } else { - return null; + String regex2 = Pattern.quote(word1) + "(.*?)$"; + Pattern pattern2 = Pattern.compile(regex2); + Matcher matcher2 = pattern2.matcher(text); + + if (matcher1.find()) { + return matcher1.group(1); + } else if (matcher2.find()) { + return matcher2.group(1); } + return null; } - public static String getHmac(String text) { + public static String parseHmac(String text) { final String word2 = "And"; String regex = Pattern.quote(word2) + "(.*?)$"; diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index bd00a15cc4dcc..f5bf1a83cd9d7 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -173,7 +173,6 @@ public DualFormatPKCS12() { private String certProtectionAlgorithm = null; private int certPbeIterationCount = -1; private String macAlgorithm = null; - private String pbmac1Hmac = null; private int macIterationCount = -1; private boolean newKeystore; @@ -1253,7 +1252,8 @@ public synchronized void engineStore(OutputStream stream, char[] password) macIterationCount = defaultMacIterationCount(); } if (password != null && !macAlgorithm.equalsIgnoreCase("NONE")) { - byte[] macData = calculateMac(password, authenticatedSafe); + byte[] macData = MacData.calculateMac(password, authenticatedSafe, + newKeystore, macAlgorithm, macIterationCount, getSalt()); pfx.write(macData); } // write PFX to output stream @@ -1468,79 +1468,6 @@ private void populateAttributes(Entry entry) { } } - /* - * Calculate MAC using HMAC algorithm (required for password integrity) - * - * Hash-based MAC algorithm combines secret key with message digest to - * create a message authentication code (MAC) - */ - private byte[] calculateMac(char[] passwd, byte[] data) - throws IOException, NoSuchAlgorithmException - { - final byte[] mData; - final PBEParameterSpec params; - final String algName; - final MacData macData; - String kdfHmac; - int writeIterationCount = macIterationCount; - - if (newKeystore) { - if (macAlgorithm.startsWith("PBEWith") || - defaultMacAlgorithm().startsWith("PBEWith")) { - kdfHmac = defaultMacAlgorithm().replace("PBEWith", ""); - if (!(kdfHmac.equals("HmacSHA512") || - kdfHmac.equals("HmacSHA256"))) { - kdfHmac = pbmac1Hmac; // use value associated with keystore - } - algName = "PBMAC1"; - // Override with value of security property. - writeIterationCount = defaultMacIterationCount(); - } else { - algName = macAlgorithm.substring(7); - kdfHmac = macAlgorithm; - } - } else { - if (pbmac1Hmac != null) { // have PBMAC1 keystore - kdfHmac = pbmac1Hmac; - algName = "PBMAC1"; - } else { - algName = macAlgorithm.substring(7); - kdfHmac = macAlgorithm; - } - } - - params = new PBEParameterSpec(getSalt(), writeIterationCount); - - var skf = SecretKeyFactory.getInstance(kdfHmac.equals("HmacSHA512") ? - "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); - try { - int keyLength = kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8; - - SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(passwd, - params.getSalt(), writeIterationCount, keyLength)); - - Mac m = Mac.getInstance(kdfHmac); - try { - m.init(pbeKey); - } finally { - destroyPBEKey(pbeKey); - } - m.update(data); - byte[] macResult = m.doFinal(); - - // encode as MacData - macData = new MacData(algName, macResult, params, - kdfHmac, keyLength); - DerOutputStream bytes = new DerOutputStream(); - bytes.write(macData.getEncoded()); - mData = bytes.toByteArray(); - } catch (Exception e) { - throw new IOException("calculateMac failed: " + e, e); - } - return mData; - } - - /* * Validate Certificate Chain */ @@ -1948,51 +1875,6 @@ private byte[] encryptContent(byte[] data, char[] password) } } - private void processMacData(AlgorithmParameterSpec params, - MacData macData, char[] password, byte[] data, String macAlgorithm) - throws Exception { - final String kdfHmac; - String tmp; - - tmp = macAlgorithm.replace("PBEWith", ""); - if (!(tmp.equals("HmacSHA512") || tmp.equals("HmacSHA256"))) { - kdfHmac = macAlgorithm; - } else { - kdfHmac = tmp; - } - - var skf = SecretKeyFactory.getInstance( - macAlgorithm.contains("HmacSHA512") ? - "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); - - RetryWithZero.run(pass -> { - SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(pass, - ((PBEParameterSpec)params).getSalt(), - ((PBEParameterSpec)params).getIterationCount(), - kdfHmac.equals("HmacSHA512") ? 64*8 : 32*8)); - Mac m = Mac.getInstance(kdfHmac); - try { - m.init(pbeKey); - } finally { - destroyPBEKey(pbeKey); - } - m.update(data); - byte[] macResult = m.doFinal(); - - if (debug != null) { - debug.println("Checking keystore integrity " + - "(" + m.getAlgorithm() + " iterations: " - + macData.getIterations() + ")"); - } - - if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { - throw new UnrecoverableKeyException("Failed PKCS12" + - " integrity checking"); - } - return (Void) null; - }, password); - } - /** * Loads the keystore from the given input stream. * @@ -2203,27 +2085,17 @@ public synchronized void engineLoad(InputStream stream, char[] password) String algName = macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); if (algName.equals("PBMAC1")) { - - String pbmac1KdfHmac = macData.getKdfHmac(); - pbmac1Hmac = pbmac1KdfHmac; - macIterationCount = ic; - macAlgorithm = "PBEWith" + pbmac1KdfHmac; - PBEParameterSpec params = - new PBEParameterSpec(salt, ic); - processMacData(params, macData, password, authSafeData, - macAlgorithm); + macAlgorithm = "PBEWith" + macData.getKdfHmac() + + "And" + macData.getHmac(); } else { - // Change SHA-1 to SHA1 algName = algName.replace("-", ""); macAlgorithm = "HmacPBE" + algName; - macIterationCount = ic; - - PBEParameterSpec params = - new PBEParameterSpec(salt, ic); - processMacData(params, macData, password, authSafeData, - macAlgorithm); } + macIterationCount = ic; + PBEParameterSpec params = new PBEParameterSpec(salt, ic); + macData.processMacData(params, macData, password, authSafeData, + macAlgorithm); } catch (Exception e) { throw new IOException("Integrity check failed: " + e, e); } From 21eca48ec55a6b375a7f41c667f96092792744a6 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Sun, 28 Sep 2025 21:40:22 -0600 Subject: [PATCH 20/30] another day another iteration --- .../sun/crypto/provider/PBMAC1Parameters.java | 50 ++++--- .../classes/sun/security/pkcs12/MacData.java | 133 +++++++----------- .../sun/security/pkcs12/PKCS12KeyStore.java | 18 +-- 3 files changed, 79 insertions(+), 122 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index e9cfb37c7894e..90bd15e874c02 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -71,6 +71,9 @@ final public class PBMAC1Parameters { // Iteration count private int iCount = 0; + private String prfAlgo; + private String hmacAlgo; + // the key derivation function (default is HmacSHA1) private final ObjectIdentifier kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.HmacSHA1); @@ -78,7 +81,7 @@ final public class PBMAC1Parameters { // length of key generated by the kdf private int keyLength = -1; - protected void engineInit(AlgorithmParameterSpec paramSpec) + protected void Init(AlgorithmParameterSpec paramSpec) throws InvalidParameterSpecException { if (!(paramSpec instanceof PBEParameterSpec)) { throw new InvalidParameterSpecException @@ -88,7 +91,7 @@ protected void engineInit(AlgorithmParameterSpec paramSpec) iCount = ((PBEParameterSpec)paramSpec).getIterationCount(); } - public void engineInit(byte[] encoded) throws IOException { + public void Init(byte[] encoded) throws IOException { DerValue pBMAC1_params = new DerValue(encoded); if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PBMAC1 parameter parsing error: " @@ -114,13 +117,13 @@ public void engineInit(byte[] encoded) throws IOException { + "derivation function"); } // Hmac function used to compute the MAC - String hmacAlgo = o.stdName(); + this.hmacAlgo = o.stdName(); DerValue kdf = pBMAC1_params.data.getDerValue(); var kdfParams = new PBKDF2Parameters(kdf); - String prfAlgo = kdfParams.getPrfAlgo(); - salt = kdfParams.getSalt(); - iCount = kdfParams.getIterationCount(); + this.prfAlgo = kdfParams.getPrfAlgo(); + this.salt = kdfParams.getSalt(); + this.iCount = kdfParams.getIterationCount(); // Key length must be present even though it is not used. keyLength = kdfParams.getKeyLength(); @@ -129,27 +132,16 @@ public void engineInit(byte[] encoded) throws IOException { + "error: missing keyLength field"); } - pbmac1AlgorithmName = "PBMAC1With" + prfAlgo + "And" + hmacAlgo; + pbmac1AlgorithmName = "PBMAC1With" + this.prfAlgo + "And" + + this.hmacAlgo; } - protected void engineInit(byte[] encoded, String decodingMethod) + protected void Init(byte[] encoded, String decodingMethod) throws IOException { - engineInit(encoded); - } - - protected - T engineGetParameterSpec(Class paramSpec) - throws InvalidParameterSpecException { - if (paramSpec.isAssignableFrom(PBEParameterSpec.class)) { - return paramSpec.cast( - new PBEParameterSpec(salt, iCount)); - } else { - throw new InvalidParameterSpecException - ("Inappropriate parameter specification"); - } + Init(encoded); } - protected byte[] engineGetEncoded() throws IOException { + protected byte[] getEncoded() throws IOException { DerOutputStream out = new DerOutputStream(); DerOutputStream pBMAC1_params = new DerOutputStream(); @@ -181,9 +173,9 @@ protected byte[] engineGetEncoded() throws IOException { return out.toByteArray(); } - protected byte[] engineGetEncoded(String encodingMethod) + protected byte[] getEncoded(String encodingMethod) throws IOException { - return engineGetEncoded(); + return getEncoded(); } /* @@ -193,10 +185,16 @@ public String engineToString() { return pbmac1AlgorithmName; } + public String getPrf() { + return this.prfAlgo; + } + public String getHmac() { + return this.hmacAlgo; + } public byte[] getSalt() { - return salt; + return this.salt; } public int getIterations() { - return iCount; + return this.iCount; } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 13d4f3b97c6a6..86bcab85ff1cb 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -30,8 +30,6 @@ import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.spec.AlgorithmParameterSpec; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; @@ -55,6 +53,7 @@ class MacData { private static final Debug debug = Debug.getInstance("pkcs12"); private final String digestAlgorithmName; + private String macAlgorithm = null; private final byte[] digest; private final byte[] macSalt; private final int iterations; @@ -93,14 +92,14 @@ class MacData { PBMAC1Parameters algParams; algParams = new PBMAC1Parameters(); - algParams.engineInit(digestAlgorithmId.getEncodedParams()); + algParams.Init(digestAlgorithmId.getEncodedParams()); this.iterations = algParams.getIterations(); this.macSalt = algParams.getSalt(); - String ps = algParams.engineToString(); - this.kdfHmac = parseKdfHmac(ps); - this.Hmac = parseHmac(ps); + this.kdfHmac = algParams.getPrf(); + this.Hmac = algParams.getHmac(); + this.macAlgorithm = "PBEWith" + this.kdfHmac + "And" + this.Hmac; } else { this.macSalt = macData[1].getOctetString(); if (macData.length > 2) { @@ -108,6 +107,8 @@ class MacData { } else { this.iterations = 1; } + this.macAlgorithm = "HmacPBE" + + this.digestAlgorithmName.replace("-", ""); } } @@ -170,31 +171,6 @@ static void destroyPBEKey(SecretKey key) { } } - /** - * Retries an action with password "\0" if "" fails. - * @param the return type - */ - @FunctionalInterface - private interface RetryWithZero { - - T tryOnce(char[] password) throws Exception; - - static S run(RetryWithZero f, char[] password) throws Exception { - try { - return f.tryOnce(password); - } catch (Exception e) { - if (password.length == 0) { - // Retry using an empty password with a NUL terminator. - if (debug != null) { - debug.println("Retry with a NUL password"); - } - return f.tryOnce(new char[1]); - } - throw e; - } - } - } - void processMacData(AlgorithmParameterSpec params, MacData macData, char[] password, byte[] data, String macAlgorithm) throws Exception { @@ -213,32 +189,29 @@ void processMacData(AlgorithmParameterSpec params, kdfHmac.equals("HmacSHA512") ? "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); - RetryWithZero.run(pass -> { - SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(pass, - ((PBEParameterSpec)params).getSalt(), - ((PBEParameterSpec)params).getIterationCount(), - Hmac.equals("HmacSHA512") ? 64*8 : 32*8)); - Mac m = Mac.getInstance(Hmac); - try { - m.init(pbeKey); - } finally { - destroyPBEKey(pbeKey); - } - m.update(data); - byte[] macResult = m.doFinal(); + SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(password, + ((PBEParameterSpec)params).getSalt(), + ((PBEParameterSpec)params).getIterationCount(), + Hmac.equals("HmacSHA512") ? 64*8 : 32*8)); + Mac m = Mac.getInstance(Hmac); + try { + m.init(pbeKey); + } finally { + destroyPBEKey(pbeKey); + } + m.update(data); + byte[] macResult = m.doFinal(); - if (debug != null) { - debug.println("Checking keystore integrity " + - "(" + m.getAlgorithm() + " iterations: " - + macData.getIterations() + ")"); - } + if (debug != null) { + debug.println("Checking keystore integrity " + + "(" + m.getAlgorithm() + " iterations: " + + macData.getIterations() + ")"); + } - if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { - throw new UnrecoverableKeyException("Failed PKCS12" + - " integrity checking"); - } - return (Void) null; - }, password); + if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { + throw new UnrecoverableKeyException("Failed PKCS12" + + " integrity checking"); + } } /* @@ -247,10 +220,10 @@ void processMacData(AlgorithmParameterSpec params, * Hash-based MAC algorithm combines secret key with message digest to * create a message authentication code (MAC) */ - public static byte[] calculateMac(char[] passwd, byte[] data, boolean newKeystore, - String macAlgorithm, int macIterationCount, byte[] salt) - throws IOException, NoSuchAlgorithmException - { + public static byte[] calculateMac(char[] passwd, byte[] data, + boolean newKeystore, String macAlgorithm, int macIterationCount, + byte[] salt) + throws IOException, NoSuchAlgorithmException { final byte[] mData; final PBEParameterSpec params; final MacData macData; @@ -267,6 +240,7 @@ public static byte[] calculateMac(char[] passwd, byte[] data, boolean newKeystor } } } else { + // existing keystore String tmp = MacData.parseKdfHmac(macAlgorithm); if (tmp != null) { kdfHmac = tmp; @@ -315,6 +289,10 @@ String getDigestAlgName() { return this.digestAlgorithmName; } + String getMacAlgorithm() { + return this.macAlgorithm; + } + byte[] getSalt() { return this.macSalt; } @@ -427,36 +405,23 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { } public static String parseKdfHmac(String text) { - final String word1 = "With"; - final String word2 = "And"; - - String regex1 = Pattern.quote(word1) + "(.*?)" + Pattern.quote(word2); - Pattern pattern1 = Pattern.compile(regex1); - Matcher matcher1 = pattern1.matcher(text); - - String regex2 = Pattern.quote(word1) + "(.*?)$"; - Pattern pattern2 = Pattern.compile(regex2); - Matcher matcher2 = pattern2.matcher(text); - - if (matcher1.find()) { - return matcher1.group(1); - } else if (matcher2.find()) { - return matcher2.group(1); + int index1 = text.indexOf("With") + 4; + int index2 = text.indexOf("And"); + if (index1 == 3) { // -1 + 4 + return null; + } else if (index2 == -1) { + return text.substring(index1); + } else { + return text.substring(index1, index2); } - return null; } public static String parseHmac(String text) { - final String word2 = "And"; - - String regex = Pattern.quote(word2) + "(.*?)$"; - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(text); - - if (matcher.find()) { - return matcher.group(1); - } else { + int index1 = text.indexOf("And") + 3;; + if (index1 == 2) { // -1 + 3 return null; + } else { + return text.substring(index1); } } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index f5bf1a83cd9d7..8169900568c4b 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -2082,20 +2082,14 @@ public synchronized void engineLoad(InputStream stream, char[] password) "MAC iteration count too large: " + ic); } - String algName = - macData.getDigestAlgName().toUpperCase(Locale.ENGLISH); - if (algName.equals("PBMAC1")) { - macAlgorithm = "PBEWith" + macData.getKdfHmac() - + "And" + macData.getHmac(); - } else { - // Change SHA-1 to SHA1 - algName = algName.replace("-", ""); - macAlgorithm = "HmacPBE" + algName; - } + macAlgorithm = macData.getMacAlgorithm(); macIterationCount = ic; PBEParameterSpec params = new PBEParameterSpec(salt, ic); - macData.processMacData(params, macData, password, authSafeData, - macAlgorithm); + RetryWithZero.run(pass -> { + macData.processMacData(params, macData, pass, + authSafeData, macAlgorithm); + return (Void) null; + }, password); } catch (Exception e) { throw new IOException("Integrity check failed: " + e, e); } From 3dea54d98c54f17e16a5d8bad482bc9c3924bd71 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 2 Oct 2025 12:41:03 -0600 Subject: [PATCH 21/30] more review comments from Weijun and Sean --- .../sun/crypto/provider/PBMAC1Parameters.java | 24 +- .../classes/sun/security/pkcs12/MacData.java | 160 +++++------ .../sun/security/pkcs12/PKCS12KeyStore.java | 10 +- .../sun/security/util/PBKDF2Parameters.java | 2 +- .../sun/security/pkcs12/PBMAC1Encoding.java | 250 +++++++++++++++++- 5 files changed, 324 insertions(+), 122 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java index 90bd15e874c02..967d64b78a96d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java @@ -63,9 +63,6 @@ */ final public class PBMAC1Parameters { - // the PBMAC1 algorithm name - private String pbmac1AlgorithmName = null; - private byte[] salt = null; // Iteration count @@ -82,13 +79,13 @@ final public class PBMAC1Parameters { private int keyLength = -1; protected void Init(AlgorithmParameterSpec paramSpec) - throws InvalidParameterSpecException { - if (!(paramSpec instanceof PBEParameterSpec)) { + throws InvalidParameterSpecException { + if (!(paramSpec instanceof PBEParameterSpec pbeParamSpec)) { throw new InvalidParameterSpecException ("Inappropriate parameter specification"); } - salt = ((PBEParameterSpec)paramSpec).getSalt().clone(); - iCount = ((PBEParameterSpec)paramSpec).getIterationCount(); + salt = pbeParamSpec.getSalt().clone(); + iCount = pbeParamSpec.getIterationCount(); } public void Init(byte[] encoded) throws IOException { @@ -131,9 +128,6 @@ public void Init(byte[] encoded) throws IOException { throw new IOException("PBMAC1 parameter parsing " + "error: missing keyLength field"); } - - pbmac1AlgorithmName = "PBMAC1With" + this.prfAlgo + "And" - + this.hmacAlgo; } protected void Init(byte[] encoded, String decodingMethod) @@ -173,18 +167,10 @@ protected byte[] getEncoded() throws IOException { return out.toByteArray(); } - protected byte[] getEncoded(String encodingMethod) - throws IOException { + protected byte[] getEncoded(String encodingMethod) throws IOException { return getEncoded(); } - /* - * Returns a formatted string describing the parameters. - */ - public String engineToString() { - return pbmac1AlgorithmName; - } - public String getPrf() { return this.prfAlgo; } diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 86bcab85ff1cb..4ac03146e9476 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -28,8 +28,11 @@ import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.InvalidAlgorithmParameterException; import java.security.UnrecoverableKeyException; +import java.security.InvalidKeyException; import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; @@ -58,7 +61,7 @@ class MacData { private final byte[] macSalt; private final int iterations; private String kdfHmac; - private String Hmac; + private String hmac; private int keyLength; private boolean pbmac1Keystore = false; @@ -98,8 +101,8 @@ class MacData { this.macSalt = algParams.getSalt(); this.kdfHmac = algParams.getPrf(); - this.Hmac = algParams.getHmac(); - this.macAlgorithm = "PBEWith" + this.kdfHmac + "And" + this.Hmac; + this.hmac = algParams.getHmac(); + this.macAlgorithm = "PBEWith" + this.kdfHmac + "And" + this.hmac; } else { this.macSalt = macData[1].getOctetString(); if (macData.length > 2) { @@ -107,13 +110,15 @@ class MacData { } else { this.iterations = 1; } + // Remove "-" from digest algorithm names this.macAlgorithm = "HmacPBE" + this.digestAlgorithmName.replace("-", ""); } } MacData(String algName, byte[] digest, AlgorithmParameterSpec params, - String kdfHmac, String Hmac, int keyLength) throws NoSuchAlgorithmException { + String kdfHmac, String hmac, int keyLength) + throws NoSuchAlgorithmException { AlgorithmId algid; if (algName == null) { @@ -145,13 +150,13 @@ class MacData { this.macSalt = p.getSalt(); this.iterations = p.getIterationCount(); this.kdfHmac = kdfHmac; - this.Hmac = Hmac; + this.hmac = hmac; this.keyLength = keyLength; } else { this.macSalt = p.getSalt(); this.iterations = p.getIterationCount(); this.kdfHmac = null; - this.Hmac = null; + this.hmac = null; this.keyLength = 0; } @@ -171,44 +176,60 @@ static void destroyPBEKey(SecretKey key) { } } - void processMacData(AlgorithmParameterSpec params, - MacData macData, char[] password, byte[] data, String macAlgorithm) - throws Exception { - final String kdfHmac; - final String Hmac; + static Mac getMac(String macAlgorithm, char[] password, + PBEParameterSpec params, byte[] data, + String kdfHmac, String hmac) + throws NoSuchAlgorithmException, InvalidKeySpecException, + InvalidKeyException, InvalidAlgorithmParameterException { + SecretKeyFactory skf; + SecretKey pbeKey; + Mac m; if (macAlgorithm.startsWith("PBEWith")) { - kdfHmac = macData.getKdfHmac(); - Hmac = macData.getHmac(); + m = Mac.getInstance(hmac); + int keyLength = m.getMacLength()*8; + skf = SecretKeyFactory.getInstance("PBKDF2With" +kdfHmac); + pbeKey = skf.generateSecret(new PBEKeySpec(password, + params.getSalt(), params.getIterationCount(), keyLength)); } else { - kdfHmac = macAlgorithm; - Hmac = macAlgorithm; + hmac = macAlgorithm; + m = Mac.getInstance(hmac); + PBEKeySpec keySpec = new PBEKeySpec(password); + skf = SecretKeyFactory.getInstance("PBE"); + pbeKey = skf.generateSecret(keySpec); } - var skf = SecretKeyFactory.getInstance( - kdfHmac.equals("HmacSHA512") ? - "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); - - SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(password, - ((PBEParameterSpec)params).getSalt(), - ((PBEParameterSpec)params).getIterationCount(), - Hmac.equals("HmacSHA512") ? 64*8 : 32*8)); - Mac m = Mac.getInstance(Hmac); try { - m.init(pbeKey); + if (macAlgorithm.startsWith("PBEWith")) { + m.init(pbeKey); + } else { + m.init(pbeKey, params); + } } finally { destroyPBEKey(pbeKey); } m.update(data); - byte[] macResult = m.doFinal(); + return m; + } + + void processMacData(PBEParameterSpec params, char[] password, + byte[] data, String macAlgorithm) throws InvalidKeySpecException, + NoSuchAlgorithmException, UnrecoverableKeyException, + InvalidKeyException, InvalidAlgorithmParameterException { + Mac m; + byte[] macResult; + + m = getMac(macAlgorithm, password, params, data, this.kdfHmac, + this.hmac); + macResult = m.doFinal(); if (debug != null) { debug.println("Checking keystore integrity " + "(" + m.getAlgorithm() + " iterations: " - + macData.getIterations() + ")"); + + this.iterations + ")"); } - if (!MessageDigest.isEqual(macData.getDigest(), macResult)) { + if (!MessageDigest.isEqual(this.digest, macResult)) { throw new UnrecoverableKeyException("Failed PKCS12" + " integrity checking"); } @@ -221,74 +242,51 @@ void processMacData(AlgorithmParameterSpec params, * create a message authentication code (MAC) */ public static byte[] calculateMac(char[] passwd, byte[] data, - boolean newKeystore, String macAlgorithm, int macIterationCount, - byte[] salt) - throws IOException, NoSuchAlgorithmException { + String macAlgorithm, int macIterationCount, byte[] salt) + throws IOException, NoSuchAlgorithmException { final byte[] mData; final PBEParameterSpec params; final MacData macData; String algName = "PBMAC1"; String kdfHmac = null; - String Hmac = null; + String hmac = null; + Mac m; + int keyLength; - if (newKeystore) { - if (macAlgorithm.startsWith("PBEWith")) { - kdfHmac = MacData.parseKdfHmac(macAlgorithm); - Hmac = MacData.parseHmac(macAlgorithm); - if (Hmac == null) { - Hmac = kdfHmac; - } - } - } else { - // existing keystore - String tmp = MacData.parseKdfHmac(macAlgorithm); - if (tmp != null) { - kdfHmac = tmp; - Hmac = MacData.parseHmac(macAlgorithm); + if (macAlgorithm.startsWith("PBEWith")) { + kdfHmac = MacData.parseKdfHmac(macAlgorithm); + hmac = MacData.parseHmac(macAlgorithm); + if (hmac == null) { + hmac = kdfHmac; } - } - // Fall back to old way of computing MAC - if (kdfHmac == null) { + } else if (macAlgorithm.equals("HmacPBESHA256")) { algName = macAlgorithm.substring(7); kdfHmac = macAlgorithm; - Hmac = macAlgorithm; + hmac = macAlgorithm; + } else { + throw new ParsingException("unexpected algorithm"); } params = new PBEParameterSpec(salt, macIterationCount); - var skf = SecretKeyFactory.getInstance(kdfHmac.equals("HmacSHA512") ? - "PBKDF2WithHmacSHA512" : "PBKDF2WithHmacSHA256"); try { - int keyLength = Hmac.equals("HmacSHA512") ? 64*8 : 32*8; - - SecretKey pbeKey = skf.generateSecret(new PBEKeySpec(passwd, - params.getSalt(), macIterationCount, keyLength)); - - Mac m = Mac.getInstance(Hmac); - try { - m.init(pbeKey); - } finally { - destroyPBEKey(pbeKey); - } - m.update(data); + m = getMac(macAlgorithm, passwd, params, data, kdfHmac, hmac); byte[] macResult = m.doFinal(); + keyLength = m.getMacLength()*8; // encode as MacData macData = new MacData(algName, macResult, params, - kdfHmac, Hmac, keyLength); + kdfHmac, hmac, keyLength); DerOutputStream bytes = new DerOutputStream(); bytes.write(macData.getEncoded()); mData = bytes.toByteArray(); - } catch (Exception e) { + } catch (InvalidKeySpecException | InvalidKeyException | + InvalidAlgorithmParameterException e) { throw new IOException("calculateMac failed: " + e, e); } return mData; } - String getDigestAlgName() { - return this.digestAlgorithmName; - } - String getMacAlgorithm() { return this.macAlgorithm; } @@ -301,18 +299,6 @@ int getIterations() { return this.iterations; } - byte[] getDigest() { - return this.digest; - } - - String getKdfHmac() { - return this.kdfHmac; - } - - String getHmac() { - return this.Hmac; - } - /** * Returns the ASN.1 encoding of this object. * @return the ASN.1 encoding. @@ -332,7 +318,7 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { DerOutputStream tmp2 = new DerOutputStream(); DerOutputStream tmp3 = new DerOutputStream(); DerOutputStream tmp4 = new DerOutputStream(); - DerOutputStream Hmac = new DerOutputStream(); + DerOutputStream hmac = new DerOutputStream(); DerOutputStream kdfHmac = new DerOutputStream(); // encode kdfHmac algorithm @@ -341,8 +327,8 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { kdfHmac.putNull(); // encode Hmac algorithm - Hmac.putOID(ObjectIdentifier.of(KnownOIDs.findMatch(this.Hmac))); - Hmac.putNull(); + hmac.putOID(ObjectIdentifier.of(KnownOIDs.findMatch(this.hmac))); + hmac.putNull(); DerOutputStream pBKDF2_params = new DerOutputStream(); @@ -359,7 +345,7 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { tmp3.putOID(pkcs5PBKDF2_OID); tmp3.write(DerValue.tag_Sequence, pBKDF2_params); tmp4.write(DerValue.tag_Sequence, tmp3); - tmp4.write(DerValue.tag_Sequence, Hmac); + tmp4.write(DerValue.tag_Sequence, hmac); tmp1.putOID(ObjectIdentifier.of(KnownOIDs .findMatch("PBMAC1"))); @@ -417,7 +403,7 @@ public static String parseKdfHmac(String text) { } public static String parseHmac(String text) { - int index1 = text.indexOf("And") + 3;; + int index1 = text.indexOf("And") + 3; if (index1 == 2) { // -1 + 3 return null; } else { diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 8169900568c4b..cb80e0667223e 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -37,7 +37,6 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.util.*; import javax.crypto.Cipher; -import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; @@ -174,7 +173,6 @@ public DualFormatPKCS12() { private int certPbeIterationCount = -1; private String macAlgorithm = null; private int macIterationCount = -1; - private boolean newKeystore; // the source of randomness private SecureRandom random; @@ -1245,7 +1243,6 @@ public synchronized void engineStore(OutputStream stream, char[] password) // -- MAC if (macAlgorithm == null) { - newKeystore = true; macAlgorithm = defaultMacAlgorithm(); } if (macIterationCount < 0) { @@ -1253,7 +1250,7 @@ public synchronized void engineStore(OutputStream stream, char[] password) } if (password != null && !macAlgorithm.equalsIgnoreCase("NONE")) { byte[] macData = MacData.calculateMac(password, authenticatedSafe, - newKeystore, macAlgorithm, macIterationCount, getSalt()); + macAlgorithm, macIterationCount, getSalt()); pfx.write(macData); } // write PFX to output stream @@ -2082,12 +2079,11 @@ public synchronized void engineLoad(InputStream stream, char[] password) "MAC iteration count too large: " + ic); } - macAlgorithm = macData.getMacAlgorithm(); macIterationCount = ic; PBEParameterSpec params = new PBEParameterSpec(salt, ic); RetryWithZero.run(pass -> { - macData.processMacData(params, macData, pass, - authSafeData, macAlgorithm); + macData.processMacData(params, pass, authSafeData, + macData.getMacAlgorithm()); return (Void) null; }, password); } catch (Exception e) { diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 9b1c8b93eb57f..01ab6333e65e9 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -148,7 +148,7 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { * each time this method is called. */ public byte[] getSalt() { - return this.salt.clone(); + return this.salt; } /** diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java index 57f34f58ba417..e84fde0145f18 100644 --- a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java +++ b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java @@ -34,6 +34,15 @@ import java.security.KeyStore; import java.util.Base64; +/* + * Tests A.1 - A.6 are from RFC 9879. + * + * A.7 was generated by openssl in 2 steps: + * openssl req -x509 -newkey rsa:4096 -keyout myKey.pem -out cert.pem -days 365 -nodes + * openssl pkcs12 -export -out keyStore.p12 -inkey myKey.pem -in cert.pem -pbmac1_pbkdf2 -macalg sha384 -passout pass:changeit + * + * A.8 is same as A7 except sha384 is changed to sha224. +*/ public class PBMAC1Encoding { // A.1. Valid PKCS #12 File with SHA-256 HMAC and PRF static final String A1 = @@ -395,6 +404,195 @@ public class PBMAC1Encoding { "BggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG3QQI" + "b0c8OLAuMXMCAggA"; + // A.7. SHA384 PRF and HMAC + static final String A7 = + "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" + + "AasECO5DNb7BgO98AgIIAA=="; + + // A.8. SHA224 PRF and HMAC + static final String A8 = + "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"; + static String password = "1234"; public static void main(String[] args) throws Exception { @@ -416,14 +614,19 @@ public static void main(String[] args) throws Exception { fis.close(); System.out.println("A.1 pass"); - // Unsupported: key length must be same as Hmac output length. - try { - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), - password.toCharArray()); - } catch (IOException e) { - System.out.println("A.2 pass"); - } + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), + password.toCharArray()); + + fos = new FileOutputStream("pbmac1KeyStore.p12"); + ks.store(fos, password.toCharArray()); + fos.close(); + + // read keystore we just wrote + fis = new FileInputStream("pbmac1KeyStore.p12"); + ks.load(fis, password.toCharArray()); + fis.close(); + System.out.println("A.2 pass"); ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A3)), @@ -443,6 +646,7 @@ public static void main(String[] args) throws Exception { ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A4)), password.toCharArray()); + throw new Exception("The expected exception was not thrown."); } catch (IOException e) { System.out.println("A.4 pass"); } @@ -451,6 +655,7 @@ public static void main(String[] args) throws Exception { ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A5)), password.toCharArray()); + throw new Exception("The expected exception was not thrown."); } catch (IOException e) { System.out.println("A.5 pass"); @@ -460,8 +665,37 @@ public static void main(String[] args) throws Exception { ks = KeyStore.getInstance("PKCS12"); ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A6)), password.toCharArray()); + throw new Exception("The expected exception was not thrown."); } catch (IOException e) { System.out.println("A.6 pass"); } + + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A7)), + "changeit".toCharArray()); + + fos = new FileOutputStream("pbmac1KeyStore.p12"); + ks.store(fos, password.toCharArray()); + fos.close(); + + // read keystore we just wrote + fis = new FileInputStream("pbmac1KeyStore.p12"); + ks.load(fis, password.toCharArray()); + fis.close(); + System.out.println("A.7 pass"); + + ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A8)), + "changeit".toCharArray()); + + fos = new FileOutputStream("pbmac1KeyStore.p12"); + ks.store(fos, password.toCharArray()); + fos.close(); + + // read keystore we just wrote + fis = new FileInputStream("pbmac1KeyStore.p12"); + ks.load(fis, password.toCharArray()); + fis.close(); + System.out.println("A.8 pass"); } } From 3b348af44c0f3b577d854d153c1c883f6519437c Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 7 Oct 2025 15:16:07 -0600 Subject: [PATCH 22/30] more review comments from Sean and Weijun --- .../sun/crypto/provider/PBKDF2KeyImpl.java | 9 +- .../classes/sun/security/pkcs12/MacData.java | 52 ++++------ .../security/pkcs12}/PBMAC1Parameters.java | 97 +++---------------- .../sun/security/pkcs12/PKCS12KeyStore.java | 2 + .../sun/security/util/PBKDF2Parameters.java | 12 +-- .../sun/security/pkcs12/PBMAC1Encoding.java | 2 +- 6 files changed, 48 insertions(+), 126 deletions(-) rename src/java.base/share/classes/{com/sun/crypto/provider => sun/security/pkcs12}/PBMAC1Parameters.java (54%) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java index 6a0ecb6d462a7..b6ce16047d73e 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java @@ -67,7 +67,7 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { // The following fields are not Serializable. See writeReplace method. private final transient Mac prf; - private final transient Cleaner.Cleanable cleaner; + private transient Cleaner.Cleanable cleaner; /** * Creates a PBE key from a given PBE key specification. @@ -225,6 +225,13 @@ public void clear() { cleaner.clean(); } + public void destroy() { + if (cleaner != null) { + cleaner.clean(); + cleaner = null; + } + } + public char[] getPassword() { try { return passwd.clone(); diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 4ac03146e9476..e1664d9dc5ee7 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -40,7 +40,6 @@ import javax.crypto.spec.PBEParameterSpec; import javax.security.auth.DestroyFailedException; -import com.sun.crypto.provider.PBMAC1Parameters; import sun.security.pkcs.ParsingException; import sun.security.util.*; import sun.security.x509.AlgorithmId; @@ -65,9 +64,6 @@ class MacData { private int keyLength; private boolean pbmac1Keystore = false; - // the ASN.1 encoded contents of this class - private byte[] encoded = null; - /** * Parses a PKCS#12 MAC data. */ @@ -94,13 +90,12 @@ class MacData { if (this.digestAlgorithmName.equals("PBMAC1")) { PBMAC1Parameters algParams; - algParams = new PBMAC1Parameters(); - algParams.Init(digestAlgorithmId.getEncodedParams()); - - this.iterations = algParams.getIterations(); - this.macSalt = algParams.getSalt(); + algParams = new PBMAC1Parameters( + digestAlgorithmId.getEncodedParams()); - this.kdfHmac = algParams.getPrf(); + this.iterations = algParams.getKdfParams().getIterationCount(); + this.macSalt = algParams.getKdfParams().getSalt(); + this.kdfHmac = algParams.getKdfParams().getPrfAlgo(); this.hmac = algParams.getHmac(); this.macAlgorithm = "PBEWith" + this.kdfHmac + "And" + this.hmac; } else { @@ -159,10 +154,6 @@ class MacData { this.hmac = null; this.keyLength = 0; } - - // delay the generation of ASN.1 encoding until - // getEncoded() is called - this.encoded = null; } /* @@ -176,7 +167,7 @@ static void destroyPBEKey(SecretKey key) { } } - static Mac getMac(String macAlgorithm, char[] password, + private static Mac getMac(String macAlgorithm, char[] password, PBEParameterSpec params, byte[] data, String kdfHmac, String hmac) throws NoSuchAlgorithmException, InvalidKeySpecException, @@ -185,25 +176,29 @@ static Mac getMac(String macAlgorithm, char[] password, SecretKey pbeKey; Mac m; + PBEKeySpec keySpec; if (macAlgorithm.startsWith("PBEWith")) { m = Mac.getInstance(hmac); int keyLength = m.getMacLength()*8; skf = SecretKeyFactory.getInstance("PBKDF2With" +kdfHmac); + keySpec = new PBEKeySpec(password, params.getSalt(), + params.getIterationCount(), keyLength); pbeKey = skf.generateSecret(new PBEKeySpec(password, params.getSalt(), params.getIterationCount(), keyLength)); } else { hmac = macAlgorithm; m = Mac.getInstance(hmac); - PBEKeySpec keySpec = new PBEKeySpec(password); + keySpec = new PBEKeySpec(password); skf = SecretKeyFactory.getInstance("PBE"); pbeKey = skf.generateSecret(keySpec); } + keySpec.clearPassword(); try { if (macAlgorithm.startsWith("PBEWith")) { - m.init(pbeKey); + m.init(pbeKey); } else { - m.init(pbeKey, params); + m.init(pbeKey, params); } } finally { destroyPBEKey(pbeKey); @@ -241,15 +236,15 @@ void processMacData(PBEParameterSpec params, char[] password, * Hash-based MAC algorithm combines secret key with message digest to * create a message authentication code (MAC) */ - public static byte[] calculateMac(char[] passwd, byte[] data, + static byte[] calculateMac(char[] passwd, byte[] data, String macAlgorithm, int macIterationCount, byte[] salt) throws IOException, NoSuchAlgorithmException { final byte[] mData; final PBEParameterSpec params; final MacData macData; String algName = "PBMAC1"; - String kdfHmac = null; - String hmac = null; + String kdfHmac; + String hmac; Mac m; int keyLength; @@ -259,7 +254,7 @@ public static byte[] calculateMac(char[] passwd, byte[] data, if (hmac == null) { hmac = kdfHmac; } - } else if (macAlgorithm.equals("HmacPBESHA256")) { + } else if (macAlgorithm.startsWith("HmacPBE")) { algName = macAlgorithm.substring(7); kdfHmac = macAlgorithm; hmac = macAlgorithm; @@ -305,7 +300,7 @@ int getIterations() { * @exception IOException if error occurs when constructing its * ASN.1 encoding. */ - public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { + byte[] getEncoded() throws NoSuchAlgorithmException, IOException { if (this.pbmac1Keystore) { ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); @@ -356,14 +351,9 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { tmp0.putOctetString(not_used); tmp0.putInteger(1); out.write(DerValue.tag_Sequence, tmp0); - encoded = out.toByteArray(); - - return encoded.clone(); + return out.toByteArray(); } - if (this.encoded != null) - return this.encoded.clone(); - DerOutputStream out = new DerOutputStream(); DerOutputStream tmp = new DerOutputStream(); @@ -385,9 +375,7 @@ public byte[] getEncoded() throws NoSuchAlgorithmException, IOException { // wrap everything into a SEQUENCE out.write(DerValue.tag_Sequence, tmp); - this.encoded = out.toByteArray(); - - return this.encoded.clone(); + return out.toByteArray(); } public static String parseKdfHmac(String text) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java similarity index 54% rename from src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java rename to src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java index 967d64b78a96d..d791d075840b0 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Parameters.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java @@ -23,12 +23,9 @@ * questions. */ -package com.sun.crypto.provider; +package sun.security.pkcs12; import java.io.IOException; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidParameterSpecException; -import javax.crypto.spec.PBEParameterSpec; import sun.security.util.*; @@ -55,52 +52,33 @@ * * -- PBKDF2 * - * {@link PBKDF2Parameters} + * See sun.security.util.PBKDF2Parameters. * * * * @since 26 */ -final public class PBMAC1Parameters { +final class PBMAC1Parameters { - private byte[] salt = null; - - // Iteration count - private int iCount = 0; - - private String prfAlgo; - private String hmacAlgo; - - // the key derivation function (default is HmacSHA1) - private final ObjectIdentifier kdfAlgo_OID = - ObjectIdentifier.of(KnownOIDs.HmacSHA1); + private final String hmacAlgo; + private final PBKDF2Parameters kdfParams; // length of key generated by the kdf - private int keyLength = -1; - - protected void Init(AlgorithmParameterSpec paramSpec) - throws InvalidParameterSpecException { - if (!(paramSpec instanceof PBEParameterSpec pbeParamSpec)) { - throw new InvalidParameterSpecException - ("Inappropriate parameter specification"); - } - salt = pbeParamSpec.getSalt().clone(); - iCount = pbeParamSpec.getIterationCount(); - } + private final int keyLength; - public void Init(byte[] encoded) throws IOException { + public PBMAC1Parameters(byte[] encoded) throws IOException { DerValue pBMAC1_params = new DerValue(encoded); if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PBMAC1 parameter parsing error: " + "not an ASN.1 SEQUENCE tag"); } - DerValue[] Info = (new DerInputStream(pBMAC1_params.toByteArray())) + DerValue[] info = new DerInputStream(pBMAC1_params.toByteArray()) .getSequence(2); - if (Info.length != 2) { + if (info.length != 2) { throw new IOException("PBMAC1 parameter parsing error: " + "expected length not 2"); } - ObjectIdentifier OID = Info[1].data.getOID(); + ObjectIdentifier OID = info[1].data.getOID(); KnownOIDs o = KnownOIDs.findMatch(OID.toString()); if (o == null || (!o.stdName().equals("HmacSHA1") && !o.stdName().equals("HmacSHA224") && @@ -117,10 +95,7 @@ public void Init(byte[] encoded) throws IOException { this.hmacAlgo = o.stdName(); DerValue kdf = pBMAC1_params.data.getDerValue(); - var kdfParams = new PBKDF2Parameters(kdf); - this.prfAlgo = kdfParams.getPrfAlgo(); - this.salt = kdfParams.getSalt(); - this.iCount = kdfParams.getIterationCount(); + this.kdfParams = new PBKDF2Parameters(kdf); // Key length must be present even though it is not used. keyLength = kdfParams.getKeyLength(); @@ -130,57 +105,11 @@ public void Init(byte[] encoded) throws IOException { } } - protected void Init(byte[] encoded, String decodingMethod) - throws IOException { - Init(encoded); - } - - protected byte[] getEncoded() throws IOException { - DerOutputStream out = new DerOutputStream(); - - DerOutputStream pBMAC1_params = new DerOutputStream(); - - DerOutputStream keyDerivationFunc = new DerOutputStream(); - keyDerivationFunc.putOID( - sun.security.util.PBKDF2Parameters.pkcs5PBKDF2_OID); - - DerOutputStream pBKDF2_params = new DerOutputStream(); - pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' - pBKDF2_params.putInteger(iCount); - - if (keyLength > 0) { - pBKDF2_params.putInteger(keyLength / 8); // derived key length (in octets) - } - - DerOutputStream prf = new DerOutputStream(); - // algorithm is id-hmacWith - prf.putOID(kdfAlgo_OID); - // parameters is 'NULL' - prf.putNull(); - pBKDF2_params.write(DerValue.tag_Sequence, prf); - - keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); - pBMAC1_params.write(DerValue.tag_Sequence, keyDerivationFunc); - - out.write(DerValue.tag_Sequence, pBMAC1_params); - - return out.toByteArray(); - } - - protected byte[] getEncoded(String encodingMethod) throws IOException { - return getEncoded(); + public PBKDF2Parameters getKdfParams() { + return this.kdfParams; } - public String getPrf() { - return this.prfAlgo; - } public String getHmac() { return this.hmacAlgo; } - public byte[] getSalt() { - return this.salt; - } - public int getIterations() { - return this.iCount; - } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index cb80e0667223e..8481c6656cc8e 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -2079,6 +2079,8 @@ public synchronized void engineLoad(InputStream stream, char[] password) "MAC iteration count too large: " + ic); } + // Store MAC algorithm of keystore that was just loaded. + macAlgorithm = macData.getMacAlgorithm(); macIterationCount = ic; PBEParameterSpec params = new PBEParameterSpec(salt, ic); RetryWithZero.run(pass -> { diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 01ab6333e65e9..10a2f27d4f9cb 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -68,7 +68,7 @@ * * */ -final public class PBKDF2Parameters { +public final class PBKDF2Parameters { public static final ObjectIdentifier pkcs5PBKDF2_OID = ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); @@ -80,10 +80,6 @@ final public class PBKDF2Parameters { // keyLength in bits, or -1 if not present private int keyLength = -1; - // the pseudorandom function (default is HmacSHA1) - private ObjectIdentifier kdfAlgo_OID = - ObjectIdentifier.of(KnownOIDs.HmacSHA1); - private String prfAlgo = "HmacSHA1"; public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { @@ -122,7 +118,8 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); if (prfDer.isPresent()) { DerValue prf = prfDer.get(); - kdfAlgo_OID = prf.data.getOID(); + // the pseudorandom function (default is HmacSHA1) + ObjectIdentifier kdfAlgo_OID = prf.data.getOID(); KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); if (o == null || (!o.stdName().equals("HmacSHA1") && !o.stdName().equals("HmacSHA224") && @@ -144,8 +141,7 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { /** * Returns the salt. * - * @return the salt. Returns a new array - * each time this method is called. + * @return the salt */ public byte[] getSalt() { return this.salt; diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java index e84fde0145f18..1f4e2f3526f10 100644 --- a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java +++ b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java @@ -36,7 +36,7 @@ /* * Tests A.1 - A.6 are from RFC 9879. - * + * * A.7 was generated by openssl in 2 steps: * openssl req -x509 -newkey rsa:4096 -keyout myKey.pem -out cert.pem -days 365 -nodes * openssl pkcs12 -export -out keyStore.p12 -inkey myKey.pem -in cert.pem -pbmac1_pbkdf2 -macalg sha384 -passout pass:changeit From 9e68d6504fe919a9b8aa06dd16605937519d1a7f Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 14 Oct 2025 17:37:34 -0600 Subject: [PATCH 23/30] remaining comments --- .../sun/crypto/provider/PBES2Parameters.java | 40 ++- .../sun/crypto/provider/PBKDF2KeyImpl.java | 11 +- .../classes/sun/security/pkcs12/MacData.java | 253 +++++------------- .../sun/security/pkcs12/PBMAC1Parameters.java | 59 +++- .../sun/security/pkcs12/PKCS12KeyStore.java | 4 +- .../classes/sun/security/util/KeyUtil.java | 3 + .../sun/security/util/PBKDF2Parameters.java | 55 ++-- 7 files changed, 180 insertions(+), 245 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index d3ce98a327798..12a2321455896 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -32,6 +32,7 @@ import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEParameterSpec; +import sun.security.util.PBKDF2Parameters; import sun.security.util.*; /** @@ -227,7 +228,21 @@ protected void engineInit(byte[] encoded) kdf = pBES2_params.data.getDerValue(); } - var kdfParams = new PBKDF2Parameters(kdf); + if (!pkcs5PBKDF2_OID.equals(kdf.data.getOID())) { + throw new IOException("PBE parameter parsing error: " + + "expecting the object identifier for PBKDF2"); + } + if (kdf.tag != DerValue.tag_Sequence) { + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue pBKDF2_params = kdf.data.getDerValue(); + if (pBKDF2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + + var kdfParams = new PBKDF2Parameters(pBKDF2_params); String kdfAlgo = kdfParams.getPrfAlgo(); salt = kdfParams.getSalt(); iCount = kdfParams.getIterationCount(); @@ -289,27 +304,8 @@ protected byte[] engineGetEncoded() throws IOException { DerOutputStream out = new DerOutputStream(); DerOutputStream pBES2_params = new DerOutputStream(); - - DerOutputStream keyDerivationFunc = new DerOutputStream(); - keyDerivationFunc.putOID(pkcs5PBKDF2_OID); - - DerOutputStream pBKDF2_params = new DerOutputStream(); - pBKDF2_params.putOctetString(salt); // choice: 'specified OCTET STRING' - pBKDF2_params.putInteger(iCount); - - if (keysize > 0) { - pBKDF2_params.putInteger(keysize / 8); // derived key length (in octets) - } - - DerOutputStream prf = new DerOutputStream(); - // algorithm is id-hmacWith - prf.putOID(kdfAlgo_OID); - // parameters is 'NULL' - prf.putNull(); - pBKDF2_params.write(DerValue.tag_Sequence, prf); - - keyDerivationFunc.write(DerValue.tag_Sequence, pBKDF2_params); - pBES2_params.write(DerValue.tag_Sequence, keyDerivationFunc); + pBES2_params.write(DerValue.tag_Sequence, + PBKDF2Parameters.encode(salt, iCount, keysize, kdfAlgo_OID)); DerOutputStream encryptionScheme = new DerOutputStream(); // algorithm is id-aes128-CBC or id-aes256-CBC diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java index b6ce16047d73e..9f3e041eebc9d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java @@ -55,7 +55,7 @@ * @author Valerie Peng * */ -final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { +public final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { @java.io.Serial private static final long serialVersionUID = -2234868909660948157L; @@ -67,7 +67,7 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { // The following fields are not Serializable. See writeReplace method. private final transient Mac prf; - private transient Cleaner.Cleanable cleaner; + private final transient Cleaner.Cleanable cleaner; /** * Creates a PBE key from a given PBE key specification. @@ -225,13 +225,6 @@ public void clear() { cleaner.clean(); } - public void destroy() { - if (cleaner != null) { - cleaner.clean(); - cleaner = null; - } - } - public char[] getPassword() { try { return passwd.clone(); diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index e1664d9dc5ee7..349452829ec2c 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -26,19 +26,14 @@ package sun.security.pkcs12; import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.InvalidAlgorithmParameterException; -import java.security.UnrecoverableKeyException; -import java.security.InvalidKeyException; -import java.security.spec.AlgorithmParameterSpec; +import java.security.*; import java.security.spec.InvalidKeySpecException; +import static java.util.Locale.ENGLISH; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; -import javax.security.auth.DestroyFailedException; import sun.security.pkcs.ParsingException; import sun.security.util.*; @@ -46,23 +41,40 @@ /** - * A MacData type, as defined in PKCS#12. + * The MacData type, as defined in PKCS#12. * * @author Sharon Liu + * + * The ASN.1 definition is as follows: + * + *
+ *
+ * MacData ::= SEQUENCE {
+ *     mac        DigestInfo,
+ *     macSalt    OCTET STRING,
+ *     iterations INTEGER DEFAULT 1
+ *      -- Note: The default is for historical reasons and its use is
+ *      -- deprecated.
+ * }
+ *
+ * DigestInfo ::= SEQUENCE {
+ *     digestAlgorithm DigestAlgorithmIdentifier,
+ *     digest OCTET STRING
+ * }
+ *
+ * 
*/ class MacData { private static final Debug debug = Debug.getInstance("pkcs12"); - private final String digestAlgorithmName; - private String macAlgorithm = null; + private final String macAlgorithm; private final byte[] digest; private final byte[] macSalt; private final int iterations; - private String kdfHmac; - private String hmac; - private int keyLength; - private boolean pbmac1Keystore = false; + private final int keyLength; + private final String kdfHmac; + private final String hmac; /** * Parses a PKCS#12 MAC data. @@ -82,23 +94,32 @@ class MacData { // Parse the DigestAlgorithmIdentifier. AlgorithmId digestAlgorithmId = AlgorithmId.parse(digestInfo[0]); - this.digestAlgorithmName = digestAlgorithmId.getName(); + String digestAlgorithmName = digestAlgorithmId.getName(); // Get the digest. this.digest = digestInfo[1].getOctetString(); - if (this.digestAlgorithmName.equals("PBMAC1")) { + if (digestAlgorithmName.equals("PBMAC1")) { PBMAC1Parameters algParams; - algParams = new PBMAC1Parameters( - digestAlgorithmId.getEncodedParams()); + algParams = new PBMAC1Parameters(digestAlgorithmId + .getEncodedParams()); this.iterations = algParams.getKdfParams().getIterationCount(); this.macSalt = algParams.getKdfParams().getSalt(); this.kdfHmac = algParams.getKdfParams().getPrfAlgo(); + this.keyLength = algParams.getKdfParams().getKeyLength(); + + // Implementations MUST NOT accept params that omit keyLength. + if (this.keyLength == -1) { + throw new IOException("error: missing keyLength field"); + } this.hmac = algParams.getHmac(); - this.macAlgorithm = "PBEWith" + this.kdfHmac + "And" + this.hmac; + this.macAlgorithm = "pbewith" + this.kdfHmac + "and" + this.hmac; } else { + this.kdfHmac = null; + this.hmac = null; + this.keyLength = -1; this.macSalt = macData[1].getOctetString(); if (macData.length > 2) { this.iterations = macData[2].getInteger(); @@ -106,70 +127,14 @@ class MacData { this.iterations = 1; } // Remove "-" from digest algorithm names - this.macAlgorithm = "HmacPBE" - + this.digestAlgorithmName.replace("-", ""); - } - } - - MacData(String algName, byte[] digest, AlgorithmParameterSpec params, - String kdfHmac, String hmac, int keyLength) - throws NoSuchAlgorithmException { - AlgorithmId algid; - - if (algName == null) { - throw new NullPointerException("the algName parameter " + - "must be non-null"); - } - if (algName.equals("PBMAC1")) { - this.pbmac1Keystore = true; - } - algid = AlgorithmId.get(algName); - - this.digestAlgorithmName = algid.getName(); - - if (digest == null) { - throw new NullPointerException("the digest " + - "parameter must be non-null"); - } else if (digest.length == 0) { - throw new IllegalArgumentException("the digest " + - "parameter must not be empty"); - } else { - this.digest = digest.clone(); - } - - if (!(params instanceof PBEParameterSpec p)) { - throw new IllegalArgumentException("unsupported parameter spec"); - } - - if (this.pbmac1Keystore) { - this.macSalt = p.getSalt(); - this.iterations = p.getIterationCount(); - this.kdfHmac = kdfHmac; - this.hmac = hmac; - this.keyLength = keyLength; - } else { - this.macSalt = p.getSalt(); - this.iterations = p.getIterationCount(); - this.kdfHmac = null; - this.hmac = null; - this.keyLength = 0; - } - } - - /* - * Destroy the key obtained from getPBEKey(). - */ - static void destroyPBEKey(SecretKey key) { - try { - key.destroy(); - } catch (DestroyFailedException e) { - // Accept this + this.macAlgorithm = "hmacpbe" + + digestAlgorithmName.replace("-", ""); } } private static Mac getMac(String macAlgorithm, char[] password, PBEParameterSpec params, byte[] data, - String kdfHmac, String hmac) + String kdfHmac, String hmac, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException { SecretKeyFactory skf; @@ -177,14 +142,14 @@ private static Mac getMac(String macAlgorithm, char[] password, Mac m; PBEKeySpec keySpec; - if (macAlgorithm.startsWith("PBEWith")) { + if (macAlgorithm.startsWith("pbewith")) { m = Mac.getInstance(hmac); - int keyLength = m.getMacLength()*8; + int len = keyLength == 0 ? m.getMacLength()*8 : keyLength; skf = SecretKeyFactory.getInstance("PBKDF2With" +kdfHmac); keySpec = new PBEKeySpec(password, params.getSalt(), - params.getIterationCount(), keyLength); + params.getIterationCount(), len); pbeKey = skf.generateSecret(new PBEKeySpec(password, - params.getSalt(), params.getIterationCount(), keyLength)); + params.getSalt(), params.getIterationCount(), len)); } else { hmac = macAlgorithm; m = Mac.getInstance(hmac); @@ -195,27 +160,28 @@ private static Mac getMac(String macAlgorithm, char[] password, keySpec.clearPassword(); try { - if (macAlgorithm.startsWith("PBEWith")) { + if (macAlgorithm.startsWith("pbewith")) { m.init(pbeKey); } else { m.init(pbeKey, params); } } finally { - destroyPBEKey(pbeKey); + sun.security.util.KeyUtil.destroySecretKeys(pbeKey); } m.update(data); return m; } - void processMacData(PBEParameterSpec params, char[] password, - byte[] data, String macAlgorithm) throws InvalidKeySpecException, + void processMacData(char[] password, byte[] data) + throws InvalidKeySpecException, NoSuchAlgorithmException, UnrecoverableKeyException, InvalidKeyException, InvalidAlgorithmParameterException { Mac m; byte[] macResult; - m = getMac(macAlgorithm, password, params, data, this.kdfHmac, - this.hmac); + m = getMac(this.macAlgorithm, password, + new PBEParameterSpec(this.macSalt, this.iterations), + data, this.kdfHmac, this.hmac, this.keyLength); macResult = m.doFinal(); if (debug != null) { @@ -241,39 +207,37 @@ static byte[] calculateMac(char[] passwd, byte[] data, throws IOException, NoSuchAlgorithmException { final byte[] mData; final PBEParameterSpec params; - final MacData macData; String algName = "PBMAC1"; String kdfHmac; String hmac; Mac m; int keyLength; - if (macAlgorithm.startsWith("PBEWith")) { + macAlgorithm = macAlgorithm.toLowerCase(ENGLISH); + if (macAlgorithm.startsWith("pbewith")) { kdfHmac = MacData.parseKdfHmac(macAlgorithm); hmac = MacData.parseHmac(macAlgorithm); if (hmac == null) { hmac = kdfHmac; } - } else if (macAlgorithm.startsWith("HmacPBE")) { + } else if (macAlgorithm.startsWith("hmacpbe")) { algName = macAlgorithm.substring(7); kdfHmac = macAlgorithm; hmac = macAlgorithm; } else { - throw new ParsingException("unexpected algorithm"); + throw new ParsingException("unexpected algorithm '" + +macAlgorithm+ "'"); } params = new PBEParameterSpec(salt, macIterationCount); try { - m = getMac(macAlgorithm, passwd, params, data, kdfHmac, hmac); + m = getMac(macAlgorithm, passwd, params, data, kdfHmac, hmac, 0); byte[] macResult = m.doFinal(); - keyLength = m.getMacLength()*8; - // encode as MacData - macData = new MacData(algName, macResult, params, - kdfHmac, hmac, keyLength); DerOutputStream bytes = new DerOutputStream(); - bytes.write(macData.getEncoded()); + bytes.write(encode(algName, macResult, params, kdfHmac, hmac, + m.getMacLength())); mData = bytes.toByteArray(); } catch (InvalidKeySpecException | InvalidKeyException | InvalidAlgorithmParameterException e) { @@ -297,90 +261,19 @@ int getIterations() { /** * Returns the ASN.1 encoding of this object. * @return the ASN.1 encoding. - * @exception IOException if error occurs when constructing its + * @exception NoSuchAlgorithmException if error occurs when constructing its * ASN.1 encoding. */ - byte[] getEncoded() throws NoSuchAlgorithmException, IOException { - if (this.pbmac1Keystore) { - ObjectIdentifier pkcs5PBKDF2_OID = - ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - - byte[] not_used = { 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }; - - DerOutputStream out = new DerOutputStream(); - DerOutputStream tmp0 = new DerOutputStream(); - DerOutputStream tmp1 = new DerOutputStream(); - DerOutputStream tmp2 = new DerOutputStream(); - DerOutputStream tmp3 = new DerOutputStream(); - DerOutputStream tmp4 = new DerOutputStream(); - DerOutputStream hmac = new DerOutputStream(); - DerOutputStream kdfHmac = new DerOutputStream(); - - // encode kdfHmac algorithm - kdfHmac.putOID(ObjectIdentifier.of(KnownOIDs - .findMatch(this.kdfHmac))); - kdfHmac.putNull(); - - // encode Hmac algorithm - hmac.putOID(ObjectIdentifier.of(KnownOIDs.findMatch(this.hmac))); - hmac.putNull(); - - DerOutputStream pBKDF2_params = new DerOutputStream(); - - pBKDF2_params.putOctetString(this.macSalt); // choice: 'specified OCTET STRING' - - // encode iterations - pBKDF2_params.putInteger(this.iterations); - - // encode derived key length - if (this.keyLength > 0) { - pBKDF2_params.putInteger(this.keyLength / 8); // derived key length (in octets) - } - pBKDF2_params.write(DerValue.tag_Sequence, kdfHmac); - tmp3.putOID(pkcs5PBKDF2_OID); - tmp3.write(DerValue.tag_Sequence, pBKDF2_params); - tmp4.write(DerValue.tag_Sequence, tmp3); - tmp4.write(DerValue.tag_Sequence, hmac); - - tmp1.putOID(ObjectIdentifier.of(KnownOIDs .findMatch("PBMAC1"))); - - tmp1.write(DerValue.tag_Sequence, tmp4); - tmp2.write(DerValue.tag_Sequence, tmp1); - tmp2.putOctetString(this.digest); - tmp0.write(DerValue.tag_Sequence, tmp2); - tmp0.putOctetString(not_used); - tmp0.putInteger(1); - out.write(DerValue.tag_Sequence, tmp0); - return out.toByteArray(); - } - - DerOutputStream out = new DerOutputStream(); - DerOutputStream tmp = new DerOutputStream(); - - DerOutputStream tmp2 = new DerOutputStream(); - // encode encryption algorithm - AlgorithmId algid = AlgorithmId.get(this.digestAlgorithmName); - algid.encode(tmp2); - - // encode digest data - tmp2.putOctetString(this.digest); - - tmp.write(DerValue.tag_Sequence, tmp2); - - // encode salt - tmp.putOctetString(this.macSalt); - - // encode iterations - tmp.putInteger(this.iterations); - - // wrap everything into a SEQUENCE - out.write(DerValue.tag_Sequence, tmp); - return out.toByteArray(); + static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, + String kdfHmac, String hmac, int keyLength) + throws NoSuchAlgorithmException { + return PBMAC1Parameters.encode(algName, p.getSalt(), + p.getIterationCount(), keyLength, kdfHmac, hmac, digest); } - public static String parseKdfHmac(String text) { - int index1 = text.indexOf("With") + 4; - int index2 = text.indexOf("And"); + private static String parseKdfHmac(String text) { + int index1 = text.indexOf("with") + 4; + int index2 = text.indexOf("and"); if (index1 == 3) { // -1 + 4 return null; } else if (index2 == -1) { @@ -390,8 +283,8 @@ public static String parseKdfHmac(String text) { } } - public static String parseHmac(String text) { - int index1 = text.indexOf("And") + 3; + private static String parseHmac(String text) { + int index1 = text.indexOf("and") + 3; if (index1 == 2) { // -1 + 3 return null; } else { diff --git a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java index d791d075840b0..5959e1ecf7199 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java @@ -26,7 +26,9 @@ package sun.security.pkcs12; import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import sun.security.x509.AlgorithmId; import sun.security.util.*; /** @@ -60,13 +62,13 @@ */ final class PBMAC1Parameters { + static final ObjectIdentifier pkcs5PBKDF2_OID = + ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + private final String hmacAlgo; private final PBKDF2Parameters kdfParams; - // length of key generated by the kdf - private final int keyLength; - - public PBMAC1Parameters(byte[] encoded) throws IOException { + PBMAC1Parameters(byte[] encoded) throws IOException { DerValue pBMAC1_params = new DerValue(encoded); if (pBMAC1_params.tag != DerValue.tag_Sequence) { throw new IOException("PBMAC1 parameter parsing error: " @@ -95,21 +97,54 @@ public PBMAC1Parameters(byte[] encoded) throws IOException { this.hmacAlgo = o.stdName(); DerValue kdf = pBMAC1_params.data.getDerValue(); - this.kdfParams = new PBKDF2Parameters(kdf); - // Key length must be present even though it is not used. - keyLength = kdfParams.getKeyLength(); - if (keyLength == -1) { - throw new IOException("PBMAC1 parameter parsing " - + "error: missing keyLength field"); + if (!pkcs5PBKDF2_OID.equals(kdf.data.getOID())) { + throw new IOException("PBKDF2 parameter parsing error: " + + "expecting the object identifier for PBKDF2"); + } + if (kdf.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue pBKDF2_params = kdf.data.getDerValue(); + if (pBKDF2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + + this.kdfParams = new PBKDF2Parameters(pBKDF2_params); + } + + static byte[] encode(String algName, byte[] salt, int iterationCount, int keyLength, + String kdfHmac, String hmac, byte[] digest) throws NoSuchAlgorithmException { + if (algName.equals("PBMAC1")) { + return new DerOutputStream().write(DerValue.tag_Sequence, new DerOutputStream() + .write(DerValue.tag_Sequence, new DerOutputStream() + .write(DerValue.tag_Sequence, new DerOutputStream() + .putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)) + .write(DerValue.tag_Sequence, new DerOutputStream() + .write(DerValue.tag_Sequence, PBKDF2Parameters.encode(salt, iterationCount, keyLength, kdfHmac)) + .write(DerValue.tag_Sequence, new DerOutputStream() + .putOID(ObjectIdentifier.of(KnownOIDs.findMatch(hmac))) + .putNull()))) + .putOctetString(digest)) + .putOctetString(new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }) + .putInteger(1)).toByteArray(); + } else { + return new DerOutputStream() + .write(DerValue.tag_Sequence, new DerOutputStream() + .write(DerValue.tag_Sequence, new DerOutputStream() + .write(AlgorithmId.get(algName)).putOctetString(digest)) + .putOctetString(salt) + .putInteger(iterationCount)).toByteArray(); } } - public PBKDF2Parameters getKdfParams() { + PBKDF2Parameters getKdfParams() { return this.kdfParams; } - public String getHmac() { + String getHmac() { return this.hmacAlgo; } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 8481c6656cc8e..9e019f0217f5c 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -2082,10 +2082,8 @@ public synchronized void engineLoad(InputStream stream, char[] password) // Store MAC algorithm of keystore that was just loaded. macAlgorithm = macData.getMacAlgorithm(); macIterationCount = ic; - PBEParameterSpec params = new PBEParameterSpec(salt, ic); RetryWithZero.run(pass -> { - macData.processMacData(params, pass, authSafeData, - macData.getMacAlgorithm()); + macData.processMacData(pass, authSafeData); return (Void) null; }, password); } catch (Exception e) { diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java index 7a58ac0d4e9ab..dd27b5f02d800 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -40,6 +40,7 @@ import javax.security.auth.DestroyFailedException; import jdk.internal.access.SharedSecrets; +import com.sun.crypto.provider.PBKDF2KeyImpl; import sun.security.jca.JCAUtil; import sun.security.x509.AlgorithmId; @@ -469,6 +470,8 @@ public static void destroySecretKeys(SecretKey... keys) { if (k instanceof SecretKeySpec sk) { SharedSecrets.getJavaxCryptoSpecAccess() .clearSecretKeySpec(sk); + } else if (k instanceof PBKDF2KeyImpl p2k) { + p2k.clear(); } else { try { k.destroy(); diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 10a2f27d4f9cb..5e98a72f4fcaa 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -70,33 +70,25 @@ */ public final class PBKDF2Parameters { - public static final ObjectIdentifier pkcs5PBKDF2_OID = - ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); - private final byte[] salt; private final int iterationCount; // keyLength in bits, or -1 if not present - private int keyLength = -1; + private final int keyLength; - private String prfAlgo = "HmacSHA1"; + private String prfAlgo; - public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { + /** + * Initialize PBKDF2Parameters from a DER encoded + * parameter block. + * + * @param keyDerivationFunc the DER encoding of the parameter block + * + * @throws IOException for parsing errors in the input stream + */ + public PBKDF2Parameters(DerValue pBKDF2_params) throws IOException { - if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { - throw new IOException("PBKDF2 parameter parsing error: " - + "expecting the object identifier for PBKDF2"); - } - if (keyDerivationFunc.tag != DerValue.tag_Sequence) { - throw new IOException("PBKDF2 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } - DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); - if (pBKDF2_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBKDF2 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } DerValue specified = pBKDF2_params.data.getDerValue(); // the 'specified' ASN.1 CHOICE for 'salt' is supported if (specified.tag == DerValue.tag_OctetString) { @@ -112,6 +104,8 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); if (ksDer.isPresent()) { keyLength = ksDer.get().getInteger() * 8; // keyLength (in bits) + } else { + keyLength = -1; } // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 @@ -135,9 +129,32 @@ public PBKDF2Parameters(DerValue keyDerivationFunc) throws IOException { prfAlgo = o.stdName(); prf.data.getOptional(DerValue.tag_Null); prf.data.atEnd(); + } else { + prfAlgo = "HmacSHA1"; } } + public static byte[] encode(byte[] salt, int iterationCount, + int keyLength, String kdfHmac) { + ObjectIdentifier kdfAlgo_OID = + ObjectIdentifier.of(KnownOIDs.findMatch(kdfHmac)); + return PBKDF2Parameters.encode(salt, iterationCount, keyLength, + kdfAlgo_OID); + } + + public static byte[] encode(byte[] salt, int iterationCount, + int keyLength, ObjectIdentifier kdfAlgo_OID) { + return new DerOutputStream() + .putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1)) + .write(DerValue.tag_Sequence, new DerOutputStream() + .putOctetString(salt) + .putInteger(iterationCount) + .putInteger(keyLength) + .write(DerValue.tag_Sequence, new DerOutputStream() + .putOID(kdfAlgo_OID) + .putNull())).toByteArray(); + } + /** * Returns the salt. * From 824bf0cddb329af4f8f2d9d38d360ca21bf69930 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 16 Oct 2025 11:28:17 -0600 Subject: [PATCH 24/30] checkpoint --- .../sun/crypto/provider/PBES2Parameters.java | 11 ++-- .../classes/sun/security/pkcs12/MacData.java | 65 ++++++++++--------- .../sun/security/pkcs12/PBMAC1Parameters.java | 36 ++++------ .../sun/security/pkcs12/PKCS12KeyStore.java | 20 ++---- .../sun/security/util/PBKDF2Parameters.java | 9 +-- 5 files changed, 65 insertions(+), 76 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index 12a2321455896..db0ba78896450 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -225,6 +225,10 @@ protected void engineInit(byte[] encoded) // next DerValue as the real PBES2-params. if (kdf.getTag() == DerValue.tag_ObjectId) { pBES2_params = pBES2_params.data.getDerValue(); + if (pBES2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } kdf = pBES2_params.data.getDerValue(); } @@ -248,10 +252,6 @@ protected void engineInit(byte[] encoded) iCount = kdfParams.getIterationCount(); keysize = kdfParams.getKeyLength(); - if (pBES2_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBE parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } String cipherAlgo = parseES(pBES2_params.data.getDerValue()); this.pbes2AlgorithmName = "PBEWith" + kdfAlgo + "And" + cipherAlgo; @@ -305,7 +305,8 @@ protected byte[] engineGetEncoded() throws IOException { DerOutputStream pBES2_params = new DerOutputStream(); pBES2_params.write(DerValue.tag_Sequence, - PBKDF2Parameters.encode(salt, iCount, keysize, kdfAlgo_OID)); + // keysize encoded as octets + PBKDF2Parameters.encode(salt, iCount, keysize/8, kdfAlgo_OID)); DerOutputStream encryptionScheme = new DerOutputStream(); // algorithm is id-aes128-CBC or id-aes256-CBC diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 349452829ec2c..d85cbdeadb977 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -43,8 +43,6 @@ /** * The MacData type, as defined in PKCS#12. * - * @author Sharon Liu - * * The ASN.1 definition is as follows: * *
@@ -63,6 +61,8 @@
  * }
  *
  * 
+ * + * @author Sharon Liu */ class MacData { @@ -132,7 +132,7 @@ class MacData { } } - private static Mac getMac(String macAlgorithm, char[] password, + private static byte[] getMac(String macAlgorithm, char[] password, PBEParameterSpec params, byte[] data, String kdfHmac, String hmac, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException, @@ -142,22 +142,22 @@ private static Mac getMac(String macAlgorithm, char[] password, Mac m; PBEKeySpec keySpec; + + // The Hmac has to be extracted from the algorithm name for + // PBMAC1 algorithms. For non-PBMAC1 macAlgorithms, the name + // and Hmac are the same. if (macAlgorithm.startsWith("pbewith")) { m = Mac.getInstance(hmac); - int len = keyLength == 0 ? m.getMacLength()*8 : keyLength; + int len = keyLength == -1 ? m.getMacLength()*8 : keyLength; skf = SecretKeyFactory.getInstance("PBKDF2With" +kdfHmac); keySpec = new PBEKeySpec(password, params.getSalt(), params.getIterationCount(), len); - pbeKey = skf.generateSecret(new PBEKeySpec(password, - params.getSalt(), params.getIterationCount(), len)); } else { - hmac = macAlgorithm; - m = Mac.getInstance(hmac); - keySpec = new PBEKeySpec(password); + m = Mac.getInstance(macAlgorithm); skf = SecretKeyFactory.getInstance("PBE"); - pbeKey = skf.generateSecret(keySpec); + keySpec = new PBEKeySpec(password); } - keySpec.clearPassword(); + pbeKey = skf.generateSecret(keySpec); try { if (macAlgorithm.startsWith("pbewith")) { @@ -166,27 +166,25 @@ private static Mac getMac(String macAlgorithm, char[] password, m.init(pbeKey, params); } } finally { + keySpec.clearPassword(); sun.security.util.KeyUtil.destroySecretKeys(pbeKey); } m.update(data); - return m; + return m.doFinal(); } void processMacData(char[] password, byte[] data) throws InvalidKeySpecException, NoSuchAlgorithmException, UnrecoverableKeyException, InvalidKeyException, InvalidAlgorithmParameterException { - Mac m; - byte[] macResult; - m = getMac(this.macAlgorithm, password, + byte[] macResult = getMac(this.macAlgorithm, password, new PBEParameterSpec(this.macSalt, this.iterations), data, this.kdfHmac, this.hmac, this.keyLength); - macResult = m.doFinal(); if (debug != null) { debug.println("Checking keystore integrity " + - "(" + m.getAlgorithm() + " iterations: " + "(" + this.macAlgorithm + " iterations: " + this.iterations + ")"); } @@ -205,16 +203,15 @@ void processMacData(char[] password, byte[] data) static byte[] calculateMac(char[] passwd, byte[] data, String macAlgorithm, int macIterationCount, byte[] salt) throws IOException, NoSuchAlgorithmException { - final byte[] mData; final PBEParameterSpec params; - String algName = "PBMAC1"; + String algName; String kdfHmac; String hmac; Mac m; - int keyLength; macAlgorithm = macAlgorithm.toLowerCase(ENGLISH); if (macAlgorithm.startsWith("pbewith")) { + algName = "PBMAC1"; kdfHmac = MacData.parseKdfHmac(macAlgorithm); hmac = MacData.parseHmac(macAlgorithm); if (hmac == null) { @@ -222,28 +219,27 @@ static byte[] calculateMac(char[] passwd, byte[] data, } } else if (macAlgorithm.startsWith("hmacpbe")) { algName = macAlgorithm.substring(7); - kdfHmac = macAlgorithm; + kdfHmac = null; hmac = macAlgorithm; } else { throw new ParsingException("unexpected algorithm '" - +macAlgorithm+ "'"); + + macAlgorithm + "'"); } params = new PBEParameterSpec(salt, macIterationCount); try { - m = getMac(macAlgorithm, passwd, params, data, kdfHmac, hmac, 0); - byte[] macResult = m.doFinal(); + byte[] macResult = getMac(macAlgorithm, passwd, params, data, + kdfHmac, hmac, -1); DerOutputStream bytes = new DerOutputStream(); bytes.write(encode(algName, macResult, params, kdfHmac, hmac, - m.getMacLength())); - mData = bytes.toByteArray(); + macResult.length)); + return bytes.toByteArray(); } catch (InvalidKeySpecException | InvalidKeyException | InvalidAlgorithmParameterException e) { throw new IOException("calculateMac failed: " + e, e); } - return mData; } String getMacAlgorithm() { @@ -267,8 +263,19 @@ int getIterations() { static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, String kdfHmac, String hmac, int keyLength) throws NoSuchAlgorithmException { - return PBMAC1Parameters.encode(algName, p.getSalt(), - p.getIterationCount(), keyLength, kdfHmac, hmac, digest); + if (algName.equals("PBMAC1")) { + return PBMAC1Parameters.encode(p.getSalt(), p.getIterationCount(), + keyLength, kdfHmac, hmac, digest); + } else { + byte[] bytes = new DerOutputStream() + .write(DerValue.tag_Sequence, new DerOutputStream() + .write(DerValue.tag_Sequence, new DerOutputStream() + .write(AlgorithmId.get(algName)) + .putOctetString(digest)) + .putOctetString(p.getSalt()) + .putInteger(p.getIterationCount())).toByteArray(); + return bytes; + } } private static String parseKdfHmac(String text) { diff --git a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java index 5959e1ecf7199..8fa1501752f13 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java @@ -96,7 +96,8 @@ final class PBMAC1Parameters { // Hmac function used to compute the MAC this.hmacAlgo = o.stdName(); - DerValue kdf = pBMAC1_params.data.getDerValue(); + //DerValue kdf = pBMAC1_params.data.getDerValue(); + DerValue kdf = info[0]; if (!pkcs5PBKDF2_OID.equals(kdf.data.getOID())) { throw new IOException("PBKDF2 parameter parsing error: " @@ -115,29 +116,20 @@ final class PBMAC1Parameters { this.kdfParams = new PBKDF2Parameters(pBKDF2_params); } - static byte[] encode(String algName, byte[] salt, int iterationCount, int keyLength, + static byte[] encode(byte[] salt, int iterationCount, int keyLength, String kdfHmac, String hmac, byte[] digest) throws NoSuchAlgorithmException { - if (algName.equals("PBMAC1")) { - return new DerOutputStream().write(DerValue.tag_Sequence, new DerOutputStream() - .write(DerValue.tag_Sequence, new DerOutputStream() - .write(DerValue.tag_Sequence, new DerOutputStream() - .putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)) - .write(DerValue.tag_Sequence, new DerOutputStream() - .write(DerValue.tag_Sequence, PBKDF2Parameters.encode(salt, iterationCount, keyLength, kdfHmac)) - .write(DerValue.tag_Sequence, new DerOutputStream() - .putOID(ObjectIdentifier.of(KnownOIDs.findMatch(hmac))) - .putNull()))) - .putOctetString(digest)) - .putOctetString(new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }) - .putInteger(1)).toByteArray(); - } else { - return new DerOutputStream() - .write(DerValue.tag_Sequence, new DerOutputStream() + return new DerOutputStream().write(DerValue.tag_Sequence, new DerOutputStream() + .write(DerValue.tag_Sequence, new DerOutputStream() .write(DerValue.tag_Sequence, new DerOutputStream() - .write(AlgorithmId.get(algName)).putOctetString(digest)) - .putOctetString(salt) - .putInteger(iterationCount)).toByteArray(); - } + .putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)) + .write(DerValue.tag_Sequence, new DerOutputStream() + .write(DerValue.tag_Sequence, PBKDF2Parameters.encode(salt, iterationCount, keyLength, kdfHmac)) + .write(DerValue.tag_Sequence, new DerOutputStream() + .putOID(ObjectIdentifier.of(KnownOIDs.findMatch(hmac))) + .putNull()))) + .putOctetString(digest)) + .putOctetString(new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }) + .putInteger(1)).toByteArray(); } PBKDF2Parameters getKdfParams() { diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 9e019f0217f5c..440fcbf97122b 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -350,7 +350,7 @@ private Key internalGetKey(Entry entry, char[] password) try { cipher.init(Cipher.DECRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + sun.security.util.KeyUtil.destroySecretKeys(skey); } byte[] keyInfo = cipher.doFinal(encryptedKey); /* @@ -839,17 +839,6 @@ private SecretKey getPBEKey(char[] password) throws IOException return skey; } - /* - * Destroy the key obtained from getPBEKey(). - */ - private void destroyPBEKey(SecretKey key) { - try { - key.destroy(); - } catch (DestroyFailedException e) { - // Accept this - } - } - /* * Encrypt private key or secret key using Password-based encryption (PBE) * as defined in PKCS#5. @@ -899,7 +888,7 @@ private byte[] encryptPrivateKey(byte[] data, try { cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + sun.security.util.KeyUtil.destroySecretKeys(skey); } byte[] encryptedKey = cipher.doFinal(data); algid = new AlgorithmId(pbeOID, cipher.getParameters()); @@ -1833,7 +1822,7 @@ private byte[] encryptContent(byte[] data, char[] password) try { cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + sun.security.util.KeyUtil.destroySecretKeys(skey); } encryptedData = cipher.doFinal(data); @@ -2043,7 +2032,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) try { cipher.init(Cipher.DECRYPT_MODE, skey, algParams); } finally { - destroyPBEKey(skey); + sun.security.util.KeyUtil.destroySecretKeys(skey); } loadSafeContents(new DerInputStream(cipher.doFinal(rawData))); return null; @@ -2071,7 +2060,6 @@ public synchronized void engineLoad(InputStream stream, char[] password) if (password != null) { MacData macData = new MacData(s); int ic = macData.getIterations(); - byte[] salt = macData.getSalt(); try { if (ic > MAX_ITERATION_COUNT) { diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 5e98a72f4fcaa..97e3cce19417b 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -77,14 +77,14 @@ public final class PBKDF2Parameters { // keyLength in bits, or -1 if not present private final int keyLength; - private String prfAlgo; + private final String prfAlgo; /** * Initialize PBKDF2Parameters from a DER encoded * parameter block. - * - * @param keyDerivationFunc the DER encoding of the parameter block - * + * + * @param pBKDF2_params the DER encoding of the parameter block + * * @throws IOException for parsing errors in the input stream */ public PBKDF2Parameters(DerValue pBKDF2_params) throws IOException { @@ -144,6 +144,7 @@ public static byte[] encode(byte[] salt, int iterationCount, public static byte[] encode(byte[] salt, int iterationCount, int keyLength, ObjectIdentifier kdfAlgo_OID) { + assert keyLength != -1; return new DerOutputStream() .putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1)) .write(DerValue.tag_Sequence, new DerOutputStream() From 96a03e6ca1df7e7775c441d4c4b2952e3640d5e7 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Wed, 22 Oct 2025 13:54:59 -0600 Subject: [PATCH 25/30] stragglers --- .../classes/sun/security/pkcs12/MacData.java | 32 ++++++++---- .../sun/security/pkcs12/PBMAC1Parameters.java | 52 +++++++++++++------ .../sun/security/util/PBKDF2Parameters.java | 38 +++++++++----- .../share/conf/security/java.security | 5 +- 4 files changed, 86 insertions(+), 41 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index d85cbdeadb977..cad96c76340c4 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -207,7 +207,6 @@ static byte[] calculateMac(char[] passwd, byte[] data, String algName; String kdfHmac; String hmac; - Mac m; macAlgorithm = macAlgorithm.toLowerCase(ENGLISH); if (macAlgorithm.startsWith("pbewith")) { @@ -262,19 +261,30 @@ int getIterations() { */ static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, String kdfHmac, String hmac, int keyLength) - throws NoSuchAlgorithmException { + throws NoSuchAlgorithmException, IOException { + final int iterations = p.getIterationCount(); + final byte[] macSalt = p.getSalt(); + if (algName.equals("PBMAC1")) { - return PBMAC1Parameters.encode(p.getSalt(), p.getIterationCount(), + return PBMAC1Parameters.encode(macSalt, iterations, keyLength, kdfHmac, hmac, digest); } else { - byte[] bytes = new DerOutputStream() - .write(DerValue.tag_Sequence, new DerOutputStream() - .write(DerValue.tag_Sequence, new DerOutputStream() - .write(AlgorithmId.get(algName)) - .putOctetString(digest)) - .putOctetString(p.getSalt()) - .putInteger(p.getIterationCount())).toByteArray(); - return bytes; + final AlgorithmId digestAlgorithm = AlgorithmId.get(algName); + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp = new DerOutputStream(); + DerOutputStream tmp2 = new DerOutputStream(); + + tmp2.write(digestAlgorithm); + tmp2.putOctetString(digest); + + // wrap into a SEQUENCE + tmp.write(DerValue.tag_Sequence, tmp2); + tmp.putOctetString(macSalt); + tmp.putInteger(iterations); + + // wrap everything into a SEQUENCE + out.write(DerValue.tag_Sequence, tmp); + return out.toByteArray(); } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java index 8fa1501752f13..9606ce4bbb63b 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java @@ -26,9 +26,7 @@ package sun.security.pkcs12; import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import sun.security.x509.AlgorithmId; import sun.security.util.*; /** @@ -116,20 +114,44 @@ final class PBMAC1Parameters { this.kdfParams = new PBKDF2Parameters(pBKDF2_params); } + /* + * Encode PBMAC1 parameters from components. + */ static byte[] encode(byte[] salt, int iterationCount, int keyLength, - String kdfHmac, String hmac, byte[] digest) throws NoSuchAlgorithmException { - return new DerOutputStream().write(DerValue.tag_Sequence, new DerOutputStream() - .write(DerValue.tag_Sequence, new DerOutputStream() - .write(DerValue.tag_Sequence, new DerOutputStream() - .putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)) - .write(DerValue.tag_Sequence, new DerOutputStream() - .write(DerValue.tag_Sequence, PBKDF2Parameters.encode(salt, iterationCount, keyLength, kdfHmac)) - .write(DerValue.tag_Sequence, new DerOutputStream() - .putOID(ObjectIdentifier.of(KnownOIDs.findMatch(hmac))) - .putNull()))) - .putOctetString(digest)) - .putOctetString(new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }) - .putInteger(1)).toByteArray(); + String kdfHmac, String hmac, byte[] digest) { + + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp0 = new DerOutputStream(); + DerOutputStream tmp1 = new DerOutputStream(); + DerOutputStream tmp2 = new DerOutputStream(); + DerOutputStream tmp3 = new DerOutputStream(); + DerOutputStream tmp4 = new DerOutputStream(); + + // messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} + tmp4.putOID(ObjectIdentifier.of(KnownOIDs.findMatch(hmac))); + tmp4.putNull(); + + // keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}} + tmp3.write(DerValue.tag_Sequence, PBKDF2Parameters.encode(salt, + iterationCount, keyLength, kdfHmac)); + tmp3.write(DerValue.tag_Sequence, tmp4); + + // id-PBMAC1 OBJECT IDENTIFIER ::= { pkcs-5 14 } + tmp2.putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)); + tmp2.write(DerValue.tag_Sequence, tmp3); + + tmp1.write(DerValue.tag_Sequence, tmp2); + tmp1.putOctetString(digest); + + tmp0.write(DerValue.tag_Sequence, tmp1); + tmp0.putOctetString( + new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }); + // Unused, but must have non-zero positive value. + tmp0.putInteger(1); + + // wrap everything into a SEQUENCE + out.write(DerValue.tag_Sequence, tmp0); + return out.toByteArray(); } PBKDF2Parameters getKdfParams() { diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 97e3cce19417b..fe5c748708593 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -136,24 +136,36 @@ public PBKDF2Parameters(DerValue pBKDF2_params) throws IOException { public static byte[] encode(byte[] salt, int iterationCount, int keyLength, String kdfHmac) { - ObjectIdentifier kdfAlgo_OID = + ObjectIdentifier prf = ObjectIdentifier.of(KnownOIDs.findMatch(kdfHmac)); - return PBKDF2Parameters.encode(salt, iterationCount, keyLength, - kdfAlgo_OID); + return PBKDF2Parameters.encode(salt, iterationCount, keyLength, prf); } + /* + * Encode PBKDF2 parameters from components. + */ public static byte[] encode(byte[] salt, int iterationCount, - int keyLength, ObjectIdentifier kdfAlgo_OID) { + int keyLength, ObjectIdentifier prf) { assert keyLength != -1; - return new DerOutputStream() - .putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1)) - .write(DerValue.tag_Sequence, new DerOutputStream() - .putOctetString(salt) - .putInteger(iterationCount) - .putInteger(keyLength) - .write(DerValue.tag_Sequence, new DerOutputStream() - .putOID(kdfAlgo_OID) - .putNull())).toByteArray(); + + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp0 = new DerOutputStream(); + DerOutputStream tmp1 = new DerOutputStream(); + + // prf AlgorithmIdentifier {{PBKDF2-PRFs}} + tmp1.putOID(prf); + tmp1.putNull(); + + tmp0.putOctetString(salt); + tmp0.putInteger(iterationCount); + tmp0.putInteger(keyLength); + tmp0.write(DerValue.tag_Sequence, tmp1); + + // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} + out.putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1)); + out.write(DerValue.tag_Sequence, tmp0); + + return out.toByteArray(); } /** diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 32d1ddaf0f7a8..9a0d6c77e7960 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1314,8 +1314,9 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep #keystore.pkcs12.keyPbeIterationCount = 10000 # 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", +# file. This can be any HmacPBE or PBEWith algorithm defined in the +# Mac section of the Java Security Standard Algorithm Names Specification, +# for example, HmacPBESHA256 or PBEWithHmacSHA256. When set to "NONE", # no Mac is generated. The default value is "HmacPBESHA256". #keystore.pkcs12.macAlgorithm = HmacPBESHA256 From 69d7c291fb3c0c3689b48e0863bd8f3aba300414 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 24 Oct 2025 19:28:58 -0600 Subject: [PATCH 26/30] Weijun code review comments --- .../sun/crypto/provider/PBES2Parameters.java | 11 +- .../classes/sun/security/pkcs12/MacData.java | 101 ++++++--- .../sun/security/pkcs12/PBMAC1Parameters.java | 20 +- .../sun/security/pkcs12/PKCS12KeyStore.java | 12 +- .../sun/security/util/PBKDF2Parameters.java | 17 +- .../share/conf/security/java.security | 4 +- test/jdk/sun/security/pkcs12/PBMAC1Test.java | 199 ++++++++++++++++++ 7 files changed, 303 insertions(+), 61 deletions(-) create mode 100644 test/jdk/sun/security/pkcs12/PBMAC1Test.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index db0ba78896450..532f87caef94b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -241,10 +241,6 @@ protected void engineInit(byte[] encoded) + "not an ASN.1 SEQUENCE tag"); } DerValue pBKDF2_params = kdf.data.getDerValue(); - if (pBKDF2_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBKDF2 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } var kdfParams = new PBKDF2Parameters(pBKDF2_params); String kdfAlgo = kdfParams.getPrfAlgo(); @@ -304,9 +300,10 @@ protected byte[] engineGetEncoded() throws IOException { DerOutputStream out = new DerOutputStream(); DerOutputStream pBES2_params = new DerOutputStream(); - pBES2_params.write(DerValue.tag_Sequence, - // keysize encoded as octets - PBKDF2Parameters.encode(salt, iCount, keysize/8, kdfAlgo_OID)); + + // keysize encoded as octets + pBES2_params.writeBytes(PBKDF2Parameters.encode(salt, iCount, + keysize/8, kdfAlgo_OID)); DerOutputStream encryptionScheme = new DerOutputStream(); // algorithm is id-aes128-CBC or id-aes256-CBC diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index cad96c76340c4..619772954e070 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -72,6 +72,8 @@ class MacData { private final byte[] digest; private final byte[] macSalt; private final int iterations; + + // The following three fields are for PBMAC1. private final int keyLength; private final String kdfHmac; private final String hmac; @@ -132,20 +134,48 @@ class MacData { } } - private static byte[] getMac(String macAlgorithm, char[] password, + /** + * Computes a MAC on the data. + * + * This is a two-step process: first generate a key and then use the + * key to generate the MAC. PBMAC1 and non-PBMAC1 keys use different + * key factories. PBMAC1 uses a pseudorandom function (kdfHmac) + * to generate keys while non-PBMAC1 does not. The MAC is computed + * according to the specified hmac algorithm. + * + * @param macAlgorithm the algorithm used to compute the MAC + * @param password the password used to generate the key + * @param params a PBEParameterSpec object + * @param data the data on which the MAC is computed + * @param kdfHmac the pseudorandom function used to compute the key + * for PBMAC1 + * @param hmac the algorithm used to compute the MAC + * @param keyLength the length of the key generated by the pseudorandom + * function + * + * @return the computed MAC as a byte array + * + * @exception NoSuchAlgorithmException if either kdfHmac or hmac is + * unknown to the Mac or SecretKeyFactory + */ + private static byte[] calculateMac(String macAlgorithm, char[] password, PBEParameterSpec params, byte[] data, String kdfHmac, String hmac, int keyLength) - throws NoSuchAlgorithmException, InvalidKeySpecException, - InvalidKeyException, InvalidAlgorithmParameterException { + throws InvalidAlgorithmParameterException, InvalidKeyException, + InvalidKeySpecException, NoSuchAlgorithmException { SecretKeyFactory skf; - SecretKey pbeKey; + SecretKey pbeKey = null; Mac m; PBEKeySpec keySpec; - // The Hmac has to be extracted from the algorithm name for - // PBMAC1 algorithms. For non-PBMAC1 macAlgorithms, the name - // and Hmac are the same. + /* + * The Hmac has to be extracted from the algorithm name for + * PBMAC1 algorithms. For non-PBMAC1 macAlgorithms, the name + * and Hmac are the same. + * + * The prefix used in Algorithm names is guaranteed to be lowercase. + */ if (macAlgorithm.startsWith("pbewith")) { m = Mac.getInstance(hmac); int len = keyLength == -1 ? m.getMacLength()*8 : keyLength; @@ -157,28 +187,39 @@ private static byte[] getMac(String macAlgorithm, char[] password, skf = SecretKeyFactory.getInstance("PBE"); keySpec = new PBEKeySpec(password); } - pbeKey = skf.generateSecret(keySpec); try { + pbeKey = skf.generateSecret(keySpec); if (macAlgorithm.startsWith("pbewith")) { m.init(pbeKey); } else { m.init(pbeKey, params); } + m.update(data); + return m.doFinal(); } finally { keySpec.clearPassword(); - sun.security.util.KeyUtil.destroySecretKeys(pbeKey); + KeyUtil.destroySecretKeys(pbeKey); } - m.update(data); - return m.doFinal(); } - void processMacData(char[] password, byte[] data) - throws InvalidKeySpecException, - NoSuchAlgorithmException, UnrecoverableKeyException, - InvalidKeyException, InvalidAlgorithmParameterException { + /** + * Verify Mac on the data. + * + * Calculate Mac on the data and compare with Mac found in input stream. + * + * @param password the password used to generate the key + * @param data the data on which the MAC is computed + * + * @exception UnrecoverableKeyException if calculated Mac and + * Mac found in input stream are different + */ + void verifyMac(char[] password, byte[] data) + throws InvalidAlgorithmParameterException, InvalidKeyException, + InvalidKeySpecException, NoSuchAlgorithmException, + UnrecoverableKeyException { - byte[] macResult = getMac(this.macAlgorithm, password, + byte[] macResult = calculateMac(this.macAlgorithm, password, new PBEParameterSpec(this.macSalt, this.iterations), data, this.kdfHmac, this.hmac, this.keyLength); @@ -195,12 +236,19 @@ void processMacData(char[] password, byte[] data) } /* - * Calculate MAC using HMAC algorithm (required for password integrity) + * Gathers parameters and generates a MAC of the data + * + * @param password the password used to generate the key + * @param data the data on which the MAC is computed + * @param macAlgorithm the algorithm used to compute the MAC + * @param macIterationCount the iteration count + * @param salt the salt * - * Hash-based MAC algorithm combines secret key with message digest to - * create a message authentication code (MAC) + * @exception IOException if the MAC cannot be calculated + * + * @return the computed MAC as a byte array */ - static byte[] calculateMac(char[] passwd, byte[] data, + static byte[] generateMac(char[] passwd, byte[] data, String macAlgorithm, int macIterationCount, byte[] salt) throws IOException, NoSuchAlgorithmException { final PBEParameterSpec params; @@ -209,6 +257,7 @@ static byte[] calculateMac(char[] passwd, byte[] data, String hmac; macAlgorithm = macAlgorithm.toLowerCase(ENGLISH); + // The prefix used in Algorithm names is guaranteed to be lowercase. if (macAlgorithm.startsWith("pbewith")) { algName = "PBMAC1"; kdfHmac = MacData.parseKdfHmac(macAlgorithm); @@ -228,7 +277,7 @@ static byte[] calculateMac(char[] passwd, byte[] data, params = new PBEParameterSpec(salt, macIterationCount); try { - byte[] macResult = getMac(macAlgorithm, passwd, params, data, + byte[] macResult = calculateMac(macAlgorithm, passwd, params, data, kdfHmac, hmac, -1); DerOutputStream bytes = new DerOutputStream(); @@ -245,23 +294,19 @@ String getMacAlgorithm() { return this.macAlgorithm; } - byte[] getSalt() { - return this.macSalt; - } - int getIterations() { return this.iterations; } /** - * Returns the ASN.1 encoding of this object. - * @return the ASN.1 encoding. + * Returns the ASN.1 encoding. + * @return the ASN.1 encoding * @exception NoSuchAlgorithmException if error occurs when constructing its * ASN.1 encoding. */ static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, String kdfHmac, String hmac, int keyLength) - throws NoSuchAlgorithmException, IOException { + throws IOException, NoSuchAlgorithmException { final int iterations = p.getIterationCount(); final byte[] macSalt = p.getSalt(); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java index 9606ce4bbb63b..ed5fe7b313e38 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java @@ -26,8 +26,10 @@ package sun.security.pkcs12; import java.io.IOException; +import java.security.NoSuchAlgorithmException; import sun.security.util.*; +import sun.security.x509.AlgorithmId; /** * This class implements the parameter set used with password-based @@ -106,10 +108,6 @@ final class PBMAC1Parameters { + "not an ASN.1 SEQUENCE tag"); } DerValue pBKDF2_params = kdf.data.getDerValue(); - if (pBKDF2_params.tag != DerValue.tag_Sequence) { - throw new IOException("PBKDF2 parameter parsing error: " - + "not an ASN.1 SEQUENCE tag"); - } this.kdfParams = new PBKDF2Parameters(pBKDF2_params); } @@ -118,23 +116,21 @@ final class PBMAC1Parameters { * Encode PBMAC1 parameters from components. */ static byte[] encode(byte[] salt, int iterationCount, int keyLength, - String kdfHmac, String hmac, byte[] digest) { + String kdfHmac, String hmac, byte[] digest) + throws IOException, NoSuchAlgorithmException { DerOutputStream out = new DerOutputStream(); DerOutputStream tmp0 = new DerOutputStream(); DerOutputStream tmp1 = new DerOutputStream(); DerOutputStream tmp2 = new DerOutputStream(); DerOutputStream tmp3 = new DerOutputStream(); - DerOutputStream tmp4 = new DerOutputStream(); - - // messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} - tmp4.putOID(ObjectIdentifier.of(KnownOIDs.findMatch(hmac))); - tmp4.putNull(); // keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}} - tmp3.write(DerValue.tag_Sequence, PBKDF2Parameters.encode(salt, + tmp3.writeBytes(PBKDF2Parameters.encode(salt, iterationCount, keyLength, kdfHmac)); - tmp3.write(DerValue.tag_Sequence, tmp4); + + // messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} + tmp3.write(AlgorithmId.get(hmac)); // id-PBMAC1 OBJECT IDENTIFIER ::= { pkcs-5 14 } tmp2.putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index 440fcbf97122b..f85ba0f9c4b92 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -350,7 +350,7 @@ private Key internalGetKey(Entry entry, char[] password) try { cipher.init(Cipher.DECRYPT_MODE, skey, algParams); } finally { - sun.security.util.KeyUtil.destroySecretKeys(skey); + KeyUtil.destroySecretKeys(skey); } byte[] keyInfo = cipher.doFinal(encryptedKey); /* @@ -888,7 +888,7 @@ private byte[] encryptPrivateKey(byte[] data, try { cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); } finally { - sun.security.util.KeyUtil.destroySecretKeys(skey); + KeyUtil.destroySecretKeys(skey); } byte[] encryptedKey = cipher.doFinal(data); algid = new AlgorithmId(pbeOID, cipher.getParameters()); @@ -1238,7 +1238,7 @@ public synchronized void engineStore(OutputStream stream, char[] password) macIterationCount = defaultMacIterationCount(); } if (password != null && !macAlgorithm.equalsIgnoreCase("NONE")) { - byte[] macData = MacData.calculateMac(password, authenticatedSafe, + byte[] macData = MacData.generateMac(password, authenticatedSafe, macAlgorithm, macIterationCount, getSalt()); pfx.write(macData); } @@ -1822,7 +1822,7 @@ private byte[] encryptContent(byte[] data, char[] password) try { cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); } finally { - sun.security.util.KeyUtil.destroySecretKeys(skey); + KeyUtil.destroySecretKeys(skey); } encryptedData = cipher.doFinal(data); @@ -2032,7 +2032,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) try { cipher.init(Cipher.DECRYPT_MODE, skey, algParams); } finally { - sun.security.util.KeyUtil.destroySecretKeys(skey); + KeyUtil.destroySecretKeys(skey); } loadSafeContents(new DerInputStream(cipher.doFinal(rawData))); return null; @@ -2071,7 +2071,7 @@ public synchronized void engineLoad(InputStream stream, char[] password) macAlgorithm = macData.getMacAlgorithm(); macIterationCount = ic; RetryWithZero.run(pass -> { - macData.processMacData(pass, authSafeData); + macData.verifyMac(pass, authSafeData); return (Void) null; }, password); } catch (Exception e) { diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index fe5c748708593..76534fc6f4022 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -27,6 +27,8 @@ import java.io.IOException; +import sun.security.x509.AlgorithmId; + /** * This class implements the parameter set used with password-based * key derivation function 2 (PBKDF2), which is defined in PKCS#5 as follows: @@ -89,6 +91,10 @@ public final class PBKDF2Parameters { */ public PBKDF2Parameters(DerValue pBKDF2_params) throws IOException { + if (pBKDF2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBKDF2 parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } DerValue specified = pBKDF2_params.data.getDerValue(); // the 'specified' ASN.1 CHOICE for 'salt' is supported if (specified.tag == DerValue.tag_OctetString) { @@ -152,20 +158,19 @@ public static byte[] encode(byte[] salt, int iterationCount, DerOutputStream tmp0 = new DerOutputStream(); DerOutputStream tmp1 = new DerOutputStream(); - // prf AlgorithmIdentifier {{PBKDF2-PRFs}} - tmp1.putOID(prf); - tmp1.putNull(); - tmp0.putOctetString(salt); tmp0.putInteger(iterationCount); tmp0.putInteger(keyLength); - tmp0.write(DerValue.tag_Sequence, tmp1); + + // prf AlgorithmIdentifier {{PBKDF2-PRFs}} + tmp0.write(new AlgorithmId(prf)); // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} out.putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1)); out.write(DerValue.tag_Sequence, tmp0); - return out.toByteArray(); + return new DerOutputStream().write(DerValue.tag_Sequence, out) + .toByteArray(); } /** diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 7e677aed8d45f..3d26c1dcd968a 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1341,8 +1341,8 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep #keystore.pkcs12.keyPbeIterationCount = 10000 # The algorithm used to calculate the optional MacData at the end of a PKCS12 -# file. This can be any HmacPBE or PBEWith algorithm defined in the -# Mac section of the Java Security Standard Algorithm Names Specification, +# file. This can be any HmacPBE or PBEWith algorithm defined in +# the Mac section of the Java Security Standard Algorithm Names Specification, # for example, HmacPBESHA256 or PBEWithHmacSHA256. When set to "NONE", # no Mac is generated. The default value is "HmacPBESHA256". #keystore.pkcs12.macAlgorithm = HmacPBESHA256 diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Test.java b/test/jdk/sun/security/pkcs12/PBMAC1Test.java new file mode 100644 index 0000000000000..f1aa82c1d8fe8 --- /dev/null +++ b/test/jdk/sun/security/pkcs12/PBMAC1Test.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025, 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 8343232 + * @summary Verify correctness of the structure of PKCS12 PBMAC1 + * keystores created with various property values. + * Verify that keystores load correctly from an input stream. + * @modules java.base/sun.security.util + * @library /test/lib + */ +import jdk.test.lib.Asserts; +import jdk.test.lib.security.DerUtils; +import sun.security.util.KnownOIDs; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class PBMAC1Test { + + static final char[] PASSWORD = "1234".toCharArray(); + + public static void main(String[] args) throws Exception { + create(); + migrate(); + overflow(); + } + + // PBMAC1 inside PKCS12 + //0019:008B [2] SEQUENCE + //001C:007B [20] SEQUENCE + //001E:0057 [200] SEQUENCE + //0020:000B [2000] OID 1.2.840.113549.1.5.14 (PBMAC1) + //002B:004A [2001] SEQUENCE + //002D:003A [20010] SEQUENCE + //002F:000B [200100] OID 1.2.840.113549.1.5.12 (PBKDF2WithHmacSHA1) + //003A:002D [200101] SEQUENCE + //003C:0016 [2001010] OCTET STRING (20 bytes of salt) + //0052:0004 [2001011] INTEGER 10000 + //0056:0003 [2001012] INTEGER 32 + //0059:000E [2001013] SEQUENCE + //005B:000A [20010130] OID 1.2.840.113549.2.9 (HmacSHA256) + //0065:0002 [20010131] NULL + //0067:000E [20011] SEQUENCE + //0069:000A [200110] OID 1.2.840.113549.2.9 (HmacSHA256) + //0073:0002 [200111] NULL + //0075:0022 [201] OCTET STRING (32 bytes of mac) + //0097:000A [21] OCTET STRING (8 bytes of useless salt) + //00A1:0003 [22] INTEGER 1 + static void create() throws Exception { + System.setProperty("keystore.pkcs12.macAlgorithm", "pbewithhmacsha256"); + var der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA256); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA256); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 32); + + System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWITHHMACSHA512"); + der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA512); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 64); + + System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWiThHmAcSHA512/224"); + der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512$224); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA512$224); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 28); + + // As strange as I can... + System.setProperty("keystore.pkcs12.macAlgorithm", + "PBEWithHmacSHA512/224AndHmacSHA3-384"); + der = emptyP12(); + DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512$224); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA3_384); + DerUtils.checkInt(der, "2001011", 10000); + DerUtils.checkInt(der, "2001012", 48); + + // Bad alg names + System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWithHmacSHA456"); + var reason = Asserts.assertThrows(NoSuchAlgorithmException.class, + () -> emptyP12()).getMessage(); + Asserts.assertTrue(reason.contains("Algorithm hmacsha456 not available"), reason); + } + + static void migrate() throws Exception { + // A pkcs12 file using PBEWithHmacSHA256 but key length is 8 + var sha2p12 = """ + MIGhAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBiDB5MFUGCSqGSIb3DQEFDjBIMDgGCSqGSIb3DQEF + DDArBBSV6e5xI+9AYtGHQlDI0X4pmvWLBQICJxACAQgwDAYIKoZIhvcNAgkFADAMBggqhkiG9w0C + CQUABCAaaSO6JgEh1lDo1pvAC0CF5HqgIFBvzt1+GZlgFy7xFQQITk9UIFVTRUQCAQE= + """; + var der = Base64.getMimeDecoder().decode(sha2p12); + DerUtils.checkInt(der, "2001012", 8); // key length used to be 8 + + der = loadAndStore(sha2p12); + DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA256); + DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA256); + DerUtils.checkInt(der, "2001012", 32); // key length changed to 32 + } + + static void overflow() throws Exception { + + // Cannot create new + System.setProperty("keystore.pkcs12.macIterationCount", "5000001"); + System.setProperty("keystore.pkcs12.macAlgorithm", "pbewithhmacsha256"); + Asserts.assertThrows(IllegalArgumentException.class, PBMAC1Test::emptyP12); + System.clearProperty("keystore.pkcs12.macAlgorithm"); + Asserts.assertThrows(IllegalArgumentException.class, PBMAC1Test::emptyP12); + + // IC=5000001 using old algorithm + var bigICt = """ + MGYCAQMwEQYJKoZIhvcNAQcBoAQEAjAAME4wMTANBglghkgBZQMEAgEFAAQgyLBK5h9/E/2o7l2A + eALbI1otiS8kT3C41Ef3T38OMjUEFIic7isrAJNr+3+8fUbnMtmB0qytAgNMS0E= + """; + + // IC=5000000 using old algorithm + var smallICt = """ + MGYCAQMwEQYJKoZIhvcNAQcBoAQEAjAAME4wMTANBglghkgBZQMEAgEFAAQgR61YZLW6H81rkGTk + XfuU138mkIugdoQBhuNsnvWuBtQEFJ0wmMlpoUiji8PlvwCrmMbqWW4XAgNMS0A= + """; + + // IC=5000001 using PBMAC1 + var bigICp = """ + MIGiAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBiTB6MFYGCSqGSIb3DQEFDjBJMDkGCSqGSIb3DQEF + DDAsBBQFNf/gHCO5jNT429D6Q5gxTKHqVAIDTEtBAgEgMAwGCCqGSIb3DQIJBQAwDAYIKoZIhvcN + AgkFAAQgwEVMcyMPQXJSXUIbWqNWjMArtnXDlNUGnKD+19B7QFkECE5PVCBVU0VEAgEB + """; + + // IC=5000000 using PBMAC1 + var smallICp = """ + MIGiAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBiTB6MFYGCSqGSIb3DQEFDjBJMDkGCSqGSIb3DQEF + DDAsBBS/ZFfC7swsDHvaCXwyQkuMrZ7dbgIDTEtAAgEgMAwGCCqGSIb3DQIJBQAwDAYIKoZIhvcN + AgkFAAQgCRvE7LDbzkcYOVv/7iBv0KB3DoUkwnpTI0nsonVfv9UECE5PVCBVU0VEAgEB"""; + + loadAndStore(smallICp); + loadAndStore(smallICt); + + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(bigICp)) + .getMessage().contains("MAC iteration count too large: 5000001")); + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(bigICt)) + .getMessage().contains("MAC iteration count too large: 5000001")); + } + + static byte[] emptyP12() throws Exception { + var ks = KeyStore.getInstance("pkcs12"); + ks.load(null, null); + var os = new ByteArrayOutputStream(); + ks.store(os, PASSWORD); + return os.toByteArray(); + } + + static byte[] loadAndStore(String data) throws Exception { + var bytes = Base64.getMimeDecoder().decode(data); + var ks = KeyStore.getInstance("PKCS12"); + ks.load(new ByteArrayInputStream(bytes), PASSWORD); + var baos = new ByteArrayOutputStream(); + ks.store(baos, PASSWORD); + var newBytes = baos.toByteArray(); + var bais = new ByteArrayInputStream(newBytes); + ks.load(bais, PASSWORD); + return newBytes; + } +} From 9d2f61f697f3db8e2eba72ffbd7fff938531ffba Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Mon, 27 Oct 2025 17:29:11 -0600 Subject: [PATCH 27/30] A4-A6 from RFC --- .../sun/security/pkcs12/PBMAC1Encoding.java | 701 ------------------ test/jdk/sun/security/pkcs12/PBMAC1Test.java | 24 + 2 files changed, 24 insertions(+), 701 deletions(-) delete mode 100644 test/jdk/sun/security/pkcs12/PBMAC1Encoding.java diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java b/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java deleted file mode 100644 index 1f4e2f3526f10..0000000000000 --- a/test/jdk/sun/security/pkcs12/PBMAC1Encoding.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * Copyright (c) 2025, 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 8343232 - * @summary PKCS#12 KeyStore support for RFC 9579: Use of Password-Based Message Authentication Code 1 (PBMAC1) - */ - -import java.io.ByteArrayInputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.security.KeyStore; -import java.util.Base64; - -/* - * Tests A.1 - A.6 are from RFC 9879. - * - * A.7 was generated by openssl in 2 steps: - * openssl req -x509 -newkey rsa:4096 -keyout myKey.pem -out cert.pem -days 365 -nodes - * openssl pkcs12 -export -out keyStore.p12 -inkey myKey.pem -in cert.pem -pbmac1_pbkdf2 -macalg sha384 -passout pass:changeit - * - * A.8 is same as A7 except sha384 is changed to sha224. -*/ -public class PBMAC1Encoding { - // A.1. Valid PKCS #12 File with SHA-256 HMAC and PRF - static final String A1 = - "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" + - "3QQITk9UIFVTRUQCAQE="; - - // A.2. Valid PKCS #12 File with SHA-256 HMAC and SHA-512 PRF - static final String A2 = - "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" + - "6QQITk9UIFVTRUQCAQE="; - - // A.3. Valid PKCS #12 File with SHA-512 HMAC and PRF - static final String A3 = - "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"; - - // Invalid PKCS #12 File with Incorrect Iteration Count - static final String A4 = - "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" + - "3QQITk9UIFVTRUQCAggA"; - - // A.5. Invalid PKCS #12 File with Incorrect Salt - static final String A5 = - "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" + - "3QQIb0c8OLAuMXMCAQE="; - - // A.6. Invalid PKCS #12 File with Missing Key Length - static final String A6 = - "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" + - "b0c8OLAuMXMCAggA"; - - // A.7. SHA384 PRF and HMAC - static final String A7 = - "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" + - "AasECO5DNb7BgO98AgIIAA=="; - - // A.8. SHA224 PRF and HMAC - static final String A8 = - "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"; - - static String password = "1234"; - - public static void main(String[] args) throws Exception { - KeyStore ks; - FileOutputStream fos; - FileInputStream fis; - - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A1)), - password.toCharArray()); - - fos = new FileOutputStream("pbmac1KeyStore.p12"); - ks.store(fos, password.toCharArray()); - fos.close(); - - // read keystore we just wrote - fis = new FileInputStream("pbmac1KeyStore.p12"); - ks.load(fis, password.toCharArray()); - fis.close(); - System.out.println("A.1 pass"); - - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A2)), - password.toCharArray()); - - fos = new FileOutputStream("pbmac1KeyStore.p12"); - ks.store(fos, password.toCharArray()); - fos.close(); - - // read keystore we just wrote - fis = new FileInputStream("pbmac1KeyStore.p12"); - ks.load(fis, password.toCharArray()); - fis.close(); - System.out.println("A.2 pass"); - - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A3)), - password.toCharArray()); - - fos = new FileOutputStream("pbmac1KeyStore.p12"); - ks.store(fos, password.toCharArray()); - fos.close(); - - // read keystore we just wrote - fis = new FileInputStream("pbmac1KeyStore.p12"); - ks.load(fis, password.toCharArray()); - fis.close(); - System.out.println("A.3 pass"); - - try { - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A4)), - password.toCharArray()); - throw new Exception("The expected exception was not thrown."); - } catch (IOException e) { - System.out.println("A.4 pass"); - } - - try { - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A5)), - password.toCharArray()); - throw new Exception("The expected exception was not thrown."); - - } catch (IOException e) { - System.out.println("A.5 pass"); - } - - try { - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A6)), - password.toCharArray()); - throw new Exception("The expected exception was not thrown."); - } catch (IOException e) { - System.out.println("A.6 pass"); - } - - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A7)), - "changeit".toCharArray()); - - fos = new FileOutputStream("pbmac1KeyStore.p12"); - ks.store(fos, password.toCharArray()); - fos.close(); - - // read keystore we just wrote - fis = new FileInputStream("pbmac1KeyStore.p12"); - ks.load(fis, password.toCharArray()); - fis.close(); - System.out.println("A.7 pass"); - - ks = KeyStore.getInstance("PKCS12"); - ks.load(new ByteArrayInputStream(Base64.getDecoder().decode(A8)), - "changeit".toCharArray()); - - fos = new FileOutputStream("pbmac1KeyStore.p12"); - ks.store(fos, password.toCharArray()); - fos.close(); - - // read keystore we just wrote - fis = new FileInputStream("pbmac1KeyStore.p12"); - ks.load(fis, password.toCharArray()); - fis.close(); - System.out.println("A.8 pass"); - } -} diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Test.java b/test/jdk/sun/security/pkcs12/PBMAC1Test.java index f1aa82c1d8fe8..0306a63ed16bf 100644 --- a/test/jdk/sun/security/pkcs12/PBMAC1Test.java +++ b/test/jdk/sun/security/pkcs12/PBMAC1Test.java @@ -175,6 +175,30 @@ static void overflow() throws Exception { .getMessage().contains("MAC iteration count too large: 5000001")); Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(bigICt)) .getMessage().contains("MAC iteration count too large: 5000001")); + + // Incorrect Salt + var incorrectSalt = """ + MIGdAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBhDB1MFEGCSqGSIb3DQEFDjBEMDYGCSqGSIb3DQEF + DDApBBSakVhBLltKvqUj6EAxvWqJi+gc7AICJxACASAwCgYIKoZIhvcNAgkwCgYIKoZIhvcNAgkE + IG+euEHE8iN/2C7txbCjCJ9mU4TgEsHPsC9L3Rxa7malBAhOT1QgVVNFRAIBAQ=="""; + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(incorrectSalt)) + .getMessage().contains("Integrity check failed")); + + // Incorrect Iteration Count + var incorrectIC = """ + MIGdAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBhDB1MFEGCSqGSIb3DQEFDjBEMDYGCSqGSIb3DQEF + DDApBBSZkVhBLltKvqUj6EAxvWqJi+gc7AICKBACASAwCgYIKoZIhvcNAgkwCgYIKoZIhvcNAgkE + IG+euEHE8iN/2C7txbCjCJ9mU4TgEsHPsC9L3Rxa7malBAhOT1QgVVNFRAIBAQ=="""; + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(incorrectIC)) + .getMessage().contains("Integrity check failed")); + + // Missing Key Length + var missingKeyLength = """ + MIGaAgEDMBEGCSqGSIb3DQEHAaAEBAIwADCBgTByME4GCSqGSIb3DQEFDjBBMDMGCSqGSIb3DQEF + DDAmBBSZkVhBLltKvqUj6EAxvWqJi+gc7AICJxAwCgYIKoZIhvcNAgkwCgYIKoZIhvcNAgkEIG+e + uEHE8iN/2C7txbCjCJ9mU4TgEsHPsC9L3Rxa7malBAhOT1QgVVNFRAIBAQ=="""; + Asserts.assertTrue(Asserts.assertThrows(IOException.class, () -> loadAndStore(missingKeyLength)) + .getMessage().contains("missing keyLength field")); } static byte[] emptyP12() throws Exception { From e55d79f826908f40fa3a0a48cf5eb7c7f8473809 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Wed, 29 Oct 2025 14:34:24 -0600 Subject: [PATCH 28/30] three comments and OID name change --- .../sun/crypto/provider/PBES2Parameters.java | 2 +- .../classes/sun/security/pkcs12/MacData.java | 34 ++++++++++++++----- .../sun/security/pkcs12/PBMAC1Parameters.java | 29 +++------------- .../classes/sun/security/util/KnownOIDs.java | 2 +- .../sun/security/util/PBKDF2Parameters.java | 5 +-- test/jdk/sun/security/pkcs12/PBMAC1Test.java | 10 +++--- .../security/pkcs12/ParamsPreferences.java | 8 ++--- 7 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java index 532f87caef94b..9d33b6689d236 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java @@ -94,7 +94,7 @@ abstract class PBES2Parameters extends AlgorithmParametersSpi { private static final ObjectIdentifier pkcs5PBKDF2_OID = - ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + ObjectIdentifier.of(KnownOIDs.PBKDF2); private static final ObjectIdentifier pkcs5PBES2_OID = ObjectIdentifier.of(KnownOIDs.PBES2); private static final ObjectIdentifier aes128CBC_OID = diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 619772954e070..f84be1118bd35 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -307,16 +307,35 @@ int getIterations() { static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, String kdfHmac, String hmac, int keyLength) throws IOException, NoSuchAlgorithmException { + final int iterations = p.getIterationCount(); final byte[] macSalt = p.getSalt(); + DerOutputStream tmp = new DerOutputStream(); + DerOutputStream out = new DerOutputStream(); + if (algName.equals("PBMAC1")) { - return PBMAC1Parameters.encode(macSalt, iterations, - keyLength, kdfHmac, hmac, digest); + DerOutputStream tmp1 = new DerOutputStream(); + DerOutputStream tmp2 = new DerOutputStream(); + DerOutputStream tmp3 = new DerOutputStream(); + + tmp3.writeBytes(PBMAC1Parameters.encode(macSalt, iterations, + keyLength, kdfHmac, hmac)); + + // id-PBMAC1 OBJECT IDENTIFIER ::= { pkcs-5 14 } + tmp2.putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)); + tmp2.write(DerValue.tag_Sequence, tmp3); + + tmp1.write(DerValue.tag_Sequence, tmp2); + tmp1.putOctetString(digest); + + tmp.write(DerValue.tag_Sequence, tmp1); + tmp.putOctetString( + new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }); + // Unused, but must have non-zero positive value. + tmp.putInteger(1); } else { final AlgorithmId digestAlgorithm = AlgorithmId.get(algName); - DerOutputStream out = new DerOutputStream(); - DerOutputStream tmp = new DerOutputStream(); DerOutputStream tmp2 = new DerOutputStream(); tmp2.write(digestAlgorithm); @@ -326,11 +345,10 @@ static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, tmp.write(DerValue.tag_Sequence, tmp2); tmp.putOctetString(macSalt); tmp.putInteger(iterations); - - // wrap everything into a SEQUENCE - out.write(DerValue.tag_Sequence, tmp); - return out.toByteArray(); } + // wrap everything into a SEQUENCE + out.write(DerValue.tag_Sequence, tmp); + return out.toByteArray(); } private static String parseKdfHmac(String text) { diff --git a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java index ed5fe7b313e38..8f9ad26a5a879 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java @@ -63,7 +63,7 @@ final class PBMAC1Parameters { static final ObjectIdentifier pkcs5PBKDF2_OID = - ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + ObjectIdentifier.of(KnownOIDs.PBKDF2); private final String hmacAlgo; private final PBKDF2Parameters kdfParams; @@ -116,37 +116,16 @@ final class PBMAC1Parameters { * Encode PBMAC1 parameters from components. */ static byte[] encode(byte[] salt, int iterationCount, int keyLength, - String kdfHmac, String hmac, byte[] digest) - throws IOException, NoSuchAlgorithmException { + String kdfHmac, String hmac) throws NoSuchAlgorithmException { DerOutputStream out = new DerOutputStream(); - DerOutputStream tmp0 = new DerOutputStream(); - DerOutputStream tmp1 = new DerOutputStream(); - DerOutputStream tmp2 = new DerOutputStream(); - DerOutputStream tmp3 = new DerOutputStream(); // keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}} - tmp3.writeBytes(PBKDF2Parameters.encode(salt, + out.writeBytes(PBKDF2Parameters.encode(salt, iterationCount, keyLength, kdfHmac)); // messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} - tmp3.write(AlgorithmId.get(hmac)); - - // id-PBMAC1 OBJECT IDENTIFIER ::= { pkcs-5 14 } - tmp2.putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)); - tmp2.write(DerValue.tag_Sequence, tmp3); - - tmp1.write(DerValue.tag_Sequence, tmp2); - tmp1.putOctetString(digest); - - tmp0.write(DerValue.tag_Sequence, tmp1); - tmp0.putOctetString( - new byte[]{ 'N', 'O', 'T', ' ', 'U', 'S', 'E', 'D' }); - // Unused, but must have non-zero positive value. - tmp0.putInteger(1); - - // wrap everything into a SEQUENCE - out.write(DerValue.tag_Sequence, tmp0); + out.write(AlgorithmId.get(hmac)); return out.toByteArray(); } diff --git a/src/java.base/share/classes/sun/security/util/KnownOIDs.java b/src/java.base/share/classes/sun/security/util/KnownOIDs.java index 0bbefaa29aeb1..6c90801f69b3b 100644 --- a/src/java.base/share/classes/sun/security/util/KnownOIDs.java +++ b/src/java.base/share/classes/sun/security/util/KnownOIDs.java @@ -208,7 +208,7 @@ public enum KnownOIDs { PBEWithMD5AndRC2("1.2.840.113549.1.5.6"), PBEWithSHA1AndDES("1.2.840.113549.1.5.10"), PBEWithSHA1AndRC2("1.2.840.113549.1.5.11"), - PBKDF2WithHmacSHA1("1.2.840.113549.1.5.12"), + PBKDF2("1.2.840.113549.1.5.12", "PBKDF2WithHmacSHA1"), PBES2("1.2.840.113549.1.5.13"), PBMAC1("1.2.840.113549.1.5.14"), diff --git a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java index 76534fc6f4022..07d4c70fecb02 100644 --- a/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java +++ b/src/java.base/share/classes/sun/security/util/PBKDF2Parameters.java @@ -27,6 +27,7 @@ import java.io.IOException; +import sun.security.util.KnownOIDs; import sun.security.x509.AlgorithmId; /** @@ -149,6 +150,7 @@ public static byte[] encode(byte[] salt, int iterationCount, /* * Encode PBKDF2 parameters from components. + * The outer algorithm ID is also encoded in addition to the parameters. */ public static byte[] encode(byte[] salt, int iterationCount, int keyLength, ObjectIdentifier prf) { @@ -156,7 +158,6 @@ public static byte[] encode(byte[] salt, int iterationCount, DerOutputStream out = new DerOutputStream(); DerOutputStream tmp0 = new DerOutputStream(); - DerOutputStream tmp1 = new DerOutputStream(); tmp0.putOctetString(salt); tmp0.putInteger(iterationCount); @@ -166,7 +167,7 @@ public static byte[] encode(byte[] salt, int iterationCount, tmp0.write(new AlgorithmId(prf)); // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} - out.putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1)); + out.putOID(ObjectIdentifier.of(KnownOIDs.PBKDF2)); out.write(DerValue.tag_Sequence, tmp0); return new DerOutputStream().write(DerValue.tag_Sequence, out) diff --git a/test/jdk/sun/security/pkcs12/PBMAC1Test.java b/test/jdk/sun/security/pkcs12/PBMAC1Test.java index 0306a63ed16bf..acb0f73a2d249 100644 --- a/test/jdk/sun/security/pkcs12/PBMAC1Test.java +++ b/test/jdk/sun/security/pkcs12/PBMAC1Test.java @@ -58,7 +58,7 @@ public static void main(String[] args) throws Exception { //0020:000B [2000] OID 1.2.840.113549.1.5.14 (PBMAC1) //002B:004A [2001] SEQUENCE //002D:003A [20010] SEQUENCE - //002F:000B [200100] OID 1.2.840.113549.1.5.12 (PBKDF2WithHmacSHA1) + //002F:000B [200100] OID 1.2.840.113549.1.5.12 (PBKDF2) //003A:002D [200101] SEQUENCE //003C:0016 [2001010] OCTET STRING (20 bytes of salt) //0052:0004 [2001011] INTEGER 10000 @@ -76,7 +76,7 @@ static void create() throws Exception { System.setProperty("keystore.pkcs12.macAlgorithm", "pbewithhmacsha256"); var der = emptyP12(); DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); - DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA256); DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA256); DerUtils.checkInt(der, "2001011", 10000); @@ -85,7 +85,7 @@ static void create() throws Exception { System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWITHHMACSHA512"); der = emptyP12(); DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); - DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512); DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA512); DerUtils.checkInt(der, "2001011", 10000); @@ -94,7 +94,7 @@ static void create() throws Exception { System.setProperty("keystore.pkcs12.macAlgorithm", "PBEWiThHmAcSHA512/224"); der = emptyP12(); DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); - DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512$224); DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA512$224); DerUtils.checkInt(der, "2001011", 10000); @@ -105,7 +105,7 @@ static void create() throws Exception { "PBEWithHmacSHA512/224AndHmacSHA3-384"); der = emptyP12(); DerUtils.checkAlg(der, "2000", KnownOIDs.PBMAC1); - DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2WithHmacSHA1); + DerUtils.checkAlg(der, "200100", KnownOIDs.PBKDF2); DerUtils.checkAlg(der, "20010130", KnownOIDs.HmacSHA512$224); DerUtils.checkAlg(der, "200110", KnownOIDs.HmacSHA3_384); DerUtils.checkInt(der, "2001011", 10000); diff --git a/test/jdk/sun/security/pkcs12/ParamsPreferences.java b/test/jdk/sun/security/pkcs12/ParamsPreferences.java index 4bedca56a786c..c40bd4f4b7059 100644 --- a/test/jdk/sun/security/pkcs12/ParamsPreferences.java +++ b/test/jdk/sun/security/pkcs12/ParamsPreferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -35,7 +35,7 @@ /* * @test - * @bug 8076190 8242151 8153005 8266293 + * @bug 8076190 8242151 8153005 8266293 8343232 * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util @@ -244,7 +244,7 @@ static void test(int n, Map sysProps, checkAlg(data, "110c10", EncryptedData); checkAlg(data, "110c110110", certAlg); if (certAlg == PBES2) { - checkAlg(data, "110c11011100", PBKDF2WithHmacSHA1); + checkAlg(data, "110c11011100", PBKDF2); checkAlg(data, "110c1101110130", (KnownOIDs)args[i++]); checkAlg(data, "110c11011110", (KnownOIDs)args[i++]); checkInt(data, "110c110111011", (int) args[i++]); @@ -257,7 +257,7 @@ static void test(int n, Map sysProps, KnownOIDs keyAlg = (KnownOIDs)args[i++]; checkAlg(data, "110c010c01000", keyAlg); if (keyAlg == PBES2) { - checkAlg(data, "110c010c0100100", PBKDF2WithHmacSHA1); + checkAlg(data, "110c010c0100100", PBKDF2); checkAlg(data, "110c010c010010130", (KnownOIDs)args[i++]); checkAlg(data, "110c010c0100110", (KnownOIDs)args[i++]); checkInt(data, "110c010c01001011", (int) args[i++]); From 409f34c57f937d71313beb2b731fd80e58bb1ae2 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 30 Oct 2025 15:02:24 -0600 Subject: [PATCH 29/30] two algorithm identifiers concatenated together without any frame --- src/java.base/share/classes/sun/security/pkcs12/MacData.java | 2 +- .../share/classes/sun/security/pkcs12/PBMAC1Parameters.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index f84be1118bd35..2cd7090975967 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -324,7 +324,7 @@ static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, // id-PBMAC1 OBJECT IDENTIFIER ::= { pkcs-5 14 } tmp2.putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)); - tmp2.write(DerValue.tag_Sequence, tmp3); + tmp2.write(tmp3); tmp1.write(DerValue.tag_Sequence, tmp2); tmp1.putOctetString(digest); diff --git a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java index 8f9ad26a5a879..2c3c6fa817172 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PBMAC1Parameters.java @@ -126,7 +126,8 @@ static byte[] encode(byte[] salt, int iterationCount, int keyLength, // messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} out.write(AlgorithmId.get(hmac)); - return out.toByteArray(); + return new DerOutputStream().write(DerValue.tag_Sequence, out) + .toByteArray(); } PBKDF2Parameters getKdfParams() { From ba2c07199f175e02ce137de0257efca6f7fb59b5 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Fri, 31 Oct 2025 09:02:24 -0600 Subject: [PATCH 30/30] unnecessary DER output stream --- .../share/classes/sun/security/pkcs12/MacData.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/sun/security/pkcs12/MacData.java b/src/java.base/share/classes/sun/security/pkcs12/MacData.java index 2cd7090975967..d45b50ad7048c 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/MacData.java +++ b/src/java.base/share/classes/sun/security/pkcs12/MacData.java @@ -317,14 +317,11 @@ static byte[] encode(String algName, byte[] digest, PBEParameterSpec p, if (algName.equals("PBMAC1")) { DerOutputStream tmp1 = new DerOutputStream(); DerOutputStream tmp2 = new DerOutputStream(); - DerOutputStream tmp3 = new DerOutputStream(); - - tmp3.writeBytes(PBMAC1Parameters.encode(macSalt, iterations, - keyLength, kdfHmac, hmac)); // id-PBMAC1 OBJECT IDENTIFIER ::= { pkcs-5 14 } tmp2.putOID(ObjectIdentifier.of(KnownOIDs.PBMAC1)); - tmp2.write(tmp3); + tmp2.writeBytes(PBMAC1Parameters.encode(macSalt, iterations, + keyLength, kdfHmac, hmac)); tmp1.write(DerValue.tag_Sequence, tmp2); tmp1.putOctetString(digest);