From 4fcb17bb9309b0283ea7c90a48f7431cde40e144 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Fri, 15 Dec 2023 04:12:49 +0000 Subject: [PATCH 01/13] 8302017: Allocate BadPaddingException only if it will be thrown Reviewed-by: bstafford, mbalao Backport-of: 334b977259930368160db705c1f2feda0b0e8707 --- .../com/sun/crypto/provider/RSACipher.java | 27 ++++++-- .../classes/sun/security/rsa/RSAPadding.java | 67 +++++++------------ .../sun/security/rsa/RSASignature.java | 26 +++---- .../sun/security/pkcs11/P11Signature.java | 11 +-- .../jdk/sun/security/rsa/RSAPaddingCheck.java | 63 +++++++++++++++++ 5 files changed, 132 insertions(+), 62 deletions(-) create mode 100644 test/jdk/sun/security/rsa/RSAPaddingCheck.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index 196acef1511..ac512e573a5 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -355,21 +355,38 @@ private byte[] doFinal() throws BadPaddingException, switch (mode) { case MODE_SIGN: paddingCopy = padding.pad(buffer, 0, bufOfs); - result = RSACore.rsa(paddingCopy, privateKey, true); + if (paddingCopy != null) { + result = RSACore.rsa(paddingCopy, privateKey, true); + } else { + throw new BadPaddingException("Padding error in signing"); + } break; case MODE_VERIFY: byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(verifyBuffer, publicKey); result = padding.unpad(paddingCopy); + if (result == null) { + throw new BadPaddingException + ("Padding error in verification"); + } break; case MODE_ENCRYPT: paddingCopy = padding.pad(buffer, 0, bufOfs); - result = RSACore.rsa(paddingCopy, publicKey); + if (paddingCopy != null) { + result = RSACore.rsa(paddingCopy, publicKey); + } else { + throw new BadPaddingException + ("Padding error in encryption"); + } break; case MODE_DECRYPT: byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false); result = padding.unpad(paddingCopy); + if (result == null) { + throw new BadPaddingException + ("Padding error in decryption"); + } break; default: throw new AssertionError("Internal error"); @@ -378,9 +395,9 @@ private byte[] doFinal() throws BadPaddingException, } finally { Arrays.fill(buffer, 0, bufOfs, (byte)0); bufOfs = 0; - if (paddingCopy != null // will not happen + if (paddingCopy != null && paddingCopy != buffer // already cleaned - && paddingCopy != result) { // DO NOT CLEAN, THIS IS RESULT! + && paddingCopy != result) { // DO NOT CLEAN, THIS IS RESULT Arrays.fill(paddingCopy, (byte)0); } } diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java index c54dbdb8d43..09d3936d872 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java @@ -30,7 +30,6 @@ import java.security.*; import java.security.spec.*; -import javax.crypto.BadPaddingException; import javax.crypto.spec.PSource; import javax.crypto.spec.OAEPParameterSpec; @@ -236,24 +235,22 @@ public int getMaxDataSize() { } /** - * Pad the data and return the padded block. + * Pad the data and return the result or null if error occurred. */ - public byte[] pad(byte[] data) throws BadPaddingException { + public byte[] pad(byte[] data) { return pad(data, 0, data.length); } /** - * Pad the data and return the padded block. + * Pad the data and return the result or null if error occurred. */ - public byte[] pad(byte[] data, int ofs, int len) - throws BadPaddingException { + public byte[] pad(byte[] data, int ofs, int len) { if (len > maxDataSize) { - throw new BadPaddingException("Data must be shorter than " - + (maxDataSize + 1) + " bytes but received " - + len + " bytes."); + return null; } switch (type) { case PAD_NONE: + // assert len == paddedSize and data.length - ofs > len? return RSACore.convert(data, ofs, len); case PAD_BLOCKTYPE_1: case PAD_BLOCKTYPE_2: @@ -266,31 +263,25 @@ public byte[] pad(byte[] data, int ofs, int len) } /** - * Unpad the padded block and return the data. + * Unpad the padded block and return the result or null if error occurred. */ - public byte[] unpad(byte[] padded) throws BadPaddingException { - if (padded.length != paddedSize) { - throw new BadPaddingException("Decryption error." + - "The padded array length (" + padded.length + - ") is not the specified padded size (" + paddedSize + ")"); - } - switch (type) { - case PAD_NONE: - return padded; - case PAD_BLOCKTYPE_1: - case PAD_BLOCKTYPE_2: - return unpadV15(padded); - case PAD_OAEP_MGF1: - return unpadOAEP(padded); - default: - throw new AssertionError(); + public byte[] unpad(byte[] padded) { + if (padded.length == paddedSize) { + return switch(type) { + case PAD_NONE -> padded; + case PAD_BLOCKTYPE_1, PAD_BLOCKTYPE_2 -> unpadV15(padded); + case PAD_OAEP_MGF1 -> unpadOAEP(padded); + default -> throw new AssertionError(); + }; + } else { + return null; } } /** * PKCS#1 v1.5 padding (blocktype 1 and 2). */ - private byte[] padV15(byte[] data, int ofs, int len) throws BadPaddingException { + private byte[] padV15(byte[] data, int ofs, int len) { byte[] padded = new byte[paddedSize]; System.arraycopy(data, ofs, padded, paddedSize - len, len); int psSize = paddedSize - 3 - len; @@ -327,10 +318,10 @@ private byte[] padV15(byte[] data, int ofs, int len) throws BadPaddingException /** * PKCS#1 v1.5 unpadding (blocktype 1 (signature) and 2 (encryption)). - * + * Return the result or null if error occurred. * Note that we want to make it a constant-time operation */ - private byte[] unpadV15(byte[] padded) throws BadPaddingException { + private byte[] unpadV15(byte[] padded) { int k = 0; boolean bp = false; @@ -366,10 +357,8 @@ private byte[] unpadV15(byte[] padded) throws BadPaddingException { byte[] data = new byte[n]; System.arraycopy(padded, p, data, 0, n); - BadPaddingException bpe = new BadPaddingException("Decryption error"); - if (bp) { - throw bpe; + return null; } else { return data; } @@ -378,8 +367,9 @@ private byte[] unpadV15(byte[] padded) throws BadPaddingException { /** * PKCS#1 v2.0 OAEP padding (MGF1). * Paragraph references refer to PKCS#1 v2.1 (June 14, 2002) + * Return the result or null if error occurred. */ - private byte[] padOAEP(byte[] M, int ofs, int len) throws BadPaddingException { + private byte[] padOAEP(byte[] M, int ofs, int len) { if (random == null) { random = JCAUtil.getSecureRandom(); } @@ -428,8 +418,9 @@ private byte[] padOAEP(byte[] M, int ofs, int len) throws BadPaddingException { /** * PKCS#1 v2.1 OAEP unpadding (MGF1). + * Return the result or null if error occurred. */ - private byte[] unpadOAEP(byte[] padded) throws BadPaddingException { + private byte[] unpadOAEP(byte[] padded) { byte[] EM = padded; boolean bp = false; int hLen = lHash.length; @@ -485,12 +476,6 @@ private byte[] unpadOAEP(byte[] padded) throws BadPaddingException { byte [] m = new byte[EM.length - mStart]; System.arraycopy(EM, mStart, m, 0, m.length); - BadPaddingException bpe = new BadPaddingException("Decryption error"); - - if (bp) { - throw bpe; - } else { - return m; - } + return (bp? null : m); } } diff --git a/src/java.base/share/classes/sun/security/rsa/RSASignature.java b/src/java.base/share/classes/sun/security/rsa/RSASignature.java index 795d5c59020..306f5dbbd81 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSASignature.java +++ b/src/java.base/share/classes/sun/security/rsa/RSASignature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -190,13 +190,15 @@ protected byte[] engineSign() throws SignatureException { try { byte[] encoded = encodeSignature(digestOID, digest); byte[] padded = padding.pad(encoded); - byte[] encrypted = RSACore.rsa(padded, privateKey, true); - return encrypted; + if (padded != null) { + return RSACore.rsa(padded, privateKey, true); + } } catch (GeneralSecurityException e) { throw new SignatureException("Could not sign data", e); } catch (IOException e) { throw new SignatureException("Could not encode data", e); } + throw new SignatureException("Could not sign data"); } // verify the data and return the result. See JCA doc @@ -208,20 +210,20 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { } try { if (sigBytes.length != RSACore.getByteLength(publicKey)) { - throw new SignatureException("Signature length not correct: got " + + throw new SignatureException("Bad signature length: got " + sigBytes.length + " but was expecting " + RSACore.getByteLength(publicKey)); } - byte[] digest = getDigestValue(); + + // https://www.rfc-editor.org/rfc/rfc8017.html#section-8.2.2 + // Step 4 suggests comparing the encoded message byte[] decrypted = RSACore.rsa(sigBytes, publicKey); - byte[] unpadded = padding.unpad(decrypted); - byte[] decodedDigest = decodeSignature(digestOID, unpadded); - return MessageDigest.isEqual(digest, decodedDigest); + + byte[] digest = getDigestValue(); + byte[] encoded = encodeSignature(digestOID, digest); + byte[] padded = padding.pad(encoded); + return MessageDigest.isEqual(padded, decrypted); } catch (javax.crypto.BadPaddingException e) { - // occurs if the app has used the wrong RSA public key - // or if sigBytes is invalid - // return false rather than propagating the exception for - // compatibility/ease of use return false; } catch (IOException e) { throw new SignatureException("Signature encoding error", e); diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java index 54206ee0a06..de48270fd59 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -759,9 +759,12 @@ private byte[] pkcs1Pad(byte[] data) { int len = (p11Key.length() + 7) >> 3; RSAPadding padding = RSAPadding.getInstance (RSAPadding.PAD_BLOCKTYPE_1, len); - byte[] padded = padding.pad(data); - return padded; - } catch (GeneralSecurityException e) { + byte[] result = padding.pad(data); + if (result == null) { + throw new ProviderException("Error padding data"); + } + return result; + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { throw new ProviderException(e); } } diff --git a/test/jdk/sun/security/rsa/RSAPaddingCheck.java b/test/jdk/sun/security/rsa/RSAPaddingCheck.java new file mode 100644 index 00000000000..807e4e3bf4b --- /dev/null +++ b/test/jdk/sun/security/rsa/RSAPaddingCheck.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, 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 8302017 + * @summary Ensure that RSAPadding class works as expected after refactoring + * @modules java.base/sun.security.rsa + */ +import java.util.Arrays; +import sun.security.rsa.RSAPadding; + +public class RSAPaddingCheck { + + private static int[] PADDING_TYPES = { + RSAPadding.PAD_BLOCKTYPE_1, + RSAPadding.PAD_BLOCKTYPE_2, + RSAPadding.PAD_NONE, + RSAPadding.PAD_OAEP_MGF1, + }; + + public static void main(String[] args) throws Exception { + int size = 2048 >> 3; + byte[] testData = "This is some random to-be-padded Data".getBytes(); + for (int type : PADDING_TYPES) { + byte[] data = (type == RSAPadding.PAD_NONE? + Arrays.copyOf(testData, size) : testData); + System.out.println("Testing PaddingType: " + type); + RSAPadding padding = RSAPadding.getInstance(type, size); + byte[] paddedData = padding.pad(data); + if (paddedData == null) { + throw new RuntimeException("Unexpected padding op failure!"); + } + + byte[] data2 = padding.unpad(paddedData); + if (data2 == null) { + throw new RuntimeException("Unexpected unpadding op failure!"); + } + if (!Arrays.equals(data, data2)) { + throw new RuntimeException("diff check failure!"); + } + } + } +} From 5355fc9070e20d8c0a3f30fc79b277fa884eab6c Mon Sep 17 00:00:00 2001 From: Alexey Bakhtin Date: Fri, 15 Dec 2023 16:23:14 +0000 Subject: [PATCH 02/13] 8320597: RSA signature verification fails on signed data that does not encode params correctly Reviewed-by: mbalao Backport-of: 11e4a925bec3c1f79e03045d48def53188b655e6 --- .../classes/sun/security/rsa/RSAPadding.java | 2 +- .../sun/security/rsa/RSASignature.java | 39 ++++++------- test/jdk/sun/security/rsa/WithoutNULL.java | 57 +++++++++++++++++++ 3 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 test/jdk/sun/security/rsa/WithoutNULL.java diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java index 09d3936d872..6954c2ad7ea 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPadding.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPadding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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/src/java.base/share/classes/sun/security/rsa/RSASignature.java b/src/java.base/share/classes/sun/security/rsa/RSASignature.java index 306f5dbbd81..8366ab8bfca 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSASignature.java +++ b/src/java.base/share/classes/sun/security/rsa/RSASignature.java @@ -220,8 +220,17 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { byte[] decrypted = RSACore.rsa(sigBytes, publicKey); byte[] digest = getDigestValue(); + byte[] encoded = encodeSignature(digestOID, digest); byte[] padded = padding.pad(encoded); + if (MessageDigest.isEqual(padded, decrypted)) { + return true; + } + + // Some vendors might omit the NULL params in digest algorithm + // identifier. Try again. + encoded = encodeSignatureWithoutNULL(digestOID, digest); + padded = padding.pad(encoded); return MessageDigest.isEqual(padded, decrypted); } catch (javax.crypto.BadPaddingException e) { return false; @@ -247,27 +256,19 @@ public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest) } /** - * Decode the signature data. Verify that the object identifier matches - * and return the message digest. + * Encode the digest without the NULL params, return the to-be-signed data. + * This is only used by SunRsaSign. */ - public static byte[] decodeSignature(ObjectIdentifier oid, byte[] sig) + static byte[] encodeSignatureWithoutNULL(ObjectIdentifier oid, byte[] digest) throws IOException { - // Enforce strict DER checking for signatures - DerInputStream in = new DerInputStream(sig, 0, sig.length, false); - DerValue[] values = in.getSequence(2); - if ((values.length != 2) || (in.available() != 0)) { - throw new IOException("SEQUENCE length error"); - } - AlgorithmId algId = AlgorithmId.parse(values[0]); - if (algId.getOID().equals(oid) == false) { - throw new IOException("ObjectIdentifier mismatch: " - + algId.getOID()); - } - if (algId.getEncodedParams() != null) { - throw new IOException("Unexpected AlgorithmId parameters"); - } - byte[] digest = values[1].getOctetString(); - return digest; + DerOutputStream out = new DerOutputStream(); + DerOutputStream oidout = new DerOutputStream(); + oidout.putOID(oid); + out.write(DerValue.tag_Sequence, oidout); + out.putOctetString(digest); + DerValue result = + new DerValue(DerValue.tag_Sequence, out.toByteArray()); + return result.toByteArray(); } // set parameter, not supported. See JCA doc diff --git a/test/jdk/sun/security/rsa/WithoutNULL.java b/test/jdk/sun/security/rsa/WithoutNULL.java new file mode 100644 index 00000000000..64cf831099d --- /dev/null +++ b/test/jdk/sun/security/rsa/WithoutNULL.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, 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 8320597 + * @summary Verify RSA signature with omitted digest params (should be encoded as NULL) + * for backward compatibility + */ +import java.security.KeyFactory; +import java.security.Signature; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; + +public class WithoutNULL { + public static void main(String[] args) throws Exception { + + // A 1024-bit RSA public key + byte[] key = Base64.getMimeDecoder().decode(""" + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrfTrEm4KvdFSpGAM7InrFEzALTKdphT9fK6Gu + eVjHtKsuCSEaULCdjhJvPpFK40ONr1JEC1Ywp1UYrfBBdKunnbDZqNZL1cFv+IzF4Yj6JO6pOeHi + 1Zpur1GaQRRlYTvzmyWY/AATQDh8JfKObNnDVwXeezFODUG8h5+XL1ZXZQIDAQAB"""); + + // A SHA1withRSA signature on an empty input where the digestAlgorithm + // inside DigestInfo does not have a parameters field. + byte[] sig = Base64.getMimeDecoder().decode(""" + D1FpiT44WEXlDfYK880bdorLO+e9qJVXZWiBgqs9dfK7lYQwyEt9dL23mbUAKm5TVEj2ZxtHkEvk + b8oaWkxk069jDTM1RhllPJZkAjeQRbw4gkg4N6wKZz9B/jdSRMNJg/b9QdRYZOHOBxsEHMbUREPV + DoCOLaxB8eIXX0EWkiE="""); + + Signature s = Signature.getInstance("SHA1withRSA", "SunRsaSign"); + s.initVerify(KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(key))); + if (!s.verify(sig)) { + throw new RuntimeException("Does not verify"); + } + } +} From 3c760354d88291713671c0adf12dbed0ce31c73c Mon Sep 17 00:00:00 2001 From: Alexey Bakhtin Date: Tue, 9 Jan 2024 15:46:05 +0100 Subject: [PATCH 03/13] 8308204: Enhanced certificate processing Reviewed-by: mbalao Backport-of: ef0ea85bf1398b73bd308ba2b395c917b449aa3b --- .../provider/certpath/ForwardBuilder.java | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java index 2fbeb8856ee..50f2daa6081 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -336,8 +336,11 @@ private void getMatchingCACerts(ForwardState currentState, } } + // Thread-local gate to prevent recursive provider lookups + private static ThreadLocal gate = new ThreadLocal<>(); + /** - * Download Certificates from the given AIA and add them to the + * Download certificates from the given AIA and add them to the * specified Collection. */ // cs.getCertificates(caSelector) returns a collection of X509Certificate's @@ -349,32 +352,47 @@ private boolean getCerts(AuthorityInfoAccessExtension aiaExt, if (Builder.USE_AIA == false) { return false; } + List adList = aiaExt.getAccessDescriptions(); if (adList == null || adList.isEmpty()) { return false; } - boolean add = false; - for (AccessDescription ad : adList) { - CertStore cs = URICertStore.getInstance(ad); - if (cs != null) { - try { - if (certs.addAll((Collection) - cs.getCertificates(caSelector))) { - add = true; - if (!searchAllCertStores) { - return true; + if (gate.get() != null) { + // Avoid recursive fetching of certificates + if (debug != null) { + debug.println("Recursive fetching of certs via the AIA " + + "extension detected"); + } + return false; + } + + gate.set(gate); + try { + boolean add = false; + for (AccessDescription ad : adList) { + CertStore cs = URICertStore.getInstance(ad); + if (cs != null) { + try { + if (certs.addAll((Collection) + cs.getCertificates(caSelector))) { + add = true; + if (!searchAllCertStores) { + return true; + } + } + } catch (CertStoreException cse) { + if (debug != null) { + debug.println("exception getting certs from CertStore:"); + cse.printStackTrace(); } - } - } catch (CertStoreException cse) { - if (debug != null) { - debug.println("exception getting certs from CertStore:"); - cse.printStackTrace(); } } } + return add; + } finally { + gate.set(null); } - return add; } /** From 5d68630e8a2b9c7aed1df294614e8a79a1bff7b9 Mon Sep 17 00:00:00 2001 From: Martin Balao Date: Tue, 9 Jan 2024 15:46:55 +0100 Subject: [PATCH 04/13] 8314295: Enhance verification of verifier Reviewed-by: yan Backport-of: 08980a0a60bc48c17eacd57fd2d7065ac2d986a8 --- src/java.base/share/native/libverify/check_code.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c index 55d6fbcf42a..126ff76e652 100644 --- a/src/java.base/share/native/libverify/check_code.c +++ b/src/java.base/share/native/libverify/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2023, 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 @@ -81,6 +81,7 @@ #include #include #include +#include #include "jni.h" #include "jni_util.h" @@ -1195,7 +1196,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) } } if (opcode == JVM_OPC_tableswitch) { - keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1; + keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1; delta = 1; } else { keys = _ck_ntohl(lpc[1]); /* number of pairs */ @@ -1677,11 +1678,13 @@ static int instruction_length(unsigned char *iptr, unsigned char *end) switch (instruction) { case JVM_OPC_tableswitch: { int *lpc = (int *)UCALIGN(iptr + 1); - int index; if (lpc + 2 >= (int *)end) { return -1; /* do not read pass the end */ } - index = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]); + int64_t low = _ck_ntohl(lpc[1]); + int64_t high = _ck_ntohl(lpc[2]); + int64_t index = high - low; + // The value of low must be less than or equal to high - i.e. index >= 0 if ((index < 0) || (index > 65535)) { return -1; /* illegal */ } else { From e54afbe819f1379b3ca4ba736debc0d34313b54d Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 9 Jan 2024 15:48:02 +0100 Subject: [PATCH 05/13] 8276123: ZipFile::getEntry will not return a file entry when there is a directory entry of the same name within a Zip File Reviewed-by: mbalao Backport-of: b85500e52479c48b02a96b28fddefa2b25d5d9bd --- .../share/classes/java/util/zip/ZipFile.java | 15 +- .../ZipFile/ZipFileDuplicateEntryTest.java | 581 ++++++++++++++++++ 2 files changed, 591 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index d47a1d26026..d10ad7f60a7 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1790,13 +1790,18 @@ private int getEntryPos(String name, boolean addSlash) { // slash int entryLen = entry.length(); int nameLen = name.length(); - if ((entryLen == nameLen && entry.equals(name)) || - (addSlash && - nameLen + 1 == entryLen && - entry.startsWith(name) && - entry.charAt(entryLen - 1) == '/')) { + if (entryLen == nameLen && entry.equals(name)) { + // Found our match return pos; } + // If addSlash is true we'll now test for name+/ providing + if (addSlash && nameLen + 1 == entryLen + && entry.startsWith(name) && + entry.charAt(entryLen - 1) == '/') { + // Found the entry "name+/", now find the CEN entry pos + int exactPos = getEntryPos(name, false); + return exactPos == -1 ? pos : exactPos; + } } catch (IllegalArgumentException iae) { // Ignore } diff --git a/test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java b/test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java new file mode 100644 index 00000000000..95a223c8e1f --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/ZipFileDuplicateEntryTest.java @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Formatter; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import static org.testng.Assert.*; + +/** + * @test + * @bug 8276123 + * @summary ZipFile::getEntry will not return a file entry when there is a + * directory entry of the same name within a Zip File + * @run testng/othervm ZipFileDuplicateEntryTest + */ +public class ZipFileDuplicateEntryTest { + + /** + * Name to use for creating Zip entries + */ + private static final String ENTRY_NAME = "entry"; + + /** + * Zip and Jar files to be created + */ + private static final Path ZIP_FILE = Paths.get("fileDirEntry.zip"); + private static final Path ZIP_FILE2 = Paths.get("OnlyDirEntry.zip"); + private static final Path DUPLICATE_FILE_ENTRY_FILE = Paths.get("DupFIleEntry.zip"); + private static final Path TEST_JAR = Paths.get("fileDirEntry.jar"); + + /** + * Directory entry added to the Zip File. + */ + private static final Entry DIR_ENTRY = + Entry.of(ENTRY_NAME + "/", ZipEntry.DEFLATED, + "I am a Directory"); + + /** + * File entry added to the Zip File. + */ + private static final Entry FILE_ENTRY = + Entry.of(ENTRY_NAME, ZipEntry.DEFLATED, "I am a File"); + + /** + * Duplicate File entry added to the Zip file. This is the 2nd entry added + * to the Zip file and is expected to be returned. + */ + private static final Entry DUPLICATE_FILE_ENTRY = + Entry.of(ENTRY_NAME, ZipEntry.DEFLATED, "Yet another File"); + /** + * Entries expected to be returned via ZipFile::stream + */ + private static final List EXPECTED_ENTRIES = + Arrays.asList(FILE_ENTRY.name, DIR_ENTRY.name); + + /** + * Max buffer size for readAllBytes method which can be used when + * InputStream::readAllBytes is not available + */ + private static final int MAX_BUFFER_SIZE = 1024; + + /** + * Flag to enable test output + */ + private static final boolean DEBUG = false; + + /** + * Array representing a Jar File with the entries: + * Name: entry, contents: "I am a File" + * Name: entry, contents: "Yet another File" + * See createByteArray() + */ + private static final byte[] DUPLICATE_ENTRY_JAR_BYTES = { + (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8, + (byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53, (byte) 0x8e, (byte) 0x39, + (byte) 0x14, (byte) 0x49, (byte) 0xd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xb, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x65, (byte) 0x6e, + (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x1, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0xb, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xd, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xf3, + (byte) 0x54, (byte) 0x48, (byte) 0xcc, (byte) 0x55, (byte) 0x48, (byte) 0x54, (byte) 0x70, (byte) 0xcb, + (byte) 0xcc, (byte) 0x49, (byte) 0x5, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x3, (byte) 0x4, + (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59, + (byte) 0x55, (byte) 0x53, (byte) 0xe1, (byte) 0x4c, (byte) 0x29, (byte) 0xa4, (byte) 0x12, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, + (byte) 0x14, (byte) 0x0, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x1, + (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x12, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8b, (byte) 0x4c, (byte) 0x2d, (byte) 0x51, (byte) 0x48, + (byte) 0xcc, (byte) 0xcb, (byte) 0x2f, (byte) 0xc9, (byte) 0x48, (byte) 0x2d, (byte) 0x52, (byte) 0x70, + (byte) 0xcb, (byte) 0xcc, (byte) 0x49, (byte) 0x5, (byte) 0x0, (byte) 0x50, (byte) 0x4b, (byte) 0x1, + (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, (byte) 0x0, (byte) 0x8, (byte) 0x8, + (byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53, (byte) 0x8e, (byte) 0x39, (byte) 0x14, + (byte) 0x49, (byte) 0xd, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0xb, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e, (byte) 0x74, (byte) 0x72, (byte) 0x79, + (byte) 0x50, (byte) 0x4b, (byte) 0x1, (byte) 0x2, (byte) 0x14, (byte) 0x0, (byte) 0x14, (byte) 0x0, + (byte) 0x0, (byte) 0x8, (byte) 0x8, (byte) 0x0, (byte) 0x60, (byte) 0x59, (byte) 0x55, (byte) 0x53, + (byte) 0xe1, (byte) 0x4c, (byte) 0x29, (byte) 0xa4, (byte) 0x12, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x10, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x5, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x44, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x65, (byte) 0x6e, + (byte) 0x74, (byte) 0x72, (byte) 0x79, (byte) 0x50, (byte) 0x4b, (byte) 0x5, (byte) 0x6, (byte) 0x0, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x2, (byte) 0x0, (byte) 0x66, + (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x8d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, + (byte) 0x0, + }; + + /** + * Create Zip files used by the tests. + * + * @throws IOException If an error occurs + */ + @BeforeTest + public static void setup() throws IOException { + + /** + * Zip contains two entries named "entry" and "entry/" + */ + Files.deleteIfExists(ZIP_FILE); + try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(ZIP_FILE))) { + zos.putNextEntry(new ZipEntry(FILE_ENTRY.name)); + zos.write(FILE_ENTRY.bytes); + zos.closeEntry(); + zos.putNextEntry(new ZipEntry(DIR_ENTRY.name)); + zos.write(DIR_ENTRY.bytes); + zos.closeEntry(); + } + + /** + * Jar contains two entries named "entry" and "entry/" + */ + Files.deleteIfExists(TEST_JAR); + try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(TEST_JAR))) { + jos.putNextEntry(new JarEntry(FILE_ENTRY.name)); + jos.write(FILE_ENTRY.bytes); + jos.closeEntry(); + jos.putNextEntry(new JarEntry(DIR_ENTRY.name)); + jos.write(DIR_ENTRY.bytes); + jos.closeEntry(); + } + + /** + * Zip contains the entry "entry/" + */ + Files.deleteIfExists(ZIP_FILE2); + try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(ZIP_FILE2))) { + zos.putNextEntry(new ZipEntry(DIR_ENTRY.name)); + zos.write(DIR_ENTRY.bytes); + zos.closeEntry(); + } + + /** + * Create a Jar that contains two entries named "entry" + */ + Files.deleteIfExists(DUPLICATE_FILE_ENTRY_FILE); + Files.write(DUPLICATE_FILE_ENTRY_FILE, DUPLICATE_ENTRY_JAR_BYTES); + } + + /** + * Clean up after the test run + * + * @throws IOException If an error occurs + */ + @AfterTest + public static void cleanup() throws IOException { + Files.deleteIfExists(ZIP_FILE); + Files.deleteIfExists(ZIP_FILE2); + Files.deleteIfExists(DUPLICATE_FILE_ENTRY_FILE); + Files.deleteIfExists(TEST_JAR); + } + + /** + * DataProvider used to specify the Zip entries to use + * + * @return The Entry to use within the test + */ + @DataProvider + public Object[][] entries() { + return new Object[][]{ + {FILE_ENTRY}, + {DIR_ENTRY} + }; + } + + /** + * Test whether ZipFile::getEntry can find a directory entry within a Zip + * file specifying "name" vs "name/" + * + * @throws IOException If an error occurs + */ + @Test + public void readDirWithoutSlash() throws IOException { + System.out.printf("%n%n**** readDirWithoutSlash ***%n"); + try (ZipFile zip = new ZipFile(ZIP_FILE2.toString())) { + ZipEntry ze = zip.getEntry(ENTRY_NAME); + if (DEBUG) { + System.out.printf(" Entry:%s, found:%s%n", ENTRY_NAME, ze != null); + } + assertNotNull(ze); + assertTrue(ze.isDirectory()); + try (InputStream in = zip.getInputStream(ze)) { + byte[] bytes = in.readAllBytes(); + if (DEBUG) { + System.out.printf("name: %s, isDirectory: %s, payload= %s%n", + ze.getName(), ze.isDirectory(), new String(bytes)); + } + assertEquals(bytes, DIR_ENTRY.bytes, + String.format("Expected payload: %s", + new String(DIR_ENTRY.bytes))); + } + } + } + + /** + * Validate that ZipFile::getEntry will return the correct entry when a file + * and directory have the same name + * + * @param entry The entry to search for + * @throws IOException If an error occurs + */ + @Test(dataProvider = "entries") + public void testSameFileDirEntryName(Entry entry) throws IOException { + System.out.printf("%n%n**** testSameFileDirEntryName ***%n"); + + try (ZipFile zip = new ZipFile(ZIP_FILE.toString())) { + ZipEntry ze = zip.getEntry(entry.name); + if (DEBUG) { + System.out.printf(" Entry:%s, found:%s%n", entry.name, ze != null); + } + assertNotNull(ze); + try (InputStream in = zip.getInputStream(ze)) { + byte[] bytes = in.readAllBytes(); + if (DEBUG) { + System.out.printf("name: %s, isDirectory: %s, payload= %s%n", + ze.getName(), ze.isDirectory(), new String(bytes)); + } + assertEquals(entry.bytes, bytes, + String.format("Expected payload: %s", new String(entry.bytes))); + } + } + } + + /** + * Validate that ZipFile::getEntry will return the correct entry, which + * is the second entry, when there are duplicate entries within the Zip file. + * + * @throws IOException If an error occurs + */ + @Test + public void DupFileEntryTest() throws IOException { + System.out.printf("%n%n**** DupFileEntryTest ***%n"); + try (ZipFile zip = + new ZipFile(DUPLICATE_FILE_ENTRY_FILE.toString())) { + ZipEntry ze = zip.getEntry(ENTRY_NAME); + if (DEBUG) { + System.out.printf(" Entry:%s, found:%s%n", ENTRY_NAME, ze != null); + } + assertNotNull(ze); + try (InputStream in = zip.getInputStream(ze)) { + byte[] bytes = in.readAllBytes(); + if (DEBUG) { + System.out.printf("name: %s, isDirectory: %s, payload= %s%n", + ze.getName(), ze.isDirectory(), new String(bytes)); + } + assertEquals(bytes, DUPLICATE_FILE_ENTRY.bytes, + String.format("Expected payload: %s", new String(DUPLICATE_FILE_ENTRY.bytes))); + } + } + } + + /** + * Verify that ZipInputStream can be used to read all Zip entries including + * a file and directory entry with the same name + * + * @throws IOException If an error occurs + */ + @Test + public void ZipInputStreamTest() throws IOException { + System.out.printf("%n%n**** ZipInputStreamTest ***%n"); + try (ZipInputStream zis = new ZipInputStream( + new FileInputStream(ZIP_FILE.toFile()))) { + ZipEntry zipEntry = zis.getNextEntry(); + assertNotNull(zipEntry); + while (zipEntry != null) { + Entry e; + if (zipEntry.getName().equals(FILE_ENTRY.name)) { + e = FILE_ENTRY; + } else if (zipEntry.getName().equals(DIR_ENTRY.name)) { + e = DIR_ENTRY; + } else { + throw new RuntimeException( + String.format("Invalid Zip entry: %s", zipEntry.getName())); + } + assertEquals(zipEntry.getMethod(), e.method); + assertEquals(zis.readAllBytes(), e.bytes, + String.format("Expected payload: %s", new String(e.bytes))); + zipEntry = zis.getNextEntry(); + } + } + } + + /** + * Verify that ZipFile::stream returns all Zip entries including + * a file and directory entry with the same name + * + * @throws IOException If an error occurs + */ + @Test + public void ZipFileStreamTest() throws IOException { + System.out.printf("%n%n**** ZipFileStreamTest ***%n"); + try (ZipFile zf = new ZipFile(ZIP_FILE.toFile())) { + List entries = zf.stream().collect(Collectors.toList()); + assertEquals(EXPECTED_ENTRIES.size(), entries.size()); + for (ZipEntry e : entries) { + assertTrue(EXPECTED_ENTRIES.contains(e.getName())); + } + } + } + + /** + * Verify that JarFile can be used to read all the entries including + * a file and directory entry with the same name + * + * @param entry The entry to validate + * @throws IOException If an error occurs + */ + @Test(dataProvider = "entries") + public static void JarFileInputStreamTest(Entry entry) throws IOException { + System.out.printf("%n%n**** JarFileInputStreamTest ***%n"); + try (JarFile jarFile = new JarFile(TEST_JAR.toFile())) { + JarEntry je = jarFile.getJarEntry(entry.name); + assertNotNull(je); + if (DEBUG) { + System.out.printf("Entry Name: %s, method: %s, Expected Method: %s%n", + entry.name, je.getMethod(), entry.method); + } + assertEquals(entry.method, je.getMethod()); + try (InputStream in = jarFile.getInputStream(je)) { + byte[] bytes = in.readAllBytes(); + if (DEBUG) { + System.out.printf("bytes= %s, expected=%s%n", + new String(bytes), new String(entry.bytes)); + } + assertEquals(bytes, entry.bytes, + String.format("Expected payload: %s", new String(entry.bytes))); + } + } + } + + /** + * Verify that JarInputStream can be used to read all entries including + * a file and directory entry with the same name + * + * @throws IOException If an error occurs + */ + @Test + public void JarInputStreamTest() throws IOException { + System.out.printf("%n%n**** JarInputStreamTest ***%n"); + try (JarInputStream jis = new JarInputStream( + new FileInputStream(TEST_JAR.toFile()))) { + JarEntry jarEntry = jis.getNextJarEntry(); + assertNotNull(jarEntry); + while (jarEntry != null) { + Entry e; + if (jarEntry.getName().equals(FILE_ENTRY.name)) { + e = FILE_ENTRY; + } else if (jarEntry.getName().equals(DIR_ENTRY.name)) { + e = DIR_ENTRY; + } else { + throw new RuntimeException( + String.format("Invalid Jar entry: %s", jarEntry.getName())); + } + assertEquals(jarEntry.getMethod(), e.method); + assertEquals(jis.readAllBytes(), e.bytes, + String.format("Expected payload: %s", new String(e.bytes))); + jarEntry = jis.getNextJarEntry(); + } + } + } + + /** + * Verify that JarURLConnection can be used to access all the entries including + * a file and directory entry with the same name within a jar file + * + * @param entry The entry to validate + * @throws IOException If an error occurs + */ + @Test(dataProvider = "entries") + public void JarURLConnectionTest(Entry entry) throws Exception { + System.out.printf("%n%n**** JarURLConnectionTest ***%n"); + URL url = new URL("jar:" + TEST_JAR.toUri().toURL() + "!/" + entry.name); + if (DEBUG) { + System.out.printf("URL=%s%n", url); + } + JarURLConnection con = (JarURLConnection) url.openConnection(); + con.connect(); + JarEntry je = con.getJarEntry(); + try (JarFile jarFile = con.getJarFile()) { + assertNotNull(je); + assertNotNull(jarFile); + assertNull(con.getAttributes()); + assertNull(con.getMainAttributes()); + assertNull(con.getManifest()); + assertEquals(je.getName(), entry.name); + assertEquals(con.getEntryName(), entry.name); + assertEquals(je.getMethod(), entry.method); + assertEquals(con.getJarFileURL(), TEST_JAR.toUri().toURL()); + if (DEBUG) { + System.out.printf(" getEntryName: %s, getJarFileURL:%s%n", + con.getEntryName(), con.getJarFileURL()); + System.out.printf(" Jar Entry= %s, size= %s%n", je.getName(), je.getSize()); + } + + try (InputStream is = jarFile.getInputStream(je)) { + byte[] bytes = is.readAllBytes(); + if (DEBUG) { + System.out.printf(" Bytes read:%s%n", new String(bytes)); + } + assertEquals(bytes, entry.bytes, + String.format("Expected payload: %s", new String(entry.bytes))); + } + } + } + + /** + * Verify that JarFile::stream returns all entries including + * a file and directory entry with the same name + * + * @throws IOException If an error occurs + */ + @Test + public void JarFileStreamTest() throws IOException { + System.out.printf("%n%n**** JarFileStreamTest ***%n"); + try (JarFile jf = new JarFile(TEST_JAR.toFile())) { + List entries = jf.stream().collect(Collectors.toList()); + assertEquals(EXPECTED_ENTRIES.size(), jf.size()); + for (JarEntry e : entries) { + assertTrue(EXPECTED_ENTRIES.contains(e.getName())); + } + } + } + + /** + * Method used to read the bytes from an InputStream. This method is + * here so that the test could be backported to JDK 8 if needed as + * InputStream::readAllBytes() does not exist + * + * @param is The InputStream to read from + * @return The byte array representing bytes read from the InputStream + * @throws IOException If an error occurs + */ + public static byte[] readAllBytes(InputStream is) throws IOException { + byte[] data = new byte[MAX_BUFFER_SIZE]; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int len; + while ((len = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, len); + } + buffer.flush(); + return buffer.toByteArray(); + } + + /** + * Method used to create a byte[] representing a Jar file with + * duplicate file entries. This uses ZipArchiveOutputStream as ZipOutputStream + * will fail with a "java.util.zip.ZipException: duplicate entry". + */ +// public static void createJarWithDuplicateFileEntries() throws IOException { +// Files.deleteIfExists(DUPFILE_ENTRY_FILE); +// try (ZipArchiveOutputStream zos = +// new ZipArchiveOutputStream(DUPFILE_ENTRY_FILE.toFile())) { +// zos.putArchiveEntry(new ZipArchiveEntry(FILE_ENTRY.name)); +// zos.write(FILE_ENTRY.bytes); +// zos.putArchiveEntry(new ZipArchiveEntry(FILE_ENTRY.name)); +// zos.write("Yet another File".getBytes(StandardCharsets.UTF_8)); +// zos.closeArchiveEntry(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// byte[] jarBytes = Files.readAllBytes(DUPFILE_ENTRY_FILE); +// String result = createByteArray(jarBytes, "DUPLICATE_ENTRY_JAR_BYTES"); +// System.out.println(result); +// } + + /** + * Utility method which takes a byte array and converts to byte array + * declaration. For example: + *
+     *     {@code
+     *        var fooJar = Files.readAllBytes(Path.of("foo.jar"));
+     *        var result = createByteArray(fooJar, "FOOBYTES");
+     *      }
+     * 
+ * + * @param bytes A byte array used to create a byte array declaration + * @param name Name to be used in the byte array declaration + * @return The formatted byte array declaration + */ + public static String createByteArray(byte[] bytes, String name) { + StringBuilder sb = new StringBuilder(bytes.length * 5); + Formatter fmt = new Formatter(sb); + fmt.format(" public static byte[] %s = {", name); + final int linelen = 8; + for (int i = 0; i < bytes.length; i++) { + if (i % linelen == 0) { + fmt.format("%n "); + } + fmt.format(" (byte) 0x%x,", bytes[i] & 0xff); + } + fmt.format("%n };%n"); + return sb.toString(); + } + + /** + * Represents an entry in a Zip file. An entry encapsulates a name, a + * compression method, and its contents/data. + */ + public static class Entry { + public final String name; + public final int method; + public final byte[] bytes; + + public Entry(String name, int method, String contents) { + this.name = name; + this.method = method; + this.bytes = contents.getBytes(StandardCharsets.UTF_8); + } + + public static Entry of(String name, int method, String contents) { + return new Entry(name, method, contents); + } + } +} From 5807e640bc9122dcd2e36b141e01613a17fffbbf Mon Sep 17 00:00:00 2001 From: Aleksei Voitylov Date: Tue, 9 Jan 2024 15:48:24 +0100 Subject: [PATCH 06/13] 8316976: Improve signature handling Reviewed-by: mbalao Backport-of: ed1269b7410759e8fa0d97d85328f20d11ae8d9a --- .../org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java | 1 - .../org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java index 8e4c2424eb7..88bf38a0606 100644 --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java @@ -318,7 +318,6 @@ byte[] sign(Key key, SignedInfo si, XMLSignContext context) throw new XMLSignatureException(e); } LOG.debug("Signature provider: {}", signature.getProvider()); - LOG.debug("Signing with key: {}", key); LOG.debug("JCA Algorithm: {}", getJCAAlgorithm()); try (SignerOutputStream outputStream = new SignerOutputStream(signature)) { diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java index 98cf1772fe8..12f923381a7 100644 --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java @@ -334,7 +334,6 @@ byte[] sign(Key key, SignedInfo si, XMLSignContext context) } signature.initSign((PrivateKey)key); LOG.debug("Signature provider: {}", signature.getProvider()); - LOG.debug("Signing with key: {}", key); LOG.debug("JCA Algorithm: {}", getJCAAlgorithm()); try (SignerOutputStream outputStream = new SignerOutputStream(signature)) { From 221f6f8c6d181ef3af32a860c5d7eef2f6dcff28 Mon Sep 17 00:00:00 2001 From: Alexey Bakhtin Date: Tue, 9 Jan 2024 15:48:45 +0100 Subject: [PATCH 07/13] 8317547: Enhance TLS connection support Reviewed-by: mbalao Backport-of: 066482f9686ca81068f9386322afda8e73323f5e --- .../com/sun/crypto/provider/RSACipher.java | 22 +++-- .../classes/sun/security/util/KeyUtil.java | 55 +++++++------ .../sun/security/mscapi/CRSACipher.java | 82 ++++++++++++------- .../windows/native/libsunmscapi/security.cpp | 36 +++++--- 4 files changed, 119 insertions(+), 76 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index ac512e573a5..b9438dfb309 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -98,6 +98,7 @@ public final class RSACipher extends CipherSpi { // cipher parameter for OAEP padding and TLS RSA premaster secret private AlgorithmParameterSpec spec = null; + private boolean forTlsPremasterSecret = false; // buffer for the data private byte[] buffer; @@ -292,6 +293,7 @@ private void init(int opmode, Key key, SecureRandom random, } spec = params; + forTlsPremasterSecret = true; this.random = random; // for TLS RSA premaster secret } int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 @@ -383,7 +385,7 @@ private byte[] doFinal() throws BadPaddingException, byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false); result = padding.unpad(paddingCopy); - if (result == null) { + if (result == null && !forTlsPremasterSecret) { throw new BadPaddingException ("Padding error in decryption"); } @@ -472,26 +474,22 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, boolean isTlsRsaPremasterSecret = algorithm.equals("TlsRsaPremasterSecret"); - Exception failover = null; byte[] encoded = null; update(wrappedKey, 0, wrappedKey.length); try { encoded = doFinal(); - } catch (BadPaddingException e) { - if (isTlsRsaPremasterSecret) { - failover = e; - } else { - throw new InvalidKeyException("Unwrapping failed", e); - } - } catch (IllegalBlockSizeException e) { - // should not occur, handled with length check above + } catch (BadPaddingException | IllegalBlockSizeException e) { + // BadPaddingException cannot happen for TLS RSA unwrap. + // In that case, padding error is indicated by returning null. + // IllegalBlockSizeException cannot happen in any case, + // because of the length check above. throw new InvalidKeyException("Unwrapping failed", e); } try { if (isTlsRsaPremasterSecret) { - if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + if (!forTlsPremasterSecret) { throw new IllegalStateException( "No TlsRsaPremasterSecretParameterSpec specified"); } @@ -500,7 +498,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, encoded = KeyUtil.checkTlsPreMasterSecretKey( ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), - random, encoded, (failover != null)); + random, encoded, encoded == null); } return ConstructKeys.constructKey(encoded, algorithm, type); 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 a62f92b7efc..d5ab03e62f4 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -288,13 +288,14 @@ public static final boolean isOracleJCEProvider(String providerName) { * contains the lower of that suggested by the client in the client * hello and the highest supported by the server. * @param encoded the encoded key in its "RAW" encoding format - * @param isFailOver whether or not the previous decryption of the - * encrypted PreMasterSecret message run into problem + * @param failure true if encoded is incorrect according to previous checks * @return the polished PreMasterSecret key in its "RAW" encoding format */ public static byte[] checkTlsPreMasterSecretKey( int clientVersion, int serverVersion, SecureRandom random, - byte[] encoded, boolean isFailOver) { + byte[] encoded, boolean failure) { + + byte[] tmp; if (random == null) { random = JCAUtil.getSecureRandom(); @@ -302,30 +303,38 @@ public static byte[] checkTlsPreMasterSecretKey( byte[] replacer = new byte[48]; random.nextBytes(replacer); - if (!isFailOver && (encoded != null)) { - // check the length - if (encoded.length != 48) { - // private, don't need to clone the byte array. - return replacer; - } - - int encodedVersion = - ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); - if (clientVersion != encodedVersion) { - if (clientVersion > 0x0301 || // 0x0301: TLSv1 - serverVersion != encodedVersion) { - encoded = replacer; - } // Otherwise, For compatibility, we maintain the behavior - // that the version in pre_master_secret can be the - // negotiated version for TLS v1.0 and SSL v3.0. - } + if (failure) { + tmp = replacer; + } else { + tmp = encoded; + } + if (tmp == null) { + encoded = replacer; + } else { + encoded = tmp; + } + // check the length + if (encoded.length != 48) { // private, don't need to clone the byte array. - return encoded; + tmp = replacer; + } else { + tmp = encoded; } - // private, don't need to clone the byte array. - return replacer; + int encodedVersion = + ((tmp[0] & 0xFF) << 8) | (tmp[1] & 0xFF); + int check1 = 0; + int check2 = 0; + int check3 = 0; + if (clientVersion != encodedVersion) check1 = 1; + if (clientVersion > 0x0301) check2 = 1; + if (serverVersion != encodedVersion) check3 = 1; + if ((check1 & (check2 | check3)) == 1) { + return replacer; + } else { + return tmp; + } } /** diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java index 133ceff4f32..e89743b8707 100644 --- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java +++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, 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 @@ -30,6 +30,7 @@ import java.security.Key; import java.security.interfaces.*; import java.security.spec.*; +import java.util.Arrays; import javax.crypto.*; import javax.crypto.spec.*; @@ -61,6 +62,9 @@ */ public final class CRSACipher extends CipherSpi { + private static final int ERROR_INVALID_PARAMETER = 0x57; + private static final int NTE_INVALID_PARAMETER = 0x80090027; + // constant for an empty byte array private static final byte[] B0 = new byte[0]; @@ -101,6 +105,8 @@ public final class CRSACipher extends CipherSpi { // cipher parameter for TLS RSA premaster secret private AlgorithmParameterSpec spec = null; + private boolean forTlsPremasterSecret = false; + // the source of randomness private SecureRandom random; @@ -171,6 +177,9 @@ protected void engineInit(int opmode, Key key, } spec = params; this.random = random; // for TLS RSA premaster secret + this.forTlsPremasterSecret = true; + } else { + this.forTlsPremasterSecret = false; } init(opmode, key); } @@ -278,8 +287,7 @@ private void update(byte[] in, int inOfs, int inLen) { } // internal doFinal() method. Here we perform the actual RSA operation - private byte[] doFinal() throws BadPaddingException, - IllegalBlockSizeException { + private byte[] doFinal() throws IllegalBlockSizeException { if (bufOfs > buffer.length) { throw new IllegalBlockSizeException("Data must not be longer " + "than " + (buffer.length - paddingLength) + " bytes"); @@ -308,7 +316,7 @@ private byte[] doFinal() throws BadPaddingException, throw new AssertionError("Internal error"); } - } catch (KeyException e) { + } catch (KeyException | BadPaddingException e) { throw new ProviderException(e); } finally { @@ -331,14 +339,14 @@ protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, // see JCE spec protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) - throws BadPaddingException, IllegalBlockSizeException { + throws IllegalBlockSizeException { update(in, inOfs, inLen); return doFinal(); } // see JCE spec protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, - int outOfs) throws ShortBufferException, BadPaddingException, + int outOfs) throws ShortBufferException, IllegalBlockSizeException { if (outputSize > out.length - outOfs) { throw new ShortBufferException @@ -354,6 +362,7 @@ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, // see JCE spec protected byte[] engineWrap(Key key) throws InvalidKeyException, IllegalBlockSizeException { + byte[] encoded = key.getEncoded(); // TODO - unextractable key if ((encoded == null) || (encoded.length == 0)) { throw new InvalidKeyException("Could not obtain encoded key"); @@ -362,12 +371,7 @@ protected byte[] engineWrap(Key key) throws InvalidKeyException, throw new InvalidKeyException("Key is too long for wrapping"); } update(encoded, 0, encoded.length); - try { - return doFinal(); - } catch (BadPaddingException e) { - // should not occur - throw new InvalidKeyException("Wrapping failed", e); - } + return doFinal(); } // see JCE spec @@ -388,31 +392,31 @@ protected java.security.Key engineUnwrap(byte[] wrappedKey, update(wrappedKey, 0, wrappedKey.length); try { encoded = doFinal(); - } catch (BadPaddingException e) { - if (isTlsRsaPremasterSecret) { - failover = e; - } else { - throw new InvalidKeyException("Unwrapping failed", e); - } } catch (IllegalBlockSizeException e) { // should not occur, handled with length check above throw new InvalidKeyException("Unwrapping failed", e); } - if (isTlsRsaPremasterSecret) { - if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { - throw new IllegalStateException( - "No TlsRsaPremasterSecretParameterSpec specified"); + try { + if (isTlsRsaPremasterSecret) { + if (!forTlsPremasterSecret) { + throw new IllegalStateException( + "No TlsRsaPremasterSecretParameterSpec specified"); + } + + // polish the TLS premaster secret + encoded = KeyUtil.checkTlsPreMasterSecretKey( + ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), + ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), + random, encoded, encoded == null); } - // polish the TLS premaster secret - encoded = KeyUtil.checkTlsPreMasterSecretKey( - ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(), - ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(), - random, encoded, (failover != null)); + return constructKey(encoded, algorithm, type); + } finally { + if (encoded != null) { + Arrays.fill(encoded, (byte) 0); + } } - - return constructKey(encoded, algorithm, type); } // see JCE spec @@ -496,7 +500,23 @@ private static Key constructKey(byte[] encodedKey, * Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY. * It expects and returns ciphertext data in big-endian form. */ - private native static byte[] encryptDecrypt(byte[] data, int dataSize, - long hCryptKey, boolean doEncrypt) throws KeyException; + private byte[] encryptDecrypt(byte[] data, int dataSize, + long hCryptKey, boolean doEncrypt) throws KeyException, BadPaddingException { + int[] returnStatus = new int[1]; + byte[] result= encryptDecrypt(returnStatus, data, dataSize, hCryptKey, doEncrypt); + if ((returnStatus[0] == ERROR_INVALID_PARAMETER) || (returnStatus[0] == NTE_INVALID_PARAMETER)) { + if (forTlsPremasterSecret) { + result = null; + } else { + throw new BadPaddingException("Error " + returnStatus[0] + " returned by MSCAPI"); + } + } else if (returnStatus[0] != 0) { + throw new KeyException("Error " + returnStatus[0] + " returned by MSCAPI"); + } + + return result; + } + private static native byte[] encryptDecrypt(int[] returnStatus, byte[] data, int dataSize, + long key, boolean doEncrypt) throws KeyException; } diff --git a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp index 7d8b13470fe..da1e3222632 100644 --- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp +++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp @@ -1889,18 +1889,25 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_destroyKeyContainer /* * Class: sun_security_mscapi_CRSACipher * Method: encryptDecrypt - * Signature: ([BIJZ)[B + * Signature: ([I[BIJZ)[B */ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt - (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey, + (JNIEnv *env, jclass clazz, jintArray jResultStatus, jbyteArray jData, jint jDataSize, jlong hKey, jboolean doEncrypt) { jbyteArray result = NULL; jbyte* pData = NULL; + jbyte* resultData = NULL; DWORD dwDataLen = jDataSize; DWORD dwBufLen = env->GetArrayLength(jData); DWORD i; BYTE tmp; + BOOL success; + DWORD ss = ERROR_SUCCESS; + DWORD lastError = ERROR_SUCCESS; + DWORD resultLen = 0; + DWORD pmsLen = 48; + jbyte pmsArr[48] = {0}; __try { @@ -1927,6 +1934,8 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt pData[i] = pData[dwBufLen - i -1]; pData[dwBufLen - i - 1] = tmp; } + resultData = pData; + resultLen = dwBufLen; } else { // convert to little-endian for (i = 0; i < dwBufLen / 2; i++) { @@ -1936,21 +1945,28 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt } // decrypt - if (! ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated - &dwBufLen)) { - - ThrowException(env, KEY_EXCEPTION, GetLastError()); - __leave; + success = ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated + &dwBufLen); + lastError = GetLastError(); + if (success) { + ss = ERROR_SUCCESS; + resultData = pData; + resultLen = dwBufLen; + } else { + ss = lastError; + resultData = pmsArr; + resultLen = pmsLen; } + env->SetIntArrayRegion(jResultStatus, 0, 1, (jint*) &ss); } - // Create new byte array - if ((result = env->NewByteArray(dwBufLen)) == NULL) { + // Create new byte array + if ((result = env->NewByteArray(resultLen)) == NULL) { __leave; } // Copy data from native buffer to Java buffer - env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData); + env->SetByteArrayRegion(result, 0, resultLen, (jbyte*) resultData); } __finally { From 3d0b51483ba0dcdd1eb34eaedbbe604d029b37d8 Mon Sep 17 00:00:00 2001 From: Jason Katonica Date: Fri, 5 Jan 2024 08:51:25 -0500 Subject: [PATCH 08/13] Use correct JNI function to call ArrayList.add() Various testcases are being run as part of the `openj9` project. Currently one of these tests is failing since they are able to detect that the wrong method signature is being used by JNI calls at runtime. This update makes the same method call only it expects a boolean to be returned from the method call. This allows for the test to pass the JNI method signature check. This fixes [openj9 issue 17795](https://github.com/eclipse-openj9/openj9/issues/17795). Signed-off-by: Jason Katonica --- .../share/native/libj2pkcs11/j2secmod.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c index 9321287300f..10eeef1eec9 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c @@ -23,6 +23,12 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2024, 2024 All Rights Reserved + * =========================================================================== + */ + #include #include #include @@ -241,7 +247,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_Secmod_nssGetModuleList if (jModule == NULL) { return NULL; } - (*env)->CallVoidMethod(env, jList, jAdd, jModule); + (*env)->CallBooleanMethod(env, jList, jAdd, jModule); if ((*env)->ExceptionCheck(env)) { return NULL; } From 10d2feeaea612e474d0385d6bed43f374485c1d5 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Tue, 9 Jan 2024 22:18:15 +0100 Subject: [PATCH 09/13] 8323422: [17u] Remove designator DEFAULT_PROMOTED_VERSION_PRE=ea for release 17.0.10 Reviewed-by: goetz --- make/conf/version-numbers.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 6c35e79d1be..9433c11c1aa 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -39,4 +39,4 @@ DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 DEFAULT_ACCEPTABLE_BOOT_VERSIONS="16 17" DEFAULT_JDK_SOURCE_TARGET_VERSION=17 -DEFAULT_PROMOTED_VERSION_PRE=ea +DEFAULT_PROMOTED_VERSION_PRE= From cb8cf294cca172f86b39a3088ead5b7473603382 Mon Sep 17 00:00:00 2001 From: Kostas Tsiounis Date: Tue, 19 Dec 2023 17:34:01 -0500 Subject: [PATCH 10/13] Specify OpenJCEPlusFIPS profile for supported platforms --- .../share/conf/security/java.security | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index f54c125eea7..dc3bfbb65bf 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -150,6 +150,59 @@ RestrictedSecurity.NSS.140-2.securerandom.provider = SunPKCS11-NSS-FIPS RestrictedSecurity.NSS.140-2.securerandom.algorithm = PKCS11 #endif +#if defined aix-ppc || defined linux-ppc || defined linux-x86 || defined windows +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.name = OpenJCEPlusFIPS Cryptographic Module FIPS 140-3 +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.default = true +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.fips = true +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.number = Certificate #XXX +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.policy = https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/ +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.sunsetDate = 2026-09-21 +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.tls.disabledNamedCurves = +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.tls.disabledAlgorithms = \ + 3DES_EDE_CBC, \ + anon, \ + DES, \ + DH keySize < 2048, \ + EC keySize < 224, \ + MD5withRSA, \ + NULL, \ + RC4, \ + SSLv3, \ + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, \ + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, \ + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, \ + TLS_DHE_DSS_WITH_AES_256_CBC_SHA, \ + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, \ + TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, \ + TLS_EMPTY_RENEGOTIATION_INFO_SCSV, \ + TLS_RSA_WITH_AES_128_CBC_SHA, \ + TLS_RSA_WITH_AES_128_CBC_SHA256, \ + TLS_RSA_WITH_AES_128_GCM_SHA256, \ + TLS_RSA_WITH_AES_256_CBC_SHA, \ + TLS_RSA_WITH_AES_256_CBC_SHA256, \ + TLS_RSA_WITH_AES_256_GCM_SHA384, \ + TLSv1, \ + TLSv1.1, \ + X25519, \ + X448 +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.tls.ephemeralDHKeySize = +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.tls.legacyAlgorithms = +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.certpath.disabledAlgorithms = +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.legacyAlgorithms = +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.1 = com.ibm.crypto.plus.provider.OpenJCEPlusFIPS +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.2 = SUN [{CertificateFactory, X.509, ImplementedIn=Software}, \ + {CertPathBuilder, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}, \ + {CertPathValidator, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}, \ + {CertStore, Collection, ImplementedIn=Software}, \ + {CertStore, com.sun.security.IndexedCollection, ImplementedIn=Software}, \ + {Configuration, JavaLoginConfig, *}, \ + {Policy, JavaPolicy, *}] +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.3 = SunJSSE +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.javax.net.ssl.keyStore = NONE +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.securerandom.provider = OpenJCEPlusFIPS +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.securerandom.algorithm = SHA512DRBG +#endif + # # A list of preferred providers for specific algorithms. These providers will # be searched for matching algorithms before the list of registered providers. From 1cbe1ff543b1ccbbb99a88c870f5f6af6ab2eec3 Mon Sep 17 00:00:00 2001 From: Tao Liu Date: Thu, 7 Dec 2023 10:24:50 -0500 Subject: [PATCH 11/13] Add provider name and class name mapping in Restricted Security For the Java security providers, for example, the SunSASL, its class name is com.sun.security.sasl.Provider. From the provider class name, can not get the provider name which defined in its construction method. So, add the mapping between the provider name and its class name in Restricted Security mode. Signed-off-by: Tao Liu --- .../internal/security/RestrictedSecurity.java | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java index db60a3f2adc..4080d338185 100644 --- a/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java +++ b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java @@ -1,6 +1,6 @@ /* * =========================================================================== - * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved + * (c) Copyright IBM Corp. 2022, 2024 All Rights Reserved * =========================================================================== * * This code is free software; you can redistribute it and/or modify it @@ -687,11 +687,19 @@ private void initProviders() { // Remove the provider's optional arguments if there are. pos = providerName.indexOf(' '); - providerName = (pos < 0) ? providerName.trim() : providerName.substring(0, pos).trim(); - // Remove the provider's class package names if there are. - pos = providerName.lastIndexOf('.'); - providerName = (pos < 0) ? providerName : providerName.substring(pos + 1, providerName.length()); - // Provider without arguments and package names. + if (pos >= 0) { + providerName = providerName.substring(0, pos); + } + providerName = providerName.trim(); + + // Remove argument, e.g. -NSS-FIPS, if present. + pos = providerName.indexOf('-'); + if (pos >= 0) { + providerName = providerName.substring(0, pos); + } + + // Provider name defined in provider construction method. + providerName = getProvidersSimpleName(providerName); providersSimpleName.add(pNum - 1, providerName); } @@ -959,11 +967,12 @@ boolean isRestrictedProviderAllowed(String providerName) { // Remove argument, e.g. -NSS-FIPS, if there is. int pos = providerName.indexOf('-'); - providerName = (pos < 0) ? providerName : providerName.substring(0, pos); + if (pos >= 0) { + providerName = providerName.substring(0, pos); + } - // Remove the provider class package name if there is. - pos = providerName.lastIndexOf('.'); - providerName = (pos < 0) ? providerName : providerName.substring(pos + 1, providerName.length()); + // Provider name defined in provider construction method. + providerName = getProvidersSimpleName(providerName); // Check if the provider is in restricted security provider list. // If not, the provider won't be registered. @@ -988,6 +997,27 @@ boolean isRestrictedProviderAllowed(String providerName) { return false; } + /** + * Get the provider name defined in provider construction method. + * + * @param providerName provider name or provider with packages + * @return provider name defined in provider construction method + */ + private static String getProvidersSimpleName(String providerName) { + if (providerName.equals("com.sun.security.sasl.Provider")) { + // The main class for the SunSASL provider is com.sun.security.sasl.Provider. + return "SunSASL"; + } else { + // Remove the provider's class package names if present. + int pos = providerName.lastIndexOf('.'); + if (pos >= 0) { + providerName = providerName.substring(pos + 1); + } + // Provider without package names. + return providerName; + } + } + /** * List audit info of all available RestrictedSecurity profiles. */ From 6ffdd77c25bc3034ba21cf40ab0132b71d3bcd51 Mon Sep 17 00:00:00 2001 From: Peter Shipton Date: Tue, 16 Jan 2024 15:48:43 -0500 Subject: [PATCH 12/13] Add OpenSSL 3.x license to openj9-openjdk-notices Signed-off-by: Peter Shipton --- openj9-openjdk-notices | 185 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 2 deletions(-) diff --git a/openj9-openjdk-notices b/openj9-openjdk-notices index 2f38153517f..eba945a5053 100644 --- a/openj9-openjdk-notices +++ b/openj9-openjdk-notices @@ -4,7 +4,7 @@ included with the JRE and JDK. If you do not wish to install the OpenSSL toolkit, you may delete the library from the JRE and JDK. ---- begin of LICENSE --- +--- begin of LICENSE for OpenSSL 1.1.1 --- LICENSE ISSUES ============== @@ -131,4 +131,185 @@ from the JRE and JDK. */ ---- end of LICENSE --- +--- end of LICENSE for OpenSSL 1.1.1 --- + +--- begin of LICENSE for OpenSSL 3.x --- + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +--- end of LICENSE for OpenSSL 3.x --- From 8d537aa07abce3b52e202e41793fb57b0b9f7f2d Mon Sep 17 00:00:00 2001 From: J9 Build Date: Tue, 16 Jan 2024 23:20:53 +0000 Subject: [PATCH 13/13] Update OPENJDK_TAG to merged level jdk-17.0.10+7 Signed-off-by: J9 Build --- closed/openjdk-tag.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/closed/openjdk-tag.gmk b/closed/openjdk-tag.gmk index b33a19cffa0..153323be634 100644 --- a/closed/openjdk-tag.gmk +++ b/closed/openjdk-tag.gmk @@ -1 +1 @@ -OPENJDK_TAG := jdk-17.0.10+6 +OPENJDK_TAG := jdk-17.0.10+7