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