1 /* 2 * Copyright (c) 2015, 2020, 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 S30CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)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 S30CertificateVerifyMessage(HandshakeContext context, ByteBuffer m)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 handshakeType()158 public SSLHandshake handshakeType() { 159 return SSLHandshake.CERTIFICATE_VERIFY; 160 } 161 162 @Override messageLength()163 public int messageLength() { 164 return 2 + signature.length; // 2: length of signature 165 } 166 167 @Override send(HandshakeOutStream hos)168 public void send(HandshakeOutStream hos) throws IOException { 169 hos.putBytes16(signature); 170 } 171 172 @Override toString()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 */ getSignature(String algorithm, Key key)195 private static Signature getSignature(String algorithm, 196 Key key) throws GeneralSecurityException { 197 Signature signer = null; 198 switch (algorithm) { 199 case "RSA": 200 signer = Signature.getInstance(JsseJce.SIGNATURE_RAWRSA); 201 break; 202 case "DSA": 203 signer = Signature.getInstance(JsseJce.SIGNATURE_RAWDSA); 204 break; 205 case "EC": 206 signer = Signature.getInstance(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. S30CertificateVerifyProducer()231 private S30CertificateVerifyProducer() { 232 // blank 233 } 234 235 @Override produce(ConnectionContext context, HandshakeMessage message)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. S30CertificateVerifyConsumer()281 private S30CertificateVerifyConsumer() { 282 // blank 283 } 284 285 @Override consume(ConnectionContext context, ByteBuffer message)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 T10CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)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 T10CertificateVerifyMessage(HandshakeContext context, ByteBuffer m)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 handshakeType()412 public SSLHandshake handshakeType() { 413 return SSLHandshake.CERTIFICATE_VERIFY; 414 } 415 416 @Override messageLength()417 public int messageLength() { 418 return 2 + signature.length; // 2: length of signature 419 } 420 421 @Override send(HandshakeOutStream hos)422 public void send(HandshakeOutStream hos) throws IOException { 423 hos.putBytes16(signature); 424 } 425 426 @Override toString()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 */ getSignature(String algorithm, Key key)449 private static Signature getSignature(String algorithm, 450 Key key) throws GeneralSecurityException { 451 Signature signer = null; 452 switch (algorithm) { 453 case "RSA": 454 signer = Signature.getInstance(JsseJce.SIGNATURE_RAWRSA); 455 break; 456 case "DSA": 457 signer = Signature.getInstance(JsseJce.SIGNATURE_RAWDSA); 458 break; 459 case "EC": 460 signer = Signature.getInstance(JsseJce.SIGNATURE_RAWECDSA); 461 break; 462 case "EdDSA": 463 signer = Signature.getInstance(JsseJce.SIGNATURE_EDDSA); 464 break; 465 default: 466 throw new SignatureException("Unrecognized algorithm: " 467 + algorithm); 468 } 469 470 if (signer != null) { 471 if (key instanceof PublicKey) { 472 signer.initVerify((PublicKey)(key)); 473 } else { 474 signer.initSign((PrivateKey)key); 475 } 476 } 477 478 return signer; 479 } 480 } 481 482 /** 483 * The "CertificateVerify" handshake message producer. 484 */ 485 private static final 486 class T10CertificateVerifyProducer implements HandshakeProducer { 487 // Prevent instantiation of this class. T10CertificateVerifyProducer()488 private T10CertificateVerifyProducer() { 489 // blank 490 } 491 492 @Override produce(ConnectionContext context, HandshakeMessage message)493 public byte[] produce(ConnectionContext context, 494 HandshakeMessage message) throws IOException { 495 // The producing happens in client side only. 496 ClientHandshakeContext chc = (ClientHandshakeContext)context; 497 X509Possession x509Possession = null; 498 for (SSLPossession possession : chc.handshakePossessions) { 499 if (possession instanceof X509Possession) { 500 x509Possession = (X509Possession)possession; 501 break; 502 } 503 } 504 505 if (x509Possession == null || 506 x509Possession.popPrivateKey == null) { 507 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 508 SSLLogger.fine( 509 "No X.509 credentials negotiated for CertificateVerify"); 510 } 511 512 return null; 513 } 514 515 T10CertificateVerifyMessage cvm = 516 new T10CertificateVerifyMessage(chc, x509Possession); 517 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 518 SSLLogger.fine( 519 "Produced CertificateVerify handshake message", cvm); 520 } 521 522 // Output the handshake message. 523 cvm.write(chc.handshakeOutput); 524 chc.handshakeOutput.flush(); 525 526 // The handshake message has been delivered. 527 return null; 528 } 529 } 530 531 /** 532 * The "CertificateVerify" handshake message consumer. 533 */ 534 private static final 535 class T10CertificateVerifyConsumer implements SSLConsumer { 536 // Prevent instantiation of this class. T10CertificateVerifyConsumer()537 private T10CertificateVerifyConsumer() { 538 // blank 539 } 540 541 @Override consume(ConnectionContext context, ByteBuffer message)542 public void consume(ConnectionContext context, 543 ByteBuffer message) throws IOException { 544 // The consuming happens in server side only. 545 ServerHandshakeContext shc = (ServerHandshakeContext)context; 546 547 // Clean up this consumer 548 shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id); 549 550 // Ensure that the CV message follows the CKE 551 if (shc.handshakeConsumers.containsKey( 552 SSLHandshake.CLIENT_KEY_EXCHANGE.id)) { 553 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, 554 "Unexpected CertificateVerify handshake message"); 555 } 556 557 T10CertificateVerifyMessage cvm = 558 new T10CertificateVerifyMessage(shc, message); 559 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 560 SSLLogger.fine( 561 "Consuming CertificateVerify handshake message", cvm); 562 } 563 564 // 565 // update 566 // 567 // Need no additional validation. 568 569 // 570 // produce 571 // 572 // Need no new handshake message producers here. } 573 } 574 } 575 576 /** 577 * The CertificateVerify handshake message (TLS 1.2). 578 */ 579 static final class T12CertificateVerifyMessage extends HandshakeMessage { 580 // the signature algorithm 581 private final SignatureScheme signatureScheme; 582 583 // signature bytes 584 private final byte[] signature; 585 T12CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)586 T12CertificateVerifyMessage(HandshakeContext context, 587 X509Possession x509Possession) throws IOException { 588 super(context); 589 590 // This happens in client side only. 591 ClientHandshakeContext chc = (ClientHandshakeContext)context; 592 Map.Entry<SignatureScheme, Signature> schemeAndSigner = 593 SignatureScheme.getSignerOfPreferableAlgorithm( 594 chc.algorithmConstraints, 595 chc.peerRequestedSignatureSchemes, 596 x509Possession, 597 chc.negotiatedProtocol); 598 if (schemeAndSigner == null) { 599 // Unlikely, the credentials generator should have 600 // selected the preferable signature algorithm properly. 601 throw chc.conContext.fatal(Alert.INTERNAL_ERROR, 602 "No supported CertificateVerify signature algorithm for " + 603 x509Possession.popPrivateKey.getAlgorithm() + 604 " key"); 605 } 606 607 this.signatureScheme = schemeAndSigner.getKey(); 608 byte[] temproary = null; 609 try { 610 Signature signer = schemeAndSigner.getValue(); 611 signer.update(chc.handshakeHash.archived()); 612 temproary = signer.sign(); 613 } catch (SignatureException ikse) { 614 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 615 "Cannot produce CertificateVerify signature", ikse); 616 } 617 618 this.signature = temproary; 619 } 620 T12CertificateVerifyMessage(HandshakeContext handshakeContext, ByteBuffer m)621 T12CertificateVerifyMessage(HandshakeContext handshakeContext, 622 ByteBuffer m) throws IOException { 623 super(handshakeContext); 624 625 // This happens in server side only. 626 ServerHandshakeContext shc = 627 (ServerHandshakeContext)handshakeContext; 628 629 // struct { 630 // SignatureAndHashAlgorithm algorithm; 631 // opaque signature<0..2^16-1>; 632 // } DigitallySigned; 633 if (m.remaining() < 4) { 634 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, 635 "Invalid CertificateVerify message: no sufficient data"); 636 } 637 638 // SignatureAndHashAlgorithm algorithm 639 int ssid = Record.getInt16(m); 640 this.signatureScheme = SignatureScheme.valueOf(ssid); 641 if (signatureScheme == null) { 642 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 643 "Invalid signature algorithm (" + ssid + 644 ") used in CertificateVerify handshake message"); 645 } 646 647 if (!shc.localSupportedSignAlgs.contains(signatureScheme)) { 648 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 649 "Unsupported signature algorithm (" + 650 signatureScheme.name + 651 ") used in CertificateVerify handshake message"); 652 } 653 654 // read and verify the signature 655 X509Credentials x509Credentials = null; 656 for (SSLCredentials cd : shc.handshakeCredentials) { 657 if (cd instanceof X509Credentials) { 658 x509Credentials = (X509Credentials)cd; 659 break; 660 } 661 } 662 663 if (x509Credentials == null || 664 x509Credentials.popPublicKey == null) { 665 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 666 "No X509 credentials negotiated for CertificateVerify"); 667 } 668 669 // opaque signature<0..2^16-1>; 670 this.signature = Record.getBytes16(m); 671 try { 672 Signature signer = 673 signatureScheme.getVerifier(x509Credentials.popPublicKey); 674 signer.update(shc.handshakeHash.archived()); 675 if (!signer.verify(signature)) { 676 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 677 "Invalid CertificateVerify signature"); 678 } 679 } catch (NoSuchAlgorithmException | 680 InvalidAlgorithmParameterException nsae) { 681 throw shc.conContext.fatal(Alert.INTERNAL_ERROR, 682 "Unsupported signature algorithm (" + 683 signatureScheme.name + 684 ") used in CertificateVerify handshake message", nsae); 685 } catch (InvalidKeyException | SignatureException ikse) { 686 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 687 "Cannot verify CertificateVerify signature", ikse); 688 } 689 } 690 691 @Override handshakeType()692 public SSLHandshake handshakeType() { 693 return SSLHandshake.CERTIFICATE_VERIFY; 694 } 695 696 @Override messageLength()697 public int messageLength() { 698 return 4 + signature.length; // 2: signature algorithm 699 // +2: length of signature 700 } 701 702 @Override send(HandshakeOutStream hos)703 public void send(HandshakeOutStream hos) throws IOException { 704 hos.putInt16(signatureScheme.id); 705 hos.putBytes16(signature); 706 } 707 708 @Override toString()709 public String toString() { 710 MessageFormat messageFormat = new MessageFormat( 711 "\"CertificateVerify\": '{'\n" + 712 " \"signature algorithm\": {0}\n" + 713 " \"signature\": '{'\n" + 714 "{1}\n" + 715 " '}'\n" + 716 "'}'", 717 Locale.ENGLISH); 718 719 HexDumpEncoder hexEncoder = new HexDumpEncoder(); 720 Object[] messageFields = { 721 signatureScheme.name, 722 Utilities.indent( 723 hexEncoder.encodeBuffer(signature), " ") 724 }; 725 726 return messageFormat.format(messageFields); 727 } 728 } 729 730 /** 731 * The "CertificateVerify" handshake message producer. 732 */ 733 private static final 734 class T12CertificateVerifyProducer implements HandshakeProducer { 735 // Prevent instantiation of this class. T12CertificateVerifyProducer()736 private T12CertificateVerifyProducer() { 737 // blank 738 } 739 740 @Override produce(ConnectionContext context, HandshakeMessage message)741 public byte[] produce(ConnectionContext context, 742 HandshakeMessage message) throws IOException { 743 // The producing happens in client side only. 744 ClientHandshakeContext chc = (ClientHandshakeContext)context; 745 746 X509Possession x509Possession = null; 747 for (SSLPossession possession : chc.handshakePossessions) { 748 if (possession instanceof X509Possession) { 749 x509Possession = (X509Possession)possession; 750 break; 751 } 752 } 753 754 if (x509Possession == null || 755 x509Possession.popPrivateKey == null) { 756 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 757 SSLLogger.fine( 758 "No X.509 credentials negotiated for CertificateVerify"); 759 } 760 761 return null; 762 } 763 764 T12CertificateVerifyMessage cvm = 765 new T12CertificateVerifyMessage(chc, x509Possession); 766 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 767 SSLLogger.fine( 768 "Produced CertificateVerify handshake message", cvm); 769 } 770 771 // Output the handshake message. 772 cvm.write(chc.handshakeOutput); 773 chc.handshakeOutput.flush(); 774 775 // The handshake message has been delivered. 776 return null; 777 } 778 } 779 780 /** 781 * The "CertificateVerify" handshake message consumer. 782 */ 783 private static final 784 class T12CertificateVerifyConsumer implements SSLConsumer { 785 // Prevent instantiation of this class. T12CertificateVerifyConsumer()786 private T12CertificateVerifyConsumer() { 787 // blank 788 } 789 790 @Override consume(ConnectionContext context, ByteBuffer message)791 public void consume(ConnectionContext context, 792 ByteBuffer message) throws IOException { 793 // The consuming happens in server side only. 794 ServerHandshakeContext shc = (ServerHandshakeContext)context; 795 796 // Clean up this consumer 797 shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id); 798 799 // Ensure that the CV message follows the CKE 800 if (shc.handshakeConsumers.containsKey( 801 SSLHandshake.CLIENT_KEY_EXCHANGE.id)) { 802 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, 803 "Unexpected CertificateVerify handshake message"); 804 } 805 806 T12CertificateVerifyMessage cvm = 807 new T12CertificateVerifyMessage(shc, message); 808 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 809 SSLLogger.fine( 810 "Consuming CertificateVerify handshake message", cvm); 811 } 812 813 // 814 // update 815 // 816 // Need no additional validation. 817 818 // 819 // produce 820 // 821 // Need no new handshake message producers here. 822 } 823 } 824 825 /** 826 * The CertificateVerify handshake message (TLS 1.3). 827 */ 828 static final class T13CertificateVerifyMessage extends HandshakeMessage { 829 private static final byte[] serverSignHead = new byte[] { 830 // repeated 0x20 for 64 times 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 (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20, 845 (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20, 846 (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20, 847 848 // "TLS 1.3, server CertificateVerify" + 0x00 849 (byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20, 850 (byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c, 851 (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x72, 852 (byte)0x76, (byte)0x65, (byte)0x72, (byte)0x20, 853 (byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74, 854 (byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63, 855 (byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56, 856 (byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66, 857 (byte)0x79, (byte)0x00 858 }; 859 860 private static final byte[] clientSignHead = new byte[] { 861 // repeated 0x20 for 64 times 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 (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20, 876 (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20, 877 (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20, 878 879 // "TLS 1.3, client CertificateVerify" + 0x00 880 (byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20, 881 (byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c, 882 (byte)0x20, (byte)0x63, (byte)0x6c, (byte)0x69, 883 (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x20, 884 (byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74, 885 (byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63, 886 (byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56, 887 (byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66, 888 (byte)0x79, (byte)0x00 889 }; 890 891 892 // the signature algorithm 893 private final SignatureScheme signatureScheme; 894 895 // signature bytes 896 private final byte[] signature; 897 T13CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)898 T13CertificateVerifyMessage(HandshakeContext context, 899 X509Possession x509Possession) throws IOException { 900 super(context); 901 902 Map.Entry<SignatureScheme, Signature> schemeAndSigner = 903 SignatureScheme.getSignerOfPreferableAlgorithm( 904 context.algorithmConstraints, 905 context.peerRequestedSignatureSchemes, 906 x509Possession, 907 context.negotiatedProtocol); 908 if (schemeAndSigner == null) { 909 // Unlikely, the credentials generator should have 910 // selected the preferable signature algorithm properly. 911 throw context.conContext.fatal(Alert.INTERNAL_ERROR, 912 "No supported CertificateVerify signature algorithm for " + 913 x509Possession.popPrivateKey.getAlgorithm() + 914 " key"); 915 } 916 917 this.signatureScheme = schemeAndSigner.getKey(); 918 919 byte[] hashValue = context.handshakeHash.digest(); 920 byte[] contentCovered; 921 if (context.sslConfig.isClientMode) { 922 contentCovered = Arrays.copyOf(clientSignHead, 923 clientSignHead.length + hashValue.length); 924 System.arraycopy(hashValue, 0, contentCovered, 925 clientSignHead.length, hashValue.length); 926 } else { 927 contentCovered = Arrays.copyOf(serverSignHead, 928 serverSignHead.length + hashValue.length); 929 System.arraycopy(hashValue, 0, contentCovered, 930 serverSignHead.length, hashValue.length); 931 } 932 933 byte[] temproary = null; 934 try { 935 Signature signer = schemeAndSigner.getValue(); 936 signer.update(contentCovered); 937 temproary = signer.sign(); 938 } catch (SignatureException ikse) { 939 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 940 "Cannot produce CertificateVerify signature", ikse); 941 } 942 943 this.signature = temproary; 944 } 945 T13CertificateVerifyMessage(HandshakeContext context, ByteBuffer m)946 T13CertificateVerifyMessage(HandshakeContext context, 947 ByteBuffer m) throws IOException { 948 super(context); 949 950 // struct { 951 // SignatureAndHashAlgorithm algorithm; 952 // opaque signature<0..2^16-1>; 953 // } DigitallySigned; 954 if (m.remaining() < 4) { 955 throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER, 956 "Invalid CertificateVerify message: no sufficient data"); 957 } 958 959 // SignatureAndHashAlgorithm algorithm 960 int ssid = Record.getInt16(m); 961 this.signatureScheme = SignatureScheme.valueOf(ssid); 962 if (signatureScheme == null) { 963 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 964 "Invalid signature algorithm (" + ssid + 965 ") used in CertificateVerify handshake message"); 966 } 967 968 if (!context.localSupportedSignAlgs.contains(signatureScheme)) { 969 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 970 "Unsupported signature algorithm (" + 971 signatureScheme.name + 972 ") used in CertificateVerify handshake message"); 973 } 974 975 // read and verify the signature 976 X509Credentials x509Credentials = null; 977 for (SSLCredentials cd : context.handshakeCredentials) { 978 if (cd instanceof X509Credentials) { 979 x509Credentials = (X509Credentials)cd; 980 break; 981 } 982 } 983 984 if (x509Credentials == null || 985 x509Credentials.popPublicKey == null) { 986 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 987 "No X509 credentials negotiated for CertificateVerify"); 988 } 989 990 // opaque signature<0..2^16-1>; 991 this.signature = Record.getBytes16(m); 992 993 byte[] hashValue = context.handshakeHash.digest(); 994 byte[] contentCovered; 995 if (context.sslConfig.isClientMode) { 996 contentCovered = Arrays.copyOf(serverSignHead, 997 serverSignHead.length + hashValue.length); 998 System.arraycopy(hashValue, 0, contentCovered, 999 serverSignHead.length, hashValue.length); 1000 } else { 1001 contentCovered = Arrays.copyOf(clientSignHead, 1002 clientSignHead.length + hashValue.length); 1003 System.arraycopy(hashValue, 0, contentCovered, 1004 clientSignHead.length, hashValue.length); 1005 } 1006 1007 try { 1008 Signature signer = 1009 signatureScheme.getVerifier(x509Credentials.popPublicKey); 1010 signer.update(contentCovered); 1011 if (!signer.verify(signature)) { 1012 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1013 "Invalid CertificateVerify signature"); 1014 } 1015 } catch (NoSuchAlgorithmException | 1016 InvalidAlgorithmParameterException nsae) { 1017 throw context.conContext.fatal(Alert.INTERNAL_ERROR, 1018 "Unsupported signature algorithm (" + 1019 signatureScheme.name + 1020 ") used in CertificateVerify handshake message", nsae); 1021 } catch (InvalidKeyException | SignatureException ikse) { 1022 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, 1023 "Cannot verify CertificateVerify signature", ikse); 1024 } 1025 } 1026 1027 @Override handshakeType()1028 public SSLHandshake handshakeType() { 1029 return SSLHandshake.CERTIFICATE_VERIFY; 1030 } 1031 1032 @Override messageLength()1033 public int messageLength() { 1034 return 4 + signature.length; // 2: signature algorithm 1035 // +2: length of signature 1036 } 1037 1038 @Override send(HandshakeOutStream hos)1039 public void send(HandshakeOutStream hos) throws IOException { 1040 hos.putInt16(signatureScheme.id); 1041 hos.putBytes16(signature); 1042 } 1043 1044 @Override toString()1045 public String toString() { 1046 MessageFormat messageFormat = new MessageFormat( 1047 "\"CertificateVerify\": '{'\n" + 1048 " \"signature algorithm\": {0}\n" + 1049 " \"signature\": '{'\n" + 1050 "{1}\n" + 1051 " '}'\n" + 1052 "'}'", 1053 Locale.ENGLISH); 1054 1055 HexDumpEncoder hexEncoder = new HexDumpEncoder(); 1056 Object[] messageFields = { 1057 signatureScheme.name, 1058 Utilities.indent( 1059 hexEncoder.encodeBuffer(signature), " ") 1060 }; 1061 1062 return messageFormat.format(messageFields); 1063 } 1064 } 1065 1066 /** 1067 * The "CertificateVerify" handshake message producer. 1068 */ 1069 private static final 1070 class T13CertificateVerifyProducer implements HandshakeProducer { 1071 // Prevent instantiation of this class. T13CertificateVerifyProducer()1072 private T13CertificateVerifyProducer() { 1073 // blank 1074 } 1075 1076 @Override produce(ConnectionContext context, HandshakeMessage message)1077 public byte[] produce(ConnectionContext context, 1078 HandshakeMessage message) throws IOException { 1079 // The producing happens in handshake context only. 1080 HandshakeContext hc = (HandshakeContext)context; 1081 1082 X509Possession x509Possession = null; 1083 for (SSLPossession possession : hc.handshakePossessions) { 1084 if (possession instanceof X509Possession) { 1085 x509Possession = (X509Possession)possession; 1086 break; 1087 } 1088 } 1089 1090 if (x509Possession == null || 1091 x509Possession.popPrivateKey == null) { 1092 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 1093 SSLLogger.fine( 1094 "No X.509 credentials negotiated for CertificateVerify"); 1095 } 1096 1097 return null; 1098 } 1099 1100 if (hc.sslConfig.isClientMode) { 1101 return onProduceCertificateVerify( 1102 (ClientHandshakeContext)context, x509Possession); 1103 } else { 1104 return onProduceCertificateVerify( 1105 (ServerHandshakeContext)context, x509Possession); 1106 } 1107 } 1108 onProduceCertificateVerify(ServerHandshakeContext shc, X509Possession x509Possession)1109 private byte[] onProduceCertificateVerify(ServerHandshakeContext shc, 1110 X509Possession x509Possession) throws IOException { 1111 T13CertificateVerifyMessage cvm = 1112 new T13CertificateVerifyMessage(shc, x509Possession); 1113 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 1114 SSLLogger.fine( 1115 "Produced server CertificateVerify handshake message", cvm); 1116 } 1117 1118 // Output the handshake message. 1119 cvm.write(shc.handshakeOutput); 1120 shc.handshakeOutput.flush(); 1121 1122 // The handshake message has been delivered. 1123 return null; 1124 } 1125 onProduceCertificateVerify(ClientHandshakeContext chc, X509Possession x509Possession)1126 private byte[] onProduceCertificateVerify(ClientHandshakeContext chc, 1127 X509Possession x509Possession) throws IOException { 1128 T13CertificateVerifyMessage cvm = 1129 new T13CertificateVerifyMessage(chc, x509Possession); 1130 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 1131 SSLLogger.fine( 1132 "Produced client CertificateVerify handshake message", cvm); 1133 } 1134 1135 // Output the handshake message. 1136 cvm.write(chc.handshakeOutput); 1137 chc.handshakeOutput.flush(); 1138 1139 // The handshake message has been delivered. 1140 return null; 1141 } 1142 } 1143 1144 /** 1145 * The "CertificateVerify" handshake message consumer. 1146 */ 1147 private static final 1148 class T13CertificateVerifyConsumer implements SSLConsumer { 1149 // Prevent instantiation of this class. T13CertificateVerifyConsumer()1150 private T13CertificateVerifyConsumer() { 1151 // blank 1152 } 1153 1154 @Override consume(ConnectionContext context, ByteBuffer message)1155 public void consume(ConnectionContext context, 1156 ByteBuffer message) throws IOException { 1157 // The producing happens in handshake context only. 1158 HandshakeContext hc = (HandshakeContext)context; 1159 1160 // Clean up this consumer 1161 hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id); 1162 1163 T13CertificateVerifyMessage cvm = 1164 new T13CertificateVerifyMessage(hc, message); 1165 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 1166 SSLLogger.fine( 1167 "Consuming CertificateVerify handshake message", cvm); 1168 } 1169 1170 // 1171 // update 1172 // 1173 // Need no additional validation. 1174 1175 // 1176 // produce 1177 // 1178 // Need no new handshake message producers here. 1179 } 1180 } 1181 } 1182