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.text.MessageFormat; 31 import java.util.Arrays; 32 import java.util.LinkedList; 33 import java.util.List; 34 import java.util.Locale; 35 import javax.net.ssl.SSLProtocolException; 36 import sun.security.ssl.SSLExtension.ExtensionConsumer; 37 import sun.security.ssl.SSLExtension.SSLExtensionSpec; 38 import sun.security.ssl.SSLHandshake.HandshakeMessage; 39 40 /** 41 * Pack of the "signature_algorithms" extensions [RFC 5246]. 42 */ 43 final class SignatureAlgorithmsExtension { 44 static final HandshakeProducer chNetworkProducer = 45 new CHSignatureSchemesProducer(); 46 static final ExtensionConsumer chOnLoadConsumer = 47 new CHSignatureSchemesConsumer(); 48 static final HandshakeAbsence chOnLoadAbsence = 49 new CHSignatureSchemesOnLoadAbsence(); 50 static final HandshakeConsumer chOnTradeConsumer = 51 new CHSignatureSchemesUpdate(); 52 static final HandshakeAbsence chOnTradeAbsence = 53 new CHSignatureSchemesOnTradeAbsence(); 54 55 static final HandshakeProducer crNetworkProducer = 56 new CRSignatureSchemesProducer(); 57 static final ExtensionConsumer crOnLoadConsumer = 58 new CRSignatureSchemesConsumer(); 59 static final HandshakeAbsence crOnLoadAbsence = 60 new CRSignatureSchemesAbsence(); 61 static final HandshakeConsumer crOnTradeConsumer = 62 new CRSignatureSchemesUpdate(); 63 64 static final SSLStringizer ssStringizer = 65 new SignatureSchemesStringizer(); 66 67 /** 68 * The "signature_algorithms" extension. 69 */ 70 static final class SignatureSchemesSpec implements SSLExtensionSpec { 71 final int[] signatureSchemes; 72 SignatureSchemesSpec(List<SignatureScheme> schemes)73 SignatureSchemesSpec(List<SignatureScheme> schemes) { 74 if (schemes != null) { 75 signatureSchemes = new int[schemes.size()]; 76 int i = 0; 77 for (SignatureScheme scheme : schemes) { 78 signatureSchemes[i++] = scheme.id; 79 } 80 } else { 81 this.signatureSchemes = new int[0]; 82 } 83 } 84 SignatureSchemesSpec(ByteBuffer buffer)85 SignatureSchemesSpec(ByteBuffer buffer) throws IOException { 86 if (buffer.remaining() < 2) { // 2: the length of the list 87 throw new SSLProtocolException( 88 "Invalid signature_algorithms: insufficient data"); 89 } 90 91 byte[] algs = Record.getBytes16(buffer); 92 if (buffer.hasRemaining()) { 93 throw new SSLProtocolException( 94 "Invalid signature_algorithms: unknown extra data"); 95 } 96 97 if (algs == null || algs.length == 0 || (algs.length & 0x01) != 0) { 98 throw new SSLProtocolException( 99 "Invalid signature_algorithms: incomplete data"); 100 } 101 102 int[] schemes = new int[algs.length / 2]; 103 for (int i = 0, j = 0; i < algs.length;) { 104 byte hash = algs[i++]; 105 byte sign = algs[i++]; 106 schemes[j++] = ((hash & 0xFF) << 8) | (sign & 0xFF); 107 } 108 109 this.signatureSchemes = schemes; 110 } 111 112 @Override toString()113 public String toString() { 114 MessageFormat messageFormat = new MessageFormat( 115 "\"signature schemes\": '['{0}']'", Locale.ENGLISH); 116 117 if (signatureSchemes == null || signatureSchemes.length == 0) { 118 Object[] messageFields = { 119 "<no supported signature schemes specified>" 120 }; 121 return messageFormat.format(messageFields); 122 } else { 123 StringBuilder builder = new StringBuilder(512); 124 boolean isFirst = true; 125 for (int pv : signatureSchemes) { 126 if (isFirst) { 127 isFirst = false; 128 } else { 129 builder.append(", "); 130 } 131 132 builder.append(SignatureScheme.nameOf(pv)); 133 } 134 135 Object[] messageFields = { 136 builder.toString() 137 }; 138 139 return messageFormat.format(messageFields); 140 } 141 } 142 } 143 144 private static final 145 class SignatureSchemesStringizer implements SSLStringizer { 146 @Override toString(ByteBuffer buffer)147 public String toString(ByteBuffer buffer) { 148 try { 149 return (new SignatureSchemesSpec(buffer)).toString(); 150 } catch (IOException ioe) { 151 // For debug logging only, so please swallow exceptions. 152 return ioe.getMessage(); 153 } 154 } 155 } 156 157 /** 158 * Network data producer of a "signature_algorithms" extension in 159 * the ClientHello handshake message. 160 */ 161 private static final 162 class CHSignatureSchemesProducer implements HandshakeProducer { 163 // Prevent instantiation of this class. CHSignatureSchemesProducer()164 private CHSignatureSchemesProducer() { 165 // blank 166 } 167 168 @Override produce(ConnectionContext context, HandshakeMessage message)169 public byte[] produce(ConnectionContext context, 170 HandshakeMessage message) throws IOException { 171 // The producing happens in client side only. 172 ClientHandshakeContext chc = (ClientHandshakeContext)context; 173 174 // Is it a supported and enabled extension? 175 if (!chc.sslConfig.isAvailable( 176 SSLExtension.CH_SIGNATURE_ALGORITHMS)) { 177 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 178 SSLLogger.fine( 179 "Ignore unavailable signature_algorithms extension"); 180 } 181 return null; 182 } 183 184 // Produce the extension. 185 if (chc.localSupportedSignAlgs == null) { 186 chc.localSupportedSignAlgs = 187 SignatureScheme.getSupportedAlgorithms( 188 chc.sslConfig, 189 chc.algorithmConstraints, chc.activeProtocols); 190 } 191 192 int vectorLen = SignatureScheme.sizeInRecord() * 193 chc.localSupportedSignAlgs.size(); 194 byte[] extData = new byte[vectorLen + 2]; 195 ByteBuffer m = ByteBuffer.wrap(extData); 196 Record.putInt16(m, vectorLen); 197 for (SignatureScheme ss : chc.localSupportedSignAlgs) { 198 Record.putInt16(m, ss.id); 199 } 200 201 // Update the context. 202 chc.handshakeExtensions.put( 203 SSLExtension.CH_SIGNATURE_ALGORITHMS, 204 new SignatureSchemesSpec(chc.localSupportedSignAlgs)); 205 206 return extData; 207 } 208 } 209 210 /** 211 * Network data consumer of a "signature_algorithms" extension in 212 * the ClientHello handshake message. 213 */ 214 private static final 215 class CHSignatureSchemesConsumer implements ExtensionConsumer { 216 // Prevent instantiation of this class. CHSignatureSchemesConsumer()217 private CHSignatureSchemesConsumer() { 218 // blank 219 } 220 221 @Override consume(ConnectionContext context, HandshakeMessage message, ByteBuffer buffer)222 public void consume(ConnectionContext context, 223 HandshakeMessage message, ByteBuffer buffer) throws IOException { 224 // The consuming happens in server side only. 225 ServerHandshakeContext shc = (ServerHandshakeContext)context; 226 227 // Is it a supported and enabled extension? 228 if (!shc.sslConfig.isAvailable( 229 SSLExtension.CH_SIGNATURE_ALGORITHMS)) { 230 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 231 SSLLogger.fine( 232 "Ignore unavailable signature_algorithms extension"); 233 } 234 return; // ignore the extension 235 } 236 237 // Parse the extension. 238 SignatureSchemesSpec spec; 239 try { 240 spec = new SignatureSchemesSpec(buffer); 241 } catch (IOException ioe) { 242 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 243 } 244 245 // Update the context. 246 shc.handshakeExtensions.put( 247 SSLExtension.CH_SIGNATURE_ALGORITHMS, spec); 248 249 // No impact on session resumption. 250 } 251 } 252 253 /** 254 * After session creation consuming of a "signature_algorithms" 255 * extension in the ClientHello handshake message. 256 */ 257 private static final class CHSignatureSchemesUpdate 258 implements HandshakeConsumer { 259 // Prevent instantiation of this class. CHSignatureSchemesUpdate()260 private CHSignatureSchemesUpdate() { 261 // blank 262 } 263 264 @Override consume(ConnectionContext context, HandshakeMessage message)265 public void consume(ConnectionContext context, 266 HandshakeMessage message) throws IOException { 267 // The consuming happens in server side only. 268 ServerHandshakeContext shc = (ServerHandshakeContext)context; 269 270 SignatureSchemesSpec spec = 271 (SignatureSchemesSpec)shc.handshakeExtensions.get( 272 SSLExtension.CH_SIGNATURE_ALGORITHMS); 273 if (spec == null) { 274 // Ignore, no "signature_algorithms" extension requested. 275 return; 276 } 277 278 // update the context 279 List<SignatureScheme> sss = 280 SignatureScheme.getSupportedAlgorithms( 281 shc.sslConfig, 282 shc.algorithmConstraints, shc.negotiatedProtocol, 283 spec.signatureSchemes); 284 shc.peerRequestedSignatureSchemes = sss; 285 286 // If no "signature_algorithms_cert" extension is present, then 287 // the "signature_algorithms" extension also applies to 288 // signatures appearing in certificates. 289 SignatureSchemesSpec certSpec = 290 (SignatureSchemesSpec)shc.handshakeExtensions.get( 291 SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); 292 if (certSpec == null) { 293 shc.peerRequestedCertSignSchemes = sss; 294 shc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); 295 } 296 297 if (!shc.isResumption && 298 shc.negotiatedProtocol.useTLS13PlusSpec()) { 299 if (shc.sslConfig.clientAuthType != 300 ClientAuthType.CLIENT_AUTH_NONE) { 301 shc.handshakeProducers.putIfAbsent( 302 SSLHandshake.CERTIFICATE_REQUEST.id, 303 SSLHandshake.CERTIFICATE_REQUEST); 304 } 305 shc.handshakeProducers.put( 306 SSLHandshake.CERTIFICATE.id, 307 SSLHandshake.CERTIFICATE); 308 shc.handshakeProducers.putIfAbsent( 309 SSLHandshake.CERTIFICATE_VERIFY.id, 310 SSLHandshake.CERTIFICATE_VERIFY); 311 } 312 } 313 } 314 315 /** 316 * The absence processing if a "signature_algorithms" extension is 317 * not present in the ClientHello handshake message. 318 */ 319 private static final 320 class CHSignatureSchemesOnLoadAbsence implements HandshakeAbsence { 321 @Override absent(ConnectionContext context, HandshakeMessage message)322 public void absent(ConnectionContext context, 323 HandshakeMessage message) throws IOException { 324 // The consuming happens in server side only. 325 ServerHandshakeContext shc = (ServerHandshakeContext)context; 326 327 // This is a mandatory extension for certificate authentication 328 // in TLS 1.3. 329 // 330 // We may support the server authentication other than X.509 331 // certificate later. 332 if (shc.negotiatedProtocol.useTLS13PlusSpec()) { 333 throw shc.conContext.fatal(Alert.MISSING_EXTENSION, 334 "No mandatory signature_algorithms extension in the " + 335 "received CertificateRequest handshake message"); 336 } 337 } 338 } 339 340 /** 341 * The absence processing if a "signature_algorithms" extension is 342 * not present in the ClientHello handshake message. 343 */ 344 private static final 345 class CHSignatureSchemesOnTradeAbsence implements HandshakeAbsence { 346 @Override absent(ConnectionContext context, HandshakeMessage message)347 public void absent(ConnectionContext context, 348 HandshakeMessage message) throws IOException { 349 // The consuming happens in server side only. 350 ServerHandshakeContext shc = (ServerHandshakeContext)context; 351 352 if (shc.negotiatedProtocol.useTLS12PlusSpec()) { 353 // Use default hash and signature algorithm: 354 // {sha1,rsa} 355 // {sha1,dsa} 356 // {sha1,ecdsa} 357 // Per RFC 5246, If the client supports only the default hash 358 // and signature algorithms, it MAY omit the 359 // signature_algorithms extension. If the client does not 360 // support the default algorithms, or supports other hash 361 // and signature algorithms (and it is willing to use them 362 // for verifying messages sent by the server, i.e., server 363 // certificates and server key exchange), it MUST send the 364 // signature_algorithms extension, listing the algorithms it 365 // is willing to accept. 366 List<SignatureScheme> schemes = Arrays.asList( 367 SignatureScheme.RSA_PKCS1_SHA1, 368 SignatureScheme.DSA_SHA1, 369 SignatureScheme.ECDSA_SHA1 370 ); 371 372 shc.peerRequestedSignatureSchemes = schemes; 373 if (shc.peerRequestedCertSignSchemes == null || 374 shc.peerRequestedCertSignSchemes.isEmpty()) { 375 shc.peerRequestedCertSignSchemes = schemes; 376 } 377 378 // Use the default peer signature algorithms. 379 shc.handshakeSession.setUseDefaultPeerSignAlgs(); 380 } 381 } 382 } 383 384 /** 385 * Network data producer of a "signature_algorithms" extension in 386 * the CertificateRequest handshake message. 387 */ 388 private static final 389 class CRSignatureSchemesProducer implements HandshakeProducer { 390 // Prevent instantiation of this class. CRSignatureSchemesProducer()391 private CRSignatureSchemesProducer() { 392 // blank 393 } 394 395 @Override produce(ConnectionContext context, HandshakeMessage message)396 public byte[] produce(ConnectionContext context, 397 HandshakeMessage message) throws IOException { 398 // The producing happens in server side only. 399 ServerHandshakeContext shc = (ServerHandshakeContext)context; 400 401 // Is it a supported and enabled extension? 402 // 403 // Note that this is a mandatory extension for CertificateRequest 404 // handshake message in TLS 1.3. 405 if (!shc.sslConfig.isAvailable( 406 SSLExtension.CR_SIGNATURE_ALGORITHMS)) { 407 throw shc.conContext.fatal(Alert.MISSING_EXTENSION, 408 "No available signature_algorithms extension " + 409 "for client certificate authentication"); 410 } 411 412 // Produce the extension. 413 List<SignatureScheme> sigAlgs = 414 SignatureScheme.getSupportedAlgorithms( 415 shc.sslConfig, 416 shc.algorithmConstraints, 417 List.of(shc.negotiatedProtocol)); 418 419 int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); 420 byte[] extData = new byte[vectorLen + 2]; 421 ByteBuffer m = ByteBuffer.wrap(extData); 422 Record.putInt16(m, vectorLen); 423 for (SignatureScheme ss : sigAlgs) { 424 Record.putInt16(m, ss.id); 425 } 426 427 // Update the context. 428 shc.handshakeExtensions.put( 429 SSLExtension.CR_SIGNATURE_ALGORITHMS, 430 new SignatureSchemesSpec(shc.localSupportedSignAlgs)); 431 432 return extData; 433 } 434 } 435 436 /** 437 * Network data consumer of a "signature_algorithms" extension in 438 * the CertificateRequest handshake message. 439 */ 440 private static final 441 class CRSignatureSchemesConsumer implements ExtensionConsumer { 442 // Prevent instantiation of this class. CRSignatureSchemesConsumer()443 private CRSignatureSchemesConsumer() { 444 // blank 445 } 446 @Override consume(ConnectionContext context, HandshakeMessage message, ByteBuffer buffer)447 public void consume(ConnectionContext context, 448 HandshakeMessage message, ByteBuffer buffer) throws IOException { 449 // The consuming happens in client side only. 450 ClientHandshakeContext chc = (ClientHandshakeContext)context; 451 452 // Is it a supported and enabled extension? 453 // 454 // Note that this is a mandatory extension for CertificateRequest 455 // handshake message in TLS 1.3. 456 if (!chc.sslConfig.isAvailable( 457 SSLExtension.CR_SIGNATURE_ALGORITHMS)) { 458 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, 459 "No available signature_algorithms extension " + 460 "for client certificate authentication"); 461 } 462 463 // Parse the extension. 464 SignatureSchemesSpec spec; 465 try { 466 spec = new SignatureSchemesSpec(buffer); 467 } catch (IOException ioe) { 468 throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); 469 } 470 471 List<SignatureScheme> knownSignatureSchemes = new LinkedList<>(); 472 for (int id : spec.signatureSchemes) { 473 SignatureScheme ss = SignatureScheme.valueOf(id); 474 if (ss != null) { 475 knownSignatureSchemes.add(ss); 476 } 477 } 478 479 // Update the context. 480 // chc.peerRequestedSignatureSchemes = knownSignatureSchemes; 481 chc.handshakeExtensions.put( 482 SSLExtension.CR_SIGNATURE_ALGORITHMS, spec); 483 484 // No impact on session resumption. 485 } 486 } 487 488 /** 489 * After session creation consuming of a "signature_algorithms" 490 * extension in the CertificateRequest handshake message. 491 */ 492 private static final class CRSignatureSchemesUpdate 493 implements HandshakeConsumer { 494 // Prevent instantiation of this class. CRSignatureSchemesUpdate()495 private CRSignatureSchemesUpdate() { 496 // blank 497 } 498 499 @Override consume(ConnectionContext context, HandshakeMessage message)500 public void consume(ConnectionContext context, 501 HandshakeMessage message) throws IOException { 502 // The consuming happens in client side only. 503 ClientHandshakeContext chc = (ClientHandshakeContext)context; 504 505 SignatureSchemesSpec spec = 506 (SignatureSchemesSpec)chc.handshakeExtensions.get( 507 SSLExtension.CR_SIGNATURE_ALGORITHMS); 508 if (spec == null) { 509 // Ignore, no "signature_algorithms" extension requested. 510 return; 511 } 512 513 // update the context 514 List<SignatureScheme> sss = 515 SignatureScheme.getSupportedAlgorithms( 516 chc.sslConfig, 517 chc.algorithmConstraints, chc.negotiatedProtocol, 518 spec.signatureSchemes); 519 chc.peerRequestedSignatureSchemes = sss; 520 521 // If no "signature_algorithms_cert" extension is present, then 522 // the "signature_algorithms" extension also applies to 523 // signatures appearing in certificates. 524 SignatureSchemesSpec certSpec = 525 (SignatureSchemesSpec)chc.handshakeExtensions.get( 526 SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); 527 if (certSpec == null) { 528 chc.peerRequestedCertSignSchemes = sss; 529 chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); 530 } 531 } 532 } 533 534 /** 535 * The absence processing if a "signature_algorithms" extension is 536 * not present in the CertificateRequest handshake message. 537 */ 538 private static final 539 class CRSignatureSchemesAbsence implements HandshakeAbsence { 540 @Override absent(ConnectionContext context, HandshakeMessage message)541 public void absent(ConnectionContext context, 542 HandshakeMessage message) throws IOException { 543 // The consuming happens in client side only. 544 ClientHandshakeContext chc = (ClientHandshakeContext)context; 545 546 // This is a mandatory extension for CertificateRequest handshake 547 // message in TLS 1.3. 548 throw chc.conContext.fatal(Alert.MISSING_EXTENSION, 549 "No mandatory signature_algorithms extension in the " + 550 "received CertificateRequest handshake message"); 551 } 552 } 553 } 554