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