| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.ssl;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
import java.nio.ByteBuffer;  | 
 | 
import java.security.GeneralSecurityException;  | 
 | 
import java.security.PrivateKey;  | 
 | 
import java.security.PublicKey;  | 
 | 
import java.text.MessageFormat;  | 
 | 
import java.util.Locale;  | 
 | 
import javax.crypto.SecretKey;  | 
 | 
import sun.security.ssl.RSAKeyExchange.EphemeralRSACredentials;  | 
 | 
import sun.security.ssl.RSAKeyExchange.EphemeralRSAPossession;  | 
 | 
import sun.security.ssl.RSAKeyExchange.RSAPremasterSecret;  | 
 | 
import sun.security.ssl.SSLHandshake.HandshakeMessage;  | 
 | 
import sun.security.ssl.X509Authentication.X509Credentials;  | 
 | 
import sun.security.ssl.X509Authentication.X509Possession;  | 
 | 
import sun.misc.HexDumpEncoder;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class RSAClientKeyExchange { | 
 | 
    static final SSLConsumer rsaHandshakeConsumer =  | 
 | 
        new RSAClientKeyExchangeConsumer();  | 
 | 
    static final HandshakeProducer rsaHandshakeProducer =  | 
 | 
        new RSAClientKeyExchangeProducer();  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class RSAClientKeyExchangeMessage extends HandshakeMessage { | 
 | 
        final int protocolVersion;  | 
 | 
        final boolean useTLS10PlusSpec;  | 
 | 
        final byte[] encrypted;  | 
 | 
 | 
 | 
        RSAClientKeyExchangeMessage(HandshakeContext context,  | 
 | 
                RSAPremasterSecret premaster,  | 
 | 
                PublicKey publicKey) throws GeneralSecurityException { | 
 | 
            super(context);  | 
 | 
            this.protocolVersion = context.clientHelloVersion;  | 
 | 
            this.encrypted = premaster.getEncoded(  | 
 | 
                    publicKey, context.sslContext.getSecureRandom());  | 
 | 
            this.useTLS10PlusSpec = ProtocolVersion.useTLS10PlusSpec(  | 
 | 
                    protocolVersion);  | 
 | 
        }  | 
 | 
 | 
 | 
        RSAClientKeyExchangeMessage(HandshakeContext context,  | 
 | 
                ByteBuffer m) throws IOException { | 
 | 
            super(context);  | 
 | 
 | 
 | 
            if (m.remaining() < 2) { | 
 | 
                throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,  | 
 | 
                    "Invalid RSA ClientKeyExchange message: insufficient data");  | 
 | 
            }  | 
 | 
 | 
 | 
            this.protocolVersion = context.clientHelloVersion;  | 
 | 
            this.useTLS10PlusSpec = ProtocolVersion.useTLS10PlusSpec(  | 
 | 
                    protocolVersion);  | 
 | 
            if (useTLS10PlusSpec) { | 
 | 
                this.encrypted = Record.getBytes16(m);  | 
 | 
            } else {     | 
 | 
                this.encrypted = new byte[m.remaining()];  | 
 | 
                m.get(encrypted);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public SSLHandshake handshakeType() { | 
 | 
            return SSLHandshake.CLIENT_KEY_EXCHANGE;  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public int messageLength() { | 
 | 
            if (useTLS10PlusSpec) { | 
 | 
                return encrypted.length + 2;  | 
 | 
            } else { | 
 | 
                return encrypted.length;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void send(HandshakeOutStream hos) throws IOException { | 
 | 
            if (useTLS10PlusSpec) { | 
 | 
                hos.putBytes16(encrypted);  | 
 | 
            } else { | 
 | 
                hos.write(encrypted);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public String toString() { | 
 | 
            MessageFormat messageFormat = new MessageFormat(  | 
 | 
                "\"RSA ClientKeyExchange\": '{'\n" + | 
 | 
                "  \"client_version\":  {0}\n" + | 
 | 
                "  \"encncrypted\": '{'\n" + | 
 | 
                "{1}\n" + | 
 | 
                "  '}'\n" +  | 
 | 
                "'}'",  | 
 | 
                Locale.ENGLISH);  | 
 | 
 | 
 | 
            HexDumpEncoder hexEncoder = new HexDumpEncoder();  | 
 | 
            Object[] messageFields = { | 
 | 
                ProtocolVersion.nameOf(protocolVersion),  | 
 | 
                Utilities.indent(  | 
 | 
                        hexEncoder.encodeBuffer(encrypted), "    "),  | 
 | 
            };  | 
 | 
            return messageFormat.format(messageFields);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class RSAClientKeyExchangeProducer implements HandshakeProducer { | 
 | 
          | 
 | 
        private RSAClientKeyExchangeProducer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public byte[] produce(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
            EphemeralRSACredentials rsaCredentials = null;  | 
 | 
            X509Credentials x509Credentials = null;  | 
 | 
            for (SSLCredentials credential : chc.handshakeCredentials) { | 
 | 
                if (credential instanceof EphemeralRSACredentials) { | 
 | 
                    rsaCredentials = (EphemeralRSACredentials)credential;  | 
 | 
                    if (x509Credentials != null) { | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                } else if (credential instanceof X509Credentials) { | 
 | 
                    x509Credentials = (X509Credentials)credential;  | 
 | 
                    if (rsaCredentials != null) { | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            if (rsaCredentials == null && x509Credentials == null) { | 
 | 
                throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,  | 
 | 
                    "No RSA credentials negotiated for client key exchange");  | 
 | 
            }  | 
 | 
 | 
 | 
            PublicKey publicKey = (rsaCredentials != null) ?  | 
 | 
                    rsaCredentials.popPublicKey : x509Credentials.popPublicKey;  | 
 | 
            if (!publicKey.getAlgorithm().equals("RSA")) {       | 
 | 
                throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,  | 
 | 
                    "Not RSA public key for client key exchange");  | 
 | 
            }  | 
 | 
 | 
 | 
            RSAPremasterSecret premaster;  | 
 | 
            RSAClientKeyExchangeMessage ckem;  | 
 | 
            try { | 
 | 
                premaster = RSAPremasterSecret.createPremasterSecret(chc);  | 
 | 
                chc.handshakePossessions.add(premaster);  | 
 | 
                ckem = new RSAClientKeyExchangeMessage(  | 
 | 
                        chc, premaster, publicKey);  | 
 | 
            } catch (GeneralSecurityException gse) { | 
 | 
                throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,  | 
 | 
                        "Cannot generate RSA premaster secret", gse);  | 
 | 
            }  | 
 | 
            if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                SSLLogger.fine(  | 
 | 
                    "Produced RSA ClientKeyExchange handshake message", ckem);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            ckem.write(chc.handshakeOutput);  | 
 | 
            chc.handshakeOutput.flush();  | 
 | 
 | 
 | 
              | 
 | 
            SSLKeyExchange ke = SSLKeyExchange.valueOf(  | 
 | 
                    chc.negotiatedCipherSuite.keyExchange,  | 
 | 
                    chc.negotiatedProtocol);  | 
 | 
            if (ke == null) {    | 
 | 
                throw chc.conContext.fatal(Alert.INTERNAL_ERROR,  | 
 | 
                        "Not supported key exchange type");  | 
 | 
            } else { | 
 | 
                SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);  | 
 | 
                SecretKey masterSecret =  | 
 | 
                        masterKD.deriveKey("MasterSecret", null); | 
 | 
 | 
 | 
                  | 
 | 
                chc.handshakeSession.setMasterSecret(masterSecret);  | 
 | 
                SSLTrafficKeyDerivation kd =  | 
 | 
                        SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);  | 
 | 
                if (kd == null) {    | 
 | 
                    throw chc.conContext.fatal(Alert.INTERNAL_ERROR,  | 
 | 
                            "Not supported key derivation: " +  | 
 | 
                            chc.negotiatedProtocol);  | 
 | 
                } else { | 
 | 
                    chc.handshakeKeyDerivation =  | 
 | 
                        kd.createKeyDerivation(chc, masterSecret);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class RSAClientKeyExchangeConsumer implements SSLConsumer { | 
 | 
          | 
 | 
        private RSAClientKeyExchangeConsumer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
                ByteBuffer message) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
            EphemeralRSAPossession rsaPossession = null;  | 
 | 
            X509Possession x509Possession = null;  | 
 | 
            for (SSLPossession possession : shc.handshakePossessions) { | 
 | 
                if (possession instanceof EphemeralRSAPossession) { | 
 | 
                    rsaPossession = (EphemeralRSAPossession)possession;  | 
 | 
                    break;  | 
 | 
                } else if (possession instanceof X509Possession) { | 
 | 
                    x509Possession = (X509Possession)possession;  | 
 | 
                    if (rsaPossession != null) { | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            if (rsaPossession == null && x509Possession == null) {   | 
 | 
                throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,  | 
 | 
                    "No RSA possessions negotiated for client key exchange");  | 
 | 
            }  | 
 | 
 | 
 | 
            PrivateKey privateKey = (rsaPossession != null) ?  | 
 | 
                    rsaPossession.popPrivateKey : x509Possession.popPrivateKey;  | 
 | 
            if (!privateKey.getAlgorithm().equals("RSA")) {      | 
 | 
                throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,  | 
 | 
                    "Not RSA private key for client key exchange");  | 
 | 
            }  | 
 | 
 | 
 | 
            RSAClientKeyExchangeMessage ckem =  | 
 | 
                    new RSAClientKeyExchangeMessage(shc, message);  | 
 | 
            if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                SSLLogger.fine(  | 
 | 
                    "Consuming RSA ClientKeyExchange handshake message", ckem);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            RSAPremasterSecret premaster;  | 
 | 
            try { | 
 | 
                premaster =  | 
 | 
                    RSAPremasterSecret.decode(shc, privateKey, ckem.encrypted);  | 
 | 
                shc.handshakeCredentials.add(premaster);  | 
 | 
            } catch (GeneralSecurityException gse) { | 
 | 
                throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,  | 
 | 
                    "Cannot decode RSA premaster secret", gse);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            SSLKeyExchange ke = SSLKeyExchange.valueOf(  | 
 | 
                    shc.negotiatedCipherSuite.keyExchange,  | 
 | 
                    shc.negotiatedProtocol);  | 
 | 
            if (ke == null) {    | 
 | 
                throw shc.conContext.fatal(Alert.INTERNAL_ERROR,  | 
 | 
                        "Not supported key exchange type");  | 
 | 
            } else { | 
 | 
                SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);  | 
 | 
                SecretKey masterSecret =  | 
 | 
                        masterKD.deriveKey("MasterSecret", null); | 
 | 
 | 
 | 
                  | 
 | 
                shc.handshakeSession.setMasterSecret(masterSecret);  | 
 | 
                SSLTrafficKeyDerivation kd =  | 
 | 
                        SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);  | 
 | 
                if (kd == null) {        | 
 | 
                    throw shc.conContext.fatal(Alert.INTERNAL_ERROR,  | 
 | 
                            "Not supported key derivation: " +  | 
 | 
                            shc.negotiatedProtocol);  | 
 | 
                } else { | 
 | 
                    shc.handshakeKeyDerivation =  | 
 | 
                        kd.createKeyDerivation(shc, masterSecret);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |