* implies one of several different kinds of key exchange. Most current * cipher suites require the server to send more than its certificate. * * The primary exceptions are when a server sends an encryption-capable * RSA public key in its cert, to be used with RSA (or RSA_export) key * exchange; and when a server sends its Diffie-Hellman cert. Those kinds * of key exchange do not require a ServerKeyExchange message. * * Key exchange can be viewed as having three modes, which are explicit * for the Diffie-Hellman flavors and poorly specified for RSA ones: * * - "Ephemeral" keys. Here, a "temporary" key is allocated by the * server, and signed. Diffie-Hellman keys signed using RSA or * DSS are ephemeral (DHE flavor). RSA keys get used to do the same * thing, to cut the key size down to 512 bits (export restrictions) * or for signing-only RSA certificates. * * - Anonymity. Here no server certificate is sent, only the public * key of the server. This case is subject to man-in-the-middle * attacks. This can be done with Diffie-Hellman keys (DH_anon) or * with RSA keys, but is only used in SSLv3 for DH_anon. * * - "Normal" case. Here a server certificate is sent, and the public * key there is used directly in exchanging the premaster secret. * For example, Diffie-Hellman "DH" flavor, and any RSA flavor with * only 512 bit keys. * * If a server certificate is sent, there is no anonymity. However, * when a certificate is sent, ephemeral keys may still be used to * exchange the premaster secret. That's how RSA_EXPORT often works, * as well as how the DHE_* flavors work. */static abstract class ServerKeyExchange extends HandshakeMessage{ int messageType() { return ht_server_key_exchange; }} /* * Using RSA for Key Exchange: exchange a session key that's not as big * as the signing-only key. Used for export applications, since exported * RSA encryption keys can't be bigger than 512 bytes. * * This is never used when keys are 512 bits or smaller, and isn't used * on "US Domestic" ciphers in any case. */static finalclass RSA_ServerKeyExchange extends ServerKeyExchange{ private byte rsa_modulus[]; // 1 to 2^16 - 1 bytes private byte rsa_exponent[]; // 1 to 2^16 - 1 bytes private Signature signature; private byte[] signatureBytes; /* * Hash the nonces and the ephemeral RSA public key. */ private void updateSignature(byte clntNonce[], byte svrNonce[]) throws SignatureException { int tmp; signature.update(clntNonce); signature.update(svrNonce); tmp = rsa_modulus.length; signature.update((byte)(tmp >> 8)); signature.update((byte)(tmp & 0x0ff)); signature.update(rsa_modulus); tmp = rsa_exponent.length; signature.update((byte)(tmp >> 8)); signature.update((byte)(tmp & 0x0ff)); signature.update(rsa_exponent); } /* * Construct an RSA server key exchange message, using data * known _only_ to the server. * * The client knows the public key corresponding to this private * key, from the Certificate message sent previously. To comply * with US export regulations we use short RSA keys ... either * long term ones in the server's X509 cert, or else ephemeral * ones sent using this message. */ RSA_ServerKeyExchange(PublicKey ephemeralKey, PrivateKey privateKey, RandomCookie clntNonce, RandomCookie svrNonce, SecureRandom sr) throws GeneralSecurityException { RSAPublicKeySpec rsaKey = JsseJce.getRSAPublicKeySpec(ephemeralKey); rsa_modulus = toByteArray(rsaKey.getModulus()); rsa_exponent = toByteArray(rsaKey.getPublicExponent()); signature = RSASignature.getInstance(); signature.initSign(privateKey, sr); updateSignature(clntNonce.random_bytes, svrNonce.random_bytes); signatureBytes = signature.sign(); } /* * Parse an RSA server key exchange message, using data known * to the client (and, in some situations, eavesdroppers). */ RSA_ServerKeyExchange(HandshakeInStream input) throws IOException, NoSuchAlgorithmException { signature = RSASignature.getInstance(); rsa_modulus = input.getBytes16(); rsa_exponent = input.getBytes16(); signatureBytes = input.getBytes16(); } /* * Get the ephemeral RSA public key that will be used in this * SSL connection. */ PublicKey getPublicKey() { try { KeyFactory kfac = JsseJce.getKeyFactory("RSA"); // modulus and exponent are always positive RSAPublicKeySpec kspec = new RSAPublicKeySpec( new BigInteger(1, rsa_modulus), new BigInteger(1, rsa_exponent)); return kfac.generatePublic(kspec); } catch (Exception e) { throw new RuntimeException(e); } } /* * Verify the signed temporary key using the hashes computed * from it and the two nonces. This is called by clients * with "exportable" RSA flavors. */ boolean verify(PublicKey certifiedKey, RandomCookie clntNonce, RandomCookie svrNonce) throws GeneralSecurityException { signature.initVerify(certifiedKey); updateSignature(clntNonce.random_bytes, svrNonce.random_bytes); return signature.verify(signatureBytes); } int messageLength() { return 6 + rsa_modulus.length + rsa_exponent.length + signatureBytes.length; } void send(HandshakeOutStream s) throws IOException { s.putBytes16(rsa_modulus); s.putBytes16(rsa_exponent); s.putBytes16(signatureBytes); } void print(PrintStream s) throws IOException { s.println("*** RSA ServerKeyExchange"); if (debug != null && Debug.isOn("verbose")) { Debug.println(s, "RSA Modulus", rsa_modulus); Debug.println(s, "RSA Public Exponent", rsa_exponent); } }} /* * Using Diffie-Hellman algorithm for key exchange. All we really need to * do is securely get Diffie-Hellman keys (using the same P, G parameters) * to our peer, then we automatically have a shared secret without need * to exchange any more data. (D-H only solutions, such as SKIP, could * eliminate key exchange negotiations and get faster connection setup. * But they still need a signature algorithm like DSS/DSA to support the * trusted distribution of keys without relying on unscalable physical * key distribution systems.) * * This class supports several DH-based key exchange algorithms, though * perhaps eventually each deserves its own class. Notably, this has * basic support for DH_anon and its DHE_DSS and DHE_RSA signed variants. */static finalclass DH_ServerKeyExchange extends ServerKeyExchange{ // Fix message encoding, see 4348279 private final static boolean dhKeyExchangeFix = Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true); private byte dh_p []; // 1 to 2^16 - 1 bytes private byte dh_g []; // 1 to 2^16 - 1 bytes private byte dh_Ys []; // 1 to 2^16 - 1 bytes private byte signature []; // protocol version being established using this ServerKeyExchange message ProtocolVersion protocolVersion; // the preferable signature algorithm used by this ServerKeyExchange message private SignatureAndHashAlgorithm preferableSignatureAlgorithm; /* * Construct from initialized DH key object, for DH_anon * key exchange. */ DH_ServerKeyExchange(DHCrypt obj, ProtocolVersion protocolVersion) { this.protocolVersion = protocolVersion; this.preferableSignatureAlgorithm = null; setValues(obj); signature = null; } /* * Construct from initialized DH key object and the key associated * with the cert chain which was sent ... for DHE_DSS and DHE_RSA * key exchange. (Constructor called by server.) */ DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[], byte svrNonce[], SecureRandom sr, SignatureAndHashAlgorithm signAlgorithm, ProtocolVersion protocolVersion) throws GeneralSecurityException { this.protocolVersion = protocolVersion; setValues(obj); Signature sig; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { this.preferableSignatureAlgorithm = signAlgorithm; sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName()); } else { this.preferableSignatureAlgorithm = null; if (key.getAlgorithm().equals("DSA")) { sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA); } else { sig = RSASignature.getInstance(); } } sig.initSign(key, sr); updateSignature(sig, clntNonce, svrNonce); signature = sig.sign(); } /* * Construct a DH_ServerKeyExchange message from an input * stream, as if sent from server to client for use with * DH_anon key exchange */ DH_ServerKeyExchange(HandshakeInStream input, ProtocolVersion protocolVersion) throws IOException { this.protocolVersion = protocolVersion; this.preferableSignatureAlgorithm = null; dh_p = input.getBytes16(); dh_g = input.getBytes16(); dh_Ys = input.getBytes16(); signature = null; } /* * Construct a DH_ServerKeyExchange message from an input stream * and a certificate, as if sent from server to client for use with * DHE_DSS or DHE_RSA key exchange. (Called by client.) */ DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey, byte clntNonce[], byte svrNonce[], int messageSize, Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs, ProtocolVersion protocolVersion) throws IOException, GeneralSecurityException { this.protocolVersion = protocolVersion; // read params: ServerDHParams dh_p = input.getBytes16(); dh_g = input.getBytes16(); dh_Ys = input.getBytes16(); // read the signature and hash algorithm if (protocolVersion.v >= ProtocolVersion.TLS12.v) { int hash = input.getInt8(); // hash algorithm int signature = input.getInt8(); // signature algorithm preferableSignatureAlgorithm = SignatureAndHashAlgorithm.valueOf(hash, signature, 0); // Is it a local supported signature algorithm? if (!localSupportedSignAlgs.contains( preferableSignatureAlgorithm)) { throw new SSLHandshakeException( "Unsupported SignatureAndHashAlgorithm in " + "ServerKeyExchange message"); } } else { this.preferableSignatureAlgorithm = null; } // read the signature byte signature[]; if (dhKeyExchangeFix) { signature = input.getBytes16(); } else { messageSize -= (dh_p.length + 2); messageSize -= (dh_g.length + 2); messageSize -= (dh_Ys.length + 2); signature = new byte[messageSize]; input.read(signature); } Signature sig; String algorithm = publicKey.getAlgorithm(); if (protocolVersion.v >= ProtocolVersion.TLS12.v) { sig = JsseJce.getSignature( preferableSignatureAlgorithm.getAlgorithmName()); } else { if (algorithm.equals("DSA")) { sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA); } else if (algorithm.equals("RSA")) { sig = RSASignature.getInstance(); } else { throw new SSLKeyException("neither an RSA or a DSA key"); } } sig.initVerify(publicKey); updateSignature(sig, clntNonce, svrNonce); if (sig.verify(signature) == false ) { throw new SSLKeyException("Server D-H key verification failed"); } } /* Return the Diffie-Hellman modulus */ BigInteger getModulus() { return new BigInteger(1, dh_p); } /* Return the Diffie-Hellman base/generator */ BigInteger getBase() { return new BigInteger(1, dh_g); } /* Return the server's Diffie-Hellman public key */ BigInteger getServerPublicKey() { return new BigInteger(1, dh_Ys); } /* * Update sig with nonces and Diffie-Hellman public key. */ private void updateSignature(Signature sig, byte clntNonce[], byte svrNonce[]) throws SignatureException { int tmp; sig.update(clntNonce); sig.update(svrNonce); tmp = dh_p.length; sig.update((byte)(tmp >> 8)); sig.update((byte)(tmp & 0x0ff)); sig.update(dh_p); tmp = dh_g.length; sig.update((byte)(tmp >> 8)); sig.update((byte)(tmp & 0x0ff)); sig.update(dh_g); tmp = dh_Ys.length; sig.update((byte)(tmp >> 8)); sig.update((byte)(tmp & 0x0ff)); sig.update(dh_Ys); } private void setValues(DHCrypt obj) { dh_p = toByteArray(obj.getModulus()); dh_g = toByteArray(obj.getBase()); dh_Ys = toByteArray(obj.getPublicKey()); } int messageLength() { int temp = 6; // overhead for p, g, y(s) values. temp += dh_p.length; temp += dh_g.length; temp += dh_Ys.length; if (signature != null) { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { temp += SignatureAndHashAlgorithm.sizeInRecord(); } temp += signature.length; if (dhKeyExchangeFix) { temp += 2; } } return temp; } void send(HandshakeOutStream s) throws IOException { s.putBytes16(dh_p); s.putBytes16(dh_g); s.putBytes16(dh_Ys); if (signature != null) { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.putInt8(preferableSignatureAlgorithm.getHashValue()); s.putInt8(preferableSignatureAlgorithm.getSignatureValue()); } if (dhKeyExchangeFix) { s.putBytes16(signature); } else { s.write(signature); } } } void print(PrintStream s) throws IOException { s.println("*** Diffie-Hellman ServerKeyExchange"); if (debug != null && Debug.isOn("verbose")) { Debug.println(s, "DH Modulus", dh_p); Debug.println(s, "DH Base", dh_g); Debug.println(s, "Server DH Public Key", dh_Ys); if (signature == null) { s.println("Anonymous"); } else { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.println("Signature Algorithm " + preferableSignatureAlgorithm.getAlgorithmName()); } s.println("Signed with a DSA or RSA public key"); } } }} /* * ECDH server key exchange message. Sent by the server for ECDHE and ECDH_anon * ciphersuites to communicate its ephemeral public key (including the * EC domain parameters). * * We support named curves only, no explicitly encoded curves. */static finalclass ECDH_ServerKeyExchange extends ServerKeyExchange { // constants for ECCurveType private final static int CURVE_EXPLICIT_PRIME = 1; private final static int CURVE_EXPLICIT_CHAR2 = 2; private final static int CURVE_NAMED_CURVE = 3; // id of the curve we are using private int curveId; // encoded public point private byte[] pointBytes; // signature bytes (or null if anonymous) private byte[] signatureBytes; // public key object encapsulated in this message private ECPublicKey publicKey; // protocol version being established using this ServerKeyExchange message ProtocolVersion protocolVersion; // the preferable signature algorithm used by this ServerKeyExchange message private SignatureAndHashAlgorithm preferableSignatureAlgorithm; ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey, byte[] clntNonce, byte[] svrNonce, SecureRandom sr, SignatureAndHashAlgorithm signAlgorithm, ProtocolVersion protocolVersion) throws GeneralSecurityException { this.protocolVersion = protocolVersion; publicKey = (ECPublicKey)obj.getPublicKey(); ECParameterSpec params = publicKey.getParams(); ECPoint point = publicKey.getW(); pointBytes = JsseJce.encodePoint(point, params.getCurve()); curveId = SupportedEllipticCurvesExtension.getCurveIndex(params); if (privateKey == null) { // ECDH_anon return; } Signature sig; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { this.preferableSignatureAlgorithm = signAlgorithm; sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName()); } else { sig = getSignature(privateKey.getAlgorithm()); } sig.initSign(privateKey); // where is the SecureRandom? updateSignature(sig, clntNonce, svrNonce); signatureBytes = sig.sign();Lines 501–1000 of 2006. Previous lines Load more
* implies one of several different kinds of key exchange. Most current * cipher suites require the server to send more than its certificate. * * The primary exceptions are when a server sends an encryption-capable * RSA public key in its cert, to be used with RSA (or RSA_export) key * exchange; and when a server sends its Diffie-Hellman cert. Those kinds * of key exchange do not require a ServerKeyExchange message. * * Key exchange can be viewed as having three modes, which are explicit * for the Diffie-Hellman flavors and poorly specified for RSA ones: * * - "Ephemeral" keys. Here, a "temporary" key is allocated by the * server, and signed. Diffie-Hellman keys signed using RSA or * DSS are ephemeral (DHE flavor). RSA keys get used to do the same * thing, to cut the key size down to 512 bits (export restrictions) * or for signing-only RSA certificates. * * - Anonymity. Here no server certificate is sent, only the public * key of the server. This case is subject to man-in-the-middle * attacks. This can be done with Diffie-Hellman keys (DH_anon) or * with RSA keys, but is only used in SSLv3 for DH_anon. * * - "Normal" case. Here a server certificate is sent, and the public * key there is used directly in exchanging the premaster secret. * For example, Diffie-Hellman "DH" flavor, and any RSA flavor with * only 512 bit keys. * * If a server certificate is sent, there is no anonymity. However, * when a certificate is sent, ephemeral keys may still be used to * exchange the premaster secret. That's how RSA_EXPORT often works, * as well as how the DHE_* flavors work. */ static abstract class ServerKeyExchange extends HandshakeMessage { int messageType() { return ht_server_key_exchange; } } /* * Using RSA for Key Exchange: exchange a session key that's not as big * as the signing-only key. Used for export applications, since exported * RSA encryption keys can't be bigger than 512 bytes. * * This is never used when keys are 512 bits or smaller, and isn't used * on "US Domestic" ciphers in any case. */ static final class RSA_ServerKeyExchange extends ServerKeyExchange { private byte rsa_modulus[]; // 1 to 2^16 - 1 bytes private byte rsa_exponent[]; // 1 to 2^16 - 1 bytes private Signature signature; private byte[] signatureBytes; /* * Hash the nonces and the ephemeral RSA public key. */ private void updateSignature(byte clntNonce[], byte svrNonce[]) throws SignatureException { int tmp; signature.update(clntNonce); signature.update(svrNonce); tmp = rsa_modulus.length; signature.update((byte)(tmp >> 8)); signature.update((byte)(tmp & 0x0ff)); signature.update(rsa_modulus); tmp = rsa_exponent.length; signature.update((byte)(tmp >> 8)); signature.update((byte)(tmp & 0x0ff)); signature.update(rsa_exponent); } /* * Construct an RSA server key exchange message, using data * known _only_ to the server. * * The client knows the public key corresponding to this private * key, from the Certificate message sent previously. To comply * with US export regulations we use short RSA keys ... either * long term ones in the server's X509 cert, or else ephemeral * ones sent using this message. */ RSA_ServerKeyExchange(PublicKey ephemeralKey, PrivateKey privateKey, RandomCookie clntNonce, RandomCookie svrNonce, SecureRandom sr) throws GeneralSecurityException { RSAPublicKeySpec rsaKey = JsseJce.getRSAPublicKeySpec(ephemeralKey); rsa_modulus = toByteArray(rsaKey.getModulus()); rsa_exponent = toByteArray(rsaKey.getPublicExponent()); signature = RSASignature.getInstance(); signature.initSign(privateKey, sr); updateSignature(clntNonce.random_bytes, svrNonce.random_bytes); signatureBytes = signature.sign(); } /* * Parse an RSA server key exchange message, using data known * to the client (and, in some situations, eavesdroppers). */ RSA_ServerKeyExchange(HandshakeInStream input) throws IOException, NoSuchAlgorithmException { signature = RSASignature.getInstance(); rsa_modulus = input.getBytes16(); rsa_exponent = input.getBytes16(); signatureBytes = input.getBytes16(); } /* * Get the ephemeral RSA public key that will be used in this * SSL connection. */ PublicKey getPublicKey() { try { KeyFactory kfac = JsseJce.getKeyFactory("RSA"); // modulus and exponent are always positive RSAPublicKeySpec kspec = new RSAPublicKeySpec( new BigInteger(1, rsa_modulus), new BigInteger(1, rsa_exponent)); return kfac.generatePublic(kspec); } catch (Exception e) { throw new RuntimeException(e); } } /* * Verify the signed temporary key using the hashes computed * from it and the two nonces. This is called by clients * with "exportable" RSA flavors. */ boolean verify(PublicKey certifiedKey, RandomCookie clntNonce, RandomCookie svrNonce) throws GeneralSecurityException { signature.initVerify(certifiedKey); updateSignature(clntNonce.random_bytes, svrNonce.random_bytes); return signature.verify(signatureBytes); } int messageLength() { return 6 + rsa_modulus.length + rsa_exponent.length + signatureBytes.length; } void send(HandshakeOutStream s) throws IOException { s.putBytes16(rsa_modulus); s.putBytes16(rsa_exponent); s.putBytes16(signatureBytes); } void print(PrintStream s) throws IOException { s.println("*** RSA ServerKeyExchange"); if (debug != null && Debug.isOn("verbose")) { Debug.println(s, "RSA Modulus", rsa_modulus); Debug.println(s, "RSA Public Exponent", rsa_exponent); } } } /* * Using Diffie-Hellman algorithm for key exchange. All we really need to * do is securely get Diffie-Hellman keys (using the same P, G parameters) * to our peer, then we automatically have a shared secret without need * to exchange any more data. (D-H only solutions, such as SKIP, could * eliminate key exchange negotiations and get faster connection setup. * But they still need a signature algorithm like DSS/DSA to support the * trusted distribution of keys without relying on unscalable physical * key distribution systems.) * * This class supports several DH-based key exchange algorithms, though * perhaps eventually each deserves its own class. Notably, this has * basic support for DH_anon and its DHE_DSS and DHE_RSA signed variants. */ static final class DH_ServerKeyExchange extends ServerKeyExchange { // Fix message encoding, see 4348279 private final static boolean dhKeyExchangeFix = Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true); private byte dh_p []; // 1 to 2^16 - 1 bytes private byte dh_g []; // 1 to 2^16 - 1 bytes private byte dh_Ys []; // 1 to 2^16 - 1 bytes private byte signature []; // protocol version being established using this ServerKeyExchange message ProtocolVersion protocolVersion; // the preferable signature algorithm used by this ServerKeyExchange message private SignatureAndHashAlgorithm preferableSignatureAlgorithm; /* * Construct from initialized DH key object, for DH_anon * key exchange. */ DH_ServerKeyExchange(DHCrypt obj, ProtocolVersion protocolVersion) { this.protocolVersion = protocolVersion; this.preferableSignatureAlgorithm = null; setValues(obj); signature = null; } /* * Construct from initialized DH key object and the key associated * with the cert chain which was sent ... for DHE_DSS and DHE_RSA * key exchange. (Constructor called by server.) */ DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[], byte svrNonce[], SecureRandom sr, SignatureAndHashAlgorithm signAlgorithm, ProtocolVersion protocolVersion) throws GeneralSecurityException { this.protocolVersion = protocolVersion; setValues(obj); Signature sig; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { this.preferableSignatureAlgorithm = signAlgorithm; sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName()); } else { this.preferableSignatureAlgorithm = null; if (key.getAlgorithm().equals("DSA")) { sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA); } else { sig = RSASignature.getInstance(); } } sig.initSign(key, sr); updateSignature(sig, clntNonce, svrNonce); signature = sig.sign(); } /* * Construct a DH_ServerKeyExchange message from an input * stream, as if sent from server to client for use with * DH_anon key exchange */ DH_ServerKeyExchange(HandshakeInStream input, ProtocolVersion protocolVersion) throws IOException { this.protocolVersion = protocolVersion; this.preferableSignatureAlgorithm = null; dh_p = input.getBytes16(); dh_g = input.getBytes16(); dh_Ys = input.getBytes16(); signature = null; } /* * Construct a DH_ServerKeyExchange message from an input stream * and a certificate, as if sent from server to client for use with * DHE_DSS or DHE_RSA key exchange. (Called by client.) */ DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey, byte clntNonce[], byte svrNonce[], int messageSize, Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs, ProtocolVersion protocolVersion) throws IOException, GeneralSecurityException { this.protocolVersion = protocolVersion; // read params: ServerDHParams dh_p = input.getBytes16(); dh_g = input.getBytes16(); dh_Ys = input.getBytes16(); // read the signature and hash algorithm if (protocolVersion.v >= ProtocolVersion.TLS12.v) { int hash = input.getInt8(); // hash algorithm int signature = input.getInt8(); // signature algorithm preferableSignatureAlgorithm = SignatureAndHashAlgorithm.valueOf(hash, signature, 0); // Is it a local supported signature algorithm? if (!localSupportedSignAlgs.contains( preferableSignatureAlgorithm)) { throw new SSLHandshakeException( "Unsupported SignatureAndHashAlgorithm in " + "ServerKeyExchange message"); } } else { this.preferableSignatureAlgorithm = null; } // read the signature byte signature[]; if (dhKeyExchangeFix) { signature = input.getBytes16(); } else { messageSize -= (dh_p.length + 2); messageSize -= (dh_g.length + 2); messageSize -= (dh_Ys.length + 2); signature = new byte[messageSize]; input.read(signature); } Signature sig; String algorithm = publicKey.getAlgorithm(); if (protocolVersion.v >= ProtocolVersion.TLS12.v) { sig = JsseJce.getSignature( preferableSignatureAlgorithm.getAlgorithmName()); } else { if (algorithm.equals("DSA")) { sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA); } else if (algorithm.equals("RSA")) { sig = RSASignature.getInstance(); } else { throw new SSLKeyException("neither an RSA or a DSA key"); } } sig.initVerify(publicKey); updateSignature(sig, clntNonce, svrNonce); if (sig.verify(signature) == false ) { throw new SSLKeyException("Server D-H key verification failed"); } } /* Return the Diffie-Hellman modulus */ BigInteger getModulus() { return new BigInteger(1, dh_p); } /* Return the Diffie-Hellman base/generator */ BigInteger getBase() { return new BigInteger(1, dh_g); } /* Return the server's Diffie-Hellman public key */ BigInteger getServerPublicKey() { return new BigInteger(1, dh_Ys); } /* * Update sig with nonces and Diffie-Hellman public key. */ private void updateSignature(Signature sig, byte clntNonce[], byte svrNonce[]) throws SignatureException { int tmp; sig.update(clntNonce); sig.update(svrNonce); tmp = dh_p.length; sig.update((byte)(tmp >> 8)); sig.update((byte)(tmp & 0x0ff)); sig.update(dh_p); tmp = dh_g.length; sig.update((byte)(tmp >> 8)); sig.update((byte)(tmp & 0x0ff)); sig.update(dh_g); tmp = dh_Ys.length; sig.update((byte)(tmp >> 8)); sig.update((byte)(tmp & 0x0ff)); sig.update(dh_Ys); } private void setValues(DHCrypt obj) { dh_p = toByteArray(obj.getModulus()); dh_g = toByteArray(obj.getBase()); dh_Ys = toByteArray(obj.getPublicKey()); } int messageLength() { int temp = 6; // overhead for p, g, y(s) values. temp += dh_p.length; temp += dh_g.length; temp += dh_Ys.length; if (signature != null) { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { temp += SignatureAndHashAlgorithm.sizeInRecord(); } temp += signature.length; if (dhKeyExchangeFix) { temp += 2; } } return temp; } void send(HandshakeOutStream s) throws IOException { s.putBytes16(dh_p); s.putBytes16(dh_g); s.putBytes16(dh_Ys); if (signature != null) { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.putInt8(preferableSignatureAlgorithm.getHashValue()); s.putInt8(preferableSignatureAlgorithm.getSignatureValue()); } if (dhKeyExchangeFix) { s.putBytes16(signature); } else { s.write(signature); } } } void print(PrintStream s) throws IOException { s.println("*** Diffie-Hellman ServerKeyExchange"); if (debug != null && Debug.isOn("verbose")) { Debug.println(s, "DH Modulus", dh_p); Debug.println(s, "DH Base", dh_g); Debug.println(s, "Server DH Public Key", dh_Ys); if (signature == null) { s.println("Anonymous"); } else { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.println("Signature Algorithm " + preferableSignatureAlgorithm.getAlgorithmName()); } s.println("Signed with a DSA or RSA public key"); } } } } /* * ECDH server key exchange message. Sent by the server for ECDHE and ECDH_anon * ciphersuites to communicate its ephemeral public key (including the * EC domain parameters). * * We support named curves only, no explicitly encoded curves. */ static final class ECDH_ServerKeyExchange extends ServerKeyExchange { // constants for ECCurveType private final static int CURVE_EXPLICIT_PRIME = 1; private final static int CURVE_EXPLICIT_CHAR2 = 2; private final static int CURVE_NAMED_CURVE = 3; // id of the curve we are using private int curveId; // encoded public point private byte[] pointBytes; // signature bytes (or null if anonymous) private byte[] signatureBytes; // public key object encapsulated in this message private ECPublicKey publicKey; // protocol version being established using this ServerKeyExchange message ProtocolVersion protocolVersion; // the preferable signature algorithm used by this ServerKeyExchange message private SignatureAndHashAlgorithm preferableSignatureAlgorithm; ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey, byte[] clntNonce, byte[] svrNonce, SecureRandom sr, SignatureAndHashAlgorithm signAlgorithm, ProtocolVersion protocolVersion) throws GeneralSecurityException { this.protocolVersion = protocolVersion; publicKey = (ECPublicKey)obj.getPublicKey(); ECParameterSpec params = publicKey.getParams(); ECPoint point = publicKey.getW(); pointBytes = JsseJce.encodePoint(point, params.getCurve()); curveId = SupportedEllipticCurvesExtension.getCurveIndex(params); if (privateKey == null) { // ECDH_anon return; } Signature sig; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { this.preferableSignatureAlgorithm = signAlgorithm; sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName()); } else { sig = getSignature(privateKey.getAlgorithm()); } sig.initSign(privateKey); // where is the SecureRandom? updateSignature(sig, clntNonce, svrNonce); signatureBytes = sig.sign();