src/java.base/share/classes/sun/security/ssl/CertificateVerify.java
branchJDK-8145252-TLS13-branch
changeset 56542 56aaa6cb3693
child 56658 fe938437f7ba
equal deleted inserted replaced
56541:92cbbfc996f3 56542:56aaa6cb3693
       
     1  /*
       
     2  * Copyright (c) 2015, 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.security.*;
       
    31 import java.text.MessageFormat;
       
    32 import java.util.Arrays;
       
    33 import java.util.Locale;
       
    34 import sun.security.ssl.SSLHandshake.HandshakeMessage;
       
    35 import sun.security.ssl.X509Authentication.X509Credentials;
       
    36 import sun.security.ssl.X509Authentication.X509Possession;
       
    37 import sun.security.util.HexDumpEncoder;
       
    38 
       
    39 /**
       
    40  * Pack of the CertificateVerify handshake message.
       
    41  */
       
    42 final class CertificateVerify {
       
    43     static final SSLConsumer s30HandshakeConsumer =
       
    44         new S30CertificateVerifyConsumer();
       
    45     static final HandshakeProducer s30HandshakeProducer =
       
    46         new S30CertificateVerifyProducer();
       
    47 
       
    48     static final SSLConsumer t10HandshakeConsumer =
       
    49         new T10CertificateVerifyConsumer();
       
    50     static final HandshakeProducer t10HandshakeProducer =
       
    51         new T10CertificateVerifyProducer();
       
    52 
       
    53     static final SSLConsumer t12HandshakeConsumer =
       
    54         new T12CertificateVerifyConsumer();
       
    55     static final HandshakeProducer t12HandshakeProducer =
       
    56         new T12CertificateVerifyProducer();
       
    57 
       
    58     static final SSLConsumer t13HandshakeConsumer =
       
    59         new T13CertificateVerifyConsumer();
       
    60     static final HandshakeProducer t13HandshakeProducer =
       
    61         new T13CertificateVerifyProducer();
       
    62 
       
    63     /**
       
    64      * The CertificateVerify handshake message (SSL 3.0).
       
    65      */
       
    66     static final class S30CertificateVerifyMessage extends HandshakeMessage {
       
    67         // signature bytes
       
    68         private final byte[] signature;
       
    69 
       
    70         S30CertificateVerifyMessage(HandshakeContext context,
       
    71                 X509Possession x509Possession) throws IOException {
       
    72             super(context);
       
    73 
       
    74             // This happens in client side only.
       
    75             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
    76             byte[] temproary = null;
       
    77             String algorithm = x509Possession.popPrivateKey.getAlgorithm();
       
    78             try {
       
    79                 Signature signer = getSignature(algorithm);
       
    80                 signer.initSign(x509Possession.popPrivateKey);
       
    81                 byte[] hashes = chc.handshakeHash.digest(algorithm,
       
    82                         chc.handshakeSession.getMasterSecret());
       
    83                 signer.update(hashes);
       
    84                 temproary = signer.sign();
       
    85             } catch (NoSuchAlgorithmException nsae) {
       
    86                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
    87                         "Unsupported signature algorithm (" + algorithm +
       
    88                         ") used in CertificateVerify handshake message", nsae);
       
    89             } catch (GeneralSecurityException gse) {
       
    90                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
    91                         "Cannot produce CertificateVerify signature", gse);
       
    92             }
       
    93 
       
    94             this.signature = temproary;
       
    95         }
       
    96 
       
    97         S30CertificateVerifyMessage(HandshakeContext context,
       
    98                 ByteBuffer m) throws IOException {
       
    99             super(context);
       
   100 
       
   101             // This happens in server side only.
       
   102             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   103 
       
   104             //  digitally-signed struct {
       
   105             //    select(SignatureAlgorithm) {
       
   106             //        case anonymous: struct { };
       
   107             //        case rsa:
       
   108             //            opaque md5_hash[16];
       
   109             //            opaque sha_hash[20];
       
   110             //        case dsa:
       
   111             //            opaque sha_hash[20];
       
   112             //    };
       
   113             //  } Signature;
       
   114             if (m.remaining() < 2) {
       
   115                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   116                     "Invalid CertificateVerify message: no sufficient data");
       
   117             }
       
   118 
       
   119             // read and verify the signature
       
   120             this.signature = Record.getBytes16(m);
       
   121             X509Credentials x509Credentials = null;
       
   122             for (SSLCredentials cd : shc.handshakeCredentials) {
       
   123                 if (cd instanceof X509Credentials) {
       
   124                     x509Credentials = (X509Credentials)cd;
       
   125                     break;
       
   126                 }
       
   127             }
       
   128 
       
   129             if (x509Credentials == null) {
       
   130                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   131                     "No X509 credentials negotiated for CertificateVerify");
       
   132             }
       
   133 
       
   134             String algorithm = x509Credentials.popPublicKey.getAlgorithm();
       
   135             try {
       
   136                 Signature signer = getSignature(algorithm);
       
   137                 signer.initVerify(x509Credentials.popPublicKey);
       
   138                 byte[] hashes = shc.handshakeHash.digest(algorithm,
       
   139                         shc.handshakeSession.getMasterSecret());
       
   140                 signer.update(hashes);
       
   141                 if (!signer.verify(signature)) {
       
   142                     shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   143                         "Invalid CertificateVerify message: invalid signature");
       
   144                 }
       
   145             } catch (NoSuchAlgorithmException nsae) {
       
   146                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   147                         "Unsupported signature algorithm (" + algorithm +
       
   148                         ") used in CertificateVerify handshake message", nsae);
       
   149             } catch (GeneralSecurityException gse) {
       
   150                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   151                         "Cannot verify CertificateVerify signature", gse);
       
   152             }
       
   153         }
       
   154 
       
   155         @Override
       
   156         public SSLHandshake handshakeType() {
       
   157             return SSLHandshake.CERTIFICATE_VERIFY;
       
   158         }
       
   159 
       
   160         @Override
       
   161         public int messageLength() {
       
   162             return 2 + signature.length;    //  2: length of signature
       
   163         }
       
   164 
       
   165         @Override
       
   166         public void send(HandshakeOutStream hos) throws IOException {
       
   167             hos.putBytes16(signature);
       
   168         }
       
   169 
       
   170         @Override
       
   171         public String toString() {
       
   172             MessageFormat messageFormat = new MessageFormat(
       
   173                     "\"CertificateVerify\": '{'\n" +
       
   174                     "  \"signature\": '{'\n" +
       
   175                     "{0}\n" +
       
   176                     "  '}'\n" +
       
   177                     "'}'",
       
   178                     Locale.ENGLISH);
       
   179 
       
   180             HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   181             Object[] messageFields = {
       
   182                 Utilities.indent(
       
   183                         hexEncoder.encodeBuffer(signature), "    ")
       
   184             };
       
   185 
       
   186             return messageFormat.format(messageFields);
       
   187         }
       
   188 
       
   189         /*
       
   190          * Get the Signature object appropriate for verification using the
       
   191          * given signature algorithm.
       
   192          */
       
   193         private static Signature getSignature(
       
   194                 String algorithm) throws GeneralSecurityException {
       
   195             switch (algorithm) {
       
   196                 case "RSA":
       
   197                     return JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA);
       
   198                 case "DSA":
       
   199                     return JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA);
       
   200                 case "EC":
       
   201                     return JsseJce.getSignature(JsseJce.SIGNATURE_RAWECDSA);
       
   202                 default:
       
   203                     throw new SignatureException("Unrecognized algorithm: "
       
   204                         + algorithm);
       
   205             }
       
   206         }
       
   207     }
       
   208 
       
   209     /**
       
   210      * The "CertificateVerify" handshake message producer.
       
   211      */
       
   212     private static final
       
   213             class S30CertificateVerifyProducer implements HandshakeProducer {
       
   214         // Prevent instantiation of this class.
       
   215         private S30CertificateVerifyProducer() {
       
   216             // blank
       
   217         }
       
   218 
       
   219         @Override
       
   220         public byte[] produce(ConnectionContext context,
       
   221                 HandshakeMessage message) throws IOException {
       
   222             // The producing happens in client side only.
       
   223             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   224 
       
   225             X509Possession x509Possession = null;
       
   226             for (SSLPossession possession : chc.handshakePossessions) {
       
   227                 if (possession instanceof X509Possession) {
       
   228                     x509Possession = (X509Possession)possession;
       
   229                     break;
       
   230                 }
       
   231             }
       
   232 
       
   233             if (x509Possession == null) {
       
   234                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   235                     SSLLogger.fine(
       
   236                         "No X.509 credentials negotiated for CertificateVerify");
       
   237                 }
       
   238 
       
   239                 return null;
       
   240             }
       
   241 
       
   242             S30CertificateVerifyMessage cvm =
       
   243                     new S30CertificateVerifyMessage(chc, x509Possession);
       
   244             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   245                 SSLLogger.fine(
       
   246                         "Produced CertificateVerify handshake message", cvm);
       
   247             }
       
   248 
       
   249             // Output the handshake message.
       
   250             cvm.write(chc.handshakeOutput);
       
   251             chc.handshakeOutput.flush();
       
   252 
       
   253             // The handshake message has been delivered.
       
   254             return null;
       
   255         }
       
   256     }
       
   257 
       
   258     /**
       
   259      * The "CertificateVerify" handshake message consumer.
       
   260      */
       
   261     private static final
       
   262             class S30CertificateVerifyConsumer implements SSLConsumer {
       
   263         // Prevent instantiation of this class.
       
   264         private S30CertificateVerifyConsumer() {
       
   265             // blank
       
   266         }
       
   267 
       
   268         @Override
       
   269         public void consume(ConnectionContext context,
       
   270                 ByteBuffer message) throws IOException {
       
   271             // The consuming happens in server side only.
       
   272             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   273             S30CertificateVerifyMessage cvm =
       
   274                     new S30CertificateVerifyMessage(shc, message);
       
   275             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   276                 SSLLogger.fine(
       
   277                     "Consuming CertificateVerify handshake message", cvm);
       
   278             }
       
   279 
       
   280             //
       
   281             // update
       
   282             //
       
   283             // Need no additional validation.
       
   284 
       
   285             //
       
   286             // produce
       
   287             //
       
   288             // Need no new handshake message producers here.
       
   289         }
       
   290     }
       
   291 
       
   292     /**
       
   293      * The CertificateVerify handshake message (TLS 1.0/1.1).
       
   294      */
       
   295     static final class T10CertificateVerifyMessage extends HandshakeMessage {
       
   296         // signature bytes
       
   297         private final byte[] signature;
       
   298 
       
   299         T10CertificateVerifyMessage(HandshakeContext context,
       
   300                 X509Possession x509Possession) throws IOException {
       
   301             super(context);
       
   302 
       
   303             // This happens in client side only.
       
   304             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   305             byte[] temproary = null;
       
   306             String algorithm = x509Possession.popPrivateKey.getAlgorithm();
       
   307             try {
       
   308                 Signature signer = getSignature(algorithm);
       
   309                 signer.initSign(x509Possession.popPrivateKey);
       
   310                 byte[] hashes = chc.handshakeHash.digest(algorithm);
       
   311                 signer.update(hashes);
       
   312                 temproary = signer.sign();
       
   313             } catch (NoSuchAlgorithmException nsae) {
       
   314                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   315                         "Unsupported signature algorithm (" + algorithm +
       
   316                         ") used in CertificateVerify handshake message", nsae);
       
   317             } catch (GeneralSecurityException gse) {
       
   318                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   319                     "Cannot produce CertificateVerify signature", gse);
       
   320             }
       
   321 
       
   322             this.signature = temproary;
       
   323         }
       
   324 
       
   325         T10CertificateVerifyMessage(HandshakeContext context,
       
   326                 ByteBuffer m) throws IOException {
       
   327             super(context);
       
   328 
       
   329             // This happens in server side only.
       
   330             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   331 
       
   332             //  digitally-signed struct {
       
   333             //    select(SignatureAlgorithm) {
       
   334             //        case anonymous: struct { };
       
   335             //        case rsa:
       
   336             //            opaque md5_hash[16];
       
   337             //            opaque sha_hash[20];
       
   338             //        case dsa:
       
   339             //            opaque sha_hash[20];
       
   340             //    };
       
   341             //  } Signature;
       
   342             if (m.remaining() < 2) {
       
   343                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   344                     "Invalid CertificateVerify message: no sufficient data");
       
   345             }
       
   346 
       
   347             // read and verify the signature
       
   348             this.signature = Record.getBytes16(m);
       
   349             X509Credentials x509Credentials = null;
       
   350             for (SSLCredentials cd : shc.handshakeCredentials) {
       
   351                 if (cd instanceof X509Credentials) {
       
   352                     x509Credentials = (X509Credentials)cd;
       
   353                     break;
       
   354                 }
       
   355             }
       
   356 
       
   357             if (x509Credentials == null) {
       
   358                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   359                     "No X509 credentials negotiated for CertificateVerify");
       
   360             }
       
   361 
       
   362             String algorithm = x509Credentials.popPublicKey.getAlgorithm();
       
   363             try {
       
   364                 Signature signer = getSignature(algorithm);
       
   365                 signer.initVerify(x509Credentials.popPublicKey);
       
   366                 byte[] hashes = shc.handshakeHash.digest(algorithm);
       
   367                 signer.update(hashes);
       
   368                 if (!signer.verify(signature)) {
       
   369                     shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   370                         "Invalid CertificateVerify message: invalid signature");
       
   371                 }
       
   372             } catch (NoSuchAlgorithmException nsae) {
       
   373                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   374                         "Unsupported signature algorithm (" + algorithm +
       
   375                         ") used in CertificateVerify handshake message", nsae);
       
   376             } catch (GeneralSecurityException gse) {
       
   377                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   378                         "Cannot verify CertificateVerify signature", gse);
       
   379             }
       
   380         }
       
   381 
       
   382         @Override
       
   383         public SSLHandshake handshakeType() {
       
   384             return SSLHandshake.CERTIFICATE_VERIFY;
       
   385         }
       
   386 
       
   387         @Override
       
   388         public int messageLength() {
       
   389             return 2 + signature.length;    //  2: length of signature
       
   390         }
       
   391 
       
   392         @Override
       
   393         public void send(HandshakeOutStream hos) throws IOException {
       
   394             hos.putBytes16(signature);
       
   395         }
       
   396 
       
   397         @Override
       
   398         public String toString() {
       
   399             MessageFormat messageFormat = new MessageFormat(
       
   400                     "\"CertificateVerify\": '{'\n" +
       
   401                     "  \"signature\": '{'\n" +
       
   402                     "{0}\n" +
       
   403                     "  '}'\n" +
       
   404                     "'}'",
       
   405                     Locale.ENGLISH);
       
   406 
       
   407             HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   408             Object[] messageFields = {
       
   409                 Utilities.indent(
       
   410                         hexEncoder.encodeBuffer(signature), "    ")
       
   411             };
       
   412 
       
   413             return messageFormat.format(messageFields);
       
   414         }
       
   415 
       
   416         /*
       
   417          * Get the Signature object appropriate for verification using the
       
   418          * given signature algorithm.
       
   419          */
       
   420         private static Signature getSignature(
       
   421                 String algorithm) throws GeneralSecurityException {
       
   422             switch (algorithm) {
       
   423                 case "RSA":
       
   424                     return JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA);
       
   425                 case "DSA":
       
   426                     return JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA);
       
   427                 case "EC":
       
   428                     return JsseJce.getSignature(JsseJce.SIGNATURE_RAWECDSA);
       
   429                 default:
       
   430                     throw new SignatureException("Unrecognized algorithm: "
       
   431                         + algorithm);
       
   432             }
       
   433         }
       
   434     }
       
   435 
       
   436     /**
       
   437      * The "CertificateVerify" handshake message producer.
       
   438      */
       
   439     private static final
       
   440             class T10CertificateVerifyProducer implements HandshakeProducer {
       
   441         // Prevent instantiation of this class.
       
   442         private T10CertificateVerifyProducer() {
       
   443             // blank
       
   444         }
       
   445 
       
   446         @Override
       
   447         public byte[] produce(ConnectionContext context,
       
   448                 HandshakeMessage message) throws IOException {
       
   449             // The producing happens in client side only.
       
   450             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   451             X509Possession x509Possession = null;
       
   452             for (SSLPossession possession : chc.handshakePossessions) {
       
   453                 if (possession instanceof X509Possession) {
       
   454                     x509Possession = (X509Possession)possession;
       
   455                     break;
       
   456                 }
       
   457             }
       
   458 
       
   459             if (x509Possession == null) {
       
   460                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   461                     SSLLogger.fine(
       
   462                         "No X.509 credentials negotiated for CertificateVerify");
       
   463                 }
       
   464 
       
   465                 return null;
       
   466             }
       
   467 
       
   468             T10CertificateVerifyMessage cvm =
       
   469                     new T10CertificateVerifyMessage(chc, x509Possession);
       
   470             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   471                 SSLLogger.fine(
       
   472                         "Produced CertificateVerify handshake message", cvm);
       
   473             }
       
   474 
       
   475             // Output the handshake message.
       
   476             cvm.write(chc.handshakeOutput);
       
   477             chc.handshakeOutput.flush();
       
   478 
       
   479             // The handshake message has been delivered.
       
   480             return null;
       
   481         }
       
   482     }
       
   483 
       
   484     /**
       
   485      * The "CertificateVerify" handshake message consumer.
       
   486      */
       
   487     private static final
       
   488             class T10CertificateVerifyConsumer implements SSLConsumer {
       
   489         // Prevent instantiation of this class.
       
   490         private T10CertificateVerifyConsumer() {
       
   491             // blank
       
   492         }
       
   493 
       
   494         @Override
       
   495         public void consume(ConnectionContext context,
       
   496                 ByteBuffer message) throws IOException {
       
   497             // The consuming happens in server side only.
       
   498             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   499             T10CertificateVerifyMessage cvm =
       
   500                     new T10CertificateVerifyMessage(shc, message);
       
   501             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   502                 SSLLogger.fine(
       
   503                         "Consuming CertificateVerify handshake message", cvm);
       
   504             }
       
   505 
       
   506             //
       
   507             // update
       
   508             //
       
   509             // Need no additional validation.
       
   510 
       
   511             //
       
   512             // produce
       
   513             //
       
   514             // Need no new handshake message producers here.        }
       
   515         }
       
   516     }
       
   517 
       
   518     /**
       
   519      * The CertificateVerify handshake message (TLS 1.2).
       
   520      */
       
   521     static final class T12CertificateVerifyMessage extends HandshakeMessage {
       
   522         // the signature algorithm
       
   523         private final SignatureScheme signatureScheme;
       
   524 
       
   525         // signature bytes
       
   526         private final byte[] signature;
       
   527 
       
   528         T12CertificateVerifyMessage(HandshakeContext context,
       
   529                 X509Possession x509Possession) throws IOException {
       
   530             super(context);
       
   531 
       
   532             // This happens in client side only.
       
   533             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   534             this.signatureScheme = SignatureScheme.getPreferableAlgorithm(
       
   535                     chc.peerRequestedSignatureSchemes,
       
   536                     x509Possession.popPrivateKey,
       
   537                     chc.negotiatedProtocol);
       
   538             if (signatureScheme == null) {
       
   539                 // Unlikely, the credentials generator should have
       
   540                 // selected the preferable signature algorithm properly.
       
   541                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   542                     "No preferred signature algorithm for CertificateVerify");
       
   543             }
       
   544 
       
   545             byte[] temproary = null;
       
   546             try {
       
   547                 Signature signer = signatureScheme.getSignature();
       
   548                 signer.initSign(x509Possession.popPrivateKey);
       
   549                 signer.update(chc.handshakeHash.archived());
       
   550                 temproary = signer.sign();
       
   551             } catch (NoSuchAlgorithmException |
       
   552                     InvalidAlgorithmParameterException nsae) {
       
   553                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   554                         "Unsupported signature algorithm (" +
       
   555                         signatureScheme.name +
       
   556                         ") used in CertificateVerify handshake message", nsae);
       
   557             } catch (InvalidKeyException | SignatureException ikse) {
       
   558                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   559                         "Cannot produce CertificateVerify signature", ikse);
       
   560             }
       
   561 
       
   562             this.signature = temproary;
       
   563         }
       
   564 
       
   565         T12CertificateVerifyMessage(HandshakeContext handshakeContext,
       
   566                 ByteBuffer m) throws IOException {
       
   567             super(handshakeContext);
       
   568 
       
   569             // This happens in server side only.
       
   570             ServerHandshakeContext shc =
       
   571                     (ServerHandshakeContext)handshakeContext;
       
   572 
       
   573             // struct {
       
   574             //     SignatureAndHashAlgorithm algorithm;
       
   575             //     opaque signature<0..2^16-1>;
       
   576             // } DigitallySigned;
       
   577             if (m.remaining() < 4) {
       
   578                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   579                     "Invalid CertificateVerify message: no sufficient data");
       
   580             }
       
   581 
       
   582             // SignatureAndHashAlgorithm algorithm
       
   583             int ssid = Record.getInt16(m);
       
   584             this.signatureScheme = SignatureScheme.valueOf(ssid);
       
   585             if (signatureScheme == null) {
       
   586                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   587                         "Invalid signature algorithm (" + ssid +
       
   588                         ") used in CertificateVerify handshake message");
       
   589             }
       
   590 
       
   591             if (!shc.localSupportedSignAlgs.contains(signatureScheme)) {
       
   592                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   593                         "Unsupported signature algorithm (" +
       
   594                         signatureScheme.name +
       
   595                         ") used in CertificateVerify handshake message");
       
   596             }
       
   597 
       
   598             // read and verify the signature
       
   599             X509Credentials x509Credentials = null;
       
   600             for (SSLCredentials cd : shc.handshakeCredentials) {
       
   601                 if (cd instanceof X509Credentials) {
       
   602                     x509Credentials = (X509Credentials)cd;
       
   603                     break;
       
   604                 }
       
   605             }
       
   606 
       
   607             if (x509Credentials == null) {
       
   608                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   609                     "No X509 credentials negotiated for CertificateVerify");
       
   610             }
       
   611 
       
   612             // opaque signature<0..2^16-1>;
       
   613             this.signature = Record.getBytes16(m);
       
   614             try {
       
   615                 Signature signer = signatureScheme.getSignature();
       
   616                 signer.initVerify(x509Credentials.popPublicKey);
       
   617                 signer.update(shc.handshakeHash.archived());
       
   618                 if (!signer.verify(signature)) {
       
   619                     shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   620                         "Invalid CertificateVerify signature");
       
   621                 }
       
   622             } catch (NoSuchAlgorithmException |
       
   623                     InvalidAlgorithmParameterException nsae) {
       
   624                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   625                         "Unsupported signature algorithm (" +
       
   626                         signatureScheme.name +
       
   627                         ") used in CertificateVerify handshake message", nsae);
       
   628             } catch (InvalidKeyException | SignatureException ikse) {
       
   629                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   630                         "Cannot verify CertificateVerify signature", ikse);
       
   631             }
       
   632         }
       
   633 
       
   634         @Override
       
   635         public SSLHandshake handshakeType() {
       
   636             return SSLHandshake.CERTIFICATE_VERIFY;
       
   637         }
       
   638 
       
   639         @Override
       
   640         public int messageLength() {
       
   641             return 4 + signature.length;    //  2: signature algorithm
       
   642                                             // +2: length of signature
       
   643         }
       
   644 
       
   645         @Override
       
   646         public void send(HandshakeOutStream hos) throws IOException {
       
   647             hos.putInt16(signatureScheme.id);
       
   648             hos.putBytes16(signature);
       
   649         }
       
   650 
       
   651         @Override
       
   652         public String toString() {
       
   653             MessageFormat messageFormat = new MessageFormat(
       
   654                     "\"CertificateVerify\": '{'\n" +
       
   655                     "  \"signature algorithm\": {0}\n" +
       
   656                     "  \"signature\": '{'\n" +
       
   657                     "{1}\n" +
       
   658                     "  '}'\n" +
       
   659                     "'}'",
       
   660                     Locale.ENGLISH);
       
   661 
       
   662             HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   663             Object[] messageFields = {
       
   664                 signatureScheme.name,
       
   665                 Utilities.indent(
       
   666                         hexEncoder.encodeBuffer(signature), "    ")
       
   667             };
       
   668 
       
   669             return messageFormat.format(messageFields);
       
   670         }
       
   671     }
       
   672 
       
   673     /**
       
   674      * The "CertificateVerify" handshake message producer.
       
   675      */
       
   676     private static final
       
   677             class T12CertificateVerifyProducer implements HandshakeProducer {
       
   678         // Prevent instantiation of this class.
       
   679         private T12CertificateVerifyProducer() {
       
   680             // blank
       
   681         }
       
   682 
       
   683         @Override
       
   684         public byte[] produce(ConnectionContext context,
       
   685                 HandshakeMessage message) throws IOException {
       
   686             // The producing happens in client side only.
       
   687             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   688 
       
   689             X509Possession x509Possession = null;
       
   690             for (SSLPossession possession : chc.handshakePossessions) {
       
   691                 if (possession instanceof X509Possession) {
       
   692                     x509Possession = (X509Possession)possession;
       
   693                     break;
       
   694                 }
       
   695             }
       
   696 
       
   697             if (x509Possession == null) {
       
   698                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   699                     SSLLogger.fine(
       
   700                         "No X.509 credentials negotiated for CertificateVerify");
       
   701                 }
       
   702 
       
   703                 return null;
       
   704             }
       
   705 
       
   706             T12CertificateVerifyMessage cvm =
       
   707                     new T12CertificateVerifyMessage(chc, x509Possession);
       
   708             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   709                 SSLLogger.fine(
       
   710                         "Produced CertificateVerify handshake message", cvm);
       
   711             }
       
   712 
       
   713             // Output the handshake message.
       
   714             cvm.write(chc.handshakeOutput);
       
   715             chc.handshakeOutput.flush();
       
   716 
       
   717             // The handshake message has been delivered.
       
   718             return null;
       
   719         }
       
   720     }
       
   721 
       
   722     /**
       
   723      * The "CertificateVerify" handshake message consumer.
       
   724      */
       
   725     private static final
       
   726             class T12CertificateVerifyConsumer implements SSLConsumer {
       
   727         // Prevent instantiation of this class.
       
   728         private T12CertificateVerifyConsumer() {
       
   729             // blank
       
   730         }
       
   731 
       
   732         @Override
       
   733         public void consume(ConnectionContext context,
       
   734                 ByteBuffer message) throws IOException {
       
   735             // The consuming happens in server side only.
       
   736             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   737             T12CertificateVerifyMessage cvm =
       
   738                     new T12CertificateVerifyMessage(shc, message);
       
   739             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   740                 SSLLogger.fine(
       
   741                         "Consuming CertificateVerify handshake message", cvm);
       
   742             }
       
   743 
       
   744             //
       
   745             // update
       
   746             //
       
   747             // Need no additional validation.
       
   748 
       
   749             //
       
   750             // produce
       
   751             //
       
   752             // Need no new handshake message producers here.
       
   753         }
       
   754     }
       
   755 
       
   756     /**
       
   757      * The CertificateVerify handshake message (TLS 1.3).
       
   758      */
       
   759     static final class T13CertificateVerifyMessage extends HandshakeMessage {
       
   760         private static final byte[] serverSignHead = new byte[] {
       
   761             // repeated 0x20 for 64 times
       
   762             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   763             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   764             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   765             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   766             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   767             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   768             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   769             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   770             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   771             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   772             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   773             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   774             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   775             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   776             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   777             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   778 
       
   779             // "TLS 1.3, server CertificateVerify" + 0x00
       
   780             (byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,
       
   781             (byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,
       
   782             (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x72,
       
   783             (byte)0x76, (byte)0x65, (byte)0x72, (byte)0x20,
       
   784             (byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,
       
   785             (byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,
       
   786             (byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,
       
   787             (byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,
       
   788             (byte)0x79, (byte)0x00
       
   789         };
       
   790 
       
   791         private static final byte[] clientSignHead = new byte[] {
       
   792             // repeated 0x20 for 64 times
       
   793             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   794             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   795             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   796             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   797             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   798             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   799             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   800             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   801             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   802             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   803             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   804             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   805             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   806             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   807             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   808             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
       
   809 
       
   810             // "TLS 1.3, client CertificateVerify" + 0x00
       
   811             (byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,
       
   812             (byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,
       
   813             (byte)0x20, (byte)0x63, (byte)0x6c, (byte)0x69,
       
   814             (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x20,
       
   815             (byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,
       
   816             (byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,
       
   817             (byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,
       
   818             (byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,
       
   819             (byte)0x79, (byte)0x00
       
   820         };
       
   821 
       
   822 
       
   823         // the signature algorithm
       
   824         private final SignatureScheme signatureScheme;
       
   825 
       
   826         // signature bytes
       
   827         private final byte[] signature;
       
   828 
       
   829         T13CertificateVerifyMessage(HandshakeContext context,
       
   830                 X509Possession x509Possession) throws IOException {
       
   831             super(context);
       
   832 
       
   833             this.signatureScheme = SignatureScheme.getPreferableAlgorithm(
       
   834                     context.peerRequestedSignatureSchemes,
       
   835                     x509Possession.popPrivateKey,
       
   836                     context.negotiatedProtocol);
       
   837             if (signatureScheme == null) {
       
   838                 // Unlikely, the credentials generator should have
       
   839                 // selected the preferable signature algorithm properly.
       
   840                 context.conContext.fatal(Alert.INTERNAL_ERROR,
       
   841                     "No preferred signature algorithm for CertificateVerify");
       
   842             }
       
   843 
       
   844             byte[] hashValue = context.handshakeHash.digest();
       
   845             byte[] contentCovered;
       
   846             if (context.sslConfig.isClientMode) {
       
   847                 contentCovered = Arrays.copyOf(clientSignHead,
       
   848                         clientSignHead.length + hashValue.length);
       
   849                 System.arraycopy(hashValue, 0, contentCovered,
       
   850                         clientSignHead.length, hashValue.length);
       
   851             } else {
       
   852                 contentCovered = Arrays.copyOf(serverSignHead,
       
   853                         serverSignHead.length + hashValue.length);
       
   854                 System.arraycopy(hashValue, 0, contentCovered,
       
   855                         serverSignHead.length, hashValue.length);
       
   856             }
       
   857 
       
   858             byte[] temproary = null;
       
   859             try {
       
   860                 Signature signer = signatureScheme.getSignature();
       
   861                 signer.initSign(x509Possession.popPrivateKey);
       
   862                 signer.update(contentCovered);
       
   863                 temproary = signer.sign();
       
   864             } catch (NoSuchAlgorithmException |
       
   865                     InvalidAlgorithmParameterException nsae) {
       
   866                 context.conContext.fatal(Alert.INTERNAL_ERROR,
       
   867                         "Unsupported signature algorithm (" +
       
   868                         signatureScheme.name +
       
   869                         ") used in CertificateVerify handshake message", nsae);
       
   870             } catch (InvalidKeyException | SignatureException ikse) {
       
   871                 context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   872                         "Cannot produce CertificateVerify signature", ikse);
       
   873             }
       
   874 
       
   875             this.signature = temproary;
       
   876         }
       
   877 
       
   878         T13CertificateVerifyMessage(HandshakeContext context,
       
   879                 ByteBuffer m) throws IOException {
       
   880              super(context);
       
   881 
       
   882             // struct {
       
   883             //     SignatureAndHashAlgorithm algorithm;
       
   884             //     opaque signature<0..2^16-1>;
       
   885             // } DigitallySigned;
       
   886             if (m.remaining() < 4) {
       
   887                 context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   888                     "Invalid CertificateVerify message: no sufficient data");
       
   889             }
       
   890 
       
   891             // SignatureAndHashAlgorithm algorithm
       
   892             int ssid = Record.getInt16(m);
       
   893             this.signatureScheme = SignatureScheme.valueOf(ssid);
       
   894             if (signatureScheme == null) {
       
   895                 context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   896                         "Invalid signature algorithm (" + ssid +
       
   897                         ") used in CertificateVerify handshake message");
       
   898             }
       
   899 
       
   900             if (!context.localSupportedSignAlgs.contains(signatureScheme)) {
       
   901                 context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   902                         "Unsupported signature algorithm (" +
       
   903                         signatureScheme.name +
       
   904                         ") used in CertificateVerify handshake message");
       
   905             }
       
   906 
       
   907             // read and verify the signature
       
   908             X509Credentials x509Credentials = null;
       
   909             for (SSLCredentials cd : context.handshakeCredentials) {
       
   910                 if (cd instanceof X509Credentials) {
       
   911                     x509Credentials = (X509Credentials)cd;
       
   912                     break;
       
   913                 }
       
   914             }
       
   915 
       
   916             if (x509Credentials == null) {
       
   917                 context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   918                     "No X509 credentials negotiated for CertificateVerify");
       
   919             }
       
   920 
       
   921             // opaque signature<0..2^16-1>;
       
   922             this.signature = Record.getBytes16(m);
       
   923 
       
   924             byte[] hashValue = context.handshakeHash.digest();
       
   925             byte[] contentCovered;
       
   926             if (context.sslConfig.isClientMode) {
       
   927                 contentCovered = Arrays.copyOf(serverSignHead,
       
   928                         serverSignHead.length + hashValue.length);
       
   929                 System.arraycopy(hashValue, 0, contentCovered,
       
   930                         serverSignHead.length, hashValue.length);
       
   931             } else {
       
   932                 contentCovered = Arrays.copyOf(clientSignHead,
       
   933                         clientSignHead.length + hashValue.length);
       
   934                 System.arraycopy(hashValue, 0, contentCovered,
       
   935                         clientSignHead.length, hashValue.length);
       
   936             }
       
   937 
       
   938             try {
       
   939                 Signature signer = signatureScheme.getSignature();
       
   940                 signer.initVerify(x509Credentials.popPublicKey);
       
   941                 signer.update(contentCovered);
       
   942                 if (!signer.verify(signature)) {
       
   943                     context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   944                         "Invalid CertificateVerify signature");
       
   945                 }
       
   946             } catch (NoSuchAlgorithmException |
       
   947                     InvalidAlgorithmParameterException nsae) {
       
   948                 context.conContext.fatal(Alert.INTERNAL_ERROR,
       
   949                         "Unsupported signature algorithm (" +
       
   950                         signatureScheme.name +
       
   951                         ") used in CertificateVerify handshake message", nsae);
       
   952             } catch (InvalidKeyException | SignatureException ikse) {
       
   953                 context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   954                         "Cannot verify CertificateVerify signature", ikse);
       
   955             }
       
   956         }
       
   957 
       
   958         @Override
       
   959         public SSLHandshake handshakeType() {
       
   960             return SSLHandshake.CERTIFICATE_VERIFY;
       
   961         }
       
   962 
       
   963         @Override
       
   964         public int messageLength() {
       
   965             return 4 + signature.length;    //  2: signature algorithm
       
   966                                             // +2: length of signature
       
   967         }
       
   968 
       
   969         @Override
       
   970         public void send(HandshakeOutStream hos) throws IOException {
       
   971             hos.putInt16(signatureScheme.id);
       
   972             hos.putBytes16(signature);
       
   973         }
       
   974 
       
   975         @Override
       
   976         public String toString() {
       
   977             MessageFormat messageFormat = new MessageFormat(
       
   978                     "\"CertificateVerify\": '{'\n" +
       
   979                     "  \"signature algorithm\": {0}\n" +
       
   980                     "  \"signature\": '{'\n" +
       
   981                     "{1}\n" +
       
   982                     "  '}'\n" +
       
   983                     "'}'",
       
   984                     Locale.ENGLISH);
       
   985 
       
   986             HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   987             Object[] messageFields = {
       
   988                 signatureScheme.name,
       
   989                 Utilities.indent(
       
   990                         hexEncoder.encodeBuffer(signature), "    ")
       
   991             };
       
   992 
       
   993             return messageFormat.format(messageFields);
       
   994         }
       
   995     }
       
   996 
       
   997     /**
       
   998      * The "CertificateVerify" handshake message producer.
       
   999      */
       
  1000     private static final
       
  1001             class T13CertificateVerifyProducer implements HandshakeProducer {
       
  1002         // Prevent instantiation of this class.
       
  1003         private T13CertificateVerifyProducer() {
       
  1004             // blank
       
  1005         }
       
  1006 
       
  1007         @Override
       
  1008         public byte[] produce(ConnectionContext context,
       
  1009                 HandshakeMessage message) throws IOException {
       
  1010             // The producing happens in handshake context only.
       
  1011             HandshakeContext hc = (HandshakeContext)context;
       
  1012 
       
  1013             X509Possession x509Possession = null;
       
  1014             for (SSLPossession possession : hc.handshakePossessions) {
       
  1015                 if (possession instanceof X509Possession) {
       
  1016                     x509Possession = (X509Possession)possession;
       
  1017                     break;
       
  1018                 }
       
  1019             }
       
  1020 
       
  1021             if (x509Possession == null) {
       
  1022                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1023                     SSLLogger.fine(
       
  1024                         "No X.509 credentials negotiated for CertificateVerify");
       
  1025                 }
       
  1026 
       
  1027                 return null;
       
  1028             }
       
  1029 
       
  1030             if (hc.sslConfig.isClientMode) {
       
  1031                 return onProduceCertificateVerify(
       
  1032                         (ClientHandshakeContext)context, x509Possession);
       
  1033             } else {
       
  1034                 return onProduceCertificateVerify(
       
  1035                         (ServerHandshakeContext)context, x509Possession);
       
  1036             }
       
  1037         }
       
  1038 
       
  1039         private byte[] onProduceCertificateVerify(ServerHandshakeContext shc,
       
  1040                 X509Possession x509Possession) throws IOException {
       
  1041             T13CertificateVerifyMessage cvm =
       
  1042                     new T13CertificateVerifyMessage(shc, x509Possession);
       
  1043             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1044                 SSLLogger.fine(
       
  1045                     "Produced server CertificateVerify handshake message", cvm);
       
  1046             }
       
  1047 
       
  1048             // Output the handshake message.
       
  1049             cvm.write(shc.handshakeOutput);
       
  1050             shc.handshakeOutput.flush();
       
  1051 
       
  1052             // The handshake message has been delivered.
       
  1053             return null;
       
  1054         }
       
  1055 
       
  1056         private byte[] onProduceCertificateVerify(ClientHandshakeContext chc,
       
  1057                 X509Possession x509Possession) throws IOException {
       
  1058             T13CertificateVerifyMessage cvm =
       
  1059                     new T13CertificateVerifyMessage(chc, x509Possession);
       
  1060             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1061                 SSLLogger.fine(
       
  1062                     "Produced client CertificateVerify handshake message", cvm);
       
  1063             }
       
  1064 
       
  1065             // Output the handshake message.
       
  1066             cvm.write(chc.handshakeOutput);
       
  1067             chc.handshakeOutput.flush();
       
  1068 
       
  1069             // The handshake message has been delivered.
       
  1070             return null;
       
  1071         }
       
  1072     }
       
  1073 
       
  1074     /**
       
  1075      * The "CertificateVerify" handshake message consumer.
       
  1076      */
       
  1077     private static final
       
  1078             class T13CertificateVerifyConsumer implements SSLConsumer {
       
  1079         // Prevent instantiation of this class.
       
  1080         private T13CertificateVerifyConsumer() {
       
  1081             // blank
       
  1082         }
       
  1083 
       
  1084         @Override
       
  1085         public void consume(ConnectionContext context,
       
  1086                 ByteBuffer message) throws IOException {
       
  1087             // The producing happens in handshake context only.
       
  1088             HandshakeContext hc = (HandshakeContext)context;
       
  1089             T13CertificateVerifyMessage cvm =
       
  1090                     new T13CertificateVerifyMessage(hc, message);
       
  1091             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
  1092                 SSLLogger.fine(
       
  1093                         "Consuming CertificateVerify handshake message", cvm);
       
  1094             }
       
  1095 
       
  1096             //
       
  1097             // update
       
  1098             //
       
  1099             // Need no additional validation.
       
  1100 
       
  1101             //
       
  1102             // produce
       
  1103             //
       
  1104             // Need no new handshake message producers here.
       
  1105         }
       
  1106     }
       
  1107 }