Tue, 25 Aug 2020 08:30:00 -0700
8245473: OCSP stapling support
Reviewed-by: mbalao
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/sun/security/provider/certpath/OCSPNonceExtension.java Tue Aug 25 08:30:00 2020 -0700 1.3 @@ -0,0 +1,179 @@ 1.4 +/* 1.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package sun.security.provider.certpath; 1.30 + 1.31 +import java.io.IOException; 1.32 +import java.util.Objects; 1.33 +import java.security.SecureRandom; 1.34 + 1.35 +import sun.security.x509.Extension; 1.36 +import sun.security.x509.PKIXExtensions; 1.37 +import sun.security.util.Debug; 1.38 +import sun.security.util.DerValue; 1.39 + 1.40 +/** 1.41 + * Represent the OCSP Nonce Extension. 1.42 + * This extension, if present, provides a nonce value in OCSP requests 1.43 + * and responses. This will cryptographically bind requests and responses 1.44 + * and help to prevent replay attacks (see RFC 6960, section 4.4.1). 1.45 + * 1.46 + * @see Extension 1.47 + */ 1.48 +public final class OCSPNonceExtension extends Extension { 1.49 + 1.50 + /** 1.51 + * Attribute name. 1.52 + */ 1.53 + private static final String EXTENSION_NAME = "OCSPNonce"; 1.54 + private byte[] nonceData = null; 1.55 + 1.56 + /** 1.57 + * Create an {@code OCSPNonceExtension} by providing the nonce length. 1.58 + * The criticality is set to false, and the OID for the extension will 1.59 + * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960. 1.60 + * 1.61 + * @param length the number of random bytes composing the nonce 1.62 + * 1.63 + * @throws IOException if any errors happen during encoding of the 1.64 + * extension. 1.65 + * @throws IllegalArgumentException if length is not a positive integer. 1.66 + */ 1.67 + public OCSPNonceExtension(int length) throws IOException { 1.68 + this(false, length); 1.69 + } 1.70 + 1.71 + /** 1.72 + * Create an {@code OCSPNonceExtension} by providing the nonce length and 1.73 + * criticality setting. The OID for the extension will 1.74 + * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960. 1.75 + * 1.76 + * @param isCritical a boolean flag indicating whether the criticality bit 1.77 + * is set for this extension 1.78 + * @param length the number of random bytes composing the nonce 1.79 + * 1.80 + * @throws IOException if any errors happen during encoding of the 1.81 + * extension. 1.82 + * @throws IllegalArgumentException if length is not a positive integer. 1.83 + */ 1.84 + public OCSPNonceExtension(boolean isCritical, int length) 1.85 + throws IOException { 1.86 + this.extensionId = PKIXExtensions.OCSPNonce_Id; 1.87 + this.critical = isCritical; 1.88 + 1.89 + if (length > 0) { 1.90 + SecureRandom rng = new SecureRandom(); 1.91 + this.nonceData = new byte[length]; 1.92 + rng.nextBytes(nonceData); 1.93 + this.extensionValue = new DerValue(DerValue.tag_OctetString, 1.94 + nonceData).toByteArray(); 1.95 + } else { 1.96 + throw new IllegalArgumentException( 1.97 + "Length must be a positive integer"); 1.98 + } 1.99 + } 1.100 + 1.101 + /** 1.102 + * Create an {@code OCSPNonceExtension} by providing a nonce value. 1.103 + * The criticality is set to false, and the OID for the extension will 1.104 + * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960. 1.105 + * 1.106 + * @param incomingNonce The nonce data to be set for the extension. This 1.107 + * must be a non-null array of at least one byte long. 1.108 + * 1.109 + * @throws IOException if any errors happen during encoding of the 1.110 + * extension. 1.111 + * @throws IllegalArgumentException if the incomingNonce length is not a 1.112 + * positive integer. 1.113 + * @throws NullPointerException if the incomingNonce is null. 1.114 + */ 1.115 + public OCSPNonceExtension(byte[] incomingNonce) throws IOException { 1.116 + this(false, incomingNonce); 1.117 + } 1.118 + 1.119 + /** 1.120 + * Create an {@code OCSPNonceExtension} by providing a nonce value and 1.121 + * criticality setting. The OID for the extension will 1.122 + * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960. 1.123 + * 1.124 + * @param isCritical a boolean flag indicating whether the criticality bit 1.125 + * is set for this extension 1.126 + * @param incomingNonce The nonce data to be set for the extension. This 1.127 + * must be a non-null array of at least one byte long. 1.128 + * 1.129 + * @throws IOException if any errors happen during encoding of the 1.130 + * extension. 1.131 + * @throws IllegalArgumentException if the incomingNonce length is not a 1.132 + * positive integer. 1.133 + * @throws NullPointerException if the incomingNonce is null. 1.134 + */ 1.135 + public OCSPNonceExtension(boolean isCritical, byte[] incomingNonce) 1.136 + throws IOException { 1.137 + this.extensionId = PKIXExtensions.OCSPNonce_Id; 1.138 + this.critical = isCritical; 1.139 + 1.140 + Objects.requireNonNull(incomingNonce, "Nonce data must be non-null"); 1.141 + if (incomingNonce.length > 0) { 1.142 + this.nonceData = incomingNonce.clone(); 1.143 + this.extensionValue = new DerValue(DerValue.tag_OctetString, 1.144 + nonceData).toByteArray(); 1.145 + } else { 1.146 + throw new IllegalArgumentException( 1.147 + "Nonce data must be at least 1 byte in length"); 1.148 + } 1.149 + } 1.150 + 1.151 + /** 1.152 + * Return the nonce bytes themselves, without any DER encoding. 1.153 + * 1.154 + * @return A copy of the underlying nonce bytes 1.155 + */ 1.156 + public byte[] getNonceValue() { 1.157 + return nonceData.clone(); 1.158 + } 1.159 + 1.160 + /** 1.161 + * Returns a printable representation of the {@code OCSPNonceExtension}. 1.162 + * 1.163 + * @return a string representation of the extension. 1.164 + */ 1.165 + @Override 1.166 + public String toString() { 1.167 + StringBuilder sb = new StringBuilder(); 1.168 + sb.append(super.toString()).append(EXTENSION_NAME).append(": "); 1.169 + sb.append((nonceData == null) ? "" : Debug.toString(nonceData)); 1.170 + sb.append("\n"); 1.171 + return sb.toString(); 1.172 + } 1.173 + 1.174 + /** 1.175 + * Return the name of the extension as a {@code String} 1.176 + * 1.177 + * @return the name of the extension 1.178 + */ 1.179 + public String getName() { 1.180 + return EXTENSION_NAME; 1.181 + } 1.182 +}
2.1 --- a/src/share/classes/sun/security/ssl/SSLContextImpl.java Tue Aug 25 09:23:47 2020 +0300 2.2 +++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java Tue Aug 25 08:30:00 2020 -0700 2.3 @@ -59,7 +59,7 @@ 2.4 private volatile HelloCookieManager.Builder helloCookieManagerBuilder; 2.5 2.6 private final boolean clientEnableStapling = Utilities.getBooleanProperty( 2.7 - "jdk.tls.client.enableStatusRequestExtension", true); 2.8 + "jdk.tls.client.enableStatusRequestExtension", false); 2.9 private final boolean serverEnableStapling = Utilities.getBooleanProperty( 2.10 "jdk.tls.server.enableStatusRequestExtension", false); 2.11 private static final Collection<CipherSuite> clientCustomizedCipherSuites =
3.1 --- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java Tue Aug 25 09:23:47 2020 +0300 3.2 +++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java Tue Aug 25 08:30:00 2020 -0700 3.3 @@ -656,7 +656,6 @@ 3.4 * been presented by the server or non-certificate based server 3.5 * authentication is used then an empty {@code List} is returned. 3.6 */ 3.7 - @Override 3.8 public List<byte[]> getStatusResponses() { 3.9 if (statusResponses == null || statusResponses.isEmpty()) { 3.10 return Collections.emptyList();
4.1 --- a/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java Tue Aug 25 09:23:47 2020 +0300 4.2 +++ b/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java Tue Aug 25 08:30:00 2020 -0700 4.3 @@ -215,9 +215,10 @@ 4.4 4.5 // Grab any stapled OCSP responses for use in validation 4.6 List<byte[]> responseList = Collections.emptyList(); 4.7 - if (!checkClientTrusted && isExtSession) { 4.8 + if (!checkClientTrusted && isExtSession && 4.9 + session instanceof SSLSessionImpl) { 4.10 responseList = 4.11 - ((ExtendedSSLSession)session).getStatusResponses(); 4.12 + ((SSLSessionImpl)session).getStatusResponses(); 4.13 } 4.14 trustedChain = validate(v, chain, responseList, 4.15 constraints, checkClientTrusted ? null : authType); 4.16 @@ -269,9 +270,10 @@ 4.17 4.18 // Grab any stapled OCSP responses for use in validation 4.19 List<byte[]> responseList = Collections.emptyList(); 4.20 - if (!checkClientTrusted && isExtSession) { 4.21 + if (!checkClientTrusted && isExtSession && 4.22 + session instanceof SSLSessionImpl) { 4.23 responseList = 4.24 - ((ExtendedSSLSession)session).getStatusResponses(); 4.25 + ((SSLSessionImpl)session).getStatusResponses(); 4.26 } 4.27 trustedChain = validate(v, chain, responseList, 4.28 constraints, checkClientTrusted ? null : authType);
5.1 --- a/src/share/classes/sun/security/validator/PKIXValidator.java Tue Aug 25 09:23:47 2020 +0300 5.2 +++ b/src/share/classes/sun/security/validator/PKIXValidator.java Tue Aug 25 08:30:00 2020 -0700 5.3 @@ -215,6 +215,7 @@ 5.4 @Override 5.5 X509Certificate[] engineValidate(X509Certificate[] chain, 5.6 Collection<X509Certificate> otherCerts, 5.7 + List<byte[]> responseList, 5.8 AlgorithmConstraints constraints, 5.9 Object parameter) throws CertificateException { 5.10 if ((chain == null) || (chain.length == 0)) { 5.11 @@ -241,6 +242,11 @@ 5.12 new AlgorithmChecker(constraints, null, variant)); 5.13 } 5.14 5.15 + // attach it to the PKIXBuilderParameters. 5.16 + if (!responseList.isEmpty()) { 5.17 + addResponses(pkixParameters, chain, responseList); 5.18 + } 5.19 + 5.20 if (TRY_VALIDATOR) { 5.21 // check that chain is in correct order and check if chain contains 5.22 // trust anchor 5.23 @@ -450,4 +456,70 @@ 5.24 ("PKIX path building failed: " + e.toString(), e); 5.25 } 5.26 } 5.27 + 5.28 + /** 5.29 + * For OCSP Stapling, add responses that came in during the handshake 5.30 + * into a {@code PKIXRevocationChecker} so we can evaluate them. 5.31 + * 5.32 + * @param pkixParams the pkixParameters object that will be used in 5.33 + * path validation. 5.34 + * @param chain the chain of certificates to verify 5.35 + * @param responseList a {@code List} of zero or more byte arrays, each 5.36 + * one being a DER-encoded OCSP response (per RFC 6960). Entries 5.37 + * in the List must match the order of the certificates in the 5.38 + * chain parameter. 5.39 + */ 5.40 + private static void addResponses(PKIXBuilderParameters pkixParams, 5.41 + X509Certificate[] chain, List<byte[]> responseList) { 5.42 + 5.43 + if (pkixParams.isRevocationEnabled()) { 5.44 + try { 5.45 + // Make a modifiable copy of the CertPathChecker list 5.46 + PKIXRevocationChecker revChecker = null; 5.47 + List<PKIXCertPathChecker> checkerList = 5.48 + new ArrayList<>(pkixParams.getCertPathCheckers()); 5.49 + 5.50 + // Find the first PKIXRevocationChecker in the list 5.51 + for (PKIXCertPathChecker checker : checkerList) { 5.52 + if (checker instanceof PKIXRevocationChecker) { 5.53 + revChecker = (PKIXRevocationChecker)checker; 5.54 + break; 5.55 + } 5.56 + } 5.57 + 5.58 + // If we still haven't found one, make one 5.59 + if (revChecker == null) { 5.60 + revChecker = (PKIXRevocationChecker)CertPathValidator. 5.61 + getInstance("PKIX").getRevocationChecker(); 5.62 + checkerList.add(revChecker); 5.63 + } 5.64 + 5.65 + // Each response in the list should be in parallel with 5.66 + // the certificate list. If there is a zero-length response 5.67 + // treat it as being absent. If the user has provided their 5.68 + // own PKIXRevocationChecker with pre-populated responses, do 5.69 + // not overwrite them with the ones from the handshake. 5.70 + Map<X509Certificate, byte[]> responseMap = 5.71 + revChecker.getOcspResponses(); 5.72 + int limit = Integer.min(chain.length, responseList.size()); 5.73 + for (int idx = 0; idx < limit; idx++) { 5.74 + byte[] respBytes = responseList.get(idx); 5.75 + if (respBytes != null && respBytes.length > 0 && 5.76 + !responseMap.containsKey(chain[idx])) { 5.77 + responseMap.put(chain[idx], respBytes); 5.78 + } 5.79 + } 5.80 + 5.81 + // Add the responses and push it all back into the 5.82 + // PKIXBuilderParameters 5.83 + revChecker.setOcspResponses(responseMap); 5.84 + pkixParams.setCertPathCheckers(checkerList); 5.85 + } catch (NoSuchAlgorithmException exc) { 5.86 + // This should not occur, but if it does happen then 5.87 + // stapled OCSP responses won't be part of revocation checking. 5.88 + // Clients can still fall back to other means of revocation 5.89 + // checking. 5.90 + } 5.91 + } 5.92 + } 5.93 }
6.1 --- a/src/share/classes/sun/security/validator/SimpleValidator.java Tue Aug 25 09:23:47 2020 +0300 6.2 +++ b/src/share/classes/sun/security/validator/SimpleValidator.java Tue Aug 25 08:30:00 2020 -0700 6.3 @@ -123,6 +123,7 @@ 6.4 @Override 6.5 X509Certificate[] engineValidate(X509Certificate[] chain, 6.6 Collection<X509Certificate> otherCerts, 6.7 + List<byte[]> responseList, 6.8 AlgorithmConstraints constraints, 6.9 Object parameter) throws CertificateException { 6.10 if ((chain == null) || (chain.length == 0)) {
7.1 --- a/src/share/classes/sun/security/validator/Validator.java Tue Aug 25 09:23:47 2020 +0300 7.2 +++ b/src/share/classes/sun/security/validator/Validator.java Tue Aug 25 08:30:00 2020 -0700 7.3 @@ -235,7 +235,8 @@ 7.4 public final X509Certificate[] validate(X509Certificate[] chain, 7.5 Collection<X509Certificate> otherCerts, Object parameter) 7.6 throws CertificateException { 7.7 - return validate(chain, otherCerts, null, parameter); 7.8 + return validate(chain, otherCerts, Collections.emptyList(), null, 7.9 + parameter); 7.10 } 7.11 7.12 /** 7.13 @@ -244,6 +245,13 @@ 7.14 * @param chain the target certificate chain 7.15 * @param otherCerts a Collection of additional X509Certificates that 7.16 * could be helpful for path building (or null) 7.17 + * @param responseList a List of zero or more byte arrays, each 7.18 + * one being a DER-encoded OCSP response (per RFC 6960). Entries 7.19 + * in the List must match the order of the certificates in the 7.20 + * chain parameter. It is possible that fewer responses may be 7.21 + * in the list than are elements in {@code chain} and a missing 7.22 + * response for a matching element in {@code chain} can be 7.23 + * represented with a zero-length byte array. 7.24 * @param constraints algorithm constraints for certification path 7.25 * processing 7.26 * @param parameter an additional parameter with variant specific meaning. 7.27 @@ -257,9 +265,11 @@ 7.28 */ 7.29 public final X509Certificate[] validate(X509Certificate[] chain, 7.30 Collection<X509Certificate> otherCerts, 7.31 + List<byte[]> responseList, 7.32 AlgorithmConstraints constraints, 7.33 Object parameter) throws CertificateException { 7.34 - chain = engineValidate(chain, otherCerts, constraints, parameter); 7.35 + chain = engineValidate(chain, otherCerts, responseList, constraints, 7.36 + parameter); 7.37 7.38 // omit EE extension check if EE cert is also trust anchor 7.39 if (chain.length > 1) { 7.40 @@ -280,6 +290,7 @@ 7.41 7.42 abstract X509Certificate[] engineValidate(X509Certificate[] chain, 7.43 Collection<X509Certificate> otherCerts, 7.44 + List<byte[]> responseList, 7.45 AlgorithmConstraints constraints, 7.46 Object parameter) throws CertificateException; 7.47