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