From 3888c76ac38ae26d597d6123dc83a202e5e54d89 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 17 Jun 2021 07:06:05 +0000 Subject: [PATCH 01/72] 8265167: Richer Text Editors Backport-of: c59311d94c3f010b9017825d767db8241c69a2a7 --- .../javax/swing/text/rtf/RTFParser.java | 64 +++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java index 88e2990942c..9b38c5cff57 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java @@ -233,25 +233,52 @@ public void write(char ch) currentCharacters.append(ch); } else { /* TODO: Test correct behavior of \bin keyword */ + if (pendingKeyword.equals("bin")) { /* magic layer-breaking kwd */ - long parameter = Long.parseLong(currentCharacters.toString()); + long parameter = 0L; + try { + parameter = Long.parseLong(currentCharacters.toString()); + } catch (NumberFormatException e) { + warning("Illegal number format " + currentCharacters.toString() + + " in \bin tag"); + pendingKeyword = null; + currentCharacters = new StringBuffer(); + state = S_text; + // Delimiters here are interpreted as text too + if (!Character.isWhitespace(ch)) + write(ch); + break; + } pendingKeyword = null; state = S_inblob; + int maxBytes = 4 * 1024 * 1024; binaryBytesLeft = parameter; - if (binaryBytesLeft > Integer.MAX_VALUE) - binaryBuf = new ByteArrayOutputStream(Integer.MAX_VALUE); - else - binaryBuf = new ByteArrayOutputStream((int)binaryBytesLeft); + + if (binaryBytesLeft > maxBytes) { + binaryBuf = new ByteArrayOutputStream(maxBytes); + } else if (binaryBytesLeft < 0) { + binaryBytesLeft = 0; + binaryBuf = new ByteArrayOutputStream((int)binaryBytesLeft); + } else { + binaryBuf = new ByteArrayOutputStream((int) binaryBytesLeft); + } savedSpecials = specialsTable; specialsTable = allSpecialsTable; break; } - int parameter = Integer.parseInt(currentCharacters.toString()); - ok = handleKeyword(pendingKeyword, parameter); - if (!ok) - warning("Unknown keyword: " + pendingKeyword + - " (param " + currentCharacters + ")"); + int parameter = 0; + try { + parameter = Integer.parseInt(currentCharacters.toString()); + ok = handleKeyword(pendingKeyword, parameter); + if (!ok) { + warning("Unknown keyword: " + pendingKeyword + + " (param " + currentCharacters + ")"); + } + } catch (NumberFormatException e) { + warning("Illegal number format " + currentCharacters.toString() + + " in " + pendingKeyword + " tag"); + } pendingKeyword = null; currentCharacters = new StringBuffer(); state = S_text; @@ -280,14 +307,15 @@ public void write(char ch) } break; case S_inblob: - binaryBuf.write(ch); - binaryBytesLeft --; - if (binaryBytesLeft == 0) { - state = S_text; - specialsTable = savedSpecials; - savedSpecials = null; - handleBinaryBlob(binaryBuf.toByteArray()); - binaryBuf = null; + if (binaryBytesLeft > 0) { + binaryBuf.write(ch); + binaryBytesLeft--; + } else { + state = S_text; + specialsTable = savedSpecials; + savedSpecials = null; + handleBinaryBlob(binaryBuf.toByteArray()); + binaryBuf = null; } } } From 80dd63d0d7b35e7b96670c9dba2e67c3491eb7b0 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Fri, 18 Jun 2021 04:21:33 +0000 Subject: [PATCH 02/72] 8267729: Improve TLS client handshaking Reviewed-by: jnimeh, ahgross, rhalade --- .../security/ssl/ECDHClientKeyExchange.java | 40 ++++++--- .../security/ssl/ECDHServerKeyExchange.java | 19 ++++- .../sun/security/ssl/KeyShareExtension.java | 50 ++++++++--- .../classes/sun/security/ssl/NamedGroup.java | 84 ++++--------------- .../classes/sun/security/ssl/SSLLogger.java | 2 +- 5 files changed, 101 insertions(+), 94 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java index f2cc67a793f..6b2264e0f13 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.security.interfaces.ECPublicKey; @@ -35,6 +36,7 @@ import java.security.spec.ECParameterSpec; import java.security.spec.NamedParameterSpec; import java.text.MessageFormat; +import java.util.EnumSet; import java.util.Locale; import javax.crypto.SecretKey; import sun.security.ssl.SSLHandshake.HandshakeMessage; @@ -317,12 +319,19 @@ public void consume(ConnectionContext context, // create the credentials try { - NamedGroup ng = namedGroup; // "effectively final" the lambda - // AlgorithmConstraints are checked internally. - SSLCredentials sslCredentials = namedGroup.decodeCredentials( - cke.encodedPoint, shc.algorithmConstraints, - s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "ClientKeyExchange " + ng + ": " + s)); + SSLCredentials sslCredentials = + namedGroup.decodeCredentials(cke.encodedPoint); + if (shc.algorithmConstraints != null && + sslCredentials instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!shc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "ClientKeyExchange for " + namedGroup + + " does not comply with algorithm constraints"); + } + } shc.handshakeCredentials.add(sslCredentials); } catch (GeneralSecurityException e) { @@ -497,12 +506,19 @@ public void consume(ConnectionContext context, // create the credentials try { - NamedGroup ng = namedGroup; // "effectively final" the lambda - // AlgorithmConstraints are checked internally. - SSLCredentials sslCredentials = namedGroup.decodeCredentials( - cke.encodedPoint, shc.algorithmConstraints, - s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "ClientKeyExchange " + ng + ": " + s)); + SSLCredentials sslCredentials = + namedGroup.decodeCredentials(cke.encodedPoint); + if (shc.algorithmConstraints != null && + sslCredentials instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!shc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "ClientKeyExchange for " + namedGroup + + " does not comply with algorithm constraints"); + } + } shc.handshakeCredentials.add(sslCredentials); } catch (GeneralSecurityException e) { diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java index 11efab71c85..09b7a6bdca2 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -37,6 +38,7 @@ import java.security.Signature; import java.security.SignatureException; import java.text.MessageFormat; +import java.util.EnumSet; import java.util.Locale; import java.util.Map; import sun.security.ssl.SSLHandshake.HandshakeMessage; @@ -214,10 +216,19 @@ class ECDHServerKeyExchangeMessage extends HandshakeMessage { } try { - sslCredentials = namedGroup.decodeCredentials( - publicPoint, handshakeContext.algorithmConstraints, - s -> chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "ServerKeyExchange " + namedGroup + ": " + (s))); + sslCredentials = + namedGroup.decodeCredentials(publicPoint); + if (handshakeContext.algorithmConstraints != null && + sslCredentials instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!handshakeContext.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "ServerKeyExchange for " + namedGroup + + " does not comply with algorithm constraints"); + } + } } catch (GeneralSecurityException ex) { throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, "Cannot decode named group: " + diff --git a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java index a0d9b98a77a..df430c557c9 100644 --- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; import java.text.MessageFormat; import java.util.Collections; @@ -349,7 +350,8 @@ public void consume(ConnectionContext context, NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId); if (ng == null || !SupportedGroups.isActivatable( shc.algorithmConstraints, ng)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unsupported named group: " + NamedGroup.nameOf(entry.namedGroupId)); @@ -359,16 +361,33 @@ public void consume(ConnectionContext context, try { SSLCredentials kaCred = - ng.decodeCredentials(entry.keyExchange, - shc.algorithmConstraints, - s -> SSLLogger.warning(s)); + ng.decodeCredentials(entry.keyExchange); + if (shc.algorithmConstraints != null && + kaCred instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!shc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + if (SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( + "key share entry of " + ng + " does not " + + " comply with algorithm constraints"); + } + + kaCred = null; + } + } + if (kaCred != null) { credentials.add(kaCred); } } catch (GeneralSecurityException ex) { - SSLLogger.warning( - "Cannot decode named group: " + - NamedGroup.nameOf(entry.namedGroupId)); + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( + "Cannot decode named group: " + + NamedGroup.nameOf(entry.namedGroupId)); + } } } @@ -646,9 +665,20 @@ public void consume(ConnectionContext context, SSLCredentials credentials = null; try { - SSLCredentials kaCred = ng.decodeCredentials( - keyShare.keyExchange, chc.algorithmConstraints, - s -> chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, s)); + SSLCredentials kaCred = + ng.decodeCredentials(keyShare.keyExchange); + if (chc.algorithmConstraints != null && + kaCred instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!chc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "key share entry of " + ng + " does not " + + " comply with algorithm constraints"); + } + } + if (kaCred != null) { credentials = kaCred; } diff --git a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java index 8febedbe989..7afa619ad5d 100644 --- a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java +++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java @@ -419,12 +419,9 @@ byte[] encodePossessionPublicKey( return spec.encodePossessionPublicKey(namedGroupPossession); } - SSLCredentials decodeCredentials(byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail) - throws IOException, GeneralSecurityException { - return spec.decodeCredentials( - this, encoded, constraints, onConstraintFail); + SSLCredentials decodeCredentials( + byte[] encoded) throws IOException, GeneralSecurityException { + return spec.decodeCredentials(this, encoded); } SSLPossession createPossession(SecureRandom random) { @@ -436,30 +433,13 @@ SSLKeyDerivation createKeyDerivation( return spec.createKeyDerivation(hc); } - interface ExceptionSupplier { - void apply(String s) throws SSLException; - } - // A list of operations related to named groups. private interface NamedGroupScheme { - default void checkConstraints(PublicKey publicKey, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail) throws SSLException { - if (!constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), publicKey)) { - onConstraintFail.apply("key share entry does not " - + "comply with algorithm constraints"); - } - } - byte[] encodePossessionPublicKey( NamedGroupPossession namedGroupPossession); - SSLCredentials decodeCredentials( - NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException; + SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException; SSLPossession createPossession(NamedGroup ng, SecureRandom random); @@ -524,13 +504,10 @@ public byte[] encodePossessionPublicKey( } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { if (scheme != null) { - return scheme.decodeCredentials( - ng, encoded, constraints, onConstraintFail); + return scheme.decodeCredentials(ng, encoded); } return null; @@ -567,18 +544,9 @@ public byte[] encodePossessionPublicKey( } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { - - DHKeyExchange.DHECredentials result - = DHKeyExchange.DHECredentials.valueOf(ng, encoded); - - checkConstraints(result.getPublicKey(), constraints, - onConstraintFail); - - return result; + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return DHKeyExchange.DHECredentials.valueOf(ng, encoded); } @Override @@ -605,18 +573,9 @@ public byte[] encodePossessionPublicKey( } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { - - ECDHKeyExchange.ECDHECredentials result - = ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded); - - checkConstraints(result.getPublicKey(), constraints, - onConstraintFail); - - return result; + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded); } @Override @@ -641,18 +600,9 @@ public byte[] encodePossessionPublicKey(NamedGroupPossession poss) { } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { - - XDHKeyExchange.XDHECredentials result - = XDHKeyExchange.XDHECredentials.valueOf(ng, encoded); - - checkConstraints(result.getPublicKey(), constraints, - onConstraintFail); - - return result; + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return XDHKeyExchange.XDHECredentials.valueOf(ng, encoded); } @Override diff --git a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java index acc3a96de09..9f2cbaf4837 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java @@ -184,7 +184,7 @@ public static void finest(String msg, Object... params) { } private static void log(Level level, String msg, Object... params) { - if (logger.isLoggable(level)) { + if (logger != null && logger.isLoggable(level)) { if (params == null || params.length == 0) { logger.log(level, msg); } else { From 4b289d6ab5f63a5218853b7d1a58a10c71eea2ac Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 18 Jun 2021 20:40:32 +0000 Subject: [PATCH 03/72] 8266109: More Resilient Classloading Reviewed-by: rhalade Backport-of: 00c10ed10286a1989a339bc35cb64302630427ae --- .../share/classes/java/net/URLClassLoader.java | 5 +++++ .../classes/jdk/internal/loader/Resource.java | 8 ++++++++ .../classes/jdk/internal/loader/URLClassPath.java | 14 ++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/java.base/share/classes/java/net/URLClassLoader.java b/src/java.base/share/classes/java/net/URLClassLoader.java index 30f0040195a..97c95bc9f59 100644 --- a/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/src/java.base/share/classes/java/net/URLClassLoader.java @@ -427,6 +427,11 @@ public Class run() throws ClassNotFoundException { return defineClass(name, res); } catch (IOException e) { throw new ClassNotFoundException(name, e); + } catch (ClassFormatError e2) { + if (res.getDataError() != null) { + e2.addSuppressed(res.getDataError()); + } + throw e2; } } else { return null; diff --git a/src/java.base/share/classes/jdk/internal/loader/Resource.java b/src/java.base/share/classes/jdk/internal/loader/Resource.java index 55002f4c8c1..d119c4b5eae 100644 --- a/src/java.base/share/classes/jdk/internal/loader/Resource.java +++ b/src/java.base/share/classes/jdk/internal/loader/Resource.java @@ -187,4 +187,12 @@ public java.security.cert.Certificate[] getCertificates() { public CodeSigner[] getCodeSigners() { return null; } + + /** + * Returns non-fatal reading error during data retrieval if there's any. + * For example, CRC error when reading a JAR entry. + */ + public Exception getDataError() { + return null; + } } diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index b34b35562e5..02b9614971c 100644 --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -61,6 +61,7 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.jar.JarFile; +import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.jar.JarEntry; import java.util.jar.Manifest; @@ -870,6 +871,7 @@ Resource checkResource(final String name, boolean check, } return new Resource() { + private Exception dataError = null; public String getName() { return name; } public URL getURL() { return url; } public URL getCodeSourceURL() { return csu; } @@ -885,6 +887,18 @@ public Certificate[] getCertificates() { return entry.getCertificates(); }; public CodeSigner[] getCodeSigners() { return entry.getCodeSigners(); }; + public Exception getDataError() + { return dataError; } + public byte[] getBytes() throws IOException { + byte[] bytes = super.getBytes(); + CRC32 crc32 = new CRC32(); + crc32.update(bytes); + if (crc32.getValue() != entry.getCrc()) { + dataError = new IOException( + "CRC error while extracting entry from JAR file"); + } + return bytes; + } }; } From 8f31f0d343217c831ad30a2d50bdcdfa7fe48d64 Mon Sep 17 00:00:00 2001 From: Julia Boes Date: Tue, 25 May 2021 10:19:55 +0000 Subject: [PATCH 04/72] 8266097: Better hashing support Reviewed-by: chegar, dfuchs, ahgross, smarks, rhalade --- .../share/classes/java/util/HashMap.java | 46 +++++++++++++------ .../share/classes/java/util/HashSet.java | 11 +++-- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/java.base/share/classes/java/util/HashMap.java b/src/java.base/share/classes/java/util/HashMap.java index 9715b6ea9b1..24fcd9516ca 100644 --- a/src/java.base/share/classes/java/util/HashMap.java +++ b/src/java.base/share/classes/java/util/HashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -1504,23 +1505,28 @@ private void writeObject(java.io.ObjectOutputStream s) * @throws IOException if an I/O error occurs */ @java.io.Serial - private void readObject(java.io.ObjectInputStream s) + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - // Read in the threshold (ignored), loadfactor, and any hidden stuff - s.defaultReadObject(); + + ObjectInputStream.GetField fields = s.readFields(); + + // Read loadFactor (ignore threshold) + float lf = fields.get("loadFactor", 0.75f); + if (lf <= 0 || Float.isNaN(lf)) + throw new InvalidObjectException("Illegal load factor: " + lf); + + lf = Math.min(Math.max(0.25f, lf), 4.0f); + HashMap.UnsafeHolder.putLoadFactor(this, lf); + reinitialize(); - if (loadFactor <= 0 || Float.isNaN(loadFactor)) - throw new InvalidObjectException("Illegal load factor: " + - loadFactor); + s.readInt(); // Read and ignore number of buckets int mappings = s.readInt(); // Read number of mappings (size) - if (mappings < 0) - throw new InvalidObjectException("Illegal mappings count: " + - mappings); - else if (mappings > 0) { // (if zero, use defaults) - // Size the table using given load factor only if within - // range of 0.25...4.0 - float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f); + if (mappings < 0) { + throw new InvalidObjectException("Illegal mappings count: " + mappings); + } else if (mappings == 0) { + // use defaults + } else if (mappings > 0) { float fc = (float)mappings / lf + 1.0f; int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ? DEFAULT_INITIAL_CAPACITY : @@ -1549,6 +1555,18 @@ else if (mappings > 0) { // (if zero, use defaults) } } + // Support for resetting final field during deserializing + private static final class UnsafeHolder { + private UnsafeHolder() { throw new InternalError(); } + private static final jdk.internal.misc.Unsafe unsafe + = jdk.internal.misc.Unsafe.getUnsafe(); + private static final long LF_OFFSET + = unsafe.objectFieldOffset(HashMap.class, "loadFactor"); + static void putLoadFactor(HashMap map, float lf) { + unsafe.putFloat(map, LF_OFFSET, lf); + } + } + /* ------------------------------------------------------------ */ // iterators diff --git a/src/java.base/share/classes/java/util/HashSet.java b/src/java.base/share/classes/java/util/HashSet.java index d370e5d6710..e28fc6d5c21 100644 --- a/src/java.base/share/classes/java/util/HashSet.java +++ b/src/java.base/share/classes/java/util/HashSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -297,8 +297,8 @@ private void writeObject(java.io.ObjectOutputStream s) @java.io.Serial private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - // Read in any hidden serialization magic - s.defaultReadObject(); + // Consume and ignore stream fields (currently zero). + s.readFields(); // Read capacity and verify non-negative. int capacity = s.readInt(); @@ -313,12 +313,13 @@ private void readObject(java.io.ObjectInputStream s) throw new InvalidObjectException("Illegal load factor: " + loadFactor); } + // Clamp load factor to range of 0.25...4.0. + loadFactor = Math.min(Math.max(0.25f, loadFactor), 4.0f); // Read size and verify non-negative. int size = s.readInt(); if (size < 0) { - throw new InvalidObjectException("Illegal size: " + - size); + throw new InvalidObjectException("Illegal size: " + size); } // Set the capacity according to the size and load factor ensuring that From 01020006580d74851d73f435336d3f48bec4c113 Mon Sep 17 00:00:00 2001 From: Prajwal Kumaraswamy Date: Tue, 22 Jun 2021 08:20:32 +0000 Subject: [PATCH 05/72] 8266137: Improve Keystore integrity Reviewed-by: coffeys, hchao Backport-of: 06acda364f1483c15adca105d612a24f1d50112c --- .../security/tools/keytool/CertAndKeyGen.java | 9 +++++++ .../sun/security/tools/keytool/Main.java | 25 +++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java b/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java index 0901edc5d97..d61d6e0d3e7 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java @@ -32,7 +32,10 @@ import java.security.*; import java.security.spec.ECGenParameterSpec; import java.security.spec.NamedParameterSpec; +import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; import sun.security.pkcs10.PKCS10; import sun.security.util.SignatureUtil; @@ -304,6 +307,12 @@ public X509Certificate getSelfCertificate (X500Name myname, Date firstDate, try { lastDate = new Date (); lastDate.setTime (firstDate.getTime () + validity * 1000); + Calendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + c.setTime(lastDate); + if (c.get(Calendar.YEAR) > 9999) { + throw new CertificateException("Validity period ends at calendar year " + + c.get(Calendar.YEAR) + " which is greater than 9999"); + } CertificateValidity interval = new CertificateValidity(firstDate,lastDate); diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index b3d466cf65d..2d38c08bdb6 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1445,8 +1445,7 @@ private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStr X509CertInfo.DN_NAME); Date firstDate = getStartDate(startDate); - Date lastDate = new Date(); - lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + Date lastDate = getLastDate(firstDate, validity); CertificateValidity interval = new CertificateValidity(firstDate, lastDate); @@ -1560,12 +1559,10 @@ private void doGenCRL(PrintStream out) X509CertInfo.DN_NAME); Date firstDate = getStartDate(startDate); - Date lastDate = (Date) firstDate.clone(); - lastDate.setTime(lastDate.getTime() + validity*1000*24*60*60); + Date lastDate = getLastDate(firstDate, validity); CertificateValidity interval = new CertificateValidity(firstDate, lastDate); - PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst; if (sigAlgName == null) { @@ -3033,8 +3030,7 @@ private void doSelfCert(String alias, String dname, String sigAlgName) // Extend its validity Date firstDate = getStartDate(startDate); - Date lastDate = new Date(); - lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + Date lastDate = getLastDate(firstDate, validity); CertificateValidity interval = new CertificateValidity(firstDate, lastDate); certInfo.set(X509CertInfo.VALIDITY, interval); @@ -4695,6 +4691,21 @@ private CertificateExtensions createV3Extensions( return result; } + private Date getLastDate(Date firstDate, long validity) + throws Exception { + Date lastDate = new Date(); + lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + + Calendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + c.setTime(lastDate); + if (c.get(Calendar.YEAR) > 9999) { + throw new Exception("Validity period ends at calendar year " + + c.get(Calendar.YEAR) + " which is greater than 9999"); + } + + return lastDate; + } + private boolean isTrustedCert(Certificate cert) throws KeyStoreException { if (caks != null && caks.getCertificateAlias(cert) != null) { return true; From 87b5f1bd82e823eeed3d32c4fd0fa8007a792a99 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 22 Jun 2021 22:01:09 +0000 Subject: [PATCH 06/72] 8267086: ArrayIndexOutOfBoundsException in java.security.KeyFactory.generatePublic Backport-of: 2e375ae9ed459527393f9dd13d15d1031ad6095f --- .../security/util/DerIndefLenConverter.java | 163 ++++++++++-------- 1 file changed, 93 insertions(+), 70 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java b/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java index de8c2e5fb22..f2b88560ca3 100644 --- a/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java +++ b/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -31,9 +31,12 @@ import java.util.Arrays; /** - * A package private utility class to convert indefinite length DER + * A package private utility class to convert indefinite length BER * encoded byte arrays to definite length DER encoded byte arrays. - * + *

+ * Note: This class only substitute indefinite length octets to definite + * length octets. It does not update the contents even if they are not DER. + *

* This assumes that the basic data structure is "tag, length, value" * triplet. In the case where the length is "indefinite", terminating * end-of-contents bytes are expected. @@ -42,26 +45,30 @@ */ class DerIndefLenConverter { - private static final int TAG_MASK = 0x1f; // bits 5-1 - private static final int FORM_MASK = 0x20; // bits 6 - private static final int CLASS_MASK = 0xC0; // bits 8 and 7 - private static final int LEN_LONG = 0x80; // bit 8 set private static final int LEN_MASK = 0x7f; // bits 7 - 1 - private static final int SKIP_EOC_BYTES = 2; private byte[] data, newData; private int newDataPos, dataPos, dataSize, index; private int unresolved = 0; + // A list to store each indefinite length occurrence. Whenever an indef + // length is seen, the position after the 0x80 byte is appended to the + // list as an integer. Whenever its matching EOC is seen, we know the + // actual length and the position value is substituted with a calculated + // length octets. At the end, the new DER encoding is a concatenation of + // all existing tags, existing definite length octets, existing contents, + // and the newly created definte length octets in this list. private ArrayList ndefsList = new ArrayList(); + // Length of extra bytes needed to convert indefinite encoding to definite. + // For each resolved indefinite length encoding, the starting 0x80 byte + // and the ending 00 00 bytes will be removed and a new definite length + // octets will be added. This value might be positive or negative. private int numOfTotalLenBytes = 0; - private boolean isEOC(int tag) { - return (((tag & TAG_MASK) == 0x00) && // EOC - ((tag & FORM_MASK) == 0x00) && // primitive - ((tag & CLASS_MASK) == 0x00)); // universal + private static boolean isEOC(byte[] data, int pos) { + return data[pos] == 0 && data[pos + 1] == 0; } // if bit 8 is set then it implies either indefinite length or long form @@ -70,9 +77,9 @@ static boolean isLongForm(int lengthByte) { } /* - * Default package private constructor + * Private constructor */ - DerIndefLenConverter() { } + private DerIndefLenConverter() { } /** * Checks whether the given length byte is of the form @@ -88,11 +95,14 @@ static boolean isIndefinite(int lengthByte) { } /** - * Parse the tag and if it is an end-of-contents tag then - * add the current position to the eocList vector. + * Consumes the tag at {@code dataPos}. + *

+ * If it is EOC then replace the matching start position (i.e. the previous + * {@code dataPos} where an indefinite length was found by #parseLength) + * in {@code ndefsList} with a length octets for this section. */ private void parseTag() throws IOException { - if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) { + if (isEOC(data, dataPos)) { int numOfEncapsulatedLenBytes = 0; Object elem = null; int index; @@ -103,6 +113,9 @@ private void parseTag() throws IOException { if (elem instanceof Integer) { break; } else { + // For each existing converted part, 3 bytes (80 at the + // beginning and 00 00 at the end) are removed and a + // new length octets is added. numOfEncapsulatedLenBytes += ((byte[])elem).length - 3; } } @@ -114,6 +127,7 @@ private void parseTag() throws IOException { numOfEncapsulatedLenBytes; byte[] sectionLenBytes = getLengthBytes(sectionLen); ndefsList.set(index, sectionLenBytes); + assert unresolved > 0; unresolved--; // Add the number of bytes required to represent this section @@ -130,34 +144,41 @@ private void parseTag() throws IOException { * then skip the tag and its 1 byte length of zero. */ private void writeTag() { - if (dataPos == dataSize) + if (dataPos == dataSize) { return; - int tag = data[dataPos++]; - if (isEOC(tag) && (data[dataPos] == 0)) { - dataPos++; // skip length + } + assert dataPos + 1 < dataSize; + if (isEOC(data, dataPos)) { + dataPos += 2; // skip tag and length writeTag(); - } else - newData[newDataPos++] = (byte)tag; + } else { + newData[newDataPos++] = data[dataPos++]; + } } /** - * Parse the length and if it is an indefinite length then add - * the current position to the ndefsList vector. + * Parse the length octets started at {@code dataPos}. After this method + * is called, {@code dataPos} is placed after the length octets except + * -1 is returned. * - * @return the length of definite length data next, or -1 if there is - * not enough bytes to determine it + * @return a) the length of definite length data next + * b) -1, if it is a definite length data next but the length + * octets is not complete to determine the actual length + * c) 0, if it is an indefinite length. Also, append the current + * position to the {@code ndefsList} vector. * @throws IOException if invalid data is read */ private int parseLength() throws IOException { - int curLen = 0; - if (dataPos == dataSize) - return curLen; + if (dataPos == dataSize) { + return 0; + } int lenByte = data[dataPos++] & 0xff; if (isIndefinite(lenByte)) { ndefsList.add(dataPos); unresolved++; - return curLen; + return 0; } + int curLen = 0; if (isLongForm(lenByte)) { lenByte &= LEN_MASK; if (lenByte > 4) { @@ -179,14 +200,17 @@ private int parseLength() throws IOException { } /** - * Write the length and if it is an indefinite length - * then calculate the definite length from the positions - * of the indefinite length and its matching EOC terminator. - * Then, write the value. + * Write the length and value. + *

+ * If it was definite length, just re-write the length and copy the value. + * If it was an indefinite length, copy the precalculated definite octets + * from {@code ndefsList}. There is no values here because they will be + * sub-encodings of a constructed encoding. */ private void writeLengthAndValue() throws IOException { - if (dataPos == dataSize) - return; + if (dataPos == dataSize) { + return; + } int curLen = 0; int lenByte = data[dataPos++] & 0xff; if (isIndefinite(lenByte)) { @@ -194,21 +218,21 @@ private void writeLengthAndValue() throws IOException { System.arraycopy(lenBytes, 0, newData, newDataPos, lenBytes.length); newDataPos += lenBytes.length; - return; - } - if (isLongForm(lenByte)) { - lenByte &= LEN_MASK; - for (int i = 0; i < lenByte; i++) { - curLen = (curLen << 8) + (data[dataPos++] & 0xff); - } - if (curLen < 0) { - throw new IOException("Invalid length bytes"); - } } else { - curLen = (lenByte & LEN_MASK); + if (isLongForm(lenByte)) { + lenByte &= LEN_MASK; + for (int i = 0; i < lenByte; i++) { + curLen = (curLen << 8) + (data[dataPos++] & 0xff); + } + if (curLen < 0) { + throw new IOException("Invalid length bytes"); + } + } else { + curLen = (lenByte & LEN_MASK); + } + writeLength(curLen); + writeValue(curLen); } - writeLength(curLen); - writeValue(curLen); } private void writeLength(int curLen) { @@ -296,19 +320,13 @@ private int getNumOfLenBytes(int len) { return numOfLenBytes; } - /** - * Parse the value; - */ - private void parseValue(int curLen) { - dataPos += curLen; - } - /** * Write the value; */ private void writeValue(int curLen) { - for (int i=0; i < curLen; i++) - newData[newDataPos++] = data[dataPos++]; + System.arraycopy(data, dataPos, newData, newDataPos, curLen); + dataPos += curLen; + newDataPos += curLen; } /** @@ -323,10 +341,8 @@ private void writeValue(int curLen) { */ byte[] convertBytes(byte[] indefData) throws IOException { data = indefData; - dataPos=0; index=0; + dataPos = 0; dataSize = data.length; - int len=0; - int unused = 0; // parse and set up the vectors of all the indefinite-lengths while (dataPos < dataSize) { @@ -335,14 +351,17 @@ byte[] convertBytes(byte[] indefData) throws IOException { return null; } parseTag(); - len = parseLength(); + int len = parseLength(); if (len < 0) { return null; } - parseValue(len); + dataPos += len; + if (dataPos < 0) { + // overflow + throw new IOException("Data overflow"); + } if (unresolved == 0) { - unused = dataSize - dataPos; - dataSize = dataPos; + assert !ndefsList.isEmpty() && ndefsList.get(0) instanceof byte[]; break; } } @@ -351,14 +370,18 @@ byte[] convertBytes(byte[] indefData) throws IOException { return null; } + int unused = dataSize - dataPos; + assert unused >= 0; + dataSize = dataPos; + newData = new byte[dataSize + numOfTotalLenBytes + unused]; - dataPos=0; newDataPos=0; index=0; + dataPos = 0; newDataPos = 0; index = 0; // write out the new byte array replacing all the indefinite-lengths // and EOCs while (dataPos < dataSize) { - writeTag(); - writeLengthAndValue(); + writeTag(); + writeLengthAndValue(); } System.arraycopy(indefData, dataSize, newData, dataSize + numOfTotalLenBytes, unused); @@ -395,7 +418,7 @@ public static byte[] convertStream(InputStream in, byte tag) if (result == null) { int next = in.read(); // This could block, but we need more if (next == -1) { - throw new IOException("not all indef len BER resolved"); + throw new IOException("not enough data to resolve indef len BER"); } int more = in.available(); // expand array to include next and more From b24dff5fefdaef80f93ad7bc125643bb032a4ac7 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 23 Jun 2021 03:47:05 +0000 Subject: [PATCH 07/72] 8267735: Better BMP support Backport-of: 67ddc7e7f3b178998ea59f68758a5fa510624e12 --- .../com/sun/imageio/plugins/bmp/BMPImageReader.java | 7 +++++++ .../com/sun/imageio/plugins/common/iio-plugin.properties | 1 + 2 files changed, 8 insertions(+) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java index 37d9a9b0384..df283e8102c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java @@ -591,6 +591,13 @@ else if (size == 124) height = Math.abs(height); } + if (metadata.compression == BI_RGB) { + long imageDataSize = (width * height * (bitsPerPixel / 8)); + if (imageDataSize > (bitmapFileSize - bitmapOffset)) { + throw new IIOException(I18N.getString("BMPImageReader9")); + } + } + // Reset Image Layout so there's only one tile. //Define the color space ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties index 0705b99eee8..5b9e47b9215 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties @@ -24,6 +24,7 @@ BMPImageReader5=Input has not been set. BMPImageReader6=Unable to read the image header. BMPImageReader7=Invalid bitmap offset. BMPImageReader8=Invalid bits per pixel in image header. +BMPImageReader9=Invalid width/height for BI_RGB image data. BMPImageWriter0=Output is not an ImageOutputStream. BMPImageWriter1=The image region to be encoded is empty. BMPImageWriter2=Only 1 or 3 band image is encoded. From 040f1053aa6fba5472397ed6b76fc5da858c89e6 Mon Sep 17 00:00:00 2001 From: pavel_kharskii Date: Thu, 24 Jun 2021 17:28:39 +0000 Subject: [PATCH 08/72] 8269297: Bump version numbers for JDK 17.0.1 Reviewed-by: robm, erikj --- make/conf/version-numbers.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 0db8f8f771d..5e967cae3fa 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -28,12 +28,12 @@ DEFAULT_VERSION_FEATURE=17 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=0 +DEFAULT_VERSION_UPDATE=1 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2021-09-14 +DEFAULT_VERSION_DATE=2021-10-19 DEFAULT_VERSION_CLASSFILE_MAJOR=61 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 From b3054c8168f132ffa91b72b80264986776701a38 Mon Sep 17 00:00:00 2001 From: Kiran Sidhartha Ravikumar Date: Thu, 8 Jul 2021 10:42:58 +0000 Subject: [PATCH 09/72] 8268506: More Manifest Digests Backport-of: 306a51b13f5307b0de9d2f04daa983ccd8f92284 --- .../sun/security/util/ManifestDigester.java | 10 +++++++--- .../sun/security/util/SignatureFileVerifier.java | 4 ++++ .../classes/jdk/security/jarsigner/JarSigner.java | 14 ++++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/ManifestDigester.java b/src/java.base/share/classes/sun/security/util/ManifestDigester.java index 3920d8a6b76..969df7c0eb8 100644 --- a/src/java.base/share/classes/sun/security/util/ManifestDigester.java +++ b/src/java.base/share/classes/sun/security/util/ManifestDigester.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -331,8 +331,12 @@ public Entry getMainAttsEntry() { * @see #MF_MAIN_ATTRS */ public Entry getMainAttsEntry(boolean oldStyle) { - mainAttsEntry.oldStyle = oldStyle; - return mainAttsEntry; + if (mainAttsEntry != null) { + mainAttsEntry.oldStyle = oldStyle; + return mainAttsEntry; + } else { + return null; + } } public Entry get(String name) { diff --git a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index 531a0c4c3e0..3ebe97768af 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -543,6 +543,10 @@ private boolean verifyManifestMainAttrs(Manifest sf, ManifestDigester md) MessageDigest digest = getDigest(algorithm); if (digest != null) { ManifestDigester.Entry mde = md.getMainAttsEntry(false); + if (mde == null) { + throw new SignatureException("Manifest Main Attribute check " + + "failed due to missing main attributes entry"); + } byte[] computedHash = mde.digest(digest); byte[] expectedHash = Base64.getMimeDecoder().decode((String)se.getValue()); diff --git a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java index 4a17faec022..08fad553cc9 100644 --- a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java +++ b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java @@ -793,13 +793,19 @@ private void sign0(ZipFile zipFile, OutputStream os) ManifestDigester oldMd = new ManifestDigester(mfRawBytes); ManifestDigester newMd = new ManifestDigester(mfNewRawBytes); + ManifestDigester.Entry oldEntry = oldMd.getMainAttsEntry(); + // main attributes - if (manifest.getMainAttributes().equals( - oldManifest.getMainAttributes()) + if (oldEntry != null + && manifest.getMainAttributes().equals( + oldManifest.getMainAttributes()) && (manifest.getEntries().isEmpty() || - oldMd.getMainAttsEntry().isProperlyDelimited())) { - oldMd.getMainAttsEntry().reproduceRaw(baos); + oldEntry.isProperlyDelimited())) { + oldEntry.reproduceRaw(baos); } else { + if (newMd.getMainAttsEntry() == null) { + throw new SignatureException("Error getting new main attribute entry"); + } newMd.getMainAttsEntry().reproduceRaw(baos); } From cf73d51d77207bae57510acc3589b98f8500007e Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 8 Jul 2021 16:28:54 +0000 Subject: [PATCH 10/72] 8269618: Better session identification Reviewed-by: jnimeh Backport-of: 116b77755f0a5d8c786a0c0ead4fc557ce359e6e --- .../sun/security/ssl/HelloCookieManager.java | 4 +- .../security/ssl/PreSharedKeyExtension.java | 3 +- .../sun/security/ssl/RandomCookie.java | 10 +-- .../sun/security/ssl/RenegoInfoExtension.java | 8 ++- .../classes/sun/security/ssl/SessionId.java | 3 +- .../classes/sun/security/util/ByteArrays.java | 67 +++++++++++++++++++ 6 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/java.base/share/classes/sun/security/util/ByteArrays.java diff --git a/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java b/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java index 6880c929ab6..f2f7b0d5da4 100644 --- a/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java +++ b/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java @@ -208,7 +208,7 @@ boolean isCookieValid(ServerHandshakeContext context, byte[] target = md.digest(secret); // 32 bytes target[0] = cookie[0]; - return Arrays.equals(target, cookie); + return MessageDigest.isEqual(target, cookie); } } @@ -361,7 +361,7 @@ boolean isCookieValid(ServerHandshakeContext context, md.update(headerBytes); byte[] headerCookie = md.digest(secret); - if (!Arrays.equals(headerCookie, prevHeadCookie)) { + if (!MessageDigest.isEqual(headerCookie, prevHeadCookie)) { return false; } diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 2d134f303fe..0b3481fbb19 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -31,7 +31,6 @@ import java.util.List; import java.util.ArrayList; import java.util.Locale; -import java.util.Arrays; import java.util.Collection; import javax.crypto.Mac; import javax.crypto.SecretKey; @@ -569,7 +568,7 @@ private static void checkBinder(ServerHandshakeContext shc, SecretKey binderKey = deriveBinderKey(shc, psk, session); byte[] computedBinder = computeBinder(shc, binderKey, session, pskBinderHash); - if (!Arrays.equals(binder, computedBinder)) { + if (!MessageDigest.isEqual(binder, computedBinder)) { throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, "Incorect PSK binder value"); } diff --git a/src/java.base/share/classes/sun/security/ssl/RandomCookie.java b/src/java.base/share/classes/sun/security/ssl/RandomCookie.java index eb3d9500ca7..ef38196b2e7 100644 --- a/src/java.base/share/classes/sun/security/ssl/RandomCookie.java +++ b/src/java.base/share/classes/sun/security/ssl/RandomCookie.java @@ -25,10 +25,12 @@ package sun.security.ssl; +import sun.security.util.ByteArrays; + import java.io.*; import java.nio.ByteBuffer; +import java.security.MessageDigest; import java.security.SecureRandom; -import java.util.Arrays; /* * RandomCookie ... SSL hands standard format random cookies (nonces) @@ -111,7 +113,7 @@ public String toString() { } boolean isHelloRetryRequest() { - return Arrays.equals(hrrRandomBytes, randomBytes); + return MessageDigest.isEqual(hrrRandomBytes, randomBytes); } // Used for client random validation of version downgrade protection. @@ -130,10 +132,10 @@ boolean isVersionDowngrade(HandshakeContext context) { } private boolean isT12Downgrade() { - return Arrays.equals(randomBytes, 24, 32, t12Protection, 0, 8); + return ByteArrays.isEqual(randomBytes, 24, 32, t12Protection, 0, 8); } private boolean isT11Downgrade() { - return Arrays.equals(randomBytes, 24, 32, t11Protection, 0, 8); + return ByteArrays.isEqual(randomBytes, 24, 32, t11Protection, 0, 8); } } diff --git a/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java b/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java index 732172a7341..2dbf7d0bf91 100644 --- a/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.security.MessageDigest; import java.text.MessageFormat; import java.util.Arrays; import java.util.Locale; @@ -37,6 +38,7 @@ import static sun.security.ssl.SSLExtension.SH_RENEGOTIATION_INFO; import sun.security.ssl.SSLExtension.SSLExtensionSpec; import sun.security.ssl.SSLHandshake.HandshakeMessage; +import sun.security.util.ByteArrays; /** * Pack of the "renegotiation_info" extensions [RFC 5746]. @@ -239,7 +241,7 @@ public void consume(ConnectionContext context, "renegotiation"); } else { // verify the client_verify_data value - if (!Arrays.equals(shc.conContext.clientVerifyData, + if (!MessageDigest.isEqual(shc.conContext.clientVerifyData, spec.renegotiatedConnection)) { throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, "Invalid renegotiation_info extension data: " + @@ -459,14 +461,14 @@ public void consume(ConnectionContext context, } byte[] cvd = chc.conContext.clientVerifyData; - if (!Arrays.equals(spec.renegotiatedConnection, + if (!ByteArrays.isEqual(spec.renegotiatedConnection, 0, cvd.length, cvd, 0, cvd.length)) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "Invalid renegotiation_info in ServerHello: " + "unmatched client_verify_data value"); } byte[] svd = chc.conContext.serverVerifyData; - if (!Arrays.equals(spec.renegotiatedConnection, + if (!ByteArrays.isEqual(spec.renegotiatedConnection, cvd.length, infoLen, svd, 0, svd.length)) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "Invalid renegotiation_info in ServerHello: " + diff --git a/src/java.base/share/classes/sun/security/ssl/SessionId.java b/src/java.base/share/classes/sun/security/ssl/SessionId.java index f7dedc68fb3..95a524e736c 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionId.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionId.java @@ -25,6 +25,7 @@ package sun.security.ssl; +import java.security.MessageDigest; import java.security.SecureRandom; import java.util.Arrays; import javax.net.ssl.SSLProtocolException; @@ -89,7 +90,7 @@ public boolean equals (Object obj) { if (obj instanceof SessionId) { SessionId that = (SessionId)obj; - return Arrays.equals(this.sessionId, that.sessionId); + return MessageDigest.isEqual(this.sessionId, that.sessionId); } return false; diff --git a/src/java.base/share/classes/sun/security/util/ByteArrays.java b/src/java.base/share/classes/sun/security/util/ByteArrays.java new file mode 100644 index 00000000000..1457489f4bf --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/ByteArrays.java @@ -0,0 +1,67 @@ +/* + * 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. 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; + +/** + * A time-instance comparison of two byte arrays. + */ +public class ByteArrays { + // See the MessageDigest.isEqual(byte[] digesta, byte[] digestb) + // implementation. This is a potential enhancement of the + // MessageDigest class. + public static boolean isEqual(byte[] a, int aFromIndex, int aToIndex, + byte[] b, int bFromIndex, int bToIndex) { + if (a == b) { + return true; + } + + if (a == null || b == null) { + return false; + } + + if (a.length == 0) { + return b.length == 0; + } + + int lenA = aToIndex - aFromIndex; + int lenB = bToIndex - bFromIndex; + + if (lenB == 0) { + return lenA == 0; + } + + int result = 0; + result |= lenA - lenB; + + // time-constant comparison + for (int indexA = 0; indexA < lenA; indexA++) { + int indexB = ((indexA - lenB) >>> 31) * indexA; + result |= a[aFromIndex + indexA] ^ b[bFromIndex + indexB]; + } + + return result == 0; + } +} From 5adbf765a24231d2d7f68332989c6c072e4dc2e2 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 8 Jul 2021 16:33:46 +0000 Subject: [PATCH 11/72] 8268205: Enhance DTLS client handshake Reviewed-by: jnimeh Backport-of: 4a0c4038401e48d5111449ca35c0795d94f9ab83 --- .../sun/security/ssl/DTLSInputRecord.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index 9fe425c49c8..931f45e68ff 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -567,6 +567,9 @@ private static final class HandshakeFlight implements Cloneable { HashMap> holesMap; + // A map used to check duplicated handshake messages. + HashMap messageSeqMap; + HandshakeFlight() { this.handshakeType = HF_UNKNOWN; this.flightEpoch = 0; @@ -577,6 +580,7 @@ private static final class HandshakeFlight implements Cloneable { this.maxRecordSeq = -1; this.holesMap = new HashMap<>(5); + this.messageSeqMap = new HashMap<>(5); } boolean isRetransmitOf(HandshakeFlight hs) { @@ -598,6 +602,7 @@ public Object clone() { hf.maxRecordSeq = this.maxRecordSeq; hf.holesMap = new HashMap<>(this.holesMap); + hf.messageSeqMap = new HashMap<>(this.messageSeqMap); return hf; } @@ -640,7 +645,7 @@ void expectingFinishFlight() { } // Queue up a handshake message. - void queueUpHandshake(HandshakeFragment hsf) { + void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { if (!isDesirable(hsf)) { // Not a dedired record, discard it. return; @@ -707,6 +712,7 @@ void queueUpHandshake(HandshakeFragment hsf) { holes.add(new HoleDescriptor(0, hsf.messageLength)); } handshakeFlight.holesMap.put(hsf.handshakeType, holes); + handshakeFlight.messageSeqMap.put(hsf.handshakeType, hsf.messageSeq); } else if (holes.isEmpty()) { // Have got the full handshake message. This record may be // a handshake message retransmission. Discard this record. @@ -778,7 +784,8 @@ void queueUpHandshake(HandshakeFragment hsf) { } // Queue up a ChangeCipherSpec message - void queueUpChangeCipherSpec(RecordFragment rf) { + void queueUpChangeCipherSpec(RecordFragment rf) + throws SSLProtocolException { if (!isDesirable(rf)) { // Not a dedired record, discard it. return; @@ -807,7 +814,7 @@ void queueUpChangeCipherSpec(RecordFragment rf) { // Queue up a ciphertext message. // // Note: not yet be able to decrypt the message. - void queueUpFragment(RecordFragment rf) { + void queueUpFragment(RecordFragment rf) throws SSLProtocolException { if (!isDesirable(rf)) { // Not a dedired record, discard it. return; @@ -895,7 +902,7 @@ private void cleanUpRetransmit(RecordFragment rf) { // Is a desired record? // // Check for retransmission and lost records. - private boolean isDesirable(RecordFragment rf) { + private boolean isDesirable(RecordFragment rf) throws SSLProtocolException { // // Discard records old than the previous epoch. // @@ -970,6 +977,25 @@ private boolean isDesirable(RecordFragment rf) { return false; } + // Unexpected duplicated handshake messages. + if (rf.recordEpoch == handshakeEpoch && + // For handshake messages only. + rf instanceof HandshakeFragment hsf && + // Check on the received handshake messages. + handshakeFlight.holesMap.containsKey(hsf.handshakeType)) { + Integer cachedMsgSeq = handshakeFlight.messageSeqMap.get( + hsf.handshakeType); + if (cachedMsgSeq != null && cachedMsgSeq != hsf.messageSeq) { + // Handshake messages of the same type but with different + // message sequence numbers are not allowed. + throw new SSLProtocolException( + "Two message sequence numbers are used for the " + + "same handshake message (" + + SSLHandshake.nameOf(hsf.handshakeType) + + ")"); + } + } + return true; } @@ -1086,6 +1112,9 @@ private void resetHandshakeFlight(HandshakeFlight prev) { // cleanup holes map handshakeFlight.holesMap.clear(); + // cleanup handshake message sequence numbers map + handshakeFlight.messageSeqMap.clear(); + // Ready to accept new input record. flightIsReady = false; needToCheckFlight = false; From 33cd383a9641ff05327422655018f15c24aae8f7 Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Thu, 8 Jul 2021 18:49:07 +0000 Subject: [PATCH 12/72] 8268193: Improve requests of certificates Reviewed-by: ascarpino Backport-of: ce8b2eac4f9643575a87617ae8091657e9458c22 --- .../sun/security/ssl/CertificateRequest.java | 29 +++++++++++++++++++ .../security/ssl/ClientHandshakeContext.java | 7 ++++- .../sun/security/ssl/ServerKeyExchange.java | 13 ++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 2f3a8e2699d..ec9991cc018 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -333,6 +333,16 @@ public void consume(ConnectionContext context, // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_REQUEST.id); + chc.receivedCertReq = true; + + // If we're processing this message and the server's certificate + // message consumer has not already run then this is a state + // machine violation. + if (chc.handshakeConsumers.containsKey( + SSLHandshake.CERTIFICATE.id)) { + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected CertificateRequest handshake message"); + } SSLConsumer certStatCons = chc.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_STATUS.id); @@ -659,6 +669,16 @@ public void consume(ConnectionContext context, // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_REQUEST.id); + chc.receivedCertReq = true; + + // If we're processing this message and the server's certificate + // message consumer has not already run then this is a state + // machine violation. + if (chc.handshakeConsumers.containsKey( + SSLHandshake.CERTIFICATE.id)) { + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected CertificateRequest handshake message"); + } SSLConsumer certStatCons = chc.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_STATUS.id); @@ -926,6 +946,15 @@ public void consume(ConnectionContext context, // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_REQUEST.id); + chc.receivedCertReq = true; + + // Ensure that the CertificateRequest has not been sent prior + // to EncryptedExtensions + if (chc.handshakeConsumers.containsKey( + SSLHandshake.ENCRYPTED_EXTENSIONS.id)) { + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected CertificateRequest handshake message"); + } T13CertificateRequestMessage crm = new T13CertificateRequestMessage(chc, message); diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java index 0ca4224c517..ff7690966bb 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -90,6 +90,11 @@ class ClientHandshakeContext extends HandshakeContext { ClientHelloMessage initialClientHelloMsg = null; + // Flag to indicate receipt of a CertificateRequest message from + // the server. Because this is optional, we cannot guarantee + // the handshakeConsumers Map will always have it present there. + boolean receivedCertReq = false; + // PSK identity is selected in first Hello and used again after HRR byte[] pskIdentity; diff --git a/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java index b9c8febd238..be5814acc50 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -92,6 +92,17 @@ public void consume(ConnectionContext context, // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.SERVER_KEY_EXCHANGE.id); + // Any receipt/consumption of the CertificateRequest before + // ServerKeyExchange is a state machine violation. We may not + // know for sure if an early CR message is a violation though until + // we have reached this point, due to other TLS features and + // optional messages. + if (chc.receivedCertReq) { + chc.receivedCertReq = false; // Reset flag + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected ServerKeyExchange handshake message"); + } + SSLConsumer certStatCons = chc.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_STATUS.id); if (certStatCons != null) { From 82d44a79de78fbcfe50915866e01fd9bccf67765 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Thu, 8 Jul 2021 21:05:06 +0000 Subject: [PATCH 13/72] 8268500: Better specified ParameterSpecs Backport-of: 04ba2a665d4f2af34ed7896e2f1b2b5f9cdf31a4 --- .../share/classes/sun/security/pkcs/SignerInfo.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java index 08c6be29c28..dffc4848cfa 100644 --- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java +++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -504,6 +504,14 @@ public static String makeSigAlg(AlgorithmId digAlgId, AlgorithmId encAlgId, case "RSASSA-PSS": PSSParameterSpec spec = (PSSParameterSpec) SignatureUtil.getParamSpec(encAlg, encAlgId.getParameters()); + /* + * RFC 4056 section 3 for Signed-data: + * signatureAlgorithm MUST contain id-RSASSA-PSS. The algorithm + * parameters field MUST contain RSASSA-PSS-params. + */ + if (spec == null) { + throw new NoSuchAlgorithmException("Missing PSSParameterSpec for RSASSA-PSS algorithm"); + } if (!AlgorithmId.get(spec.getDigestAlgorithm()).equals(digAlgId)) { throw new NoSuchAlgorithmException("Incompatible digest algorithm"); } From da5e3490885409f0c0c4d4d83205aa753a034da6 Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Thu, 8 Jul 2021 21:29:14 +0000 Subject: [PATCH 14/72] 8268199: Correct certificate requests Backport-of: afeccc7639d3d09041b58cf0f5672eb7310b2cbd --- .../sun/security/ssl/CertificateRequest.java | 41 +++++++++++++++---- .../sun/security/ssl/X509Authentication.java | 6 +-- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index ec9991cc018..84b128b23a0 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -31,6 +31,7 @@ import java.security.cert.X509Certificate; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -44,6 +45,7 @@ import sun.security.ssl.CipherSuite.KeyExchange; import sun.security.ssl.SSLHandshake.HandshakeMessage; import sun.security.ssl.X509Authentication.X509Possession; +import sun.security.ssl.X509Authentication.X509PossessionGenerator; /** * Pack of the CertificateRequest handshake message. @@ -724,12 +726,11 @@ public void consume(ConnectionContext context, chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); chc.peerSupportedAuthorities = crm.getAuthorities(); - // For TLS 1.2, we no longer use the certificate_types field - // from the CertificateRequest message to directly determine - // the SSLPossession. Instead, the choosePossession method - // will use the accepted signature schemes in the message to - // determine the set of acceptable certificate types to select from. - SSLPossession pos = choosePossession(chc); + // For TLS 1.2, we need to use a combination of the CR message's + // allowed key types and the signature algorithms in order to + // find a certificate chain that has the right key and all certs + // using one or more of the allowed cert signature schemes. + SSLPossession pos = choosePossession(chc, crm); if (pos == null) { return; } @@ -739,8 +740,8 @@ public void consume(ConnectionContext context, SSLHandshake.CERTIFICATE_VERIFY); } - private static SSLPossession choosePossession(HandshakeContext hc) - throws IOException { + private static SSLPossession choosePossession(HandshakeContext hc, + T12CertificateRequestMessage crm) throws IOException { if (hc.peerRequestedCertSignSchemes == null || hc.peerRequestedCertSignSchemes.isEmpty()) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { @@ -750,6 +751,9 @@ private static SSLPossession choosePossession(HandshakeContext hc) return null; } + // Put the CR key type into a more friendly format for searching + List crKeyTypes = Arrays.asList(crm.getKeyTypes()); + Collection checkedKeyTypes = new HashSet<>(); for (SignatureScheme ss : hc.peerRequestedCertSignSchemes) { if (checkedKeyTypes.contains(ss.keyAlgorithm)) { @@ -776,7 +780,7 @@ private static SSLPossession choosePossession(HandshakeContext hc) continue; } - SSLAuthentication ka = X509Authentication.valueOf(ss); + X509Authentication ka = X509Authentication.valueOf(ss); if (ka == null) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning( @@ -784,6 +788,25 @@ private static SSLPossession choosePossession(HandshakeContext hc) } checkedKeyTypes.add(ss.keyAlgorithm); continue; + } else { + // Any auth object will have a possession generator and + // we need to make sure the key types for that generator + // share at least one common algorithm with the CR's + // allowed key types. + if (ka.possessionGenerator instanceof + X509PossessionGenerator xpg) { + if (Collections.disjoint(crKeyTypes, + Arrays.asList(xpg.keyTypes))) { + if (SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( + "Unsupported authentication scheme: " + + ss.name); + } + checkedKeyTypes.add(ss.keyAlgorithm); + continue; + } + } } SSLPossession pos = ka.createPossession(hc); diff --git a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java index 7962ffa161c..cd41ab506fd 100644 --- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java +++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java @@ -194,9 +194,9 @@ static final class X509Credentials implements SSLCredentials { } } - private static final - class X509PossessionGenerator implements SSLPossessionGenerator { - private final String[] keyTypes; + static final class X509PossessionGenerator + implements SSLPossessionGenerator { + final String[] keyTypes; private X509PossessionGenerator(String[] keyTypes) { this.keyTypes = keyTypes; From 78cb6a1e6caa87fe516c802d36ada443d2069a3e Mon Sep 17 00:00:00 2001 From: Prajwal Kumaraswamy Date: Mon, 12 Jul 2021 11:40:02 +0000 Subject: [PATCH 15/72] 8266115: More Manifest Jar Loading Reviewed-by: coffeys, weijun Backport-of: 1834a749a1d51c82fb1a1c34770c7ab5b4ff9fce --- .../share/classes/java/util/jar/JarFile.java | 2 +- .../jar/JarFile/LargeManifestOOMTest.java | 78 ------------------- 2 files changed, 1 insertion(+), 79 deletions(-) delete mode 100644 test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index 8f9b42b6c58..de4a519685e 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -795,7 +795,7 @@ private byte[] getBytes(ZipEntry ze) throws IOException { try (InputStream is = super.getInputStream(ze)) { long uncompressedSize = ze.getSize(); if (uncompressedSize > MAX_ARRAY_SIZE) { - throw new OutOfMemoryError("Required array size too large"); + throw new IOException("Unsupported size: " + uncompressedSize); } int len = (int)uncompressedSize; int bytesRead; diff --git a/test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java b/test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java deleted file mode 100644 index 514a2d4d2d4..00000000000 --- a/test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import jdk.test.lib.util.JarUtils; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.jar.JarFile; - -/** - * @test - * @bug 8242882 - * @summary Verify that opening a jar file with a large manifest throws an OutOfMemoryError - * and not a NegativeArraySizeException - * @library /test/lib - * @run testng LargeManifestOOMTest - */ -public class LargeManifestOOMTest { - // file will be created with size greater than Integer.MAX_VALUE - private static final long MANIFEST_FILE_SIZE = Integer.MAX_VALUE + 1024L; - - /** - * Creates a jar which has a large manifest file and then uses the {@link JarFile} to - * {@link JarFile#getManifest() load the manifest}. The call to the {@link JarFile#getManifest()} - * is then expected to throw a {@link OutOfMemoryError} - */ - @Test - public void testOutOfMemoryError() throws Exception { - final Path jarSourceRoot = Paths.get("jar-source"); - createLargeManifest(jarSourceRoot.resolve("META-INF")); - final Path jarFilePath = Paths.get("oom-test.jar"); - JarUtils.createJarFile(jarFilePath.toAbsolutePath(), jarSourceRoot); - final JarFile jar = new JarFile(jarFilePath.toFile()); - Assert.assertThrows(OutOfMemoryError.class, () -> jar.getManifest()); - } - - /** - * Creates a {@code MANIFEST.MF}, whose content is {@link #MANIFEST_FILE_SIZE} in size, - * in the {@code parentDir} - * - * @param parentDir The directory in which the MANIFEST.MF file will be created - */ - private static void createLargeManifest(final Path parentDir) throws IOException { - Files.createDirectories(parentDir.toAbsolutePath()); - final Path manifestFile = parentDir.resolve("MANIFEST.MF"); - try (final RandomAccessFile largeManifest = new RandomAccessFile(manifestFile.toFile(), "rw")) { - largeManifest.writeUTF("Manifest-Version: 1.0\n"); - largeManifest.writeUTF("OOM-Test: a\n"); - largeManifest.setLength(MANIFEST_FILE_SIZE); - } - System.out.println("Size of file " + manifestFile + " is " + manifestFile.toFile().length()); - } -} From 4fcc43dce7fa10baf924cf317f2b57ec61bb71e7 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 13 Jul 2021 09:27:43 +0000 Subject: [PATCH 16/72] 8265574: Improve handling of sheets Backport-of: a20f56155d675fd606ed57fddb153aeb9dc270ae --- .../classes/javax/swing/text/rtf/RTFReader.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java index ed7a97e29ad..888bfacc299 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java @@ -983,19 +983,27 @@ public boolean handleKeyword(String keyword, int parameter) return true; } - public Style realize() + public Style realize() { + return realize(null); + } + + private Style realize(Set alreadyMetBasisIndexSet) { Style basis = null; Style next = null; + if (alreadyMetBasisIndexSet == null) { + alreadyMetBasisIndexSet = new HashSet<>(); + } + if (realizedStyle != null) return realizedStyle; - if (basedOn != STYLENUMBER_NONE) { + if (basedOn != STYLENUMBER_NONE && alreadyMetBasisIndexSet.add(basedOn)) { StyleDefiningDestination styleDest; - styleDest = definedStyles.get(Integer.valueOf(basedOn)); + styleDest = definedStyles.get(basedOn); if (styleDest != null && styleDest != this) { - basis = styleDest.realize(); + basis = styleDest.realize(alreadyMetBasisIndexSet); } } From 4fa8b8fd542823291b9d6caa7c1fa755ca569c9d Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 16 Jul 2021 16:57:46 +0000 Subject: [PATCH 17/72] 8265580: Enhanced style for RTF kit Backport-of: dd4a17f711b0027ed6377ca57c43a7d68d4df566 --- .../javax/swing/text/rtf/RTFReader.java | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java index 888bfacc299..03884693553 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java @@ -66,12 +66,12 @@ class RTFReader extends RTFParser Dictionary fontTable; /** This array maps color indices to Color objects. */ Color[] colorTable; - /** This array maps character style numbers to Style objects. */ - Style[] characterStyles; - /** This array maps paragraph style numbers to Style objects. */ - Style[] paragraphStyles; - /** This array maps section style numbers to Style objects. */ - Style[] sectionStyles; + /** This Map maps character style numbers to Style objects. */ + Map characterStyles; + /** This Map maps paragraph style numbers to Style objects. */ + Map paragraphStyles; + /** This Map maps section style numbers to Style objects. */ + Map sectionStyles; /** This is the RTF version number, extracted from the \rtf keyword. * The version information is currently not used. */ @@ -842,9 +842,9 @@ public void begingroup() public void close() { - Vector