0N/A/*
5357N/A * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.ssl;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.math.BigInteger;
0N/Aimport java.security.*;
0N/Aimport java.security.interfaces.*;
0N/Aimport java.security.spec.*;
0N/Aimport java.security.cert.*;
0N/Aimport java.security.cert.Certificate;
0N/Aimport java.util.*;
0N/Aimport java.util.concurrent.ConcurrentHashMap;
0N/A
0N/Aimport java.lang.reflect.*;
0N/A
0N/Aimport javax.security.auth.x500.X500Principal;
0N/A
0N/Aimport javax.crypto.KeyGenerator;
0N/Aimport javax.crypto.SecretKey;
5690N/Aimport javax.crypto.spec.DHPublicKeySpec;
0N/A
0N/Aimport javax.net.ssl.*;
0N/A
0N/Aimport sun.security.internal.spec.TlsPrfParameterSpec;
0N/Aimport sun.security.ssl.CipherSuite.*;
3002N/Aimport static sun.security.ssl.CipherSuite.PRF.*;
5690N/Aimport sun.security.util.KeyUtil;
0N/A
0N/A/**
0N/A * Many data structures are involved in the handshake messages. These
0N/A * classes are used as structures, with public data members. They are
0N/A * not visible outside the SSL package.
0N/A *
0N/A * Handshake messages all have a common header format, and they are all
0N/A * encoded in a "handshake data" SSL record substream. The base class
0N/A * here (HandshakeMessage) provides a common framework and records the
0N/A * SSL record type of the particular handshake message.
0N/A *
0N/A * This file contains subclasses for all the basic handshake messages.
0N/A * All handshake messages know how to encode and decode themselves on
0N/A * SSL streams; this facilitates using the same code on SSL client and
0N/A * server sides, although they don't send and receive the same messages.
0N/A *
0N/A * Messages also know how to print themselves, which is quite handy
0N/A * for debugging. They always identify their type, and can optionally
0N/A * dump all of their content.
0N/A *
0N/A * @author David Brownell
0N/A */
1870N/Apublic abstract class HandshakeMessage {
0N/A
0N/A HandshakeMessage() { }
0N/A
0N/A // enum HandshakeType:
0N/A static final byte ht_hello_request = 0;
0N/A static final byte ht_client_hello = 1;
0N/A static final byte ht_server_hello = 2;
0N/A
0N/A static final byte ht_certificate = 11;
0N/A static final byte ht_server_key_exchange = 12;
0N/A static final byte ht_certificate_request = 13;
0N/A static final byte ht_server_hello_done = 14;
0N/A static final byte ht_certificate_verify = 15;
0N/A static final byte ht_client_key_exchange = 16;
0N/A
0N/A static final byte ht_finished = 20;
0N/A
0N/A /* Class and subclass dynamic debugging support */
1870N/A public static final Debug debug = Debug.getInstance("ssl");
0N/A
0N/A /**
0N/A * Utility method to convert a BigInteger to a byte array in unsigned
0N/A * format as needed in the handshake messages. BigInteger uses
0N/A * 2's complement format, i.e. it prepends an extra zero if the MSB
0N/A * is set. We remove that.
0N/A */
0N/A static byte[] toByteArray(BigInteger bi) {
0N/A byte[] b = bi.toByteArray();
0N/A if ((b.length > 1) && (b[0] == 0)) {
0N/A int n = b.length - 1;
0N/A byte[] newarray = new byte[n];
0N/A System.arraycopy(b, 1, newarray, 0, n);
0N/A b = newarray;
0N/A }
0N/A return b;
0N/A }
0N/A
0N/A /*
0N/A * SSL 3.0 MAC padding constants.
0N/A * Also used by CertificateVerify and Finished during the handshake.
0N/A */
0N/A static final byte[] MD5_pad1 = genPad(0x36, 48);
0N/A static final byte[] MD5_pad2 = genPad(0x5c, 48);
0N/A
0N/A static final byte[] SHA_pad1 = genPad(0x36, 40);
0N/A static final byte[] SHA_pad2 = genPad(0x5c, 40);
0N/A
0N/A private static byte[] genPad(int b, int count) {
0N/A byte[] padding = new byte[count];
0N/A Arrays.fill(padding, (byte)b);
0N/A return padding;
0N/A }
0N/A
0N/A /*
0N/A * Write a handshake message on the (handshake) output stream.
0N/A * This is just a four byte header followed by the data.
0N/A *
0N/A * NOTE that huge messages -- notably, ones with huge cert
0N/A * chains -- are handled correctly.
0N/A */
0N/A final void write(HandshakeOutStream s) throws IOException {
0N/A int len = messageLength();
5357N/A if (len >= Record.OVERFLOW_OF_INT24) {
0N/A throw new SSLException("Handshake message too big"
0N/A + ", type = " + messageType() + ", len = " + len);
0N/A }
0N/A s.write(messageType());
0N/A s.putInt24(len);
0N/A send(s);
0N/A }
0N/A
0N/A /*
0N/A * Subclasses implement these methods so those kinds of
0N/A * messages can be emitted. Base class delegates to subclass.
0N/A */
0N/A abstract int messageType();
0N/A abstract int messageLength();
0N/A abstract void send(HandshakeOutStream s) throws IOException;
0N/A
0N/A /*
0N/A * Write a descriptive message on the output stream; for debugging.
0N/A */
0N/A abstract void print(PrintStream p) throws IOException;
0N/A
0N/A//
0N/A// NOTE: the rest of these classes are nested within this one, and are
0N/A// imported by other classes in this package. There are a few other
0N/A// handshake message classes, not neatly nested here because of current
0N/A// licensing requirement for native (RSA) methods. They belong here,
0N/A// but those native methods complicate things a lot!
0N/A//
0N/A
0N/A
0N/A/*
0N/A * HelloRequest ... SERVER --> CLIENT
0N/A *
0N/A * Server can ask the client to initiate a new handshake, e.g. to change
0N/A * session parameters after a connection has been (re)established.
0N/A */
2890N/Astatic final class HelloRequest extends HandshakeMessage {
0N/A int messageType() { return ht_hello_request; }
0N/A
0N/A HelloRequest() { }
0N/A
0N/A HelloRequest(HandshakeInStream in) throws IOException
0N/A {
0N/A // nothing in this message
0N/A }
0N/A
0N/A int messageLength() { return 0; }
0N/A
0N/A void send(HandshakeOutStream out) throws IOException
0N/A {
0N/A // nothing in this messaage
0N/A }
0N/A
0N/A void print(PrintStream out) throws IOException
0N/A {
0N/A out.println("*** HelloRequest (empty)");
0N/A }
0N/A
0N/A}
0N/A
0N/A
0N/A/*
0N/A * ClientHello ... CLIENT --> SERVER
0N/A *
0N/A * Client initiates handshake by telling server what it wants, and what it
0N/A * can support (prioritized by what's first in the ciphe suite list).
0N/A *
0N/A * By RFC2246:7.4.1.2 it's explicitly anticipated that this message
0N/A * will have more data added at the end ... e.g. what CAs the client trusts.
0N/A * Until we know how to parse it, we will just read what we know
0N/A * about, and let our caller handle the jumps over unknown data.
0N/A */
2890N/Astatic final class ClientHello extends HandshakeMessage {
0N/A
0N/A ProtocolVersion protocolVersion;
0N/A RandomCookie clnt_random;
0N/A SessionId sessionId;
0N/A private CipherSuiteList cipherSuites;
0N/A byte[] compression_methods;
0N/A
0N/A HelloExtensions extensions = new HelloExtensions();
0N/A
0N/A private final static byte[] NULL_COMPRESSION = new byte[] {0};
0N/A
2890N/A ClientHello(SecureRandom generator, ProtocolVersion protocolVersion,
2890N/A SessionId sessionId, CipherSuiteList cipherSuites) {
0N/A
2890N/A this.protocolVersion = protocolVersion;
2890N/A this.sessionId = sessionId;
2890N/A this.cipherSuites = cipherSuites;
0N/A
0N/A if (cipherSuites.containsEC()) {
0N/A extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
0N/A extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT);
0N/A }
0N/A
2890N/A clnt_random = new RandomCookie(generator);
2890N/A compression_methods = NULL_COMPRESSION;
0N/A }
0N/A
0N/A ClientHello(HandshakeInStream s, int messageLength) throws IOException {
0N/A protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8());
0N/A clnt_random = new RandomCookie(s);
0N/A sessionId = new SessionId(s.getBytes8());
0N/A cipherSuites = new CipherSuiteList(s);
0N/A compression_methods = s.getBytes8();
0N/A if (messageLength() != messageLength) {
0N/A extensions = new HelloExtensions(s);
0N/A }
0N/A }
0N/A
2890N/A CipherSuiteList getCipherSuites() {
2890N/A return cipherSuites;
2890N/A }
2890N/A
2890N/A // add renegotiation_info extension
2890N/A void addRenegotiationInfoExtension(byte[] clientVerifyData) {
2890N/A HelloExtension renegotiationInfo = new RenegotiationInfoExtension(
2890N/A clientVerifyData, new byte[0]);
2890N/A extensions.add(renegotiationInfo);
2890N/A }
2890N/A
3002N/A // add server_name extension
3002N/A void addServerNameIndicationExtension(String hostname) {
3002N/A // We would have checked that the hostname ia a FQDN.
3401N/A ArrayList<String> hostnames = new ArrayList<>(1);
3002N/A hostnames.add(hostname);
3002N/A
3002N/A try {
3002N/A extensions.add(new ServerNameExtension(hostnames));
3002N/A } catch (IOException ioe) {
3002N/A // ignore the exception and return
3002N/A }
3002N/A }
3002N/A
3002N/A // add signature_algorithm extension
3002N/A void addSignatureAlgorithmsExtension(
3002N/A Collection<SignatureAndHashAlgorithm> algorithms) {
3002N/A HelloExtension signatureAlgorithm =
3002N/A new SignatureAlgorithmsExtension(algorithms);
3002N/A extensions.add(signatureAlgorithm);
3002N/A }
3002N/A
2890N/A @Override
2890N/A int messageType() { return ht_client_hello; }
2890N/A
2890N/A @Override
2890N/A int messageLength() {
2890N/A /*
2890N/A * Add fixed size parts of each field...
2890N/A * version + random + session + cipher + compress
2890N/A */
2890N/A return (2 + 32 + 1 + 2 + 1
2890N/A + sessionId.length() /* ... + variable parts */
2890N/A + (cipherSuites.size() * 2)
2890N/A + compression_methods.length)
2890N/A + extensions.length();
2890N/A }
2890N/A
2890N/A @Override
0N/A void send(HandshakeOutStream s) throws IOException {
0N/A s.putInt8(protocolVersion.major);
0N/A s.putInt8(protocolVersion.minor);
0N/A clnt_random.send(s);
0N/A s.putBytes8(sessionId.getId());
0N/A cipherSuites.send(s);
0N/A s.putBytes8(compression_methods);
0N/A extensions.send(s);
0N/A }
0N/A
2890N/A @Override
0N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** ClientHello, " + protocolVersion);
0N/A
0N/A if (debug != null && Debug.isOn("verbose")) {
3002N/A s.print("RandomCookie: ");
3002N/A clnt_random.print(s);
0N/A
0N/A s.print("Session ID: ");
0N/A s.println(sessionId);
0N/A
0N/A s.println("Cipher Suites: " + cipherSuites);
0N/A
0N/A Debug.println(s, "Compression Methods", compression_methods);
0N/A extensions.print(s);
0N/A s.println("***");
0N/A }
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * ServerHello ... SERVER --> CLIENT
0N/A *
0N/A * Server chooses protocol options from among those it supports and the
0N/A * client supports. Then it sends the basic session descriptive parameters
0N/A * back to the client.
0N/A */
0N/Astatic final
0N/Aclass ServerHello extends HandshakeMessage
0N/A{
0N/A int messageType() { return ht_server_hello; }
0N/A
0N/A ProtocolVersion protocolVersion;
0N/A RandomCookie svr_random;
0N/A SessionId sessionId;
0N/A CipherSuite cipherSuite;
0N/A byte compression_method;
0N/A HelloExtensions extensions = new HelloExtensions();
0N/A
0N/A ServerHello() {
0N/A // empty
0N/A }
0N/A
3002N/A ServerHello(HandshakeInStream input, int messageLength)
3002N/A throws IOException {
0N/A protocolVersion = ProtocolVersion.valueOf(input.getInt8(),
0N/A input.getInt8());
0N/A svr_random = new RandomCookie(input);
0N/A sessionId = new SessionId(input.getBytes8());
0N/A cipherSuite = CipherSuite.valueOf(input.getInt8(), input.getInt8());
0N/A compression_method = (byte)input.getInt8();
0N/A if (messageLength() != messageLength) {
0N/A extensions = new HelloExtensions(input);
0N/A }
0N/A }
0N/A
0N/A int messageLength()
0N/A {
0N/A // almost fixed size, except session ID and extensions:
0N/A // major + minor = 2
0N/A // random = 32
0N/A // session ID len field = 1
0N/A // cipher suite + compression = 3
0N/A // extensions: if present, 2 + length of extensions
0N/A return 38 + sessionId.length() + extensions.length();
0N/A }
0N/A
0N/A void send(HandshakeOutStream s) throws IOException
0N/A {
0N/A s.putInt8(protocolVersion.major);
0N/A s.putInt8(protocolVersion.minor);
0N/A svr_random.send(s);
0N/A s.putBytes8(sessionId.getId());
0N/A s.putInt8(cipherSuite.id >> 8);
0N/A s.putInt8(cipherSuite.id & 0xff);
0N/A s.putInt8(compression_method);
0N/A extensions.send(s);
0N/A }
0N/A
0N/A void print(PrintStream s) throws IOException
0N/A {
0N/A s.println("*** ServerHello, " + protocolVersion);
0N/A
0N/A if (debug != null && Debug.isOn("verbose")) {
3002N/A s.print("RandomCookie: ");
3002N/A svr_random.print(s);
0N/A
0N/A int i;
0N/A
0N/A s.print("Session ID: ");
0N/A s.println(sessionId);
0N/A
0N/A s.println("Cipher Suite: " + cipherSuite);
0N/A s.println("Compression Method: " + compression_method);
0N/A extensions.print(s);
0N/A s.println("***");
0N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/A/*
0N/A * CertificateMsg ... send by both CLIENT and SERVER
0N/A *
0N/A * Each end of a connection may need to pass its certificate chain to
0N/A * the other end. Such chains are intended to validate an identity with
0N/A * reference to some certifying authority. Examples include companies
0N/A * like Verisign, or financial institutions. There's some control over
0N/A * the certifying authorities which are sent.
0N/A *
0N/A * NOTE: that these messages might be huge, taking many handshake records.
0N/A * Up to 2^48 bytes of certificate may be sent, in records of at most 2^14
0N/A * bytes each ... up to 2^32 records sent on the output stream.
0N/A */
0N/Astatic final
0N/Aclass CertificateMsg extends HandshakeMessage
0N/A{
0N/A int messageType() { return ht_certificate; }
0N/A
0N/A private X509Certificate[] chain;
0N/A
0N/A private List<byte[]> encodedChain;
0N/A
0N/A private int messageLength;
0N/A
0N/A CertificateMsg(X509Certificate[] certs) {
0N/A chain = certs;
0N/A }
0N/A
0N/A CertificateMsg(HandshakeInStream input) throws IOException {
0N/A int chainLen = input.getInt24();
3401N/A List<Certificate> v = new ArrayList<>(4);
0N/A
0N/A CertificateFactory cf = null;
0N/A while (chainLen > 0) {
0N/A byte[] cert = input.getBytes24();
0N/A chainLen -= (3 + cert.length);
0N/A try {
0N/A if (cf == null) {
0N/A cf = CertificateFactory.getInstance("X.509");
0N/A }
0N/A v.add(cf.generateCertificate(new ByteArrayInputStream(cert)));
0N/A } catch (CertificateException e) {
3002N/A throw (SSLProtocolException)new SSLProtocolException(
3002N/A e.getMessage()).initCause(e);
0N/A }
0N/A }
0N/A
0N/A chain = v.toArray(new X509Certificate[v.size()]);
0N/A }
0N/A
0N/A int messageLength() {
0N/A if (encodedChain == null) {
0N/A messageLength = 3;
0N/A encodedChain = new ArrayList<byte[]>(chain.length);
0N/A try {
0N/A for (X509Certificate cert : chain) {
0N/A byte[] b = cert.getEncoded();
0N/A encodedChain.add(b);
0N/A messageLength += b.length + 3;
0N/A }
0N/A } catch (CertificateEncodingException e) {
0N/A encodedChain = null;
0N/A throw new RuntimeException("Could not encode certificates", e);
0N/A }
0N/A }
0N/A return messageLength;
0N/A }
0N/A
0N/A void send(HandshakeOutStream s) throws IOException {
0N/A s.putInt24(messageLength() - 3);
0N/A for (byte[] b : encodedChain) {
0N/A s.putBytes24(b);
0N/A }
0N/A }
0N/A
0N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** Certificate chain");
0N/A
0N/A if (debug != null && Debug.isOn("verbose")) {
0N/A for (int i = 0; i < chain.length; i++)
0N/A s.println("chain [" + i + "] = " + chain[i]);
0N/A s.println("***");
0N/A }
0N/A }
0N/A
0N/A X509Certificate[] getCertificateChain() {
3002N/A return chain.clone();
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * ServerKeyExchange ... SERVER --> CLIENT
0N/A *
0N/A * The cipher suite selected, when combined with the certificate exchanged,
0N/A * implies one of several different kinds of key exchange. Most current
0N/A * cipher suites require the server to send more than its certificate.
0N/A *
0N/A * The primary exceptions are when a server sends an encryption-capable
0N/A * RSA public key in its cert, to be used with RSA (or RSA_export) key
0N/A * exchange; and when a server sends its Diffie-Hellman cert. Those kinds
0N/A * of key exchange do not require a ServerKeyExchange message.
0N/A *
0N/A * Key exchange can be viewed as having three modes, which are explicit
0N/A * for the Diffie-Hellman flavors and poorly specified for RSA ones:
0N/A *
0N/A * - "Ephemeral" keys. Here, a "temporary" key is allocated by the
0N/A * server, and signed. Diffie-Hellman keys signed using RSA or
0N/A * DSS are ephemeral (DHE flavor). RSA keys get used to do the same
0N/A * thing, to cut the key size down to 512 bits (export restrictions)
0N/A * or for signing-only RSA certificates.
0N/A *
0N/A * - Anonymity. Here no server certificate is sent, only the public
0N/A * key of the server. This case is subject to man-in-the-middle
0N/A * attacks. This can be done with Diffie-Hellman keys (DH_anon) or
0N/A * with RSA keys, but is only used in SSLv3 for DH_anon.
0N/A *
0N/A * - "Normal" case. Here a server certificate is sent, and the public
0N/A * key there is used directly in exchanging the premaster secret.
0N/A * For example, Diffie-Hellman "DH" flavor, and any RSA flavor with
0N/A * only 512 bit keys.
0N/A *
0N/A * If a server certificate is sent, there is no anonymity. However,
0N/A * when a certificate is sent, ephemeral keys may still be used to
0N/A * exchange the premaster secret. That's how RSA_EXPORT often works,
0N/A * as well as how the DHE_* flavors work.
0N/A */
0N/Astatic abstract class ServerKeyExchange extends HandshakeMessage
0N/A{
0N/A int messageType() { return ht_server_key_exchange; }
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Using RSA for Key Exchange: exchange a session key that's not as big
0N/A * as the signing-only key. Used for export applications, since exported
0N/A * RSA encryption keys can't be bigger than 512 bytes.
0N/A *
0N/A * This is never used when keys are 512 bits or smaller, and isn't used
0N/A * on "US Domestic" ciphers in any case.
0N/A */
0N/Astatic final
0N/Aclass RSA_ServerKeyExchange extends ServerKeyExchange
0N/A{
0N/A private byte rsa_modulus[]; // 1 to 2^16 - 1 bytes
0N/A private byte rsa_exponent[]; // 1 to 2^16 - 1 bytes
0N/A
0N/A private Signature signature;
0N/A private byte[] signatureBytes;
0N/A
0N/A /*
0N/A * Hash the nonces and the ephemeral RSA public key.
0N/A */
0N/A private void updateSignature(byte clntNonce[], byte svrNonce[])
0N/A throws SignatureException {
0N/A int tmp;
0N/A
0N/A signature.update(clntNonce);
0N/A signature.update(svrNonce);
0N/A
0N/A tmp = rsa_modulus.length;
0N/A signature.update((byte)(tmp >> 8));
0N/A signature.update((byte)(tmp & 0x0ff));
0N/A signature.update(rsa_modulus);
0N/A
0N/A tmp = rsa_exponent.length;
0N/A signature.update((byte)(tmp >> 8));
0N/A signature.update((byte)(tmp & 0x0ff));
0N/A signature.update(rsa_exponent);
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Construct an RSA server key exchange message, using data
0N/A * known _only_ to the server.
0N/A *
0N/A * The client knows the public key corresponding to this private
0N/A * key, from the Certificate message sent previously. To comply
0N/A * with US export regulations we use short RSA keys ... either
0N/A * long term ones in the server's X509 cert, or else ephemeral
0N/A * ones sent using this message.
0N/A */
0N/A RSA_ServerKeyExchange(PublicKey ephemeralKey, PrivateKey privateKey,
0N/A RandomCookie clntNonce, RandomCookie svrNonce, SecureRandom sr)
0N/A throws GeneralSecurityException {
0N/A RSAPublicKeySpec rsaKey = JsseJce.getRSAPublicKeySpec(ephemeralKey);
0N/A rsa_modulus = toByteArray(rsaKey.getModulus());
0N/A rsa_exponent = toByteArray(rsaKey.getPublicExponent());
0N/A signature = RSASignature.getInstance();
0N/A signature.initSign(privateKey, sr);
0N/A updateSignature(clntNonce.random_bytes, svrNonce.random_bytes);
0N/A signatureBytes = signature.sign();
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Parse an RSA server key exchange message, using data known
0N/A * to the client (and, in some situations, eavesdroppers).
0N/A */
0N/A RSA_ServerKeyExchange(HandshakeInStream input)
0N/A throws IOException, NoSuchAlgorithmException {
0N/A signature = RSASignature.getInstance();
0N/A rsa_modulus = input.getBytes16();
0N/A rsa_exponent = input.getBytes16();
0N/A signatureBytes = input.getBytes16();
0N/A }
0N/A
0N/A /*
0N/A * Get the ephemeral RSA public key that will be used in this
0N/A * SSL connection.
0N/A */
0N/A PublicKey getPublicKey() {
0N/A try {
0N/A KeyFactory kfac = JsseJce.getKeyFactory("RSA");
0N/A // modulus and exponent are always positive
3002N/A RSAPublicKeySpec kspec = new RSAPublicKeySpec(
3002N/A new BigInteger(1, rsa_modulus),
3002N/A new BigInteger(1, rsa_exponent));
0N/A return kfac.generatePublic(kspec);
0N/A } catch (Exception e) {
0N/A throw new RuntimeException(e);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Verify the signed temporary key using the hashes computed
0N/A * from it and the two nonces. This is called by clients
0N/A * with "exportable" RSA flavors.
0N/A */
0N/A boolean verify(PublicKey certifiedKey, RandomCookie clntNonce,
0N/A RandomCookie svrNonce) throws GeneralSecurityException {
0N/A signature.initVerify(certifiedKey);
0N/A updateSignature(clntNonce.random_bytes, svrNonce.random_bytes);
0N/A return signature.verify(signatureBytes);
0N/A }
0N/A
0N/A int messageLength() {
0N/A return 6 + rsa_modulus.length + rsa_exponent.length
0N/A + signatureBytes.length;
0N/A }
0N/A
0N/A void send(HandshakeOutStream s) throws IOException {
0N/A s.putBytes16(rsa_modulus);
0N/A s.putBytes16(rsa_exponent);
0N/A s.putBytes16(signatureBytes);
0N/A }
0N/A
0N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** RSA ServerKeyExchange");
0N/A
0N/A if (debug != null && Debug.isOn("verbose")) {
0N/A Debug.println(s, "RSA Modulus", rsa_modulus);
0N/A Debug.println(s, "RSA Public Exponent", rsa_exponent);
0N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/A/*
0N/A * Using Diffie-Hellman algorithm for key exchange. All we really need to
0N/A * do is securely get Diffie-Hellman keys (using the same P, G parameters)
0N/A * to our peer, then we automatically have a shared secret without need
0N/A * to exchange any more data. (D-H only solutions, such as SKIP, could
0N/A * eliminate key exchange negotiations and get faster connection setup.
0N/A * But they still need a signature algorithm like DSS/DSA to support the
0N/A * trusted distribution of keys without relying on unscalable physical
0N/A * key distribution systems.)
0N/A *
0N/A * This class supports several DH-based key exchange algorithms, though
0N/A * perhaps eventually each deserves its own class. Notably, this has
0N/A * basic support for DH_anon and its DHE_DSS and DHE_RSA signed variants.
0N/A */
0N/Astatic final
0N/Aclass DH_ServerKeyExchange extends ServerKeyExchange
0N/A{
0N/A // Fix message encoding, see 4348279
0N/A private final static boolean dhKeyExchangeFix =
0N/A Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true);
0N/A
0N/A private byte dh_p []; // 1 to 2^16 - 1 bytes
0N/A private byte dh_g []; // 1 to 2^16 - 1 bytes
0N/A private byte dh_Ys []; // 1 to 2^16 - 1 bytes
0N/A
0N/A private byte signature [];
0N/A
3002N/A // protocol version being established using this ServerKeyExchange message
3002N/A ProtocolVersion protocolVersion;
3002N/A
3002N/A // the preferable signature algorithm used by this ServerKeyExchange message
3002N/A private SignatureAndHashAlgorithm preferableSignatureAlgorithm;
3002N/A
0N/A /*
0N/A * Construct from initialized DH key object, for DH_anon
0N/A * key exchange.
0N/A */
3002N/A DH_ServerKeyExchange(DHCrypt obj, ProtocolVersion protocolVersion) {
3002N/A this.protocolVersion = protocolVersion;
3002N/A this.preferableSignatureAlgorithm = null;
3002N/A
5690N/A // The DH key has been validated in the constructor of DHCrypt.
3002N/A setValues(obj);
0N/A signature = null;
0N/A }
0N/A
0N/A /*
0N/A * Construct from initialized DH key object and the key associated
0N/A * with the cert chain which was sent ... for DHE_DSS and DHE_RSA
0N/A * key exchange. (Constructor called by server.)
0N/A */
0N/A DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[],
3002N/A byte svrNonce[], SecureRandom sr,
3002N/A SignatureAndHashAlgorithm signAlgorithm,
3002N/A ProtocolVersion protocolVersion) throws GeneralSecurityException {
0N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
5690N/A // The DH key has been validated in the constructor of DHCrypt.
3002N/A setValues(obj);
0N/A
0N/A Signature sig;
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A this.preferableSignatureAlgorithm = signAlgorithm;
3002N/A sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
0N/A } else {
3002N/A this.preferableSignatureAlgorithm = null;
3002N/A if (key.getAlgorithm().equals("DSA")) {
3002N/A sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
3002N/A } else {
3002N/A sig = RSASignature.getInstance();
3002N/A }
0N/A }
3002N/A
0N/A sig.initSign(key, sr);
0N/A updateSignature(sig, clntNonce, svrNonce);
0N/A signature = sig.sign();
0N/A }
0N/A
0N/A /*
0N/A * Construct a DH_ServerKeyExchange message from an input
0N/A * stream, as if sent from server to client for use with
0N/A * DH_anon key exchange
0N/A */
3002N/A DH_ServerKeyExchange(HandshakeInStream input,
5690N/A ProtocolVersion protocolVersion)
5690N/A throws IOException, GeneralSecurityException {
3002N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A this.preferableSignatureAlgorithm = null;
3002N/A
0N/A dh_p = input.getBytes16();
0N/A dh_g = input.getBytes16();
0N/A dh_Ys = input.getBytes16();
5690N/A KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys),
5690N/A new BigInteger(1, dh_p),
5690N/A new BigInteger(1, dh_g)));
5690N/A
0N/A signature = null;
0N/A }
0N/A
0N/A /*
0N/A * Construct a DH_ServerKeyExchange message from an input stream
0N/A * and a certificate, as if sent from server to client for use with
0N/A * DHE_DSS or DHE_RSA key exchange. (Called by client.)
0N/A */
0N/A DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey,
3002N/A byte clntNonce[], byte svrNonce[], int messageSize,
3002N/A Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
3002N/A ProtocolVersion protocolVersion)
0N/A throws IOException, GeneralSecurityException {
0N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
3002N/A // read params: ServerDHParams
0N/A dh_p = input.getBytes16();
0N/A dh_g = input.getBytes16();
0N/A dh_Ys = input.getBytes16();
5690N/A KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys),
5690N/A new BigInteger(1, dh_p),
5690N/A new BigInteger(1, dh_g)));
0N/A
3002N/A // read the signature and hash algorithm
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A int hash = input.getInt8(); // hash algorithm
3002N/A int signature = input.getInt8(); // signature algorithm
3002N/A
3002N/A preferableSignatureAlgorithm =
3002N/A SignatureAndHashAlgorithm.valueOf(hash, signature, 0);
3002N/A
3002N/A // Is it a local supported signature algorithm?
3002N/A if (!localSupportedSignAlgs.contains(
3002N/A preferableSignatureAlgorithm)) {
3002N/A throw new SSLHandshakeException(
3002N/A "Unsupported SignatureAndHashAlgorithm in " +
3002N/A "ServerKeyExchange message");
3002N/A }
3002N/A } else {
3002N/A this.preferableSignatureAlgorithm = null;
3002N/A }
3002N/A
3002N/A // read the signature
0N/A byte signature[];
0N/A if (dhKeyExchangeFix) {
0N/A signature = input.getBytes16();
0N/A } else {
0N/A messageSize -= (dh_p.length + 2);
0N/A messageSize -= (dh_g.length + 2);
0N/A messageSize -= (dh_Ys.length + 2);
0N/A
0N/A signature = new byte[messageSize];
0N/A input.read(signature);
0N/A }
0N/A
0N/A Signature sig;
0N/A String algorithm = publicKey.getAlgorithm();
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A sig = JsseJce.getSignature(
3002N/A preferableSignatureAlgorithm.getAlgorithmName());
0N/A } else {
3002N/A if (algorithm.equals("DSA")) {
3002N/A sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
3002N/A } else if (algorithm.equals("RSA")) {
3002N/A sig = RSASignature.getInstance();
3002N/A } else {
3002N/A throw new SSLKeyException("neither an RSA or a DSA key");
3002N/A }
0N/A }
0N/A
0N/A sig.initVerify(publicKey);
0N/A updateSignature(sig, clntNonce, svrNonce);
0N/A
0N/A if (sig.verify(signature) == false ) {
0N/A throw new SSLKeyException("Server D-H key verification failed");
0N/A }
0N/A }
0N/A
3865N/A /* Return the Diffie-Hellman modulus */
3865N/A BigInteger getModulus() {
3865N/A return new BigInteger(1, dh_p);
3865N/A }
3865N/A
3865N/A /* Return the Diffie-Hellman base/generator */
3865N/A BigInteger getBase() {
3865N/A return new BigInteger(1, dh_g);
3865N/A }
3865N/A
3865N/A /* Return the server's Diffie-Hellman public key */
3865N/A BigInteger getServerPublicKey() {
3865N/A return new BigInteger(1, dh_Ys);
3865N/A }
3865N/A
3865N/A /*
3865N/A * Update sig with nonces and Diffie-Hellman public key.
3865N/A */
3865N/A private void updateSignature(Signature sig, byte clntNonce[],
3865N/A byte svrNonce[]) throws SignatureException {
3865N/A int tmp;
3865N/A
3865N/A sig.update(clntNonce);
3865N/A sig.update(svrNonce);
3865N/A
3865N/A tmp = dh_p.length;
3865N/A sig.update((byte)(tmp >> 8));
3865N/A sig.update((byte)(tmp & 0x0ff));
3865N/A sig.update(dh_p);
3865N/A
3865N/A tmp = dh_g.length;
3865N/A sig.update((byte)(tmp >> 8));
3865N/A sig.update((byte)(tmp & 0x0ff));
3865N/A sig.update(dh_g);
3865N/A
3865N/A tmp = dh_Ys.length;
3865N/A sig.update((byte)(tmp >> 8));
3865N/A sig.update((byte)(tmp & 0x0ff));
3865N/A sig.update(dh_Ys);
3865N/A }
3865N/A
3865N/A private void setValues(DHCrypt obj) {
3865N/A dh_p = toByteArray(obj.getModulus());
3865N/A dh_g = toByteArray(obj.getBase());
3865N/A dh_Ys = toByteArray(obj.getPublicKey());
3865N/A }
3865N/A
0N/A int messageLength() {
0N/A int temp = 6; // overhead for p, g, y(s) values.
0N/A
0N/A temp += dh_p.length;
0N/A temp += dh_g.length;
0N/A temp += dh_Ys.length;
3002N/A
0N/A if (signature != null) {
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A temp += SignatureAndHashAlgorithm.sizeInRecord();
3002N/A }
3002N/A
0N/A temp += signature.length;
0N/A if (dhKeyExchangeFix) {
0N/A temp += 2;
0N/A }
0N/A }
3002N/A
0N/A return temp;
0N/A }
0N/A
0N/A void send(HandshakeOutStream s) throws IOException {
0N/A s.putBytes16(dh_p);
0N/A s.putBytes16(dh_g);
0N/A s.putBytes16(dh_Ys);
3002N/A
0N/A if (signature != null) {
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A s.putInt8(preferableSignatureAlgorithm.getHashValue());
3002N/A s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
3002N/A }
3002N/A
0N/A if (dhKeyExchangeFix) {
0N/A s.putBytes16(signature);
0N/A } else {
0N/A s.write(signature);
0N/A }
0N/A }
0N/A }
0N/A
0N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** Diffie-Hellman ServerKeyExchange");
0N/A
0N/A if (debug != null && Debug.isOn("verbose")) {
0N/A Debug.println(s, "DH Modulus", dh_p);
0N/A Debug.println(s, "DH Base", dh_g);
0N/A Debug.println(s, "Server DH Public Key", dh_Ys);
0N/A
0N/A if (signature == null) {
0N/A s.println("Anonymous");
0N/A } else {
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A s.println("Signature Algorithm " +
3002N/A preferableSignatureAlgorithm.getAlgorithmName());
3002N/A }
3002N/A
0N/A s.println("Signed with a DSA or RSA public key");
0N/A }
0N/A }
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * ECDH server key exchange message. Sent by the server for ECDHE and ECDH_anon
0N/A * ciphersuites to communicate its ephemeral public key (including the
0N/A * EC domain parameters).
0N/A *
0N/A * We support named curves only, no explicitly encoded curves.
0N/A */
0N/Astatic final
3865N/Aclass ECDH_ServerKeyExchange extends ServerKeyExchange {
0N/A
0N/A // constants for ECCurveType
0N/A private final static int CURVE_EXPLICIT_PRIME = 1;
0N/A private final static int CURVE_EXPLICIT_CHAR2 = 2;
0N/A private final static int CURVE_NAMED_CURVE = 3;
0N/A
0N/A // id of the curve we are using
0N/A private int curveId;
0N/A // encoded public point
0N/A private byte[] pointBytes;
0N/A
0N/A // signature bytes (or null if anonymous)
0N/A private byte[] signatureBytes;
0N/A
0N/A // public key object encapsulated in this message
0N/A private ECPublicKey publicKey;
0N/A
3002N/A // protocol version being established using this ServerKeyExchange message
3002N/A ProtocolVersion protocolVersion;
3002N/A
3002N/A // the preferable signature algorithm used by this ServerKeyExchange message
3002N/A private SignatureAndHashAlgorithm preferableSignatureAlgorithm;
3002N/A
0N/A ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey,
3002N/A byte[] clntNonce, byte[] svrNonce, SecureRandom sr,
3002N/A SignatureAndHashAlgorithm signAlgorithm,
3002N/A ProtocolVersion protocolVersion) throws GeneralSecurityException {
3002N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
0N/A publicKey = (ECPublicKey)obj.getPublicKey();
0N/A ECParameterSpec params = publicKey.getParams();
0N/A ECPoint point = publicKey.getW();
0N/A pointBytes = JsseJce.encodePoint(point, params.getCurve());
0N/A curveId = SupportedEllipticCurvesExtension.getCurveIndex(params);
0N/A
0N/A if (privateKey == null) {
0N/A // ECDH_anon
0N/A return;
0N/A }
0N/A
3002N/A Signature sig;
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A this.preferableSignatureAlgorithm = signAlgorithm;
3002N/A sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
3002N/A } else {
3002N/A sig = getSignature(privateKey.getAlgorithm());
3002N/A }
3002N/A sig.initSign(privateKey); // where is the SecureRandom?
0N/A
0N/A updateSignature(sig, clntNonce, svrNonce);
0N/A signatureBytes = sig.sign();
0N/A }
0N/A
0N/A /*
0N/A * Parse an ECDH server key exchange message.
0N/A */
0N/A ECDH_ServerKeyExchange(HandshakeInStream input, PublicKey signingKey,
3002N/A byte[] clntNonce, byte[] svrNonce,
3002N/A Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
3002N/A ProtocolVersion protocolVersion)
0N/A throws IOException, GeneralSecurityException {
3002N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
3002N/A // read params: ServerECDHParams
0N/A int curveType = input.getInt8();
0N/A ECParameterSpec parameters;
0N/A // These parsing errors should never occur as we negotiated
0N/A // the supported curves during the exchange of the Hello messages.
0N/A if (curveType == CURVE_NAMED_CURVE) {
0N/A curveId = input.getInt16();
3002N/A if (SupportedEllipticCurvesExtension.isSupported(curveId)
3002N/A == false) {
3002N/A throw new SSLHandshakeException(
3002N/A "Unsupported curveId: " + curveId);
0N/A }
3002N/A String curveOid =
3002N/A SupportedEllipticCurvesExtension.getCurveOid(curveId);
0N/A if (curveOid == null) {
3002N/A throw new SSLHandshakeException(
3002N/A "Unknown named curve: " + curveId);
0N/A }
0N/A parameters = JsseJce.getECParameterSpec(curveOid);
0N/A if (parameters == null) {
3002N/A throw new SSLHandshakeException(
3002N/A "Unsupported curve: " + curveOid);
0N/A }
0N/A } else {
3002N/A throw new SSLHandshakeException(
3002N/A "Unsupported ECCurveType: " + curveType);
0N/A }
0N/A pointBytes = input.getBytes8();
0N/A
0N/A ECPoint point = JsseJce.decodePoint(pointBytes, parameters.getCurve());
0N/A KeyFactory factory = JsseJce.getKeyFactory("EC");
3002N/A publicKey = (ECPublicKey)factory.generatePublic(
3002N/A new ECPublicKeySpec(point, parameters));
0N/A
0N/A if (signingKey == null) {
0N/A // ECDH_anon
0N/A return;
0N/A }
0N/A
3002N/A // read the signature and hash algorithm
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A int hash = input.getInt8(); // hash algorithm
3002N/A int signature = input.getInt8(); // signature algorithm
3002N/A
3002N/A preferableSignatureAlgorithm =
3002N/A SignatureAndHashAlgorithm.valueOf(hash, signature, 0);
3002N/A
3002N/A // Is it a local supported signature algorithm?
3002N/A if (!localSupportedSignAlgs.contains(
3002N/A preferableSignatureAlgorithm)) {
3002N/A throw new SSLHandshakeException(
3002N/A "Unsupported SignatureAndHashAlgorithm in " +
3002N/A "ServerKeyExchange message");
3002N/A }
3002N/A }
3002N/A
3002N/A // read the signature
0N/A signatureBytes = input.getBytes16();
3002N/A
3002N/A // verify the signature
3002N/A Signature sig;
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A sig = JsseJce.getSignature(
3002N/A preferableSignatureAlgorithm.getAlgorithmName());
3002N/A } else {
3002N/A sig = getSignature(signingKey.getAlgorithm());
3002N/A }
0N/A sig.initVerify(signingKey);
0N/A
0N/A updateSignature(sig, clntNonce, svrNonce);
0N/A
0N/A if (sig.verify(signatureBytes) == false ) {
3002N/A throw new SSLKeyException(
3002N/A "Invalid signature on ECDH server key exchange message");
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Get the ephemeral EC public key encapsulated in this message.
0N/A */
0N/A ECPublicKey getPublicKey() {
0N/A return publicKey;
0N/A }
0N/A
3002N/A private static Signature getSignature(String keyAlgorithm)
3002N/A throws NoSuchAlgorithmException {
0N/A if (keyAlgorithm.equals("EC")) {
0N/A return JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA);
0N/A } else if (keyAlgorithm.equals("RSA")) {
0N/A return RSASignature.getInstance();
0N/A } else {
0N/A throw new NoSuchAlgorithmException("neither an RSA or a EC key");
0N/A }
0N/A }
0N/A
0N/A private void updateSignature(Signature sig, byte clntNonce[],
0N/A byte svrNonce[]) throws SignatureException {
0N/A sig.update(clntNonce);
0N/A sig.update(svrNonce);
0N/A
0N/A sig.update((byte)CURVE_NAMED_CURVE);
0N/A sig.update((byte)(curveId >> 8));
0N/A sig.update((byte)curveId);
0N/A sig.update((byte)pointBytes.length);
0N/A sig.update(pointBytes);
0N/A }
0N/A
0N/A int messageLength() {
3865N/A int sigLen = 0;
3865N/A if (signatureBytes != null) {
3865N/A sigLen = 2 + signatureBytes.length;
3865N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3865N/A sigLen += SignatureAndHashAlgorithm.sizeInRecord();
3865N/A }
3002N/A }
3002N/A
0N/A return 4 + pointBytes.length + sigLen;
0N/A }
0N/A
0N/A void send(HandshakeOutStream s) throws IOException {
0N/A s.putInt8(CURVE_NAMED_CURVE);
0N/A s.putInt16(curveId);
0N/A s.putBytes8(pointBytes);
3002N/A
0N/A if (signatureBytes != null) {
3865N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3865N/A s.putInt8(preferableSignatureAlgorithm.getHashValue());
3865N/A s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
3865N/A }
3865N/A
0N/A s.putBytes16(signatureBytes);
0N/A }
0N/A }
0N/A
0N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** ECDH ServerKeyExchange");
0N/A
0N/A if (debug != null && Debug.isOn("verbose")) {
3865N/A if (signatureBytes == null) {
3865N/A s.println("Anonymous");
3865N/A } else {
3865N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3865N/A s.println("Signature Algorithm " +
3865N/A preferableSignatureAlgorithm.getAlgorithmName());
3865N/A }
3002N/A }
3002N/A
0N/A s.println("Server key: " + publicKey);
0N/A }
0N/A }
0N/A}
0N/A
0N/Astatic final class DistinguishedName {
0N/A
0N/A /*
0N/A * DER encoded distinguished name.
0N/A * TLS requires that its not longer than 65535 bytes.
0N/A */
0N/A byte name[];
0N/A
0N/A DistinguishedName(HandshakeInStream input) throws IOException {
0N/A name = input.getBytes16();
0N/A }
0N/A
0N/A DistinguishedName(X500Principal dn) {
0N/A name = dn.getEncoded();
0N/A }
0N/A
0N/A X500Principal getX500Principal() throws IOException {
0N/A try {
0N/A return new X500Principal(name);
0N/A } catch (IllegalArgumentException e) {
3002N/A throw (SSLProtocolException)new SSLProtocolException(
3002N/A e.getMessage()).initCause(e);
0N/A }
0N/A }
0N/A
0N/A int length() {
0N/A return 2 + name.length;
0N/A }
0N/A
0N/A void send(HandshakeOutStream output) throws IOException {
0N/A output.putBytes16(name);
0N/A }
0N/A
0N/A void print(PrintStream output) throws IOException {
0N/A X500Principal principal = new X500Principal(name);
0N/A output.println("<" + principal.toString() + ">");
0N/A }
0N/A}
0N/A
0N/A/*
0N/A * CertificateRequest ... SERVER --> CLIENT
0N/A *
0N/A * Authenticated servers may ask clients to authenticate themselves
0N/A * in turn, using this message.
3002N/A *
3002N/A * Prior to TLS 1.2, the structure of the message is defined as:
3002N/A * struct {
3002N/A * ClientCertificateType certificate_types<1..2^8-1>;
3002N/A * DistinguishedName certificate_authorities<0..2^16-1>;
3002N/A * } CertificateRequest;
3002N/A *
3002N/A * In TLS 1.2, the structure is changed to:
3002N/A * struct {
3002N/A * ClientCertificateType certificate_types<1..2^8-1>;
3002N/A * SignatureAndHashAlgorithm
3002N/A * supported_signature_algorithms<2^16-1>;
3002N/A * DistinguishedName certificate_authorities<0..2^16-1>;
3002N/A * } CertificateRequest;
3002N/A *
0N/A */
0N/Astatic final
0N/Aclass CertificateRequest extends HandshakeMessage
0N/A{
0N/A // enum ClientCertificateType
0N/A static final int cct_rsa_sign = 1;
0N/A static final int cct_dss_sign = 2;
0N/A static final int cct_rsa_fixed_dh = 3;
0N/A static final int cct_dss_fixed_dh = 4;
0N/A
0N/A // The existance of these two values is a bug in the SSL specification.
0N/A // They are never used in the protocol.
0N/A static final int cct_rsa_ephemeral_dh = 5;
0N/A static final int cct_dss_ephemeral_dh = 6;
0N/A
0N/A // From RFC 4492 (ECC)
0N/A static final int cct_ecdsa_sign = 64;
0N/A static final int cct_rsa_fixed_ecdh = 65;
0N/A static final int cct_ecdsa_fixed_ecdh = 66;
0N/A
0N/A private final static byte[] TYPES_NO_ECC = { cct_rsa_sign, cct_dss_sign };
0N/A private final static byte[] TYPES_ECC =
0N/A { cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign };
0N/A
0N/A byte types []; // 1 to 255 types
0N/A DistinguishedName authorities []; // 3 to 2^16 - 1
0N/A // ... "3" because that's the smallest DER-encoded X500 DN
0N/A
3002N/A // protocol version being established using this CertificateRequest message
3002N/A ProtocolVersion protocolVersion;
3002N/A
3002N/A // supported_signature_algorithms for TLS 1.2 or later
3002N/A private Collection<SignatureAndHashAlgorithm> algorithms;
3002N/A
3002N/A // length of supported_signature_algorithms
3002N/A private int algorithmsLen;
3002N/A
3002N/A CertificateRequest(X509Certificate ca[], KeyExchange keyExchange,
3002N/A Collection<SignatureAndHashAlgorithm> signAlgs,
3002N/A ProtocolVersion protocolVersion) throws IOException {
3002N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
0N/A // always use X500Principal
0N/A authorities = new DistinguishedName[ca.length];
0N/A for (int i = 0; i < ca.length; i++) {
0N/A X500Principal x500Principal = ca[i].getSubjectX500Principal();
0N/A authorities[i] = new DistinguishedName(x500Principal);
0N/A }
0N/A // we support RSA, DSS, and ECDSA client authentication and they
0N/A // can be used with all ciphersuites. If this changes, the code
0N/A // needs to be adapted to take keyExchange into account.
0N/A // We only request ECDSA client auth if we have ECC crypto available.
0N/A this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC;
3002N/A
3002N/A // Use supported_signature_algorithms for TLS 1.2 or later.
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A if (signAlgs == null || signAlgs.isEmpty()) {
3002N/A throw new SSLProtocolException(
3002N/A "No supported signature algorithms");
3002N/A }
3002N/A
3002N/A algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
3002N/A algorithmsLen =
3002N/A SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
3002N/A } else {
3002N/A algorithms = new ArrayList<SignatureAndHashAlgorithm>();
3002N/A algorithmsLen = 0;
3002N/A }
0N/A }
0N/A
3002N/A CertificateRequest(HandshakeInStream input,
3002N/A ProtocolVersion protocolVersion) throws IOException {
3002N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
3002N/A // Read the certificate_types.
0N/A types = input.getBytes8();
3002N/A
3002N/A // Read the supported_signature_algorithms for TLS 1.2 or later.
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A algorithmsLen = input.getInt16();
3002N/A if (algorithmsLen < 2) {
3002N/A throw new SSLProtocolException(
3002N/A "Invalid supported_signature_algorithms field");
3002N/A }
3002N/A
3002N/A algorithms = new ArrayList<SignatureAndHashAlgorithm>();
3002N/A int remains = algorithmsLen;
3002N/A int sequence = 0;
3002N/A while (remains > 1) { // needs at least two bytes
3002N/A int hash = input.getInt8(); // hash algorithm
3002N/A int signature = input.getInt8(); // signature algorithm
3002N/A
3002N/A SignatureAndHashAlgorithm algorithm =
3002N/A SignatureAndHashAlgorithm.valueOf(hash, signature,
3002N/A ++sequence);
3002N/A algorithms.add(algorithm);
3002N/A remains -= 2; // one byte for hash, one byte for signature
3002N/A }
3002N/A
3002N/A if (remains != 0) {
3002N/A throw new SSLProtocolException(
3002N/A "Invalid supported_signature_algorithms field");
3002N/A }
3002N/A } else {
3002N/A algorithms = new ArrayList<SignatureAndHashAlgorithm>();
3002N/A algorithmsLen = 0;
3002N/A }
3002N/A
3002N/A // read the certificate_authorities
0N/A int len = input.getInt16();
3401N/A ArrayList<DistinguishedName> v = new ArrayList<>();
0N/A while (len >= 3) {
0N/A DistinguishedName dn = new DistinguishedName(input);
0N/A v.add(dn);
0N/A len -= dn.length();
0N/A }
0N/A
0N/A if (len != 0) {
0N/A throw new SSLProtocolException("Bad CertificateRequest DN length");
0N/A }
0N/A
0N/A authorities = v.toArray(new DistinguishedName[v.size()]);
0N/A }
0N/A
0N/A X500Principal[] getAuthorities() throws IOException {
0N/A X500Principal[] ret = new X500Principal[authorities.length];
0N/A for (int i = 0; i < authorities.length; i++) {
0N/A ret[i] = authorities[i].getX500Principal();
0N/A }
0N/A return ret;
0N/A }
0N/A
3002N/A Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
3002N/A return algorithms;
3002N/A }
3002N/A
3002N/A @Override
3002N/A int messageType() {
3002N/A return ht_certificate_request;
3002N/A }
0N/A
3002N/A @Override
3002N/A int messageLength() {
3002N/A int len = 1 + types.length + 2;
3002N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A len += algorithmsLen + 2;
3002N/A }
3002N/A
3002N/A for (int i = 0; i < authorities.length; i++) {
0N/A len += authorities[i].length();
3002N/A }
3002N/A
0N/A return len;
0N/A }
0N/A
3002N/A @Override
3002N/A void send(HandshakeOutStream output) throws IOException {
3002N/A // put certificate_types
3002N/A output.putBytes8(types);
0N/A
3002N/A // put supported_signature_algorithms
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A output.putInt16(algorithmsLen);
3002N/A for (SignatureAndHashAlgorithm algorithm : algorithms) {
3002N/A output.putInt8(algorithm.getHashValue()); // hash
3002N/A output.putInt8(algorithm.getSignatureValue()); // signature
3002N/A }
3002N/A }
3002N/A
3002N/A // put certificate_authorities
3002N/A int len = 0;
3002N/A for (int i = 0; i < authorities.length; i++) {
0N/A len += authorities[i].length();
3002N/A }
0N/A
0N/A output.putInt16(len);
3002N/A for (int i = 0; i < authorities.length; i++) {
0N/A authorities[i].send(output);
3002N/A }
0N/A }
0N/A
3002N/A @Override
3002N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** CertificateRequest");
0N/A
0N/A if (debug != null && Debug.isOn("verbose")) {
0N/A s.print("Cert Types: ");
0N/A for (int i = 0; i < types.length; i++) {
0N/A switch (types[i]) {
0N/A case cct_rsa_sign:
0N/A s.print("RSA"); break;
0N/A case cct_dss_sign:
0N/A s.print("DSS"); break;
0N/A case cct_rsa_fixed_dh:
0N/A s.print("Fixed DH (RSA sig)"); break;
0N/A case cct_dss_fixed_dh:
0N/A s.print("Fixed DH (DSS sig)"); break;
0N/A case cct_rsa_ephemeral_dh:
0N/A s.print("Ephemeral DH (RSA sig)"); break;
0N/A case cct_dss_ephemeral_dh:
0N/A s.print("Ephemeral DH (DSS sig)"); break;
0N/A case cct_ecdsa_sign:
0N/A s.print("ECDSA"); break;
0N/A case cct_rsa_fixed_ecdh:
0N/A s.print("Fixed ECDH (RSA sig)"); break;
0N/A case cct_ecdsa_fixed_ecdh:
0N/A s.print("Fixed ECDH (ECDSA sig)"); break;
0N/A default:
0N/A s.print("Type-" + (types[i] & 0xff)); break;
0N/A }
0N/A if (i != types.length - 1) {
0N/A s.print(", ");
0N/A }
0N/A }
0N/A s.println();
0N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A StringBuffer buffer = new StringBuffer();
3002N/A boolean opened = false;
3002N/A for (SignatureAndHashAlgorithm signAlg : algorithms) {
3002N/A if (opened) {
3002N/A buffer.append(", " + signAlg.getAlgorithmName());
3002N/A } else {
3002N/A buffer.append(signAlg.getAlgorithmName());
3002N/A opened = true;
3002N/A }
3002N/A }
3002N/A s.println("Supported Signature Algorithms: " + buffer);
3002N/A }
3002N/A
0N/A s.println("Cert Authorities:");
2998N/A if (authorities.length == 0) {
2998N/A s.println("<Empty>");
2998N/A } else {
2998N/A for (int i = 0; i < authorities.length; i++) {
2998N/A authorities[i].print(s);
2998N/A }
2998N/A }
0N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/A/*
0N/A * ServerHelloDone ... SERVER --> CLIENT
0N/A *
0N/A * When server's done sending its messages in response to the client's
0N/A * "hello" (e.g. its own hello, certificate, key exchange message, perhaps
0N/A * client certificate request) it sends this message to flag that it's
0N/A * done that part of the handshake.
0N/A */
0N/Astatic final
0N/Aclass ServerHelloDone extends HandshakeMessage
0N/A{
0N/A int messageType() { return ht_server_hello_done; }
0N/A
0N/A ServerHelloDone() { }
0N/A
0N/A ServerHelloDone(HandshakeInStream input)
0N/A {
0N/A // nothing to do
0N/A }
0N/A
0N/A int messageLength()
0N/A {
0N/A return 0;
0N/A }
0N/A
0N/A void send(HandshakeOutStream s) throws IOException
0N/A {
0N/A // nothing to send
0N/A }
0N/A
0N/A void print(PrintStream s) throws IOException
0N/A {
0N/A s.println("*** ServerHelloDone");
0N/A }
0N/A}
0N/A
0N/A
0N/A/*
0N/A * CertificateVerify ... CLIENT --> SERVER
0N/A *
0N/A * Sent after client sends signature-capable certificates (e.g. not
0N/A * Diffie-Hellman) to verify.
0N/A */
0N/Astatic final class CertificateVerify extends HandshakeMessage {
0N/A
3002N/A // the signature bytes
3002N/A private byte[] signature;
0N/A
3002N/A // protocol version being established using this ServerKeyExchange message
3002N/A ProtocolVersion protocolVersion;
3002N/A
3002N/A // the preferable signature algorithm used by this CertificateVerify message
3002N/A private SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
0N/A
0N/A /*
0N/A * Create an RSA or DSA signed certificate verify message.
0N/A */
3002N/A CertificateVerify(ProtocolVersion protocolVersion,
3002N/A HandshakeHash handshakeHash, PrivateKey privateKey,
3002N/A SecretKey masterSecret, SecureRandom sr,
3002N/A SignatureAndHashAlgorithm signAlgorithm)
3002N/A throws GeneralSecurityException {
3002N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
0N/A String algorithm = privateKey.getAlgorithm();
3002N/A Signature sig = null;
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A this.preferableSignatureAlgorithm = signAlgorithm;
3002N/A sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
3002N/A } else {
3002N/A sig = getSignature(protocolVersion, algorithm);
3002N/A }
0N/A sig.initSign(privateKey, sr);
0N/A updateSignature(sig, protocolVersion, handshakeHash, algorithm,
0N/A masterSecret);
0N/A signature = sig.sign();
0N/A }
0N/A
0N/A //
0N/A // Unmarshal the signed data from the input stream.
0N/A //
3002N/A CertificateVerify(HandshakeInStream input,
3002N/A Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
3002N/A ProtocolVersion protocolVersion) throws IOException {
3002N/A
3002N/A this.protocolVersion = protocolVersion;
3002N/A
3002N/A // read the signature and hash algorithm
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A int hashAlg = input.getInt8(); // hash algorithm
3002N/A int signAlg = input.getInt8(); // signature algorithm
3002N/A
3002N/A preferableSignatureAlgorithm =
3002N/A SignatureAndHashAlgorithm.valueOf(hashAlg, signAlg, 0);
3002N/A
3002N/A // Is it a local supported signature algorithm?
3002N/A if (!localSupportedSignAlgs.contains(
3002N/A preferableSignatureAlgorithm)) {
3002N/A throw new SSLHandshakeException(
3002N/A "Unsupported SignatureAndHashAlgorithm in " +
3002N/A "ServerKeyExchange message");
3002N/A }
3002N/A }
3002N/A
3002N/A // read the signature
0N/A signature = input.getBytes16();
0N/A }
0N/A
0N/A /*
3002N/A * Get the preferable signature algorithm used by this message
3002N/A */
3002N/A SignatureAndHashAlgorithm getPreferableSignatureAlgorithm() {
3002N/A return preferableSignatureAlgorithm;
3002N/A }
3002N/A
3002N/A /*
0N/A * Verify a certificate verify message. Return the result of verification,
0N/A * if there is a problem throw a GeneralSecurityException.
0N/A */
0N/A boolean verify(ProtocolVersion protocolVersion,
0N/A HandshakeHash handshakeHash, PublicKey publicKey,
0N/A SecretKey masterSecret) throws GeneralSecurityException {
0N/A String algorithm = publicKey.getAlgorithm();
3002N/A Signature sig = null;
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A sig = JsseJce.getSignature(
3002N/A preferableSignatureAlgorithm.getAlgorithmName());
3002N/A } else {
3002N/A sig = getSignature(protocolVersion, algorithm);
3002N/A }
0N/A sig.initVerify(publicKey);
0N/A updateSignature(sig, protocolVersion, handshakeHash, algorithm,
0N/A masterSecret);
0N/A return sig.verify(signature);
0N/A }
0N/A
0N/A /*
0N/A * Get the Signature object appropriate for verification using the
0N/A * given signature algorithm and protocol version.
0N/A */
0N/A private static Signature getSignature(ProtocolVersion protocolVersion,
0N/A String algorithm) throws GeneralSecurityException {
0N/A if (algorithm.equals("RSA")) {
0N/A return RSASignature.getInternalInstance();
0N/A } else if (algorithm.equals("DSA")) {
0N/A return JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA);
0N/A } else if (algorithm.equals("EC")) {
0N/A return JsseJce.getSignature(JsseJce.SIGNATURE_RAWECDSA);
0N/A } else {
0N/A throw new SignatureException("Unrecognized algorithm: "
0N/A + algorithm);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Update the Signature with the data appropriate for the given
0N/A * signature algorithm and protocol version so that the object is
0N/A * ready for signing or verifying.
0N/A */
0N/A private static void updateSignature(Signature sig,
0N/A ProtocolVersion protocolVersion,
0N/A HandshakeHash handshakeHash, String algorithm, SecretKey masterKey)
0N/A throws SignatureException {
3002N/A
0N/A if (algorithm.equals("RSA")) {
3002N/A if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
3002N/A MessageDigest md5Clone = handshakeHash.getMD5Clone();
3002N/A MessageDigest shaClone = handshakeHash.getSHAClone();
3002N/A
3002N/A if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
3002N/A updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey);
3002N/A updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
3002N/A }
3002N/A
3002N/A // The signature must be an instance of RSASignature, need
3002N/A // to use these hashes directly.
3002N/A RSASignature.setHashes(sig, md5Clone, shaClone);
3002N/A } else { // TLS1.2+
3002N/A sig.update(handshakeHash.getAllHandshakeMessages());
0N/A }
0N/A } else { // DSA, ECDSA
3002N/A if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
3002N/A MessageDigest shaClone = handshakeHash.getSHAClone();
3002N/A
3002N/A if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
3002N/A updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
3002N/A }
3002N/A
3002N/A sig.update(shaClone.digest());
3002N/A } else { // TLS1.2+
3002N/A sig.update(handshakeHash.getAllHandshakeMessages());
0N/A }
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Update the MessageDigest for SSLv3 certificate verify or finished
0N/A * message calculation. The digest must already have been updated with
0N/A * all preceding handshake messages.
0N/A * Used by the Finished class as well.
0N/A */
3002N/A private static void updateDigest(MessageDigest md,
3002N/A byte[] pad1, byte[] pad2,
0N/A SecretKey masterSecret) {
0N/A // Digest the key bytes if available.
0N/A // Otherwise (sensitive key), try digesting the key directly.
0N/A // That is currently only implemented in SunPKCS11 using a private
0N/A // reflection API, so we avoid that if possible.
0N/A byte[] keyBytes = "RAW".equals(masterSecret.getFormat())
0N/A ? masterSecret.getEncoded() : null;
0N/A if (keyBytes != null) {
0N/A md.update(keyBytes);
0N/A } else {
0N/A digestKey(md, masterSecret);
0N/A }
0N/A md.update(pad1);
0N/A byte[] temp = md.digest();
0N/A
0N/A if (keyBytes != null) {
0N/A md.update(keyBytes);
0N/A } else {
0N/A digestKey(md, masterSecret);
0N/A }
0N/A md.update(pad2);
0N/A md.update(temp);
0N/A }
0N/A
0N/A private final static Class delegate;
0N/A private final static Field spiField;
0N/A
0N/A static {
0N/A try {
0N/A delegate = Class.forName("java.security.MessageDigest$Delegate");
0N/A spiField = delegate.getDeclaredField("digestSpi");
0N/A } catch (Exception e) {
0N/A throw new RuntimeException("Reflection failed", e);
0N/A }
0N/A makeAccessible(spiField);
0N/A }
0N/A
0N/A private static void makeAccessible(final AccessibleObject o) {
0N/A AccessController.doPrivileged(new PrivilegedAction<Object>() {
0N/A public Object run() {
0N/A o.setAccessible(true);
0N/A return null;
0N/A }
0N/A });
0N/A }
0N/A
0N/A // ConcurrentHashMap does not allow null values, use this marker object
0N/A private final static Object NULL_OBJECT = new Object();
0N/A
0N/A // cache Method objects per Spi class
0N/A // Note that this will prevent the Spi classes from being GC'd. We assume
0N/A // that is not a problem.
0N/A private final static Map<Class,Object> methodCache =
3401N/A new ConcurrentHashMap<>();
0N/A
0N/A private static void digestKey(MessageDigest md, SecretKey key) {
0N/A try {
0N/A // Verify that md is implemented via MessageDigestSpi, not
0N/A // via JDK 1.1 style MessageDigest subclassing.
0N/A if (md.getClass() != delegate) {
0N/A throw new Exception("Digest is not a MessageDigestSpi");
0N/A }
0N/A MessageDigestSpi spi = (MessageDigestSpi)spiField.get(md);
0N/A Class<?> clazz = spi.getClass();
0N/A Object r = methodCache.get(clazz);
0N/A if (r == null) {
0N/A try {
0N/A r = clazz.getDeclaredMethod("implUpdate", SecretKey.class);
0N/A makeAccessible((Method)r);
0N/A } catch (NoSuchMethodException e) {
0N/A r = NULL_OBJECT;
0N/A }
0N/A methodCache.put(clazz, r);
0N/A }
0N/A if (r == NULL_OBJECT) {
3002N/A throw new Exception(
3002N/A "Digest does not support implUpdate(SecretKey)");
0N/A }
0N/A Method update = (Method)r;
0N/A update.invoke(spi, key);
0N/A } catch (Exception e) {
3002N/A throw new RuntimeException(
3002N/A "Could not obtain encoded key and "
3002N/A + "MessageDigest cannot digest key", e);
0N/A }
0N/A }
0N/A
3002N/A @Override
3002N/A int messageType() {
3002N/A return ht_certificate_verify;
0N/A }
0N/A
3002N/A @Override
3002N/A int messageLength() {
3002N/A int temp = 2;
3002N/A
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A temp += SignatureAndHashAlgorithm.sizeInRecord();
3002N/A }
3002N/A
3002N/A return temp + signature.length;
3002N/A }
3002N/A
3002N/A @Override
0N/A void send(HandshakeOutStream s) throws IOException {
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A s.putInt8(preferableSignatureAlgorithm.getHashValue());
3002N/A s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
3002N/A }
3002N/A
0N/A s.putBytes16(signature);
0N/A }
0N/A
3002N/A @Override
0N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** CertificateVerify");
3002N/A
3002N/A if (debug != null && Debug.isOn("verbose")) {
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A s.println("Signature Algorithm " +
3002N/A preferableSignatureAlgorithm.getAlgorithmName());
3002N/A }
3002N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/A/*
0N/A * FINISHED ... sent by both CLIENT and SERVER
0N/A *
0N/A * This is the FINISHED message as defined in the SSL and TLS protocols.
0N/A * Both protocols define this handshake message slightly differently.
0N/A * This class supports both formats.
0N/A *
0N/A * When handshaking is finished, each side sends a "change_cipher_spec"
0N/A * record, then immediately sends a "finished" handshake message prepared
0N/A * according to the newly adopted cipher spec.
0N/A *
0N/A * NOTE that until this is sent, no application data may be passed, unless
0N/A * some non-default cipher suite has already been set up on this connection
0N/A * connection (e.g. a previous handshake arranged one).
0N/A */
0N/Astatic final class Finished extends HandshakeMessage {
0N/A
0N/A // constant for a Finished message sent by the client
0N/A final static int CLIENT = 1;
0N/A
0N/A // constant for a Finished message sent by the server
0N/A final static int SERVER = 2;
0N/A
0N/A // enum Sender: "CLNT" and "SRVR"
0N/A private static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 };
0N/A private static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 };
0N/A
0N/A /*
0N/A * Contents of the finished message ("checksum"). For TLS, it
0N/A * is 12 bytes long, for SSLv3 36 bytes.
0N/A */
0N/A private byte[] verifyData;
0N/A
0N/A /*
3002N/A * Current cipher suite we are negotiating. TLS 1.2 has
3002N/A * ciphersuite-defined PRF algorithms.
3002N/A */
3002N/A private ProtocolVersion protocolVersion;
3002N/A private CipherSuite cipherSuite;
3002N/A
3002N/A /*
0N/A * Create a finished message to send to the remote peer.
0N/A */
0N/A Finished(ProtocolVersion protocolVersion, HandshakeHash handshakeHash,
3002N/A int sender, SecretKey master, CipherSuite cipherSuite) {
3002N/A this.protocolVersion = protocolVersion;
3002N/A this.cipherSuite = cipherSuite;
3002N/A verifyData = getFinished(handshakeHash, sender, master);
0N/A }
0N/A
0N/A /*
0N/A * Constructor that reads FINISHED message from stream.
0N/A */
3002N/A Finished(ProtocolVersion protocolVersion, HandshakeInStream input,
3002N/A CipherSuite cipherSuite) throws IOException {
3002N/A this.protocolVersion = protocolVersion;
3002N/A this.cipherSuite = cipherSuite;
0N/A int msgLen = (protocolVersion.v >= ProtocolVersion.TLS10.v) ? 12 : 36;
0N/A verifyData = new byte[msgLen];
0N/A input.read(verifyData);
0N/A }
0N/A
0N/A /*
0N/A * Verify that the hashes here are what would have been produced
0N/A * according to a given set of inputs. This is used to ensure that
0N/A * both client and server are fully in sync, and that the handshake
0N/A * computations have been successful.
0N/A */
3002N/A boolean verify(HandshakeHash handshakeHash, int sender, SecretKey master) {
3002N/A byte[] myFinished = getFinished(handshakeHash, sender, master);
0N/A return Arrays.equals(myFinished, verifyData);
0N/A }
0N/A
0N/A /*
0N/A * Perform the actual finished message calculation.
0N/A */
3002N/A private byte[] getFinished(HandshakeHash handshakeHash,
3002N/A int sender, SecretKey masterKey) {
0N/A byte[] sslLabel;
0N/A String tlsLabel;
0N/A if (sender == CLIENT) {
0N/A sslLabel = SSL_CLIENT;
0N/A tlsLabel = "client finished";
0N/A } else if (sender == SERVER) {
0N/A sslLabel = SSL_SERVER;
0N/A tlsLabel = "server finished";
0N/A } else {
0N/A throw new RuntimeException("Invalid sender: " + sender);
0N/A }
3002N/A
0N/A if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
3002N/A // TLS 1.0+
0N/A try {
3002N/A byte [] seed;
3002N/A String prfAlg;
3002N/A PRF prf;
3002N/A
3002N/A // Get the KeyGenerator alg and calculate the seed.
3002N/A if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
3002N/A // TLS 1.2
3002N/A seed = handshakeHash.getFinishedHash();
3002N/A
3002N/A prfAlg = "SunTls12Prf";
3002N/A prf = cipherSuite.prfAlg;
3002N/A } else {
3002N/A // TLS 1.0/1.1
3002N/A MessageDigest md5Clone = handshakeHash.getMD5Clone();
3002N/A MessageDigest shaClone = handshakeHash.getSHAClone();
3002N/A seed = new byte[36];
3002N/A md5Clone.digest(seed, 0, 16);
3002N/A shaClone.digest(seed, 16, 20);
0N/A
3002N/A prfAlg = "SunTlsPrf";
3002N/A prf = P_NONE;
3002N/A }
3002N/A
3002N/A String prfHashAlg = prf.getPRFHashAlg();
3002N/A int prfHashLength = prf.getPRFHashLength();
3002N/A int prfBlockSize = prf.getPRFBlockSize();
3002N/A
3002N/A /*
3002N/A * RFC 5246/7.4.9 says that finished messages can
3002N/A * be ciphersuite-specific in both length/PRF hash
3002N/A * algorithm. If we ever run across a different
3002N/A * length, this call will need to be updated.
3002N/A */
3002N/A TlsPrfParameterSpec spec = new TlsPrfParameterSpec(
3002N/A masterKey, tlsLabel, seed, 12,
3002N/A prfHashAlg, prfHashLength, prfBlockSize);
3002N/A
3002N/A KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg);
3002N/A kg.init(spec);
3002N/A SecretKey prfKey = kg.generateKey();
0N/A if ("RAW".equals(prfKey.getFormat()) == false) {
3002N/A throw new ProviderException(
3002N/A "Invalid PRF output, format must be RAW");
0N/A }
0N/A byte[] finished = prfKey.getEncoded();
0N/A return finished;
0N/A } catch (GeneralSecurityException e) {
0N/A throw new RuntimeException("PRF failed", e);
0N/A }
0N/A } else {
0N/A // SSLv3
3002N/A MessageDigest md5Clone = handshakeHash.getMD5Clone();
3002N/A MessageDigest shaClone = handshakeHash.getSHAClone();
0N/A updateDigest(md5Clone, sslLabel, MD5_pad1, MD5_pad2, masterKey);
0N/A updateDigest(shaClone, sslLabel, SHA_pad1, SHA_pad2, masterKey);
0N/A byte[] finished = new byte[36];
0N/A try {
0N/A md5Clone.digest(finished, 0, 16);
0N/A shaClone.digest(finished, 16, 20);
0N/A } catch (DigestException e) {
0N/A // cannot occur
0N/A throw new RuntimeException("Digest failed", e);
0N/A }
0N/A return finished;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Update the MessageDigest for SSLv3 finished message calculation.
0N/A * The digest must already have been updated with all preceding handshake
0N/A * messages. This operation is almost identical to the certificate verify
0N/A * hash, reuse that code.
0N/A */
0N/A private static void updateDigest(MessageDigest md, byte[] sender,
0N/A byte[] pad1, byte[] pad2, SecretKey masterSecret) {
0N/A md.update(sender);
0N/A CertificateVerify.updateDigest(md, pad1, pad2, masterSecret);
0N/A }
0N/A
2890N/A // get the verify_data of the finished message
2890N/A byte[] getVerifyData() {
2890N/A return verifyData;
2890N/A }
2890N/A
2890N/A @Override
2890N/A int messageType() { return ht_finished; }
2890N/A
2890N/A @Override
0N/A int messageLength() {
0N/A return verifyData.length;
0N/A }
0N/A
2890N/A @Override
0N/A void send(HandshakeOutStream out) throws IOException {
0N/A out.write(verifyData);
0N/A }
0N/A
2890N/A @Override
0N/A void print(PrintStream s) throws IOException {
0N/A s.println("*** Finished");
0N/A if (debug != null && Debug.isOn("verbose")) {
0N/A Debug.println(s, "verify_data", verifyData);
0N/A s.println("***");
0N/A }
0N/A }
0N/A}
0N/A
0N/A//
0N/A// END of nested classes
0N/A//
0N/A
0N/A}