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 }