8245473: OCSP stapling support

Tue, 25 Aug 2020 08:30:00 -0700

author
abakhtin
date
Tue, 25 Aug 2020 08:30:00 -0700
changeset 14191
896bbc5499ff
parent 14190
b58fdaa80b5a
child 14192
80cdee1da353

8245473: OCSP stapling support
Reviewed-by: mbalao

src/share/classes/sun/security/provider/certpath/OCSPNonceExtension.java file | annotate | diff | comparison | revisions
src/share/classes/sun/security/ssl/SSLContextImpl.java file | annotate | diff | comparison | revisions
src/share/classes/sun/security/ssl/SSLSessionImpl.java file | annotate | diff | comparison | revisions
src/share/classes/sun/security/ssl/X509TrustManagerImpl.java file | annotate | diff | comparison | revisions
src/share/classes/sun/security/validator/PKIXValidator.java file | annotate | diff | comparison | revisions
src/share/classes/sun/security/validator/SimpleValidator.java file | annotate | diff | comparison | revisions
src/share/classes/sun/security/validator/Validator.java file | annotate | diff | comparison | revisions
     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  

mercurial