2006 lines · 67.7 KB · Java
RawDownload
 * 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