0001:/*
0002: * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026:
0027:package sun.security.ssl;
0028:
0029:import java.io.*;
0030:import java.math.BigInteger;
0031:import java.security.*;
0032:import java.security.interfaces.*;
0033:import java.security.spec.*;
0034:import java.security.cert.*;
0035:import java.security.cert.Certificate;
0036:import java.util.*;
0037:import java.util.concurrent.ConcurrentHashMap;
0038:
0039:import java.lang.reflect.*;
0040:
0041:import javax.security.auth.x500.X500Principal;
0042:
0043:import javax.crypto.KeyGenerator;
0044:import javax.crypto.SecretKey;
0045:import javax.crypto.spec.SecretKeySpec;
0046:
0047:import javax.net.ssl.*;
0048:
0049:import sun.security.action.GetPropertyAction;
0050:
0051:import sun.security.internal.spec.TlsPrfParameterSpec;
0052:
0053:import sun.security.ssl.CipherSuite.*;
0054:
0055:/**
0056: * Many data structures are involved in the handshake messages. These
0057: * classes are used as structures, with public data members. They are
0058: * not visible outside the SSL package.
0059: *
0060: * Handshake messages all have a common header format, and they are all
0061: * encoded in a "handshake data" SSL record substream. The base class
0062: * here (HandshakeMessage) provides a common framework and records the
0063: * SSL record type of the particular handshake message.
0064: *
0065: * This file contains subclasses for all the basic handshake messages.
0066: * All handshake messages know how to encode and decode themselves on
0067: * SSL streams; this facilitates using the same code on SSL client and
0068: * server sides, although they don't send and receive the same messages.
0069: *
0070: * Messages also know how to print themselves, which is quite handy
0071: * for debugging. They always identify their type, and can optionally
0072: * dump all of their content.
0073: *
0074: * @version 1.104, 05/05/07
0075: * @author David Brownell
0076: */
0077:abstract class HandshakeMessage {
0078:
0079: HandshakeMessage() { }
0080:
0081: // enum HandshakeType:
0082: static final byte ht_hello_request = 0;
0083: static final byte ht_client_hello = 1;
0084: static final byte ht_server_hello = 2;
0085:
0086: static final byte ht_certificate = 11;
0087: static final byte ht_server_key_exchange = 12;
0088: static final byte ht_certificate_request = 13;
0089: static final byte ht_server_hello_done = 14;
0090: static final byte ht_certificate_verify = 15;
0091: static final byte ht_client_key_exchange = 16;
0092:
0093: static final byte ht_finished = 20;
0094:
0095: /* Class and subclass dynamic debugging support */
0096: static final Debug debug = Debug.getInstance("ssl");
0097:
0098: /**
0099: * Utility method to convert a BigInteger to a byte array in unsigned
0100: * format as needed in the handshake messages. BigInteger uses
0101: * 2's complement format, i.e. it prepends an extra zero if the MSB
0102: * is set. We remove that.
0103: */
0104: static byte[] toByteArray(BigInteger bi) {
0105: byte[] b = bi.toByteArray();
0106: if ((b.length > 1) && (b[0] == 0)) {
0107: int n = b.length - 1;
0108: byte[] newarray = new byte[n];
0109: System.arraycopy(b, 1, newarray, 0, n);
0110: b = newarray;
0111: }
0112: return b;
0113: }
0114:
0115: /*
0116: * SSL 3.0 MAC padding constants.
0117: * Also used by CertificateVerify and Finished during the handshake.
0118: */
0119: static final byte[] MD5_pad1 = genPad(0x36, 48);
0120: static final byte[] MD5_pad2 = genPad(0x5c, 48);
0121:
0122: static final byte[] SHA_pad1 = genPad(0x36, 40);
0123: static final byte[] SHA_pad2 = genPad(0x5c, 40);
0124:
0125: private static byte[] genPad(int b, int count) {
0126: byte[] padding = new byte[count];
0127: Arrays.fill(padding, (byte)b);
0128: return padding;
0129: }
0130:
0131: /*
0132: * Write a handshake message on the (handshake) output stream.
0133: * This is just a four byte header followed by the data.
0134: *
0135: * NOTE that huge messages -- notably, ones with huge cert
0136: * chains -- are handled correctly.
0137: */
0138: final void write(HandshakeOutStream s) throws IOException {
0139: int len = messageLength();
0140: if (len > (1 << 24)) {
0141: throw new SSLException("Handshake message too big"
0142: + ", type = " + messageType() + ", len = " + len);
0143: }
0144: s.write(messageType());
0145: s.putInt24(len);
0146: send(s);
0147: }
0148:
0149: /*
0150: * Subclasses implement these methods so those kinds of
0151: * messages can be emitted. Base class delegates to subclass.
0152: */
0153: abstract int messageType();
0154: abstract int messageLength();
0155: abstract void send(HandshakeOutStream s) throws IOException;
0156:
0157: /*
0158: * Write a descriptive message on the output stream; for debugging.
0159: */
0160: abstract void print(PrintStream p) throws IOException;
0161:
0162://
0163:// NOTE: the rest of these classes are nested within this one, and are
0164:// imported by other classes in this package. There are a few other
0165:// handshake message classes, not neatly nested here because of current
0166:// licensing requirement for native (RSA) methods. They belong here,
0167:// but those native methods complicate things a lot!
0168://
0169:
0170:
0171:/*
0172: * HelloRequest ... SERVER --> CLIENT
0173: *
0174: * Server can ask the client to initiate a new handshake, e.g. to change
0175: * session parameters after a connection has been (re)established.
0176: */
0177:static final
0178:class HelloRequest extends HandshakeMessage
0179:{
0180: int messageType() { return ht_hello_request; }
0181:
0182: HelloRequest() { }
0183:
0184: HelloRequest(HandshakeInStream in) throws IOException
0185: {
0186: // nothing in this message
0187: }
0188:
0189: int messageLength() { return 0; }
0190:
0191: void send(HandshakeOutStream out) throws IOException
0192: {
0193: // nothing in this messaage
0194: }
0195:
0196: void print(PrintStream out) throws IOException
0197: {
0198: out.println("*** HelloRequest (empty)");
0199: }
0200:
0201:}
0202:
0203:
0204:/*
0205: * ClientHello ... CLIENT --> SERVER
0206: *
0207: * Client initiates handshake by telling server what it wants, and what it
0208: * can support (prioritized by what's first in the ciphe suite list).
0209: *
0210: * By RFC2246:7.4.1.2 it's explicitly anticipated that this message
0211: * will have more data added at the end ... e.g. what CAs the client trusts.
0212: * Until we know how to parse it, we will just read what we know
0213: * about, and let our caller handle the jumps over unknown data.
0214: */
0215:static final
0216:class ClientHello extends HandshakeMessage
0217:{
0218: int messageType() { return ht_client_hello; }
0219:
0220: ProtocolVersion protocolVersion;
0221: RandomCookie clnt_random;
0222: SessionId sessionId;
0223: private CipherSuiteList cipherSuites;
0224: byte[] compression_methods;
0225:
0226: HelloExtensions extensions = new HelloExtensions();
0227:
0228: private final static byte[] NULL_COMPRESSION = new byte[] {0};
0229:
0230: ClientHello(SecureRandom generator, ProtocolVersion protocolVersion) {
0231: this .protocolVersion = protocolVersion;
0232: clnt_random = new RandomCookie(generator);
0233: compression_methods = NULL_COMPRESSION;
0234: // sessionId, cipher_suites TBS later
0235: }
0236:
0237: CipherSuiteList getCipherSuites() {
0238: return cipherSuites;
0239: }
0240:
0241: // Set the ciphersuites.
0242: // This method may only be called once.
0243: void setCipherSuites(CipherSuiteList cipherSuites) {
0244: this .cipherSuites = cipherSuites;
0245: if (cipherSuites.containsEC()) {
0246: extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
0247: extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT);
0248: }
0249: }
0250:
0251: int messageLength() {
0252: /*
0253: * Add fixed size parts of each field...
0254: * version + random + session + cipher + compress
0255: */
0256: return (2 + 32 + 1 + 2 + 1
0257: + sessionId.length() /* ... + variable parts */
0258: + (cipherSuites.size() * 2)
0259: + compression_methods.length)
0260: + extensions.length();
0261: }
0262:
0263: ClientHello(HandshakeInStream s, int messageLength) throws IOException {
0264: protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8());
0265: clnt_random = new RandomCookie(s);
0266: sessionId = new SessionId(s.getBytes8());
0267: cipherSuites = new CipherSuiteList(s);
0268: compression_methods = s.getBytes8();
0269: if (messageLength() != messageLength) {
0270: extensions = new HelloExtensions(s);
0271: }
0272: }
0273:
0274: void send(HandshakeOutStream s) throws IOException {
0275: s.putInt8(protocolVersion.major);
0276: s.putInt8(protocolVersion.minor);
0277: clnt_random.send(s);
0278: s.putBytes8(sessionId.getId());
0279: cipherSuites.send(s);
0280: s.putBytes8(compression_methods);
0281: extensions.send(s);
0282: }
0283:
0284: void print(PrintStream s) throws IOException {
0285: s.println("*** ClientHello, " + protocolVersion);
0286:
0287: if (debug != null && Debug.isOn("verbose")) {
0288: s.print ("RandomCookie: "); clnt_random.print(s);
0289:
0290: s.print("Session ID: ");
0291: s.println(sessionId);
0292:
0293: s.println("Cipher Suites: " + cipherSuites);
0294:
0295: Debug.println(s, "Compression Methods", compression_methods);
0296: extensions.print(s);
0297: s.println("***");
0298: }
0299: }
0300:}
0301:
0302:/*
0303: * ServerHello ... SERVER --> CLIENT
0304: *
0305: * Server chooses protocol options from among those it supports and the
0306: * client supports. Then it sends the basic session descriptive parameters
0307: * back to the client.
0308: */
0309:static final
0310:class ServerHello extends HandshakeMessage
0311:{
0312: int messageType() { return ht_server_hello; }
0313:
0314: ProtocolVersion protocolVersion;
0315: RandomCookie svr_random;
0316: SessionId sessionId;
0317: CipherSuite cipherSuite;
0318: byte compression_method;
0319: HelloExtensions extensions = new HelloExtensions();
0320: int extensionLength;
0321:
0322: ServerHello() {
0323: // empty
0324: }
0325:
0326: ServerHello(HandshakeInStream input, int messageLength) throws IOException {
0327: protocolVersion = ProtocolVersion.valueOf(input.getInt8(),
0328: input.getInt8());
0329: svr_random = new RandomCookie(input);
0330: sessionId = new SessionId(input.getBytes8());
0331: cipherSuite = CipherSuite.valueOf(input.getInt8(), input.getInt8());
0332: compression_method = (byte)input.getInt8();
0333: if (messageLength() != messageLength) {
0334: extensions = new HelloExtensions(input);
0335: }
0336: }
0337:
0338: int messageLength()
0339: {
0340: // almost fixed size, except session ID and extensions:
0341: // major + minor = 2
0342: // random = 32
0343: // session ID len field = 1
0344: // cipher suite + compression = 3
0345: // extensions: if present, 2 + length of extensions
0346: return 38 + sessionId.length() + extensions.length();
0347: }
0348:
0349: void send(HandshakeOutStream s) throws IOException
0350: {
0351: s.putInt8(protocolVersion.major);
0352: s.putInt8(protocolVersion.minor);
0353: svr_random.send(s);
0354: s.putBytes8(sessionId.getId());
0355: s.putInt8(cipherSuite.id >> 8);
0356: s.putInt8(cipherSuite.id & 0xff);
0357: s.putInt8(compression_method);
0358: extensions.send(s);
0359: }
0360:
0361: void print(PrintStream s) throws IOException
0362: {
0363: s.println("*** ServerHello, " + protocolVersion);
0364:
0365: if (debug != null && Debug.isOn("verbose")) {
0366: s.print ("RandomCookie: "); svr_random.print(s);
0367:
0368: int i;
0369:
0370: s.print("Session ID: ");
0371: s.println(sessionId);
0372:
0373: s.println("Cipher Suite: " + cipherSuite);
0374: s.println("Compression Method: " + compression_method);
0375: extensions.print(s);
0376: s.println("***");
0377: }
0378: }
0379:}
0380:
0381:
0382:/*
0383: * CertificateMsg ... send by both CLIENT and SERVER
0384: *
0385: * Each end of a connection may need to pass its certificate chain to
0386: * the other end. Such chains are intended to validate an identity with
0387: * reference to some certifying authority. Examples include companies
0388: * like Verisign, or financial institutions. There's some control over
0389: * the certifying authorities which are sent.
0390: *
0391: * NOTE: that these messages might be huge, taking many handshake records.
0392: * Up to 2^48 bytes of certificate may be sent, in records of at most 2^14
0393: * bytes each ... up to 2^32 records sent on the output stream.
0394: */
0395:static final
0396:class CertificateMsg extends HandshakeMessage
0397:{
0398: int messageType() { return ht_certificate; }
0399:
0400: private X509Certificate[] chain;
0401:
0402: private List<byte[]> encodedChain;
0403:
0404: private int messageLength;
0405:
0406: CertificateMsg(X509Certificate[] certs) {
0407: chain = certs;
0408: }
0409:
0410: CertificateMsg(HandshakeInStream input) throws IOException {
0411: int chainLen = input.getInt24();
0412: List<Certificate> v = new ArrayList<Certificate>(4);
0413:
0414: CertificateFactory cf = null;
0415: while (chainLen > 0) {
0416: byte[] cert = input.getBytes24();
0417: chainLen -= (3 + cert.length);
0418: try {
0419: if (cf == null) {
0420: cf = CertificateFactory.getInstance("X.509");
0421: }
0422: v.add(cf.generateCertificate(new ByteArrayInputStream(cert)));
0423: } catch (CertificateException e) {
0424: throw (SSLProtocolException)new SSLProtocolException
0425: (e.getMessage()).initCause(e);
0426: }
0427: }
0428:
0429: chain = v.toArray(new X509Certificate[v.size()]);
0430: }
0431:
0432: int messageLength() {
0433: if (encodedChain == null) {
0434: messageLength = 3;
0435: encodedChain = new ArrayList<byte[]>(chain.length);
0436: try {
0437: for (X509Certificate cert : chain) {
0438: byte[] b = cert.getEncoded();
0439: encodedChain.add(b);
0440: messageLength += b.length + 3;
0441: }
0442: } catch (CertificateEncodingException e) {
0443: encodedChain = null;
0444: throw new RuntimeException("Could not encode certificates", e);
0445: }
0446: }
0447: return messageLength;
0448: }
0449:
0450: void send(HandshakeOutStream s) throws IOException {
0451: s.putInt24(messageLength() - 3);
0452: for (byte[] b : encodedChain) {
0453: s.putBytes24(b);
0454: }
0455: }
0456:
0457: void print(PrintStream s) throws IOException {
0458: s.println("*** Certificate chain");
0459:
0460: if (debug != null && Debug.isOn("verbose")) {
0461: for (int i = 0; i < chain.length; i++)
0462: s.println("chain [" + i + "] = " + chain[i]);
0463: s.println("***");
0464: }
0465: }
0466:
0467: X509Certificate[] getCertificateChain() {
0468: return chain;
0469: }
0470:}
0471:
0472:
0473:/*
0474: * ServerKeyExchange ... SERVER --> CLIENT
0475: *
0476: * The cipher suite selected, when combined with the certificate exchanged,
0477: * implies one of several different kinds of key exchange. Most current
0478: * cipher suites require the server to send more than its certificate.
0479: *
0480: * The primary exceptions are when a server sends an encryption-capable
0481: * RSA public key in its cert, to be used with RSA (or RSA_export) key
0482: * exchange; and when a server sends its Diffie-Hellman cert. Those kinds
0483: * of key exchange do not require a ServerKeyExchange message.
0484: *
0485: * Key exchange can be viewed as having three modes, which are explicit
0486: * for the Diffie-Hellman flavors and poorly specified for RSA ones:
0487: *
0488: * - "Ephemeral" keys. Here, a "temporary" key is allocated by the
0489: * server, and signed. Diffie-Hellman keys signed using RSA or
0490: * DSS are ephemeral (DHE flavor). RSA keys get used to do the same
0491: * thing, to cut the key size down to 512 bits (export restrictions)
0492: * or for signing-only RSA certificates.
0493: *
0494: * - Anonymity. Here no server certificate is sent, only the public
0495: * key of the server. This case is subject to man-in-the-middle
0496: * attacks. This can be done with Diffie-Hellman keys (DH_anon) or
0497: * with RSA keys, but is only used in SSLv3 for DH_anon.
0498: *
0499: * - "Normal" case. Here a server certificate is sent, and the public
0500: * key there is used directly in exchanging the premaster secret.
0501: * For example, Diffie-Hellman "DH" flavor, and any RSA flavor with
0502: * only 512 bit keys.
0503: *
0504: * If a server certificate is sent, there is no anonymity. However,
0505: * when a certificate is sent, ephemeral keys may still be used to
0506: * exchange the premaster secret. That's how RSA_EXPORT often works,
0507: * as well as how the DHE_* flavors work.
0508: */
0509:static abstract class ServerKeyExchange extends HandshakeMessage
0510:{
0511: int messageType() { return ht_server_key_exchange; }
0512:}
0513:
0514:
0515:/*
0516: * Using RSA for Key Exchange: exchange a session key that's not as big
0517: * as the signing-only key. Used for export applications, since exported
0518: * RSA encryption keys can't be bigger than 512 bytes.
0519: *
0520: * This is never used when keys are 512 bits or smaller, and isn't used
0521: * on "US Domestic" ciphers in any case.
0522: */
0523:static final
0524:class RSA_ServerKeyExchange extends ServerKeyExchange
0525:{
0526: private byte rsa_modulus[]; // 1 to 2^16 - 1 bytes
0527: private byte rsa_exponent[]; // 1 to 2^16 - 1 bytes
0528:
0529: private Signature signature;
0530: private byte[] signatureBytes;
0531:
0532: /*
0533: * Hash the nonces and the ephemeral RSA public key.
0534: */
0535: private void updateSignature(byte clntNonce[], byte svrNonce[])
0536: throws SignatureException {
0537: int tmp;
0538:
0539: signature.update(clntNonce);
0540: signature.update(svrNonce);
0541:
0542: tmp = rsa_modulus.length;
0543: signature.update((byte)(tmp >> 8));
0544: signature.update((byte)(tmp & 0x0ff));
0545: signature.update(rsa_modulus);
0546:
0547: tmp = rsa_exponent.length;
0548: signature.update((byte)(tmp >> 8));
0549: signature.update((byte)(tmp & 0x0ff));
0550: signature.update(rsa_exponent);
0551: }
0552:
0553:
0554: /*
0555: * Construct an RSA server key exchange message, using data
0556: * known _only_ to the server.
0557: *
0558: * The client knows the public key corresponding to this private
0559: * key, from the Certificate message sent previously. To comply
0560: * with US export regulations we use short RSA keys ... either
0561: * long term ones in the server's X509 cert, or else ephemeral
0562: * ones sent using this message.
0563: */
0564: RSA_ServerKeyExchange(PublicKey ephemeralKey, PrivateKey privateKey,
0565: RandomCookie clntNonce, RandomCookie svrNonce, SecureRandom sr)
0566: throws GeneralSecurityException {
0567: RSAPublicKeySpec rsaKey = JsseJce.getRSAPublicKeySpec(ephemeralKey);
0568: rsa_modulus = toByteArray(rsaKey.getModulus());
0569: rsa_exponent = toByteArray(rsaKey.getPublicExponent());
0570: signature = RSASignature.getInstance();
0571: signature.initSign(privateKey, sr);
0572: updateSignature(clntNonce.random_bytes, svrNonce.random_bytes);
0573: signatureBytes = signature.sign();
0574: }
0575:
0576:
0577: /*
0578: * Parse an RSA server key exchange message, using data known
0579: * to the client (and, in some situations, eavesdroppers).
0580: */
0581: RSA_ServerKeyExchange(HandshakeInStream input)
0582: throws IOException, NoSuchAlgorithmException {
0583: signature = RSASignature.getInstance();
0584: rsa_modulus = input.getBytes16();
0585: rsa_exponent = input.getBytes16();
0586: signatureBytes = input.getBytes16();
0587: }
0588:
0589: /*
0590: * Get the ephemeral RSA public key that will be used in this
0591: * SSL connection.
0592: */
0593: PublicKey getPublicKey() {
0594: try {
0595: KeyFactory kfac = JsseJce.getKeyFactory("RSA");
0596: // modulus and exponent are always positive
0597: RSAPublicKeySpec kspec = new RSAPublicKeySpec
0598: (new BigInteger(1, rsa_modulus),
0599: new BigInteger(1, rsa_exponent));
0600: return kfac.generatePublic(kspec);
0601: } catch (Exception e) {
0602: throw new RuntimeException(e);
0603: }
0604: }
0605:
0606: /*
0607: * Verify the signed temporary key using the hashes computed
0608: * from it and the two nonces. This is called by clients
0609: * with "exportable" RSA flavors.
0610: */
0611: boolean verify(PublicKey certifiedKey, RandomCookie clntNonce,
0612: RandomCookie svrNonce) throws GeneralSecurityException {
0613: signature.initVerify(certifiedKey);
0614: updateSignature(clntNonce.random_bytes, svrNonce.random_bytes);
0615: return signature.verify(signatureBytes);
0616: }
0617:
0618: int messageLength() {
0619: return 6 + rsa_modulus.length + rsa_exponent.length
0620: + signatureBytes.length;
0621: }
0622:
0623: void send(HandshakeOutStream s) throws IOException {
0624: s.putBytes16(rsa_modulus);
0625: s.putBytes16(rsa_exponent);
0626: s.putBytes16(signatureBytes);
0627: }
0628:
0629: void print(PrintStream s) throws IOException {
0630: s.println("*** RSA ServerKeyExchange");
0631:
0632: if (debug != null && Debug.isOn("verbose")) {
0633: Debug.println(s, "RSA Modulus", rsa_modulus);
0634: Debug.println(s, "RSA Public Exponent", rsa_exponent);
0635: }
0636: }
0637:}
0638:
0639:
0640:/*
0641: * Using Diffie-Hellman algorithm for key exchange. All we really need to
0642: * do is securely get Diffie-Hellman keys (using the same P, G parameters)
0643: * to our peer, then we automatically have a shared secret without need
0644: * to exchange any more data. (D-H only solutions, such as SKIP, could
0645: * eliminate key exchange negotiations and get faster connection setup.
0646: * But they still need a signature algorithm like DSS/DSA to support the
0647: * trusted distribution of keys without relying on unscalable physical
0648: * key distribution systems.)
0649: *
0650: * This class supports several DH-based key exchange algorithms, though
0651: * perhaps eventually each deserves its own class. Notably, this has
0652: * basic support for DH_anon and its DHE_DSS and DHE_RSA signed variants.
0653: */
0654:static final
0655:class DH_ServerKeyExchange extends ServerKeyExchange
0656:{
0657: // Fix message encoding, see 4348279
0658: private final static boolean dhKeyExchangeFix =
0659: Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true);
0660:
0661: private byte dh_p []; // 1 to 2^16 - 1 bytes
0662: private byte dh_g []; // 1 to 2^16 - 1 bytes
0663: private byte dh_Ys []; // 1 to 2^16 - 1 bytes
0664:
0665: private byte signature [];
0666:
0667: /* Return the Diffie-Hellman modulus */
0668: BigInteger getModulus() {
0669: return new BigInteger(1, dh_p);
0670: }
0671:
0672: /* Return the Diffie-Hellman base/generator */
0673: BigInteger getBase() {
0674: return new BigInteger(1, dh_g);
0675: }
0676:
0677: /* Return the server's Diffie-Hellman public key */
0678: BigInteger getServerPublicKey() {
0679: return new BigInteger(1, dh_Ys);
0680: }
0681:
0682: /*
0683: * Update sig with nonces and Diffie-Hellman public key.
0684: */
0685: private void updateSignature(Signature sig, byte clntNonce[],
0686: byte svrNonce[]) throws SignatureException {
0687: int tmp;
0688:
0689: sig.update(clntNonce);
0690: sig.update(svrNonce);
0691:
0692: tmp = dh_p.length;
0693: sig.update((byte)(tmp >> 8));
0694: sig.update((byte)(tmp & 0x0ff));
0695: sig.update(dh_p);
0696:
0697: tmp = dh_g.length;
0698: sig.update((byte)(tmp >> 8));
0699: sig.update((byte)(tmp & 0x0ff));
0700: sig.update(dh_g);
0701:
0702: tmp = dh_Ys.length;
0703: sig.update((byte)(tmp >> 8));
0704: sig.update((byte)(tmp & 0x0ff));
0705: sig.update(dh_Ys);
0706: }
0707:
0708: /*
0709: * Construct from initialized DH key object, for DH_anon
0710: * key exchange.
0711: */
0712: DH_ServerKeyExchange(DHCrypt obj) {
0713: getValues(obj);
0714: signature = null;
0715: }
0716:
0717: /*
0718: * Construct from initialized DH key object and the key associated
0719: * with the cert chain which was sent ... for DHE_DSS and DHE_RSA
0720: * key exchange. (Constructor called by server.)
0721: */
0722: DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[],
0723: byte svrNonce[], SecureRandom sr) throws GeneralSecurityException {
0724:
0725: getValues(obj);
0726:
0727: Signature sig;
0728: if (key.getAlgorithm().equals("DSA")) {
0729: sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
0730: } else {
0731: sig = RSASignature.getInstance();
0732: }
0733: sig.initSign(key, sr);
0734: updateSignature(sig, clntNonce, svrNonce);
0735: signature = sig.sign();
0736: }
0737:
0738: private void getValues(DHCrypt obj) {
0739: dh_p = toByteArray(obj.getModulus());
0740: dh_g = toByteArray(obj.getBase());
0741: dh_Ys = toByteArray(obj.getPublicKey());
0742: }
0743:
0744: /*
0745: * Construct a DH_ServerKeyExchange message from an input
0746: * stream, as if sent from server to client for use with
0747: * DH_anon key exchange
0748: */
0749: DH_ServerKeyExchange(HandshakeInStream input) throws IOException {
0750: dh_p = input.getBytes16();
0751: dh_g = input.getBytes16();
0752: dh_Ys = input.getBytes16();
0753: signature = null;
0754: }
0755:
0756: /*
0757: * Construct a DH_ServerKeyExchange message from an input stream
0758: * and a certificate, as if sent from server to client for use with
0759: * DHE_DSS or DHE_RSA key exchange. (Called by client.)
0760: */
0761: DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey,
0762: byte clntNonce[], byte svrNonce[], int messageSize)
0763: throws IOException, GeneralSecurityException {
0764:
0765: dh_p = input.getBytes16();
0766: dh_g = input.getBytes16();
0767: dh_Ys = input.getBytes16();
0768:
0769: byte signature[];
0770: if (dhKeyExchangeFix) {
0771: signature = input.getBytes16();
0772: } else {
0773: messageSize -= (dh_p.length + 2);
0774: messageSize -= (dh_g.length + 2);
0775: messageSize -= (dh_Ys.length + 2);
0776:
0777: signature = new byte[messageSize];
0778: input.read(signature);
0779: }
0780:
0781: Signature sig;
0782: String algorithm = publicKey.getAlgorithm();
0783: if (algorithm.equals("DSA")) {
0784: sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
0785: } else if (algorithm.equals("RSA")) {
0786: sig = RSASignature.getInstance();
0787: } else {
0788: throw new SSLKeyException("neither an RSA or a DSA key");
0789: }
0790:
0791: sig.initVerify(publicKey);
0792: updateSignature(sig, clntNonce, svrNonce);
0793:
0794: if (sig.verify(signature) == false ) {
0795: throw new SSLKeyException("Server D-H key verification failed");
0796: }
0797: }
0798:
0799: int messageLength() {
0800: int temp = 6; // overhead for p, g, y(s) values.
0801:
0802: temp += dh_p.length;
0803: temp += dh_g.length;
0804: temp += dh_Ys.length;
0805: if (signature != null) {
0806: temp += signature.length;
0807: if (dhKeyExchangeFix) {
0808: temp += 2;
0809: }
0810: }
0811: return temp;
0812: }
0813:
0814: void send(HandshakeOutStream s) throws IOException {
0815: s.putBytes16(dh_p);
0816: s.putBytes16(dh_g);
0817: s.putBytes16(dh_Ys);
0818: if (signature != null) {
0819: if (dhKeyExchangeFix) {
0820: s.putBytes16(signature);
0821: } else {
0822: s.write(signature);
0823: }
0824: }
0825: }
0826:
0827: void print(PrintStream s) throws IOException {
0828: s.println("*** Diffie-Hellman ServerKeyExchange");
0829:
0830: if (debug != null && Debug.isOn("verbose")) {
0831: Debug.println(s, "DH Modulus", dh_p);
0832: Debug.println(s, "DH Base", dh_g);
0833: Debug.println(s, "Server DH Public Key", dh_Ys);
0834:
0835: if (signature == null) {
0836: s.println("Anonymous");
0837: } else {
0838: s.println("Signed with a DSA or RSA public key");
0839: }
0840: }
0841: }
0842:}
0843:
0844:/*
0845: * ECDH server key exchange message. Sent by the server for ECDHE and ECDH_anon
0846: * ciphersuites to communicate its ephemeral public key (including the
0847: * EC domain parameters).
0848: *
0849: * We support named curves only, no explicitly encoded curves.
0850: */
0851:static final
0852:class ECDH_ServerKeyExchange extends ServerKeyExchange
0853:{
0854:
0855: // constants for ECCurveType
0856: private final static int CURVE_EXPLICIT_PRIME = 1;
0857: private final static int CURVE_EXPLICIT_CHAR2 = 2;
0858: private final static int CURVE_NAMED_CURVE = 3;
0859:
0860: // id of the curve we are using
0861: private int curveId;
0862: // encoded public point
0863: private byte[] pointBytes;
0864:
0865: // signature bytes (or null if anonymous)
0866: private byte[] signatureBytes;
0867:
0868: // public key object encapsulated in this message
0869: private ECPublicKey publicKey;
0870:
0871: ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey,
0872: byte[] clntNonce, byte[] svrNonce, SecureRandom sr)
0873: throws GeneralSecurityException {
0874: publicKey = (ECPublicKey)obj.getPublicKey();
0875: ECParameterSpec params = publicKey.getParams();
0876: ECPoint point = publicKey.getW();
0877: pointBytes = JsseJce.encodePoint(point, params.getCurve());
0878: curveId = SupportedEllipticCurvesExtension.getCurveIndex(params);
0879:
0880: if (privateKey == null) {
0881: // ECDH_anon
0882: return;
0883: }
0884:
0885: Signature sig = getSignature(privateKey.getAlgorithm());
0886: sig.initSign(privateKey);
0887:
0888: updateSignature(sig, clntNonce, svrNonce);
0889: signatureBytes = sig.sign();
0890: }
0891:
0892: /*
0893: * Parse an ECDH server key exchange message.
0894: */
0895: ECDH_ServerKeyExchange(HandshakeInStream input, PublicKey signingKey,
0896: byte[] clntNonce, byte[] svrNonce)
0897: throws IOException, GeneralSecurityException {
0898: int curveType = input.getInt8();
0899: ECParameterSpec parameters;
0900: // These parsing errors should never occur as we negotiated
0901: // the supported curves during the exchange of the Hello messages.
0902: if (curveType == CURVE_NAMED_CURVE) {
0903: curveId = input.getInt16();
0904: if (SupportedEllipticCurvesExtension.isSupported(curveId) == false) {
0905: throw new SSLHandshakeException("Unsupported curveId: " + curveId);
0906: }
0907: String curveOid = SupportedEllipticCurvesExtension.getCurveOid(curveId);
0908: if (curveOid == null) {
0909: throw new SSLHandshakeException("Unknown named curve: " + curveId);
0910: }
0911: parameters = JsseJce.getECParameterSpec(curveOid);
0912: if (parameters == null) {
0913: throw new SSLHandshakeException("Unsupported curve: " + curveOid);
0914: }
0915: } else {
0916: throw new SSLHandshakeException("Unsupported ECCurveType: " + curveType);
0917: }
0918: pointBytes = input.getBytes8();
0919:
0920: ECPoint point = JsseJce.decodePoint(pointBytes, parameters.getCurve());
0921: KeyFactory factory = JsseJce.getKeyFactory("EC");
0922: publicKey = (ECPublicKey)factory.generatePublic(new ECPublicKeySpec(point, parameters));
0923:
0924: if (signingKey == null) {
0925: // ECDH_anon
0926: return;
0927: }
0928:
0929: // verify the signature
0930: signatureBytes = input.getBytes16();
0931: Signature sig = getSignature(signingKey.getAlgorithm());
0932: sig.initVerify(signingKey);
0933:
0934: updateSignature(sig, clntNonce, svrNonce);
0935:
0936: if (sig.verify(signatureBytes) == false ) {
0937: throw new SSLKeyException
0938: ("Invalid signature on ECDH server key exchange message");
0939: }
0940: }
0941:
0942: /*
0943: * Get the ephemeral EC public key encapsulated in this message.
0944: */
0945: ECPublicKey getPublicKey() {
0946: return publicKey;
0947: }
0948:
0949: private static Signature getSignature(String keyAlgorithm) throws NoSuchAlgorithmException {
0950: if (keyAlgorithm.equals("EC")) {
0951: return JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA);
0952: } else if (keyAlgorithm.equals("RSA")) {
0953: return RSASignature.getInstance();
0954: } else {
0955: throw new NoSuchAlgorithmException("neither an RSA or a EC key");
0956: }
0957: }
0958:
0959: private void updateSignature(Signature sig, byte clntNonce[],
0960: byte svrNonce[]) throws SignatureException {
0961: sig.update(clntNonce);
0962: sig.update(svrNonce);
0963:
0964: sig.update((byte)CURVE_NAMED_CURVE);
0965: sig.update((byte)(curveId >> 8));
0966: sig.update((byte)curveId);
0967: sig.update((byte)pointBytes.length);
0968: sig.update(pointBytes);
0969: }
0970:
0971: int messageLength() {
0972: int sigLen = (signatureBytes == null) ? 0 : 2 + signatureBytes.length;
0973: return 4 + pointBytes.length + sigLen;
0974: }
0975:
0976: void send(HandshakeOutStream s) throws IOException {
0977: s.putInt8(CURVE_NAMED_CURVE);
0978: s.putInt16(curveId);
0979: s.putBytes8(pointBytes);
0980: if (signatureBytes != null) {
0981: s.putBytes16(signatureBytes);
0982: }
0983: }
0984:
0985: void print(PrintStream s) throws IOException {
0986: s.println("*** ECDH ServerKeyExchange");
0987:
0988: if (debug != null && Debug.isOn("verbose")) {
0989: s.println("Server key: " + publicKey);
0990: }
0991: }
0992:}
0993:
0994:static final class DistinguishedName {
0995:
0996: /*
0997: * DER encoded distinguished name.
0998: * TLS requires that its not longer than 65535 bytes.
0999: */
1000: byte name[];
1001:
1002: DistinguishedName(HandshakeInStream input) throws IOException {
1003: name = input.getBytes16();
1004: }
1005:
1006: DistinguishedName(X500Principal dn) {
1007: name = dn.getEncoded();
1008: }
1009:
1010: X500Principal getX500Principal() throws IOException {
1011: try {
1012: return new X500Principal(name);
1013: } catch (IllegalArgumentException e) {
1014: throw (SSLProtocolException)new SSLProtocolException
1015: (e.getMessage()).initCause(e);
1016: }
1017: }
1018:
1019: int length() {
1020: return 2 + name.length;
1021: }
1022:
1023: void send(HandshakeOutStream output) throws IOException {
1024: output.putBytes16(name);
1025: }
1026:
1027: void print(PrintStream output) throws IOException {
1028: X500Principal principal = new X500Principal(name);
1029: output.println("<" + principal.toString() + ">");
1030: }
1031:}
1032:
1033:/*
1034: * CertificateRequest ... SERVER --> CLIENT
1035: *
1036: * Authenticated servers may ask clients to authenticate themselves
1037: * in turn, using this message.
1038: */
1039:static final
1040:class CertificateRequest extends HandshakeMessage
1041:{
1042: int messageType() { return ht_certificate_request; }
1043:
1044: // enum ClientCertificateType
1045: static final int cct_rsa_sign = 1;
1046: static final int cct_dss_sign = 2;
1047: static final int cct_rsa_fixed_dh = 3;
1048: static final int cct_dss_fixed_dh = 4;
1049:
1050: // The existance of these two values is a bug in the SSL specification.
1051: // They are never used in the protocol.
1052: static final int cct_rsa_ephemeral_dh = 5;
1053: static final int cct_dss_ephemeral_dh = 6;
1054:
1055: // From RFC 4492 (ECC)
1056: static final int cct_ecdsa_sign = 64;
1057: static final int cct_rsa_fixed_ecdh = 65;
1058: static final int cct_ecdsa_fixed_ecdh = 66;
1059:
1060: private final static byte[] TYPES_NO_ECC = { cct_rsa_sign, cct_dss_sign };
1061: private final static byte[] TYPES_ECC =
1062: { cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign };
1063:
1064: byte types []; // 1 to 255 types
1065: DistinguishedName authorities []; // 3 to 2^16 - 1
1066: // ... "3" because that's the smallest DER-encoded X500 DN
1067:
1068: CertificateRequest(X509Certificate ca[], KeyExchange keyExchange)
1069: throws IOException {
1070: // always use X500Principal
1071: authorities = new DistinguishedName[ca.length];
1072: for (int i = 0; i < ca.length; i++) {
1073: X500Principal x500Principal = ca[i].getSubjectX500Principal();
1074: authorities[i] = new DistinguishedName(x500Principal);
1075: }
1076: // we support RSA, DSS, and ECDSA client authentication and they
1077: // can be used with all ciphersuites. If this changes, the code
1078: // needs to be adapted to take keyExchange into account.
1079: // We only request ECDSA client auth if we have ECC crypto available.
1080: this .types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC;
1081: }
1082:
1083: CertificateRequest(HandshakeInStream input) throws IOException {
1084: types = input.getBytes8();
1085: int len = input.getInt16();
1086: ArrayList<DistinguishedName> v = new ArrayList<DistinguishedName>();
1087: while (len >= 3) {
1088: DistinguishedName dn = new DistinguishedName(input);
1089: v.add(dn);
1090: len -= dn.length();
1091: }
1092:
1093: if (len != 0) {
1094: throw new SSLProtocolException("Bad CertificateRequest DN length");
1095: }
1096:
1097: authorities = v.toArray(new DistinguishedName[v.size()]);
1098: }
1099:
1100: X500Principal[] getAuthorities() throws IOException {
1101: X500Principal[] ret = new X500Principal[authorities.length];
1102: for (int i = 0; i < authorities.length; i++) {
1103: ret[i] = authorities[i].getX500Principal();
1104: }
1105: return ret;
1106: }
1107:
1108: int messageLength()
1109: {
1110: int len;
1111:
1112: len = 1 + types.length + 2;
1113: for (int i = 0; i < authorities.length; i++)
1114: len += authorities[i].length();
1115: return len;
1116: }
1117:
1118: void send(HandshakeOutStream output) throws IOException
1119: {
1120: int len = 0;
1121:
1122: for (int i = 0; i < authorities.length; i++)
1123: len += authorities[i].length();
1124:
1125: output.putBytes8(types);
1126: output.putInt16(len);
1127: for (int i = 0; i < authorities.length; i++)
1128: authorities[i].send(output);
1129: }
1130:
1131: void print(PrintStream s) throws IOException
1132: {
1133: s.println("*** CertificateRequest");
1134:
1135: if (debug != null && Debug.isOn("verbose")) {
1136: s.print("Cert Types: ");
1137: for (int i = 0; i < types.length; i++) {
1138: switch (types[i]) {
1139: case cct_rsa_sign:
1140: s.print("RSA"); break;
1141: case cct_dss_sign:
1142: s.print("DSS"); break;
1143: case cct_rsa_fixed_dh:
1144: s.print("Fixed DH (RSA sig)"); break;
1145: case cct_dss_fixed_dh:
1146: s.print("Fixed DH (DSS sig)"); break;
1147: case cct_rsa_ephemeral_dh:
1148: s.print("Ephemeral DH (RSA sig)"); break;
1149: case cct_dss_ephemeral_dh:
1150: s.print("Ephemeral DH (DSS sig)"); break;
1151: case cct_ecdsa_sign:
1152: s.print("ECDSA"); break;
1153: case cct_rsa_fixed_ecdh:
1154: s.print("Fixed ECDH (RSA sig)"); break;
1155: case cct_ecdsa_fixed_ecdh:
1156: s.print("Fixed ECDH (ECDSA sig)"); break;
1157: default:
1158: s.print("Type-" + (types[i] & 0xff)); break;
1159: }
1160: if (i != types.length - 1) {
1161: s.print(", ");
1162: }
1163: }
1164: s.println();
1165:
1166: s.println("Cert Authorities:");
1167: for (int i = 0; i < authorities.length; i++)
1168: authorities[i].print(s);
1169: }
1170: }
1171:}
1172:
1173:
1174:/*
1175: * ServerHelloDone ... SERVER --> CLIENT
1176: *
1177: * When server's done sending its messages in response to the client's
1178: * "hello" (e.g. its own hello, certificate, key exchange message, perhaps
1179: * client certificate request) it sends this message to flag that it's
1180: * done that part of the handshake.
1181: */
1182:static final
1183:class ServerHelloDone extends HandshakeMessage
1184:{
1185: int messageType() { return ht_server_hello_done; }
1186:
1187: ServerHelloDone() { }
1188:
1189: ServerHelloDone(HandshakeInStream input)
1190: {
1191: // nothing to do
1192: }
1193:
1194: int messageLength()
1195: {
1196: return 0;
1197: }
1198:
1199: void send(HandshakeOutStream s) throws IOException
1200: {
1201: // nothing to send
1202: }
1203:
1204: void print(PrintStream s) throws IOException
1205: {
1206: s.println("*** ServerHelloDone");
1207: }
1208:}
1209:
1210:
1211:/*
1212: * CertificateVerify ... CLIENT --> SERVER
1213: *
1214: * Sent after client sends signature-capable certificates (e.g. not
1215: * Diffie-Hellman) to verify.
1216: */
1217:static final class CertificateVerify extends HandshakeMessage {
1218:
1219: int messageType() { return ht_certificate_verify; }
1220:
1221: private byte[] signature;
1222:
1223: /*
1224: * Create an RSA or DSA signed certificate verify message.
1225: */
1226: CertificateVerify(ProtocolVersion protocolVersion, HandshakeHash
1227: handshakeHash, PrivateKey privateKey, SecretKey masterSecret,
1228: SecureRandom sr) throws GeneralSecurityException {
1229: String algorithm = privateKey.getAlgorithm();
1230: Signature sig = getSignature(protocolVersion, algorithm);
1231: sig.initSign(privateKey, sr);
1232: updateSignature(sig, protocolVersion, handshakeHash, algorithm,
1233: masterSecret);
1234: signature = sig.sign();
1235: }
1236:
1237: //
1238: // Unmarshal the signed data from the input stream.
1239: //
1240: CertificateVerify(HandshakeInStream input) throws IOException {
1241: signature = input.getBytes16();
1242: }
1243:
1244: /*
1245: * Verify a certificate verify message. Return the result of verification,
1246: * if there is a problem throw a GeneralSecurityException.
1247: */
1248: boolean verify(ProtocolVersion protocolVersion,
1249: HandshakeHash handshakeHash, PublicKey publicKey,
1250: SecretKey masterSecret) throws GeneralSecurityException {
1251: String algorithm = publicKey.getAlgorithm();
1252: Signature sig = getSignature(protocolVersion, algorithm);
1253: sig.initVerify(publicKey);
1254: updateSignature(sig, protocolVersion, handshakeHash, algorithm,
1255: masterSecret);
1256: return sig.verify(signature);
1257: }
1258:
1259: /*
1260: * Get the Signature object appropriate for verification using the
1261: * given signature algorithm and protocol version.
1262: */
1263: private static Signature getSignature(ProtocolVersion protocolVersion,
1264: String algorithm) throws GeneralSecurityException {
1265: if (algorithm.equals("RSA")) {
1266: return RSASignature.getInternalInstance();
1267: } else if (algorithm.equals("DSA")) {
1268: return JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA);
1269: } else if (algorithm.equals("EC")) {
1270: return JsseJce.getSignature(JsseJce.SIGNATURE_RAWECDSA);
1271: } else {
1272: throw new SignatureException("Unrecognized algorithm: "
1273: + algorithm);
1274: }
1275: }
1276:
1277: /*
1278: * Update the Signature with the data appropriate for the given
1279: * signature algorithm and protocol version so that the object is
1280: * ready for signing or verifying.
1281: */
1282: private static void updateSignature(Signature sig,
1283: ProtocolVersion protocolVersion,
1284: HandshakeHash handshakeHash, String algorithm, SecretKey masterKey)
1285: throws SignatureException {
1286: MessageDigest md5Clone = handshakeHash.getMD5Clone();
1287: MessageDigest shaClone = handshakeHash.getSHAClone();
1288: boolean tls = protocolVersion.v >= ProtocolVersion.TLS10.v;
1289: if (algorithm.equals("RSA")) {
1290: if (tls) {
1291: // nothing to do
1292: } else { // SSLv3
1293: updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey);
1294: updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
1295: }
1296: // need to use these hashes directly
1297: RSASignature.setHashes(sig, md5Clone, shaClone);
1298: } else { // DSA, ECDSA
1299: if (tls) {
1300: // nothing to do
1301: } else { // SSLv3
1302: updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
1303: }
1304: sig.update(shaClone.digest());
1305: }
1306: }
1307:
1308: /*
1309: * Update the MessageDigest for SSLv3 certificate verify or finished
1310: * message calculation. The digest must already have been updated with
1311: * all preceding handshake messages.
1312: * Used by the Finished class as well.
1313: */
1314: static void updateDigest(MessageDigest md, byte[] pad1, byte[] pad2,
1315: SecretKey masterSecret) {
1316: // Digest the key bytes if available.
1317: // Otherwise (sensitive key), try digesting the key directly.
1318: // That is currently only implemented in SunPKCS11 using a private
1319: // reflection API, so we avoid that if possible.
1320: byte[] keyBytes = "RAW".equals(masterSecret.getFormat())
1321: ? masterSecret.getEncoded() : null;
1322: if (keyBytes != null) {
1323: md.update(keyBytes);
1324: } else {
1325: digestKey(md, masterSecret);
1326: }
1327: md.update(pad1);
1328: byte[] temp = md.digest();
1329:
1330: if (keyBytes != null) {
1331: md.update(keyBytes);
1332: } else {
1333: digestKey(md, masterSecret);
1334: }
1335: md.update(pad2);
1336: md.update(temp);
1337: }
1338:
1339: private final static Class delegate;
1340: private final static Field spiField;
1341:
1342: static {
1343: try {
1344: delegate = Class.forName("java.security.MessageDigest$Delegate");
1345: spiField = delegate.getDeclaredField("digestSpi");
1346: } catch (Exception e) {
1347: throw new RuntimeException("Reflection failed", e);
1348: }
1349: makeAccessible(spiField);
1350: }
1351:
1352: private static void makeAccessible(final AccessibleObject o) {
1353: AccessController.doPrivileged(new PrivilegedAction<Object>() {
1354: public Object run() {
1355: o.setAccessible(true);
1356: return null;
1357: }
1358: });
1359: }
1360:
1361: // ConcurrentHashMap does not allow null values, use this marker object
1362: private final static Object NULL_OBJECT = new Object();
1363:
1364: // cache Method objects per Spi class
1365: // Note that this will prevent the Spi classes from being GC'd. We assume
1366: // that is not a problem.
1367: private final static Map<Class,Object> methodCache =
1368: new ConcurrentHashMap<Class,Object>();
1369:
1370: private static void digestKey(MessageDigest md, SecretKey key) {
1371: try {
1372: // Verify that md is implemented via MessageDigestSpi, not
1373: // via JDK 1.1 style MessageDigest subclassing.
1374: if (md.getClass() != delegate) {
1375: throw new Exception("Digest is not a MessageDigestSpi");
1376: }
1377: MessageDigestSpi spi = (MessageDigestSpi)spiField.get(md);
1378: Class<?> clazz = spi.getClass();
1379: Object r = methodCache.get(clazz);
1380: if (r == null) {
1381: try {
1382: r = clazz.getDeclaredMethod("implUpdate", SecretKey.class);
1383: makeAccessible((Method)r);
1384: } catch (NoSuchMethodException e) {
1385: r = NULL_OBJECT;
1386: }
1387: methodCache.put(clazz, r);
1388: }
1389: if (r == NULL_OBJECT) {
1390: throw new Exception("Digest does not support implUpdate(SecretKey)");
1391: }
1392: Method update = (Method)r;
1393: update.invoke(spi, key);
1394: } catch (Exception e) {
1395: throw new RuntimeException
1396: ("Could not obtain encoded key and MessageDigest cannot digest key", e);
1397: }
1398: }
1399:
1400: int messageLength() {
1401: return 2 + signature.length;
1402: }
1403:
1404: void send(HandshakeOutStream s) throws IOException {
1405: s.putBytes16(signature);
1406: }
1407:
1408: void print(PrintStream s) throws IOException {
1409: s.println("*** CertificateVerify");
1410: }
1411:}
1412:
1413:
1414:/*
1415: * FINISHED ... sent by both CLIENT and SERVER
1416: *
1417: * This is the FINISHED message as defined in the SSL and TLS protocols.
1418: * Both protocols define this handshake message slightly differently.
1419: * This class supports both formats.
1420: *
1421: * When handshaking is finished, each side sends a "change_cipher_spec"
1422: * record, then immediately sends a "finished" handshake message prepared
1423: * according to the newly adopted cipher spec.
1424: *
1425: * NOTE that until this is sent, no application data may be passed, unless
1426: * some non-default cipher suite has already been set up on this connection
1427: * connection (e.g. a previous handshake arranged one).
1428: */
1429:static final class Finished extends HandshakeMessage {
1430:
1431: int messageType() { return ht_finished; }
1432:
1433: // constant for a Finished message sent by the client
1434: final static int CLIENT = 1;
1435:
1436: // constant for a Finished message sent by the server
1437: final static int SERVER = 2;
1438:
1439: // enum Sender: "CLNT" and "SRVR"
1440: private static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 };
1441: private static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 };
1442:
1443: /*
1444: * Contents of the finished message ("checksum"). For TLS, it
1445: * is 12 bytes long, for SSLv3 36 bytes.
1446: */
1447: private byte[] verifyData;
1448:
1449: /*
1450: * Create a finished message to send to the remote peer.
1451: */
1452: Finished(ProtocolVersion protocolVersion, HandshakeHash handshakeHash,
1453: int sender, SecretKey master) {
1454: verifyData = getFinished(protocolVersion, handshakeHash, sender,
1455: master);
1456: }
1457:
1458: /*
1459: * Constructor that reads FINISHED message from stream.
1460: */
1461: Finished(ProtocolVersion protocolVersion, HandshakeInStream input)
1462: throws IOException {
1463: int msgLen = (protocolVersion.v >= ProtocolVersion.TLS10.v) ? 12 : 36;
1464: verifyData = new byte[msgLen];
1465: input.read(verifyData);
1466: }
1467:
1468: /*
1469: * Verify that the hashes here are what would have been produced
1470: * according to a given set of inputs. This is used to ensure that
1471: * both client and server are fully in sync, and that the handshake
1472: * computations have been successful.
1473: */
1474: boolean verify(ProtocolVersion protocolVersion,
1475: HandshakeHash handshakeHash, int sender, SecretKey master) {
1476: byte[] myFinished = getFinished(protocolVersion, handshakeHash,
1477: sender, master);
1478: return Arrays.equals(myFinished, verifyData);
1479: }
1480:
1481: /*
1482: * Perform the actual finished message calculation.
1483: */
1484: private static byte[] getFinished(ProtocolVersion protocolVersion,
1485: HandshakeHash handshakeHash, int sender, SecretKey masterKey) {
1486: byte[] sslLabel;
1487: String tlsLabel;
1488: if (sender == CLIENT) {
1489: sslLabel = SSL_CLIENT;
1490: tlsLabel = "client finished";
1491: } else if (sender == SERVER) {
1492: sslLabel = SSL_SERVER;
1493: tlsLabel = "server finished";
1494: } else {
1495: throw new RuntimeException("Invalid sender: " + sender);
1496: }
1497: MessageDigest md5Clone = handshakeHash.getMD5Clone();
1498: MessageDigest shaClone = handshakeHash.getSHAClone();
1499: if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
1500: // TLS
1501: try {
1502: byte[] seed = new byte[36];
1503: md5Clone.digest(seed, 0, 16);
1504: shaClone.digest(seed, 16, 20);
1505:
1506: TlsPrfParameterSpec spec = new TlsPrfParameterSpec
1507: (masterKey, tlsLabel, seed, 12);
1508: KeyGenerator prf = JsseJce.getKeyGenerator("SunTlsPrf");
1509: prf.init(spec);
1510: SecretKey prfKey = prf.generateKey();
1511: if ("RAW".equals(prfKey.getFormat()) == false) {
1512: throw new ProviderException
1513: ("Invalid PRF output, format must be RAW");
1514: }
1515: byte[] finished = prfKey.getEncoded();
1516: return finished;
1517: } catch (GeneralSecurityException e) {
1518: throw new RuntimeException("PRF failed", e);
1519: }
1520: } else {
1521: // SSLv3
1522: updateDigest(md5Clone, sslLabel, MD5_pad1, MD5_pad2, masterKey);
1523: updateDigest(shaClone, sslLabel, SHA_pad1, SHA_pad2, masterKey);
1524: byte[] finished = new byte[36];
1525: try {
1526: md5Clone.digest(finished, 0, 16);
1527: shaClone.digest(finished, 16, 20);
1528: } catch (DigestException e) {
1529: // cannot occur
1530: throw new RuntimeException("Digest failed", e);
1531: }
1532: return finished;
1533: }
1534: }
1535:
1536: /*
1537: * Update the MessageDigest for SSLv3 finished message calculation.
1538: * The digest must already have been updated with all preceding handshake
1539: * messages. This operation is almost identical to the certificate verify
1540: * hash, reuse that code.
1541: */
1542: private static void updateDigest(MessageDigest md, byte[] sender,
1543: byte[] pad1, byte[] pad2, SecretKey masterSecret) {
1544: md.update(sender);
1545: CertificateVerify.updateDigest(md, pad1, pad2, masterSecret);
1546: }
1547:
1548: int messageLength() {
1549: return verifyData.length;
1550: }
1551:
1552: void send(HandshakeOutStream out) throws IOException {
1553: out.write(verifyData);
1554: }
1555:
1556: void print(PrintStream s) throws IOException {
1557: s.println("*** Finished");
1558: if (debug != null && Debug.isOn("verbose")) {
1559: Debug.println(s, "verify_data", verifyData);
1560: s.println("***");
1561: }
1562: }
1563:
1564:}
1565:
1566://
1567:// END of nested classes
1568://
1569:
1570:}
|