1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import java.nio.ByteBuffer;
  30 import java.util.List;
  31 import sun.security.ssl.SSLExtension.ExtensionConsumer;
  32 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  33 import sun.security.ssl.SignatureAlgorithmsExtension.SignatureSchemesSpec;
  34 
  35 /**
  36  * Pack of the "signature_algorithms_cert" extensions.
  37  */
  38 final class CertSignAlgsExtension {
  39     static final HandshakeProducer chNetworkProducer =
  40             new CHCertSignatureSchemesProducer();
  41     static final ExtensionConsumer chOnLoadConcumer =
  42             new CHCertSignatureSchemesConsumer();
  43     static final HandshakeConsumer chOnTradeConsumer =
  44             new CHCertSignatureSchemesUpdate();
  45 
  46     static final HandshakeProducer crNetworkProducer =
  47             new CRCertSignatureSchemesProducer();
  48     static final ExtensionConsumer crOnLoadConcumer =
  49             new CRCertSignatureSchemesConsumer();
  50     static final HandshakeConsumer crOnTradeConsumer =
  51             new CRCertSignatureSchemesUpdate();
  52 
  53     static final SSLStringize ssStringize =
  54             new CertSignatureSchemesStringize();
  55 
  56     private static final
  57             class CertSignatureSchemesStringize implements SSLStringize {
  58         @Override
  59         public String toString(ByteBuffer buffer) {
  60             try {
  61                 return (new SignatureSchemesSpec(buffer)).toString();
  62             } catch (IOException ioe) {
  63                 // For debug logging only, so please swallow exceptions.
  64                 return ioe.getMessage();
  65             }
  66         }
  67     }
  68 
  69     /**
  70      * Network data producer of a "signature_algorithms_cert" extension in
  71      * the ClientHello handshake message.
  72      */
  73     private static final
  74             class CHCertSignatureSchemesProducer implements HandshakeProducer {
  75         // Prevent instantiation of this class.
  76         private CHCertSignatureSchemesProducer() {
  77             // blank
  78         }
  79 
  80         @Override
  81         public byte[] produce(ConnectionContext context,
  82                 HandshakeMessage message) throws IOException {
  83             // The producing happens in client side only.
  84             ClientHandshakeContext chc = (ClientHandshakeContext)context;
  85 
  86             // Is it a supported and enabled extension?
  87             if (!chc.sslConfig.isAvailable(
  88                     SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) {
  89                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
  90                     SSLLogger.fine(
  91                             "Ignore unavailable " +
  92                             "signature_algorithms_cert extension");
  93                 }
  94 
  95                 return null;    // ignore the extension
  96             }
  97 
  98             // Produce the extension.
  99             if (chc.localSupportedSignAlgs == null) {
 100                 chc.localSupportedSignAlgs =
 101                     SignatureScheme.getSupportedAlgorithms(
 102                             chc.algorithmConstraints, chc.activeProtocols);
 103             }
 104 
 105             int vectorLen = SignatureScheme.sizeInRecord() *
 106                     chc.localSupportedSignAlgs.size();
 107             byte[] extData = new byte[vectorLen + 2];
 108             ByteBuffer m = ByteBuffer.wrap(extData);
 109             Record.putInt16(m, vectorLen);
 110             for (SignatureScheme ss : chc.localSupportedSignAlgs) {
 111                 Record.putInt16(m, ss.id);
 112             }
 113 
 114             // Update the context.
 115             chc.handshakeExtensions.put(
 116                     SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT,
 117                     new SignatureSchemesSpec(chc.localSupportedSignAlgs));
 118 
 119             return extData;
 120         }
 121     }
 122 
 123     /**
 124      * Network data consumer of a "signature_algorithms_cert" extension in
 125      * the ClientHello handshake message.
 126      */
 127     private static final
 128             class CHCertSignatureSchemesConsumer implements ExtensionConsumer {
 129         // Prevent instantiation of this class.
 130         private CHCertSignatureSchemesConsumer() {
 131             // blank
 132         }
 133 
 134         @Override
 135         public void consume(ConnectionContext context,
 136             HandshakeMessage message, ByteBuffer buffer) throws IOException {
 137             // The comsuming happens in server side only.
 138             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 139 
 140             // Is it a supported and enabled extension?
 141             if (!shc.sslConfig.isAvailable(
 142                     SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) {
 143                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 144                     SSLLogger.fine(
 145                             "Ignore unavailable " +
 146                             "signature_algorithms_cert extension");
 147                 }
 148                 return;     // ignore the extension
 149             }
 150 
 151             // Parse the extension.
 152             SignatureSchemesSpec spec;
 153             try {
 154                 spec = new SignatureSchemesSpec(buffer);
 155             } catch (IOException ioe) {
 156                 shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
 157                 return;     // fatal() always throws, make the compiler happy.
 158             }
 159 
 160             // Update the context.
 161             shc.handshakeExtensions.put(
 162                     SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT, spec);
 163 
 164             // No impact on session resumption.
 165         }
 166     }
 167 
 168     /**
 169      * After session creation consuming of a "signature_algorithms_cert"
 170      * extension in the ClientHello handshake message.
 171      */
 172     private static final class CHCertSignatureSchemesUpdate
 173             implements HandshakeConsumer {
 174         // Prevent instantiation of this class.
 175         private CHCertSignatureSchemesUpdate() {
 176             // blank
 177         }
 178 
 179         @Override
 180         public void consume(ConnectionContext context,
 181                 HandshakeMessage message) throws IOException {
 182             // The comsuming happens in server side only.
 183             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 184 
 185             SignatureSchemesSpec spec = (SignatureSchemesSpec)
 186                     shc.handshakeExtensions.get(
 187                             SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT);
 188             if (spec == null) {
 189                 // Ignore, no signature_algorithms_cert extension requested.
 190                 return;
 191             }
 192 
 193             // update the context
 194             List<SignatureScheme> shemes =
 195                     SignatureScheme.getSupportedAlgorithms(
 196                             shc.algorithmConstraints, shc.negotiatedProtocol,
 197                             spec.signatureSchemes);
 198             shc.peerRequestedCertSignSchemes = shemes;
 199 
 200             if (!shc.isResumption && shc.negotiatedProtocol.useTLS13PlusSpec()) {
 201                 if (shc.sslConfig.clientAuthType !=
 202                         ClientAuthType.CLIENT_AUTH_NONE) {
 203                     shc.handshakeProducers.putIfAbsent(
 204                             SSLHandshake.CERTIFICATE_REQUEST.id,
 205                             SSLHandshake.CERTIFICATE_REQUEST);
 206                 }
 207                 shc.handshakeProducers.put(SSLHandshake.CERTIFICATE.id,
 208                         SSLHandshake.CERTIFICATE);
 209                 shc.handshakeProducers.putIfAbsent(
 210                         SSLHandshake.CERTIFICATE_VERIFY.id,
 211                         SSLHandshake.CERTIFICATE_VERIFY);
 212             }
 213         }
 214     }
 215 
 216     /**
 217      * Network data producer of a "signature_algorithms_cert" extension in
 218      * the CertificateRequest handshake message.
 219      */
 220     private static final
 221             class CRCertSignatureSchemesProducer implements HandshakeProducer {
 222         // Prevent instantiation of this class.
 223         private CRCertSignatureSchemesProducer() {
 224             // blank
 225         }
 226 
 227         @Override
 228         public byte[] produce(ConnectionContext context,
 229                 HandshakeMessage message) throws IOException {
 230             // The producing happens in server side only.
 231             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 232 
 233             // Is it a supported and enabled extension?
 234             if (!shc.sslConfig.isAvailable(
 235                     SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) {
 236                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 237                     SSLLogger.fine(
 238                             "Ignore unavailable " +
 239                             "signature_algorithms_cert extension");
 240                 }
 241                 return null;    // ignore the extension
 242             }
 243 
 244             // Produce the extension.
 245             if (shc.localSupportedSignAlgs == null) {
 246                 shc.localSupportedSignAlgs =
 247                     SignatureScheme.getSupportedAlgorithms(
 248                             shc.algorithmConstraints, shc.activeProtocols);
 249             }
 250 
 251             int vectorLen = SignatureScheme.sizeInRecord() *
 252                     shc.localSupportedSignAlgs.size();
 253             byte[] extData = new byte[vectorLen + 2];
 254             ByteBuffer m = ByteBuffer.wrap(extData);
 255             Record.putInt16(m, vectorLen);
 256             for (SignatureScheme ss : shc.localSupportedSignAlgs) {
 257                 Record.putInt16(m, ss.id);
 258             }
 259 
 260             // Update the context.
 261             shc.handshakeExtensions.put(
 262                     SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT,
 263                     new SignatureSchemesSpec(shc.localSupportedSignAlgs));
 264 
 265             return extData;
 266         }
 267     }
 268 
 269     /**
 270      * Network data consumer of a "signature_algorithms_cert" extension in
 271      * the CertificateRequest handshake message.
 272      */
 273     private static final
 274             class CRCertSignatureSchemesConsumer implements ExtensionConsumer {
 275         // Prevent instantiation of this class.
 276         private CRCertSignatureSchemesConsumer() {
 277             // blank
 278         }
 279         @Override
 280         public void consume(ConnectionContext context,
 281             HandshakeMessage message, ByteBuffer buffer) throws IOException {
 282             // The comsuming happens in client side only.
 283             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 284 
 285             // Is it a supported and enabled extension?
 286             if (!chc.sslConfig.isAvailable(
 287                     SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT)) {
 288                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 289                     SSLLogger.fine(
 290                             "Ignore unavailable " +
 291                             "signature_algorithms_cert extension");
 292                 }
 293                 return;     // ignore the extension
 294             }
 295 
 296             // Parse the extension.
 297             SignatureSchemesSpec spec;
 298             try {
 299                 spec = new SignatureSchemesSpec(buffer);
 300             } catch (IOException ioe) {
 301                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
 302                 return;     // fatal() always throws, make the compiler happy.
 303             }
 304 
 305             // Update the context.
 306             chc.handshakeExtensions.put(
 307                     SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT, spec);
 308 
 309             // No impact on session resumption.
 310         }
 311     }
 312 
 313     /**
 314      * After session creation consuming of a "signature_algorithms_cert"
 315      * extension in the CertificateRequest handshake message.
 316      */
 317     private static final class CRCertSignatureSchemesUpdate
 318             implements HandshakeConsumer {
 319         // Prevent instantiation of this class.
 320         private CRCertSignatureSchemesUpdate() {
 321             // blank
 322         }
 323 
 324         @Override
 325         public void consume(ConnectionContext context,
 326                 HandshakeMessage message) throws IOException {
 327             // The comsuming happens in client side only.
 328             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 329 
 330             SignatureSchemesSpec spec = (SignatureSchemesSpec)
 331                     chc.handshakeExtensions.get(
 332                             SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT);
 333             if (spec == null) {
 334                 // Ignore, no "signature_algorithms_cert" extension requested.
 335                 return;
 336             }
 337 
 338             // update the context
 339             List<SignatureScheme> shemes =
 340                     SignatureScheme.getSupportedAlgorithms(
 341                             chc.algorithmConstraints, chc.negotiatedProtocol,
 342                             spec.signatureSchemes);
 343             chc.peerRequestedCertSignSchemes = shemes;
 344         }
 345     }
 346 }