31 import java.util.List; |
31 import java.util.List; |
32 import java.util.ArrayList; |
32 import java.util.ArrayList; |
33 import java.util.Locale; |
33 import java.util.Locale; |
34 import java.util.Arrays; |
34 import java.util.Arrays; |
35 import java.util.Optional; |
35 import java.util.Optional; |
|
36 import java.util.Collection; |
36 import javax.crypto.Mac; |
37 import javax.crypto.Mac; |
37 import javax.crypto.SecretKey; |
38 import javax.crypto.SecretKey; |
|
39 import javax.net.ssl.SSLPeerUnverifiedException; |
|
40 import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED; |
38 import sun.security.ssl.ClientHello.ClientHelloMessage; |
41 import sun.security.ssl.ClientHello.ClientHelloMessage; |
39 import sun.security.ssl.SSLExtension.ExtensionConsumer; |
42 import sun.security.ssl.SSLExtension.ExtensionConsumer; |
40 import sun.security.ssl.SSLExtension.SSLExtensionSpec; |
43 import sun.security.ssl.SSLExtension.SSLExtensionSpec; |
41 import sun.security.ssl.SSLHandshake.HandshakeMessage; |
44 import sun.security.ssl.SSLHandshake.HandshakeMessage; |
42 import static sun.security.ssl.SSLExtension.*; |
45 import static sun.security.ssl.SSLExtension.*; |
188 int bindersEncodedLength = getBindersEncodedLength(); |
191 int bindersEncodedLength = getBindersEncodedLength(); |
189 int encodedLength = 4 + idsEncodedLength + bindersEncodedLength; |
192 int encodedLength = 4 + idsEncodedLength + bindersEncodedLength; |
190 byte[] buffer = new byte[encodedLength]; |
193 byte[] buffer = new byte[encodedLength]; |
191 ByteBuffer m = ByteBuffer.wrap(buffer); |
194 ByteBuffer m = ByteBuffer.wrap(buffer); |
192 Record.putInt16(m, idsEncodedLength); |
195 Record.putInt16(m, idsEncodedLength); |
193 for(PskIdentity curId : identities) { |
196 for (PskIdentity curId : identities) { |
194 curId.writeEncoded(m); |
197 curId.writeEncoded(m); |
195 } |
198 } |
196 Record.putInt16(m, bindersEncodedLength); |
199 Record.putInt16(m, bindersEncodedLength); |
197 for (byte[] curBinder : binders) { |
200 for (byte[] curBinder : binders) { |
198 Record.putBytes8(m, curBinder); |
201 Record.putBytes8(m, curBinder); |
218 return messageFormat.format(messageFields); |
221 return messageFormat.format(messageFields); |
219 } |
222 } |
220 |
223 |
221 String identitiesString() { |
224 String identitiesString() { |
222 StringBuilder result = new StringBuilder(); |
225 StringBuilder result = new StringBuilder(); |
223 for(PskIdentity curId : identities) { |
226 for (PskIdentity curId : identities) { |
224 result.append(curId.toString() + "\n"); |
227 result.append(curId.toString() + "\n"); |
225 } |
228 } |
226 |
229 |
227 return result.toString(); |
230 return result.toString(); |
228 } |
231 } |
229 |
232 |
230 String bindersString() { |
233 String bindersString() { |
231 StringBuilder result = new StringBuilder(); |
234 StringBuilder result = new StringBuilder(); |
232 for(byte[] curBinder : binders) { |
235 for (byte[] curBinder : binders) { |
233 result.append("{" + Utilities.toHexString(curBinder) + "}\n"); |
236 result.append("{" + Utilities.toHexString(curBinder) + "}\n"); |
234 } |
237 } |
235 |
238 |
236 return result.toString(); |
239 return result.toString(); |
237 } |
240 } |
326 |
329 |
327 @Override |
330 @Override |
328 public void consume(ConnectionContext context, |
331 public void consume(ConnectionContext context, |
329 HandshakeMessage message, |
332 HandshakeMessage message, |
330 ByteBuffer buffer) throws IOException { |
333 ByteBuffer buffer) throws IOException { |
|
334 ClientHelloMessage clientHello = (ClientHelloMessage) message; |
331 ServerHandshakeContext shc = (ServerHandshakeContext)context; |
335 ServerHandshakeContext shc = (ServerHandshakeContext)context; |
332 // Is it a supported and enabled extension? |
336 // Is it a supported and enabled extension? |
333 if (!shc.sslConfig.isAvailable(SSLExtension.CH_PRE_SHARED_KEY)) { |
337 if (!shc.sslConfig.isAvailable(SSLExtension.CH_PRE_SHARED_KEY)) { |
334 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
338 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
335 SSLLogger.fine( |
339 SSLLogger.fine( |
365 SSLSessionContextImpl sessionCache = (SSLSessionContextImpl) |
369 SSLSessionContextImpl sessionCache = (SSLSessionContextImpl) |
366 shc.sslContext.engineGetServerSessionContext(); |
370 shc.sslContext.engineGetServerSessionContext(); |
367 int idIndex = 0; |
371 int idIndex = 0; |
368 for (PskIdentity requestedId : pskSpec.identities) { |
372 for (PskIdentity requestedId : pskSpec.identities) { |
369 SSLSessionImpl s = sessionCache.get(requestedId.identity); |
373 SSLSessionImpl s = sessionCache.get(requestedId.identity); |
370 if (s != null && s.isRejoinable() && |
374 if (s != null && canRejoin(clientHello, shc, s)) { |
371 s.getPreSharedKey().isPresent()) { |
|
372 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
375 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
373 SSLLogger.fine("Resuming session: ", s); |
376 SSLLogger.fine("Resuming session: ", s); |
374 } |
377 } |
375 |
378 |
376 // binder will be checked later |
379 // binder will be checked later |
390 } |
393 } |
391 } |
394 } |
392 |
395 |
393 // update the context |
396 // update the context |
394 shc.handshakeExtensions.put( |
397 shc.handshakeExtensions.put( |
395 SSLExtension.CH_PRE_SHARED_KEY, pskSpec); |
398 SSLExtension.CH_PRE_SHARED_KEY, pskSpec); |
396 } |
399 } |
|
400 } |
|
401 |
|
402 private static boolean canRejoin(ClientHelloMessage clientHello, |
|
403 ServerHandshakeContext shc, SSLSessionImpl s) { |
|
404 |
|
405 boolean result = s.isRejoinable() && s.getPreSharedKey().isPresent(); |
|
406 |
|
407 // Check protocol version |
|
408 if (result && s.getProtocolVersion() != shc.negotiatedProtocol) { |
|
409 if (SSLLogger.isOn && |
|
410 SSLLogger.isOn("ssl,handshake,verbose")) { |
|
411 |
|
412 SSLLogger.finest("Can't resume, incorrect protocol version"); |
|
413 } |
|
414 result = false; |
|
415 } |
|
416 |
|
417 // Validate the required client authentication. |
|
418 if (result && |
|
419 (shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) { |
|
420 try { |
|
421 s.getPeerPrincipal(); |
|
422 } catch (SSLPeerUnverifiedException e) { |
|
423 if (SSLLogger.isOn && |
|
424 SSLLogger.isOn("ssl,handshake,verbose")) { |
|
425 SSLLogger.finest( |
|
426 "Can't resume, " + |
|
427 "client authentication is required"); |
|
428 } |
|
429 result = false; |
|
430 } |
|
431 |
|
432 // Make sure the list of supported signature algorithms matches |
|
433 Collection<SignatureScheme> sessionSigAlgs = |
|
434 s.getLocalSupportedSignatureSchemes(); |
|
435 if (result && |
|
436 !shc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { |
|
437 |
|
438 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
439 SSLLogger.fine("Can't resume. Session uses different " + |
|
440 "signature algorithms"); |
|
441 } |
|
442 result = false; |
|
443 } |
|
444 } |
|
445 |
|
446 // Ensure cipher suite can be negotiated |
|
447 if (result && (!shc.isNegotiable(s.getSuite()) || |
|
448 !clientHello.cipherSuites.contains(s.getSuite()))) { |
|
449 if (SSLLogger.isOn && |
|
450 SSLLogger.isOn("ssl,handshake,verbose")) { |
|
451 SSLLogger.finest( |
|
452 "Can't resume, unavailable session cipher suite"); |
|
453 } |
|
454 result = false; |
|
455 } |
|
456 |
|
457 return result; |
397 } |
458 } |
398 |
459 |
399 private static final |
460 private static final |
400 class CHPreSharedKeyUpdate implements HandshakeConsumer { |
461 class CHPreSharedKeyUpdate implements HandshakeConsumer { |
401 // Prevent instantiation of this class. |
462 // Prevent instantiation of this class. |
545 SSLLogger.fine("No session to resume."); |
606 SSLLogger.fine("No session to resume."); |
546 } |
607 } |
547 return null; |
608 return null; |
548 } |
609 } |
549 |
610 |
|
611 // Make sure the list of supported signature algorithms matches |
|
612 Collection<SignatureScheme> sessionSigAlgs = |
|
613 chc.resumingSession.getLocalSupportedSignatureSchemes(); |
|
614 if (!chc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { |
|
615 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
616 SSLLogger.fine("Existing session uses different " + |
|
617 "signature algorithms"); |
|
618 } |
|
619 return null; |
|
620 } |
|
621 |
|
622 // The session must have a pre-shared key |
550 Optional<SecretKey> pskOpt = chc.resumingSession.getPreSharedKey(); |
623 Optional<SecretKey> pskOpt = chc.resumingSession.getPreSharedKey(); |
551 if (!pskOpt.isPresent()) { |
624 if (!pskOpt.isPresent()) { |
552 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
625 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
553 SSLLogger.fine("Existing session has no PSK."); |
626 SSLLogger.fine("Existing session has no PSK."); |
554 } |
627 } |
656 hmac.init(finishedKey); |
729 hmac.init(finishedKey); |
657 return hmac.doFinal(digest); |
730 return hmac.doFinal(digest); |
658 } catch (NoSuchAlgorithmException | InvalidKeyException ex) { |
731 } catch (NoSuchAlgorithmException | InvalidKeyException ex) { |
659 throw new IOException(ex); |
732 throw new IOException(ex); |
660 } |
733 } |
661 } catch(GeneralSecurityException ex) { |
734 } catch (GeneralSecurityException ex) { |
662 throw new IOException(ex); |
735 throw new IOException(ex); |
663 } |
736 } |
664 } |
737 } |
665 |
738 |
666 private static SecretKey deriveBinderKey(SecretKey psk, |
739 private static SecretKey deriveBinderKey(SecretKey psk, |