--- old/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Fri May 29 00:48:30 2015 +++ new/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Fri May 29 00:48:29 2015 @@ -58,7 +58,7 @@ final class ServerHandshaker extends Handshaker { // is the server going to require the client to authenticate? - private byte doClientAuth; + private ClientAuthType doClientAuth; // our authentication info private X509Certificate[] certs; @@ -143,13 +143,13 @@ * Constructor ... use the keys found in the auth context. */ ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context, - ProtocolList enabledProtocols, byte clientAuth, + ProtocolList enabledProtocols, ClientAuthType clientAuth, ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, boolean secureRenegotiation, byte[] clientVerifyData, byte[] serverVerifyData) { super(socket, context, enabledProtocols, - (clientAuth != SSLEngineImpl.clauth_none), false, + (clientAuth != ClientAuthType.CLIENT_AUTH_NONE), false, activeProtocolVersion, isInitialHandshake, secureRenegotiation, clientVerifyData, serverVerifyData); doClientAuth = clientAuth; @@ -159,15 +159,16 @@ * Constructor ... use the keys found in the auth context. */ ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context, - ProtocolList enabledProtocols, byte clientAuth, + ProtocolList enabledProtocols, ClientAuthType clientAuth, ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { + byte[] clientVerifyData, byte[] serverVerifyData, + boolean isDTLS) { super(engine, context, enabledProtocols, - (clientAuth != SSLEngineImpl.clauth_none), false, + (clientAuth != ClientAuthType.CLIENT_AUTH_NONE), false, activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); + clientVerifyData, serverVerifyData, isDTLS); doClientAuth = clientAuth; } @@ -176,7 +177,7 @@ * whether client authentication is required. Otherwise, * we will need to wait for the next handshake. */ - void setClientAuth(byte clientAuth) { + void setClientAuth(ClientAuthType clientAuth) { doClientAuth = clientAuth; } @@ -192,21 +193,15 @@ @Override void processMessage(byte type, int message_len) throws IOException { - // - // In SSLv3 and TLS, messages follow strictly increasing - // numerical order _except_ for one annoying special case. - // - if ((state >= type) - && (state != HandshakeMessage.ht_client_key_exchange - && type != HandshakeMessage.ht_certificate_verify)) { - throw new SSLProtocolException( - "Handshake message sequence violation, state = " + state - + ", type = " + type); - } + // check the handshake state + handshakeState.check(type); + switch (type) { case HandshakeMessage.ht_client_hello: - ClientHello ch = new ClientHello(input, message_len); + ClientHello ch = new ClientHello(input, message_len, isDTLS); + handshakeState.update(ch, resumingSession); + /* * send it off for processing. */ @@ -214,12 +209,14 @@ break; case HandshakeMessage.ht_certificate: - if (doClientAuth == SSLEngineImpl.clauth_none) { + if (doClientAuth == ClientAuthType.CLIENT_AUTH_NONE) { fatalSE(Alerts.alert_unexpected_message, "client sent unsolicited cert chain"); // NOTREACHED } - this.clientCertificate(new CertificateMsg(input)); + CertificateMsg certificateMsg = new CertificateMsg(input); + handshakeState.update(certificateMsg, resumingSession); + this.clientCertificate(certificateMsg); break; case HandshakeMessage.ht_client_key_exchange: @@ -237,17 +234,20 @@ protocolVersion, clientRequestedVersion, sslContext.getSecureRandom(), input, message_len, privateKey); + handshakeState.update(pms, resumingSession); preMasterSecret = this.clientKeyExchange(pms); break; case K_KRB5: case K_KRB5_EXPORT: - preMasterSecret = this.clientKeyExchange( + KerberosClientKeyExchange kke = new KerberosClientKeyExchange(protocolVersion, clientRequestedVersion, sslContext.getSecureRandom(), input, this.getAccSE(), - serviceCreds)); + serviceCreds); + handshakeState.update(kke, resumingSession); + preMasterSecret = this.clientKeyExchange(kke); break; case K_DHE_RSA: case K_DHE_DSS: @@ -258,8 +258,9 @@ * protocol difference in these five flavors is in how * the ServerKeyExchange message was constructed! */ - preMasterSecret = this.clientKeyExchange( - new DHClientKeyExchange(input)); + DHClientKeyExchange dhcke = new DHClientKeyExchange(input); + handshakeState.update(dhcke, resumingSession); + preMasterSecret = this.clientKeyExchange(dhcke); break; case K_ECDH_RSA: case K_ECDH_ECDSA: @@ -266,8 +267,10 @@ case K_ECDHE_RSA: case K_ECDHE_ECDSA: case K_ECDH_ANON: - preMasterSecret = this.clientKeyExchange - (new ECDHClientKeyExchange(input)); + ECDHClientKeyExchange ecdhcke = + new ECDHClientKeyExchange(input); + handshakeState.update(ecdhcke, resumingSession); + preMasterSecret = this.clientKeyExchange(ecdhcke); break; default: throw new SSLProtocolException @@ -282,20 +285,20 @@ break; case HandshakeMessage.ht_certificate_verify: - this.clientCertificateVerify(new CertificateVerify(input, - localSupportedSignAlgs, protocolVersion)); + CertificateVerify cvm = + new CertificateVerify(input, + localSupportedSignAlgs, protocolVersion); + handshakeState.update(cvm, resumingSession); + this.clientCertificateVerify(cvm); + break; case HandshakeMessage.ht_finished: - // A ChangeCipherSpec record must have been received prior to - // reception of the Finished message (RFC 5246, 7.4.9). - if (!receivedChangeCipherSpec()) { - fatalSE(Alerts.alert_handshake_failure, - "Received Finished message before ChangeCipherSpec"); - } + Finished cfm = + new Finished(protocolVersion, input, cipherSuite); + handshakeState.update(cfm, resumingSession); + this.clientFinished(cfm); - this.clientFinished( - new Finished(protocolVersion, input, cipherSuite)); break; default: @@ -303,17 +306,6 @@ "Illegal server handshake msg, " + type); } - // - // Move state machine forward if the message handling - // code didn't already do so - // - if (state < type) { - if(type == HandshakeMessage.ht_certificate_verify) { - state = type + 2; // an annoying special case - } else { - state = type; - } - } } @@ -344,7 +336,7 @@ // // This will not have any impact on server initiated renegotiation. if (rejectClientInitiatedRenego && !isInitialHandshake && - state != HandshakeMessage.ht_hello_request) { + !serverHelloRequested) { fatalSE(Alerts.alert_handshake_failure, "Client initiated renegotiation is not allowed"); } @@ -438,7 +430,7 @@ } } else if (!allowUnsafeRenegotiation) { // abort the handshake - if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { + if (activeProtocolVersion.useTLS10PlusSpec()) { // respond with a no_renegotiation warning warningSE(Alerts.alert_no_renegotiation); @@ -480,12 +472,53 @@ } } - /* - * Always make sure this entire record has been digested before we - * start emitting output, to ensure correct digesting order. - */ - input.digestNow(); + // check the "max_fragment_length" extension + MaxFragmentLengthExtension maxFragLenExt = (MaxFragmentLengthExtension) + mesg.extensions.get(ExtensionType.EXT_MAX_FRAGMENT_LENGTH); + if ((maxFragLenExt != null) && (maximumPacketSize != 0)) { + // Not yet consider the impact of IV/MAC/padding. + int estimatedMaxFragSize = maximumPacketSize; + if (isDTLS) { + estimatedMaxFragSize -= DTLSRecord.headerSize; + } else { + estimatedMaxFragSize -= SSLRecord.headerSize; + } + if (maxFragLenExt.getMaxFragLen() > estimatedMaxFragSize) { + // For better interoperability, abort the maximum fragment + // length negotiation, rather than terminate the connection + // with a fatal alert. + maxFragLenExt = null; + + // fatalSE(Alerts.alert_illegal_parameter, + // "Not an allowed max_fragment_length value"); + } + } + + // cookie exchange + if (isDTLS) { + HelloCookieManager hcMgr = sslContext.getHelloCookieManager(); + if ((mesg.cookie == null) || (mesg.cookie.length == 0) || + (!hcMgr.isValid(mesg))) { + + // + // Perform cookie exchange for DTLS handshaking if no cookie + // or the cookie is invalid in the ClientHello message. + // + HelloVerifyRequest m0 = new HelloVerifyRequest(hcMgr, mesg); + + if (debug != null && Debug.isOn("handshake")) { + m0.print(System.out); + } + + m0.write(output); + handshakeState.update(m0, resumingSession); + output.flush(); + + return; + } + } + /* * FIRST, construct the ServerHello using the options and priorities * from the ClientHello. Update the (pending) cipher spec as we do @@ -580,7 +613,7 @@ } if (resumingSession && - (doClientAuth == SSLEngineImpl.clauth_required)) { + (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED)) { try { previous.getPeerPrincipal(); } catch (SSLPeerUnverifiedException e) { @@ -660,7 +693,7 @@ } } } - } // else client did not try to resume + } // else client did not try to resume // // If client hasn't specified a session we can resume, start a @@ -677,7 +710,7 @@ // We only need to handle the "signature_algorithm" extension // for full handshakes and TLS 1.2 or later. - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { SignatureAlgorithmsExtension signAlgs = (SignatureAlgorithmsExtension)mesg.extensions.get( ExtensionType.EXT_SIGNATURE_ALGORITHMS); @@ -708,7 +741,7 @@ sslContext.getSecureRandom(), getHostAddressSE(), getPortSE()); - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { if (peerSupportedSignAlgs != null) { session.setPeerSupportedSignatureAlgorithms( peerSupportedSignAlgs); @@ -734,12 +767,41 @@ session.setLocalPrivateKey(privateKey); // chooseCompression(mesg); + + // set the negotiated maximum fragment in the session + // + // The protocol version and cipher suite have been negotiated + // in previous processes. + if (maxFragLenExt != null) { + int maxFragLen = maxFragLenExt.getMaxFragLen(); + + // More check of the requested "max_fragment_length" extension. + if (maximumPacketSize != 0) { + int estimatedMaxFragSize = cipherSuite.calculatePacketSize( + maxFragLen, protocolVersion, isDTLS); + if (estimatedMaxFragSize > maximumPacketSize) { + // For better interoperability, abort the maximum + // fragment length negotiation, rather than terminate + // the connection with a fatal alert. + maxFragLenExt = null; + + // fatalSE(Alerts.alert_illegal_parameter, + // "Not an allowed max_fragment_length value"); + } + } + + if (maxFragLenExt != null) { + session.setNegotiatedMaxFragSize(maxFragLen); + } + } + + session.setMaximumPacketSize(maximumPacketSize); } else { // set the handshake session setHandshakeSessionSE(session); } - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg()); } @@ -771,11 +833,20 @@ } } + if ((maxFragLenExt != null) && !resumingSession) { + // When resuming a session, the server MUST NOT include a + // max_fragment_length extension in the server hello. + // + // Otherwise, use the same value as the requested extension. + m1.extensions.add(maxFragLenExt); + } + if (debug != null && Debug.isOn("handshake")) { m1.print(System.out); System.out.println("Cipher suite: " + session.getSuite()); } m1.write(output); + handshakeState.update(m1, resumingSession); // // If we are resuming a session, we finish writing handshake @@ -784,6 +855,10 @@ if (resumingSession) { calculateConnectionKeys(session.getMasterSecret()); sendChangeCipherAndFinish(false); + + // expecting the final ChangeCipherSpec and Finished messages + expectingFinishFlightSE(); + return; } @@ -815,6 +890,7 @@ m2.print(System.out); } m2.write(output); + handshakeState.update(m2, resumingSession); // XXX has some side effects with OS TCP buffering, // leave it out for now @@ -853,9 +929,9 @@ sslContext.getSecureRandom()); privateKey = tempPrivateKey; } catch (GeneralSecurityException e) { - throwSSLException - ("Error generating RSA server key exchange", e); m3 = null; // make compiler happy + throw new SSLException( + "Error generating RSA server key exchange", e); } } else { // RSA_EXPORT with short key, don't need ServerKeyExchange @@ -873,8 +949,9 @@ preferableSignatureAlgorithm, protocolVersion); } catch (GeneralSecurityException e) { - throwSSLException("Error generating DH server key exchange", e); m3 = null; // make compiler happy + throw new SSLException( + "Error generating DH server key exchange", e); } break; case K_DH_ANON: @@ -892,9 +969,9 @@ preferableSignatureAlgorithm, protocolVersion); } catch (GeneralSecurityException e) { - throwSSLException( - "Error generating ECDH server key exchange", e); m3 = null; // make compiler happy + throw new SSLException( + "Error generating ECDH server key exchange", e); } break; case K_ECDH_RSA: @@ -910,6 +987,7 @@ m3.print(System.out); } m3.write(output); + handshakeState.update(m3, resumingSession); } // @@ -923,7 +1001,7 @@ // Illegal for anonymous flavors, so we need to check that. // // CertificateRequest is omitted for Kerberos ciphers - if (doClientAuth != SSLEngineImpl.clauth_none && + if (doClientAuth != ClientAuthType.CLIENT_AUTH_NONE && keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON && keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) { @@ -931,7 +1009,7 @@ X509Certificate caCerts[]; Collection localSignAlgs = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { // We currently use all local upported signature and hash // algorithms. However, to minimize the computation cost // of requested hash algorithms, we may use a restricted @@ -959,6 +1037,7 @@ m4.print(System.out); } m4.write(output); + handshakeState.update(m4, resumingSession); } /* @@ -970,6 +1049,7 @@ m5.print(System.out); } m5.write(output); + handshakeState.update(m5, resumingSession); /* * Flush any buffered messages so the client will see them. @@ -1000,7 +1080,7 @@ continue; } - if (doClientAuth == SSLEngineImpl.clauth_required) { + if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED) { if ((suite.keyExchange == K_DH_ANON) || (suite.keyExchange == K_ECDH_ANON)) { continue; @@ -1043,12 +1123,12 @@ } // must not negotiate the obsoleted weak cipher suites. - if (protocolVersion.v >= suite.obsoleted) { + if (protocolVersion.obsoletes(suite)) { return false; } // must not negotiate unsupported cipher suites. - if (protocolVersion.v < suite.supported) { + if (!protocolVersion.supports(suite)) { return false; } @@ -1062,7 +1142,7 @@ tempPublicKey = null; Collection supportedSignAlgs = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { if (peerSupportedSignAlgs != null) { supportedSignAlgs = peerSupportedSignAlgs; } else { @@ -1151,7 +1231,7 @@ } // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "RSA", privateKey); @@ -1169,7 +1249,7 @@ } // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "RSA", privateKey); @@ -1184,7 +1264,7 @@ break; case K_DHE_DSS: // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "DSA"); @@ -1202,7 +1282,7 @@ break; case K_ECDHE_ECDSA: // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "ECDSA"); @@ -1257,7 +1337,7 @@ setCipherSuite(suite); // set the peer implicit supported signature algorithms - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { if (peerSupportedSignAlgs == null) { setPeerSupportedSignAlgs(supportedSignAlgs); // we had alreay update the session @@ -1571,7 +1651,7 @@ mesg.print(System.out); } - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + if (protocolVersion.useTLS12PlusSpec()) { SignatureAndHashAlgorithm signAlg = mesg.getPreferableSignatureAlgorithm(); if (signAlg == null) { @@ -1623,7 +1703,7 @@ * Verify if client did send the certificate when client * authentication was required, otherwise server should not proceed */ - if (doClientAuth == SSLEngineImpl.clauth_required) { + if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED) { // get X500Principal of the end-entity certificate for X509-based // ciphersuites, or Kerberos principal for Kerberos ciphersuites session.getPeerPrincipal(); @@ -1664,8 +1744,9 @@ * the change_cipher_spec and Finished message. */ if (!resumingSession) { - input.digestNow(); sendChangeCipherAndFinish(true); + } else { + handshakeFinished = true; } /* @@ -1695,7 +1776,8 @@ private void sendChangeCipherAndFinish(boolean finishedTag) throws IOException { - output.flush(); + // Reload if this message has been reserved. + handshakeHash.reload(); Finished mesg = new Finished(protocolVersion, handshakeHash, Finished.SERVER, session.getMasterSecret(), cipherSuite); @@ -1713,16 +1795,6 @@ if (secureRenegotiation) { serverVerifyData = mesg.getVerifyData(); } - - /* - * Update state machine so client MUST send 'finished' next - * The update should only take place if it is not in the fast - * handshake mode since the server has to wait for a finished - * message from the client. - */ - if (finishedTag) { - state = HandshakeMessage.ht_finished; - } } @@ -1757,7 +1829,7 @@ * session will get an SSLPeerUnverifiedException. */ if ((description == Alerts.alert_no_certificate) && - (doClientAuth == SSLEngineImpl.clauth_requested)) { + (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED)) { return; } @@ -1798,7 +1870,7 @@ * If the client authentication is only *REQUESTED* (e.g. * not *REQUIRED*, this is an acceptable condition.) */ - if (doClientAuth == SSLEngineImpl.clauth_requested) { + if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED) { return; } else { fatalSE(Alerts.alert_bad_certificate,