switch (keyExchange) { case K_RSA: // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } break; case K_RSA_EXPORT: // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } try { if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) { if (!setupEphemeralRSAKeys(suite.exportable)) { return false; } } } catch (RuntimeException e) { // could not determine keylength, ignore key return false; } break; case K_DHE_RSA: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "RSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } setupEphemeralDHKeys(suite.exportable); break; case K_ECDHE_RSA: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "RSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } if (setupEphemeralECDHKeys() == false) { return false; } break; case K_DHE_DSS: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "DSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need DSS certs for authentication if (setupPrivateKeyAndChain("DSA") == false) { return false; } setupEphemeralDHKeys(suite.exportable); break; case K_ECDHE_ECDSA: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "ECDSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need EC cert signed using EC if (setupPrivateKeyAndChain("EC_EC") == false) { return false; } if (setupEphemeralECDHKeys() == false) { return false; } break; case K_ECDH_RSA: // need EC cert signed using RSA if (setupPrivateKeyAndChain("EC_RSA") == false) { return false; } setupStaticECDHKeys(); break; case K_ECDH_ECDSA: // need EC cert signed using EC if (setupPrivateKeyAndChain("EC_EC") == false) { return false; } setupStaticECDHKeys(); break; case K_KRB5: case K_KRB5_EXPORT: // need Kerberos Key if (!setupKerberosKeys()) { return false; } break; case K_DH_ANON: // no certs needed for anonymous setupEphemeralDHKeys(suite.exportable); break; case K_ECDH_ANON: // no certs needed for anonymous if (setupEphemeralECDHKeys() == false) { return false; } break; default: // internal error, unknown key exchange throw new RuntimeException("Unrecognized cipherSuite: " + suite); } setCipherSuite(suite); // set the peer implicit supported signature algorithms if (protocolVersion.v >= ProtocolVersion.TLS12.v) { if (peerSupportedSignAlgs == null) { setPeerSupportedSignAlgs(supportedSignAlgs); // we had alreay update the session } } return true; } /* * Get some "ephemeral" RSA keys for this context. This means * generating them if it's not already been done. * * Note that we currently do not implement any ciphersuites that use * strong ephemeral RSA. (We do not support the EXPORT1024 ciphersuites * and standard RSA ciphersuites prohibit ephemeral mode for some reason) * This means that export is always true and 512 bit keys are generated. */ private boolean setupEphemeralRSAKeys(boolean export) { KeyPair kp = sslContext.getEphemeralKeyManager(). getRSAKeyPair(export, sslContext.getSecureRandom()); if (kp == null) { return false; } else { tempPublicKey = kp.getPublic(); tempPrivateKey = kp.getPrivate(); return true; } } /* * Acquire some "ephemeral" Diffie-Hellman keys for this handshake. * We don't reuse these, for improved forward secrecy. */ private void setupEphemeralDHKeys(boolean export) { /* * Diffie-Hellman keys ... we use 768 bit private keys due * to the "use twice as many key bits as bits you want secret" * rule of thumb, assuming we want the same size premaster * secret with Diffie-Hellman and RSA key exchanges. Except * that exportable ciphers max out at 512 bits modulus values. */ dh = new DHCrypt((export ? 512 : 768), sslContext.getSecureRandom()); } // Setup the ephemeral ECDH parameters. // If we cannot continue because we do not support any of the curves that // the client requested, return false. Otherwise (all is well), return true. private boolean setupEphemeralECDHKeys() { int index = -1; if (supportedCurves != null) { // if the client sent the supported curves extension, pick the // first one that we support; for (int curveId : supportedCurves.curveIds()) { if (SupportedEllipticCurvesExtension.isSupported(curveId)) { index = curveId; break; } } if (index < 0) { // no match found, cannot use this ciphersuite return false; } } else { // pick our preference index = SupportedEllipticCurvesExtension.DEFAULT.curveIds()[0]; } String oid = SupportedEllipticCurvesExtension.getCurveOid(index); ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom()); return true; } private void setupStaticECDHKeys() { // don't need to check whether the curve is supported, already done // in setupPrivateKeyAndChain(). ecdh = new ECDHCrypt(privateKey, certs[0].getPublicKey()); } /** * Retrieve the server key and certificate for the specified algorithm * from the KeyManager and set the instance variables. * * @return true if successful, false if not available or invalid */ private boolean setupPrivateKeyAndChain(String algorithm) { X509ExtendedKeyManager km = sslContext.getX509KeyManager(); String alias; if (conn != null) { alias = km.chooseServerAlias(algorithm, null, conn); } else { alias = km.chooseEngineServerAlias(algorithm, null, engine); } if (alias == null) { return false; } PrivateKey tempPrivateKey = km.getPrivateKey(alias); if (tempPrivateKey == null) { return false; } X509Certificate[] tempCerts = km.getCertificateChain(alias); if ((tempCerts == null) || (tempCerts.length == 0)) { return false; } String keyAlgorithm = algorithm.split("_")[0]; PublicKey publicKey = tempCerts[0].getPublicKey(); if ((tempPrivateKey.getAlgorithm().equals(keyAlgorithm) == false) || (publicKey.getAlgorithm().equals(keyAlgorithm) == false)) { return false; } // For ECC certs, check whether we support the EC domain parameters. // If the client sent a SupportedEllipticCurves ClientHello extension, // check against that too. if (keyAlgorithm.equals("EC")) { if (publicKey instanceof ECPublicKey == false) { return false; } ECParameterSpec params = ((ECPublicKey)publicKey).getParams(); int index = SupportedEllipticCurvesExtension.getCurveIndex(params); if (SupportedEllipticCurvesExtension.isSupported(index) == false) { return false; } if ((supportedCurves != null) && !supportedCurves.contains(index)) { return false; } } this.privateKey = tempPrivateKey; this.certs = tempCerts; return true; } /** * Retrieve the Kerberos key for the specified server principal * from the JAAS configuration file. * * @return true if successful, false if not available or invalid */ private boolean setupKerberosKeys() { if (kerberosKeys != null) { return true; } try { final AccessControlContext acc = getAccSE(); kerberosKeys = AccessController.doPrivileged( // Eliminate dependency on KerberosKey new PrivilegedExceptionAction<SecretKey[]>() { public SecretKey[] run() throws Exception { // get kerberos key for the default principal return Krb5Helper.getServerKeys(acc); }}); // check permission to access and use the secret key of the // Kerberized "host" service if (kerberosKeys != null && kerberosKeys.length > 0) { if (debug != null && Debug.isOn("handshake")) { for (SecretKey k: kerberosKeys) { System.out.println("Using Kerberos key: " + k); } } String serverPrincipal = Krb5Helper.getServerPrincipalName(kerberosKeys[0]); SecurityManager sm = System.getSecurityManager(); try { if (sm != null) { // Eliminate dependency on ServicePermission sm.checkPermission(Krb5Helper.getServicePermission( serverPrincipal, "accept"), acc); } } catch (SecurityException se) { kerberosKeys = null; // %%% destroy keys? or will that affect Subject? if (debug != null && Debug.isOn("handshake")) System.out.println("Permission to access Kerberos" + " secret key denied"); return false; } } return (kerberosKeys != null); } catch (PrivilegedActionException e) { // Likely exception here is LoginExceptin if (debug != null && Debug.isOn("handshake")) { System.out.println("Attempt to obtain Kerberos key failed: " + e.toString()); } return false; } } /* * For Kerberos ciphers, the premaster secret is encrypted using * the session key. See RFC 2712. */ private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } // Record the principals involved in exchange session.setPeerPrincipal(mesg.getPeerPrincipal()); session.setLocalPrincipal(mesg.getLocalPrincipal()); byte[] b = mesg.getUnencryptedPreMasterSecret(); return new SecretKeySpec(b, "TlsPremasterSecret"); } /* * Diffie Hellman key exchange is used when the server presented * D-H parameters in its certificate (signed using RSA or DSS/DSA), * or else the server presented no certificate but sent D-H params * in a ServerKeyExchange message. Use of D-H is specified by the * cipher suite chosen. * * The message optionally contains the client's D-H public key (if * it wasn't not sent in a client certificate). As always with D-H, * if a client and a server have each other's D-H public keys and * they use common algorithm parameters, they have a shared key * that's derived via the D-H calculation. That key becomes the * pre-master secret. */ private SecretKey clientKeyExchange(DHClientKeyExchange mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } return dh.getAgreedSecret(mesg.getClientPublicKey()); } private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } return ecdh.getAgreedSecret(mesg.getEncodedPoint()); } /* * Client wrote a message to verify the certificate it sent earlier. * * Note that this certificate isn't involved in key exchange. Client * authentication messages are included in the checksums used to * validate the handshake (e.g. Finished messages). Other than that, * the _exact_ identity of the client is less fundamental to protocol * security than its role in selecting keys via the pre-master secret. */ private void clientCertificateVerify(CertificateVerify mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } if (protocolVersion.v >= ProtocolVersion.TLS12.v) { SignatureAndHashAlgorithm signAlg = mesg.getPreferableSignatureAlgorithm(); if (signAlg == null) { throw new SSLHandshakeException( "Illegal CertificateVerify message"); } String hashAlg = SignatureAndHashAlgorithm.getHashAlgorithmName(signAlg); if (hashAlg == null || hashAlg.length() == 0) { throw new SSLHandshakeException( "No supported hash algorithm"); } handshakeHash.setCertificateVerifyAlg(hashAlg); } try { PublicKey publicKey = session.getPeerCertificates()[0].getPublicKey(); boolean valid = mesg.verify(protocolVersion, handshakeHash, publicKey, session.getMasterSecret()); if (valid == false) { fatalSE(Alerts.alert_bad_certificate, "certificate verify message signature error"); } } catch (GeneralSecurityException e) { fatalSE(Alerts.alert_bad_certificate, "certificate verify format error", e); } // reset the flag for clientCertificateVerify message needClientVerify = false; } /* * Client writes "finished" at the end of its handshake, after cipher * spec is changed. We verify it and then send ours. * * When we're resuming a session, we'll have already sent our own * Finished message so just the verification is needed. */ private void clientFinished(Finished mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } /* * Verify if client did send the certificate when client * authentication was required, otherwise server should not proceed */ if (doClientAuth == SSLEngineImpl.clauth_required) { // get X500Principal of the end-entity certificate for X509-based // ciphersuites, or Kerberos principal for Kerberos ciphersuites session.getPeerPrincipal(); } /* * Verify if client did send clientCertificateVerify message following * the client Certificate, otherwise server should not proceed */ if (needClientVerify) { fatalSE(Alerts.alert_handshake_failure, "client did not send certificate verify message"); } /* * Verify the client's message with the "before" digest of messages, * and forget about continuing to use that digest. */ boolean verified = mesg.verify(handshakeHash, Finished.CLIENT, session.getMasterSecret()); if (!verified) { fatalSE(Alerts.alert_handshake_failure, "client 'finished' message doesn't verify"); // NOTREACHED } /* * save client verify data for secure renegotiation */ if (secureRenegotiation) { clientVerifyData = mesg.getVerifyData(); } /* * OK, it verified. If we're doing the full handshake, add that * "Finished" message to the hash of handshake messages, then send * the change_cipher_spec and Finished message. */ if (!resumingSession) { input.digestNow(); sendChangeCipherAndFinish(true); } /* * Update the session cache only after the handshake completed, else * we're open to an attack against a partially completed handshake. */ session.setLastAccessedTime(System.currentTimeMillis()); if (!resumingSession && session.isRejoinable()) { ((SSLSessionContextImpl)sslContext.engineGetServerSessionContext()) .put(session); if (debug != null && Debug.isOn("session")) { System.out.println(Lines 1001–1500 of 1678. Previous lines Load more
switch (keyExchange) { case K_RSA: // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } break; case K_RSA_EXPORT: // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } try { if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) { if (!setupEphemeralRSAKeys(suite.exportable)) { return false; } } } catch (RuntimeException e) { // could not determine keylength, ignore key return false; } break; case K_DHE_RSA: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "RSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } setupEphemeralDHKeys(suite.exportable); break; case K_ECDHE_RSA: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "RSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need RSA certs for authentication if (setupPrivateKeyAndChain("RSA") == false) { return false; } if (setupEphemeralECDHKeys() == false) { return false; } break; case K_DHE_DSS: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "DSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need DSS certs for authentication if (setupPrivateKeyAndChain("DSA") == false) { return false; } setupEphemeralDHKeys(suite.exportable); break; case K_ECDHE_ECDSA: // get preferable peer signature algorithm for server key exchange if (protocolVersion.v >= ProtocolVersion.TLS12.v) { preferableSignatureAlgorithm = SignatureAndHashAlgorithm.getPreferableAlgorithm( supportedSignAlgs, "ECDSA"); if (preferableSignatureAlgorithm == null) { return false; } } // need EC cert signed using EC if (setupPrivateKeyAndChain("EC_EC") == false) { return false; } if (setupEphemeralECDHKeys() == false) { return false; } break; case K_ECDH_RSA: // need EC cert signed using RSA if (setupPrivateKeyAndChain("EC_RSA") == false) { return false; } setupStaticECDHKeys(); break; case K_ECDH_ECDSA: // need EC cert signed using EC if (setupPrivateKeyAndChain("EC_EC") == false) { return false; } setupStaticECDHKeys(); break; case K_KRB5: case K_KRB5_EXPORT: // need Kerberos Key if (!setupKerberosKeys()) { return false; } break; case K_DH_ANON: // no certs needed for anonymous setupEphemeralDHKeys(suite.exportable); break; case K_ECDH_ANON: // no certs needed for anonymous if (setupEphemeralECDHKeys() == false) { return false; } break; default: // internal error, unknown key exchange throw new RuntimeException("Unrecognized cipherSuite: " + suite); } setCipherSuite(suite); // set the peer implicit supported signature algorithms if (protocolVersion.v >= ProtocolVersion.TLS12.v) { if (peerSupportedSignAlgs == null) { setPeerSupportedSignAlgs(supportedSignAlgs); // we had alreay update the session } } return true; } /* * Get some "ephemeral" RSA keys for this context. This means * generating them if it's not already been done. * * Note that we currently do not implement any ciphersuites that use * strong ephemeral RSA. (We do not support the EXPORT1024 ciphersuites * and standard RSA ciphersuites prohibit ephemeral mode for some reason) * This means that export is always true and 512 bit keys are generated. */ private boolean setupEphemeralRSAKeys(boolean export) { KeyPair kp = sslContext.getEphemeralKeyManager(). getRSAKeyPair(export, sslContext.getSecureRandom()); if (kp == null) { return false; } else { tempPublicKey = kp.getPublic(); tempPrivateKey = kp.getPrivate(); return true; } } /* * Acquire some "ephemeral" Diffie-Hellman keys for this handshake. * We don't reuse these, for improved forward secrecy. */ private void setupEphemeralDHKeys(boolean export) { /* * Diffie-Hellman keys ... we use 768 bit private keys due * to the "use twice as many key bits as bits you want secret" * rule of thumb, assuming we want the same size premaster * secret with Diffie-Hellman and RSA key exchanges. Except * that exportable ciphers max out at 512 bits modulus values. */ dh = new DHCrypt((export ? 512 : 768), sslContext.getSecureRandom()); } // Setup the ephemeral ECDH parameters. // If we cannot continue because we do not support any of the curves that // the client requested, return false. Otherwise (all is well), return true. private boolean setupEphemeralECDHKeys() { int index = -1; if (supportedCurves != null) { // if the client sent the supported curves extension, pick the // first one that we support; for (int curveId : supportedCurves.curveIds()) { if (SupportedEllipticCurvesExtension.isSupported(curveId)) { index = curveId; break; } } if (index < 0) { // no match found, cannot use this ciphersuite return false; } } else { // pick our preference index = SupportedEllipticCurvesExtension.DEFAULT.curveIds()[0]; } String oid = SupportedEllipticCurvesExtension.getCurveOid(index); ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom()); return true; } private void setupStaticECDHKeys() { // don't need to check whether the curve is supported, already done // in setupPrivateKeyAndChain(). ecdh = new ECDHCrypt(privateKey, certs[0].getPublicKey()); } /** * Retrieve the server key and certificate for the specified algorithm * from the KeyManager and set the instance variables. * * @return true if successful, false if not available or invalid */ private boolean setupPrivateKeyAndChain(String algorithm) { X509ExtendedKeyManager km = sslContext.getX509KeyManager(); String alias; if (conn != null) { alias = km.chooseServerAlias(algorithm, null, conn); } else { alias = km.chooseEngineServerAlias(algorithm, null, engine); } if (alias == null) { return false; } PrivateKey tempPrivateKey = km.getPrivateKey(alias); if (tempPrivateKey == null) { return false; } X509Certificate[] tempCerts = km.getCertificateChain(alias); if ((tempCerts == null) || (tempCerts.length == 0)) { return false; } String keyAlgorithm = algorithm.split("_")[0]; PublicKey publicKey = tempCerts[0].getPublicKey(); if ((tempPrivateKey.getAlgorithm().equals(keyAlgorithm) == false) || (publicKey.getAlgorithm().equals(keyAlgorithm) == false)) { return false; } // For ECC certs, check whether we support the EC domain parameters. // If the client sent a SupportedEllipticCurves ClientHello extension, // check against that too. if (keyAlgorithm.equals("EC")) { if (publicKey instanceof ECPublicKey == false) { return false; } ECParameterSpec params = ((ECPublicKey)publicKey).getParams(); int index = SupportedEllipticCurvesExtension.getCurveIndex(params); if (SupportedEllipticCurvesExtension.isSupported(index) == false) { return false; } if ((supportedCurves != null) && !supportedCurves.contains(index)) { return false; } } this.privateKey = tempPrivateKey; this.certs = tempCerts; return true; } /** * Retrieve the Kerberos key for the specified server principal * from the JAAS configuration file. * * @return true if successful, false if not available or invalid */ private boolean setupKerberosKeys() { if (kerberosKeys != null) { return true; } try { final AccessControlContext acc = getAccSE(); kerberosKeys = AccessController.doPrivileged( // Eliminate dependency on KerberosKey new PrivilegedExceptionAction<SecretKey[]>() { public SecretKey[] run() throws Exception { // get kerberos key for the default principal return Krb5Helper.getServerKeys(acc); }}); // check permission to access and use the secret key of the // Kerberized "host" service if (kerberosKeys != null && kerberosKeys.length > 0) { if (debug != null && Debug.isOn("handshake")) { for (SecretKey k: kerberosKeys) { System.out.println("Using Kerberos key: " + k); } } String serverPrincipal = Krb5Helper.getServerPrincipalName(kerberosKeys[0]); SecurityManager sm = System.getSecurityManager(); try { if (sm != null) { // Eliminate dependency on ServicePermission sm.checkPermission(Krb5Helper.getServicePermission( serverPrincipal, "accept"), acc); } } catch (SecurityException se) { kerberosKeys = null; // %%% destroy keys? or will that affect Subject? if (debug != null && Debug.isOn("handshake")) System.out.println("Permission to access Kerberos" + " secret key denied"); return false; } } return (kerberosKeys != null); } catch (PrivilegedActionException e) { // Likely exception here is LoginExceptin if (debug != null && Debug.isOn("handshake")) { System.out.println("Attempt to obtain Kerberos key failed: " + e.toString()); } return false; } } /* * For Kerberos ciphers, the premaster secret is encrypted using * the session key. See RFC 2712. */ private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } // Record the principals involved in exchange session.setPeerPrincipal(mesg.getPeerPrincipal()); session.setLocalPrincipal(mesg.getLocalPrincipal()); byte[] b = mesg.getUnencryptedPreMasterSecret(); return new SecretKeySpec(b, "TlsPremasterSecret"); } /* * Diffie Hellman key exchange is used when the server presented * D-H parameters in its certificate (signed using RSA or DSS/DSA), * or else the server presented no certificate but sent D-H params * in a ServerKeyExchange message. Use of D-H is specified by the * cipher suite chosen. * * The message optionally contains the client's D-H public key (if * it wasn't not sent in a client certificate). As always with D-H, * if a client and a server have each other's D-H public keys and * they use common algorithm parameters, they have a shared key * that's derived via the D-H calculation. That key becomes the * pre-master secret. */ private SecretKey clientKeyExchange(DHClientKeyExchange mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } return dh.getAgreedSecret(mesg.getClientPublicKey()); } private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } return ecdh.getAgreedSecret(mesg.getEncodedPoint()); } /* * Client wrote a message to verify the certificate it sent earlier. * * Note that this certificate isn't involved in key exchange. Client * authentication messages are included in the checksums used to * validate the handshake (e.g. Finished messages). Other than that, * the _exact_ identity of the client is less fundamental to protocol * security than its role in selecting keys via the pre-master secret. */ private void clientCertificateVerify(CertificateVerify mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } if (protocolVersion.v >= ProtocolVersion.TLS12.v) { SignatureAndHashAlgorithm signAlg = mesg.getPreferableSignatureAlgorithm(); if (signAlg == null) { throw new SSLHandshakeException( "Illegal CertificateVerify message"); } String hashAlg = SignatureAndHashAlgorithm.getHashAlgorithmName(signAlg); if (hashAlg == null || hashAlg.length() == 0) { throw new SSLHandshakeException( "No supported hash algorithm"); } handshakeHash.setCertificateVerifyAlg(hashAlg); } try { PublicKey publicKey = session.getPeerCertificates()[0].getPublicKey(); boolean valid = mesg.verify(protocolVersion, handshakeHash, publicKey, session.getMasterSecret()); if (valid == false) { fatalSE(Alerts.alert_bad_certificate, "certificate verify message signature error"); } } catch (GeneralSecurityException e) { fatalSE(Alerts.alert_bad_certificate, "certificate verify format error", e); } // reset the flag for clientCertificateVerify message needClientVerify = false; } /* * Client writes "finished" at the end of its handshake, after cipher * spec is changed. We verify it and then send ours. * * When we're resuming a session, we'll have already sent our own * Finished message so just the verification is needed. */ private void clientFinished(Finished mesg) throws IOException { if (debug != null && Debug.isOn("handshake")) { mesg.print(System.out); } /* * Verify if client did send the certificate when client * authentication was required, otherwise server should not proceed */ if (doClientAuth == SSLEngineImpl.clauth_required) { // get X500Principal of the end-entity certificate for X509-based // ciphersuites, or Kerberos principal for Kerberos ciphersuites session.getPeerPrincipal(); } /* * Verify if client did send clientCertificateVerify message following * the client Certificate, otherwise server should not proceed */ if (needClientVerify) { fatalSE(Alerts.alert_handshake_failure, "client did not send certificate verify message"); } /* * Verify the client's message with the "before" digest of messages, * and forget about continuing to use that digest. */ boolean verified = mesg.verify(handshakeHash, Finished.CLIENT, session.getMasterSecret()); if (!verified) { fatalSE(Alerts.alert_handshake_failure, "client 'finished' message doesn't verify"); // NOTREACHED } /* * save client verify data for secure renegotiation */ if (secureRenegotiation) { clientVerifyData = mesg.getVerifyData(); } /* * OK, it verified. If we're doing the full handshake, add that * "Finished" message to the hash of handshake messages, then send * the change_cipher_spec and Finished message. */ if (!resumingSession) { input.digestNow(); sendChangeCipherAndFinish(true); } /* * Update the session cache only after the handshake completed, else * we're open to an attack against a partially completed handshake. */ session.setLastAccessedTime(System.currentTimeMillis()); if (!resumingSession && session.isRejoinable()) { ((SSLSessionContextImpl)sslContext.engineGetServerSessionContext()) .put(session); if (debug != null && Debug.isOn("session")) { System.out.println(