Source Code Cross Referenced for Handshake.java in  » Portal » Open-Portal » com » sun » portal » kssl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Portal » Open Portal » com.sun.portal.kssl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * @(#)Handshake.java	1.30 02/07/24 @(#)
0003:         *
0004:         * Copyright (c) 2000-2002 Sun Microsystems, Inc.  All rights reserved.
0005:         * PROPRIETARY/CONFIDENTIAL
0006:         * Use is subject to license terms.
0007:         */
0008:
0009:        package com.sun.portal.kssl;
0010:
0011:        import java.io.IOException;
0012:        import java.io.InputStream;
0013:
0014:        import java.lang.Exception;
0015:
0016:        import com.sun.portal.microedition.pki.CertificateException;
0017:
0018:        import com.sun.portal.ksecurity.CryptoException;
0019:        import com.sun.portal.ksecurity.MessageDigest;
0020:        import com.sun.portal.ksecurity.RandomData;
0021:        import com.sun.portal.ksecurity.RSAPublicKey;
0022:        import com.sun.portal.ksecurity.KeyBuilder;
0023:        import com.sun.portal.ksecurity.CertStore;
0024:
0025:        /**
0026:         * This class implements the SSL handshake protocol which is responsible
0027:         * for negotiating security parameters used by the record layer.
0028:         * Currently, only client-side functionality is implemented.
0029:         */
0030:        // visible only within this package
0031:        class Handshake {
0032:
0033:            /**
0034:             * This contains the cipher suite encoding length in the first
0035:             * two bytes, followed by an encoding of the cipher suites followed
0036:             * by the compression suite length in one byte and the compression
0037:             * suite. For now, we only propose the two most commonly used
0038:             * cipher suites.
0039:             */
0040:            private byte[] SUITES_AND_COMP = {
0041:                    // Use this to propose 128-bit encryption as preferred
0042:                    //Support for new Ciphers
0043:                    /*0x00, 0x06, 0x00, ARCFOUR_128_SHA, 0x00, ARCFOUR_128_MD5,
0044:                    0x00, ARCFOUR_40_MD5, 0x01, 0x00*/
0045:                    0x00, 0x0A, 0x00, CipherSuites.ARCFOUR_128_SHA, 0x00,
0046:                    CipherSuites.ARCFOUR_128_MD5, 0x00,
0047:                    CipherSuites.ARCFOUR_40_MD5, 0x00,
0048:                    CipherSuites.DES_CBC_SHA, 0x00,
0049:                    CipherSuites.TRIPLEDES_CBC_SHA, 0x01, 0x00
0050:            // Use this to propose 40-bit encryption as preferred
0051:            // 0x00, 0x06, 0x00, ARCFOUR_40_MD5, 0x00, ARCFOUR_128_RSA,
0052:            // 0x00, ARCFOUR_128_SHA, 0x01, 0x00
0053:            };
0054:
0055:            /**
0056:             * Array of suite names.
0057:             */
0058:            private static String[] suiteNames = { "", "", "",
0059:                    "SSL3_RSA_EXPORT_WITH_RC4_40_MD5",
0060:                    "SSL3_RSA_WITH_RC4_128_MD5", "SSL3_RSA_WITH_RC4_128_SHA",
0061:                    //Support for new Ciphers        
0062:                    "", "", "", "SSL3_RSA_WITH_DES_CBC_SHA",
0063:                    "SSL3_RSA_WITH_3DES_EDE_CBC_SHA"
0064:
0065:            };
0066:
0067:            /**
0068:             * Each handshake message has a four-byte header containing
0069:             * the type (1 byte) and length (3 byte).
0070:             */
0071:            private static final byte HDR_SIZE = 4;
0072:
0073:            // Handshake message types
0074:            /** Hello Request (0). */
0075:            private static final byte HELLO_REQ = 0;
0076:            /** Client Hello (1). */
0077:            private static final byte C_HELLO = 1;
0078:            /** Server Hello (2). */
0079:            private static final byte S_HELLO = 2;
0080:            /** Certificate (11). */
0081:            private static final byte CERT = 11;
0082:            /** Server Key Exchange (12). */
0083:            private static final byte S_KEYEXCH = 12;
0084:            /** Certificate Request (13). */
0085:            private static final byte CERT_REQ = 13;
0086:            /** Server Hello Done (14). */
0087:            private static final byte S_DONE = 14;
0088:            /** Certificate Verify (15). */
0089:            private static final byte CERT_VRFY = 15;
0090:            /** Client Key Exchange (16). */
0091:            private static final byte C_KEYEXCH = 16;
0092:            /** Finished (20). */
0093:            private static final byte FINISH = 20;
0094:
0095:            // Number of bytes in an MD5/SHA digest
0096:            /** Number of bytes in an MD5 Digest (16). */
0097:            private static final byte MD5_SIZE = 16;
0098:            /** Number of bytes in an SHA Digest (20). */
0099:            private static final byte SHA_SIZE = 20;
0100:
0101:            /**
0102:             * The Finish message contains one MD5 and one SHA hash
0103:             * and has a length of 4+16+20 = 40 = 0x24 bytes.
0104:             */
0105:            private static final byte[] FINISH_PREFIX = { FINISH, 0x00, 0x00,
0106:                    0x24 };
0107:
0108:            /** Current record to process. */
0109:            private Record rec;
0110:            /** Peer host name . */
0111:            private String peerHost;
0112:            /** Peer port number. */
0113:            private int peerPort;
0114:            /** Local random number seed. */
0115:            private RandomData rnd = null;
0116:            /** Previous session context to this host and port, if there was one. */
0117:            private Session cSession = null;
0118:            /** Session id returned by server. */
0119:            private byte[] sSessionId = null;
0120:            /** Client random number. */
0121:            private byte[] crand = null;
0122:            /** Server random number. */
0123:            private byte[] srand = null;
0124:
0125:            /** Proposed SSL version. */
0126:            private byte ver;
0127:            /** Role (always CLIENT for now). */
0128:            private byte role;
0129:            /** Negotiated cipher suite. */
0130:            byte negSuite;
0131:            /** Name of negotiated cipher suite. */
0132:            String negSuiteName;
0133:            /** Flag to indicate certificate request received. */
0134:            private byte gotCertReq = 0;
0135:            /** Pre-master secret. */
0136:            private byte[] preMaster = null;
0137:            /** Master secret. */
0138:            private byte[] master = null;
0139:            /** Server public key. */
0140:            private RSAPublicKey sKey = null;
0141:            /**
0142:             * Public key used to encrypt the appropriate 
0143:             * usage of sKey certs in chain.
0144:             */
0145:            private RSAPublicKey eKey = null;
0146:            /** Skey usage. */
0147:            private int sKeyUsage = 0;
0148:            /** Certificate count. */
0149:            private byte certCnt = 0;
0150:            // we also need a temporary place to store the server certificate 
0151:            // in parseChain so it can be examined later rcvSrvrKeyExch() for
0152:            // keyUsage checks and the parent connection.
0153:            /** Temporary storage for server certificate. */
0154:            X509Certificate sCert = null;
0155:
0156:            /*
0157:             * These accumulate MD5 and SHA digests of all handshake 
0158:             * messages seen so far.
0159:             */
0160:            /** Accumulation of MD5 digests. */
0161:            private MessageDigest ourMD5 = null;
0162:            /** Accumulation of SHA digests. */
0163:            private MessageDigest ourSHA = null;
0164:
0165:            /*
0166:             * The following fields maintain a buffer of available handshake
0167:             * messages. Note that a single SSL record may include multiple
0168:             * handshake messages.
0169:             */
0170:            /** Start of message in data buffer. */
0171:            private int start = 0;
0172:            /** Start of next message in data buffer. */
0173:            private int nextMsgStart = 0;
0174:            /** Count of bytes left in the data buffer. */
0175:            private int cnt = 0;
0176:
0177:            /**
0178:             * Validates a chain of certificates and returns the RSA public
0179:             * key from the first certificate in that chain. The format of 
0180:             * the chain is specific to the ServerCertificate payload in an
0181:             * SSL handshake.
0182:             * <P />
0183:             * @param site site name to be matched against the subject 
0184:             *             name inside the server certificate
0185:             * @param msg  byte array containing the SSL ServerCertificate
0186:             *             payload (this is a chain of DER-encoded X.509 
0187:             *             certificates, in which each certificate is preceded
0188:             *             by a 3-byte length field)
0189:             * @param off  offset in the byte array where the cert chain begins
0190:             * @param end  position in the byte array where the cert chain ends + 1
0191:             * @param tcs  certificate store containing trusted certificates
0192:             * @return the public key from the first certificate in the chain or null
0193:             *             (in case of problems)
0194:             */
0195:            private RSAPublicKey parseChain(String site, byte[] msg, int off,
0196:                    int end, CertStore tcs) throws IOException {
0197:
0198:                RSAPublicKey sKey = null;
0199:                X509Certificate c;
0200:                X509Certificate pc = null; // previous cert in chain
0201:                X509Certificate ts; // trusted signer certificate
0202:                X509Certificate[] ic;
0203:                int len;
0204:                byte worstCode = CertificateException.UNRECOGNIZED_ISSUER;
0205:                int pLen = -1; // 0 means 1 so -1 means no chain
0206:
0207:                if (tcs == null) {
0208:                    throw new IllegalArgumentException(
0209:                            "no trusted certificate store given");
0210:                }
0211:
0212:                certCnt = 0; // use this to count number of certs processed
0213:
0214:                // We have a 3-byte length field before each cert in list
0215:                while (off < (end - 3)) {
0216:                    len = ((msg[off++] & 0xff) << 16)
0217:                            + ((msg[off++] & 0xff) << 8) + (msg[off++] & 0xff);
0218:
0219:                    if (len < 0 || len + off > msg.length) {
0220:                        throw new IOException("SSL certificate length too long");
0221:                    }
0222:
0223:                    c = X509Certificate.generateCertificate(msg, off, len);
0224:
0225:                    // Check if this certificate has any bad extensions
0226:                    c.checkExtensions();
0227:
0228:                    // Check if the certificate is valid at the current time
0229:                    c.checkValidity();
0230:
0231:                    if (certCnt == 0) {
0232:                        /*
0233:                         * This is the first certificate in chain.
0234:                         * Save the server certificate.
0235:                         */
0236:                        sCert = c;
0237:
0238:                        // Save the server public key and key usage bits
0239:                        sKey = (RSAPublicKey) c.getPublicKey();
0240:                        sKeyUsage = c.getKeyUsage();
0241:                    } else {
0242:                        /*
0243:                         * This is a chain, check chain link:
0244:                         * the subject of this certificate must be the issuer of
0245:                         * the previous certificate
0246:                         */
0247:                        if (pc.getIssuer().compareTo(c.getSubject()) != 0) {
0248:                            // this error cannot be overridden
0249:                            throw new CertificateException(pc,
0250:                                    CertificateException.BROKEN_CHAIN);
0251:                        }
0252:
0253:                        pc.verify(c.getPublicKey());
0254:
0255:                        /*
0256:                         * Check if basicConstraints are satisfied. Note a zero
0257:                         * pathLength means we should have only processed one cert
0258:                         * so far.
0259:                         *
0260:                         * We want to check the chain length last because the
0261:                         * other errors are more critical.
0262:                         */
0263:                        int prevPathLen = pLen;
0264:                        pLen = c.getBasicConstraints();
0265:                        if (pLen != X509Certificate.UNLIMITED_CERT_CHAIN_LENGTH
0266:                                && pLen <= prevPathLen) {
0267:                            if (c.getSubject().equals(c.getIssuer())) {
0268:                                /*
0269:                                 * This is a redundent, self signed CA cert
0270:                                 * allowed to be at the end of the chain.
0271:                                 * These certificates may version 1, so will not
0272:                                 * have extensions. So this really should be the
0273:                                 * worst code we have encountered this far for
0274:                                 * the previous certificate in the chain.
0275:                                 */
0276:                                throw new CertificateException(pc, worstCode);
0277:                            }
0278:
0279:                            if (pLen == X509Certificate.MISSING_PATH_LENGTH_CONSTRAINT) {
0280:
0281:                                throw new CertificateException(
0282:                                        pc,
0283:                                        CertificateException.UNAUTHORIZED_INTERMEDIATE_CA);
0284:                            }
0285:
0286:                            /*
0287:                             * An intermediate CA has over granted
0288:                             * its given authority to the previous CA in the
0289:                             * chain.
0290:                             */
0291:                            throw new CertificateException(
0292:                                    pc,
0293:                                    CertificateException.CERTIFICATE_CHAIN_TOO_LONG);
0294:                        }
0295:                    }
0296:
0297:                    certCnt++;
0298:
0299:                    /*
0300:                     * Or if this certificate was issued (signed) by a trusted 
0301:                     * issuer, we are done. An issuer may have more than one
0302:                     * key so we must use the trial and error method.
0303:                     *
0304:                     * NOTE: An issuer whose certificate is expired gets 
0305:                     * treated the same way as an unrecognized issuer
0306:                     */
0307:                    ic = tcs.getCertificates(c.getIssuer());
0308:                    if (ic == null) {
0309:                        //System.out.println("Netlet found self signed certificate."); 
0310:                        Utils.logln(Utils.LOG_INFO,
0311:                                "Netlet found self signed certificate. ");
0312:                        return sKey;
0313:                    }
0314:                    if (ic != null) {
0315:                        for (int i = ic.length - 1; i >= 0; i--) {
0316:                            if (!ic[i].getType().equals("X.509")) {
0317:                                continue;
0318:                            }
0319:
0320:                            ts = ic[i];
0321:
0322:                            try {
0323:                                c.verify(ts.getPublicKey());
0324:                            } catch (CertificateException e) {
0325:                                System.out
0326:                                        .println("Cerificate verification exception");
0327:                                e.printStackTrace();
0328:                                /*
0329:                                 * may not be the correct key try the next key,
0330:                                 * but this is worse than unrecognized issuer
0331:                                 */
0332:                                worstCode = e.getReason();
0333:                                continue;
0334:                            }
0335:
0336:                            try {
0337:                                ts.checkValidity();
0338:                            } catch (CertificateException e) {
0339:                                /*
0340:                                 * we need to change the exception reason, so the
0341:                                 * application knows that the problem is with
0342:                                 * the device and not the server.
0343:                                 */
0344:                                throw new CertificateException(ts,
0345:                                        CertificateException.ROOT_CA_EXPIRED);
0346:                            }
0347:
0348:                            return sKey;
0349:                        }
0350:                    }
0351:
0352:                    ts = null;
0353:                    off += len;
0354:                    pc = c;
0355:                }
0356:
0357:                throw new CertificateException(pc, worstCode);
0358:            }
0359:
0360:            /**
0361:             * Creates an Handshake object that is used to negotiate a
0362:             * version 3 handshake with an SSL peer.
0363:             *
0364:             * @param host hostname of the peer
0365:             * @param port port number of the peer
0366:             * @param r    Record instance through which handshake
0367:             *             will occur
0368:             */
0369:            Handshake(String host, int port, Record r) {
0370:                peerHost = new String(host);
0371:                peerPort = port;
0372:                rec = r;
0373:                sKey = eKey = null;
0374:                gotCertReq = 0;
0375:                start = 0;
0376:                cnt = 0;
0377:
0378:                try {
0379:                    ourMD5 = MessageDigest.getInstance(MessageDigest.ALG_MD5,
0380:                            false);
0381:                    ourSHA = MessageDigest.getInstance(MessageDigest.ALG_SHA,
0382:                            false);
0383:                    rnd = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
0384:                } catch (CryptoException e) {
0385:                    // should not happen, if code above is correct
0386:                    throw new RuntimeException(e.getMessage());
0387:                }
0388:            }
0389:
0390:            /**
0391:             * Frees data structures associated with the handshake layer.
0392:             */
0393:            public void destroy() {
0394:                rec = null;
0395:                peerHost = null;
0396:                rnd = null;
0397:                cSession = null;
0398:                sSessionId = null;
0399:                crand = srand = null;
0400:                preMaster = null;
0401:                master = null;
0402:                sKey = null;
0403:                eKey = null;
0404:                ourMD5 = null;
0405:                ourSHA = null;
0406:            }
0407:
0408:            /**
0409:             * Obtains the next available handshake message.
0410:             * <p>
0411:             * The message returned has the header plus the number of
0412:             * bytes indicated in the handshake message header.</p>
0413:             * 
0414:             * @param type the desired handshake message type
0415:             * @return number of bytes in the next handshake message
0416:             * of the desired type or -1 if the next message is not of
0417:             * the desired type
0418:             * @exception IOException if there is a problem reading the
0419:             * next handshake message
0420:             */
0421:            private int getNextMsg(byte type) throws IOException {
0422:                if (cnt == 0) {
0423:                    rec.rdRec(Record.HNDSHK);
0424:
0425:                    if (rec.plainTextLength < HDR_SIZE) {
0426:                        throw new IOException("getNextMsg refill failed");
0427:                    }
0428:
0429:                    cnt = rec.plainTextLength;
0430:                    nextMsgStart = rec.plainTextOffset;
0431:                }
0432:
0433:                if (rec.inputData[nextMsgStart] == type) {
0434:                    int len = ((rec.inputData[nextMsgStart + 1] & 0xff) << 16)
0435:                            + ((rec.inputData[nextMsgStart + 2] & 0xff) << 8)
0436:                            + (rec.inputData[nextMsgStart + 3] & 0xff)
0437:                            + HDR_SIZE;
0438:
0439:                    if (cnt < len) {
0440:                        throw new IOException("Refill got short msg " + "c="
0441:                                + cnt + " l=" + len);
0442:                    }
0443:
0444:                    start = nextMsgStart;
0445:                    nextMsgStart += len;
0446:                    cnt -= len;
0447:                    return len;
0448:                } else {
0449:                    return -1;
0450:                }
0451:            }
0452:
0453:            /**
0454:             * Sends an SSL version 3.0 Client hello handshake message.
0455:             * <P />
0456:             * @exception IOException if there is a problem writing to 
0457:             * the record layer
0458:             */
0459:            private void sndHello3() throws IOException {
0460:                cSession = Session.get(peerHost, peerPort);
0461:                int len = (cSession == null) ? 0 : cSession.id.length;
0462:                /*
0463:                 * Size = 4 (HDR_SIZE) + 2 (client_version) + 32 (crand.length) + 
0464:                 * 1 (session length) + len + 2 (cipher suite length) + 
0465:                 * (2*CipherSuiteList.length) + 1 (compression length) + 1 (comp code)
0466:                 */
0467:                byte[] msg = new byte[39 + len + SUITES_AND_COMP.length];
0468:                int idx = 0;
0469:                // Fill the header -- type (1 byte) length (3 bytes)
0470:                msg[idx++] = C_HELLO;
0471:                int mlen = msg.length - HDR_SIZE;
0472:                msg[idx++] = (byte) (mlen >>> 16);
0473:                msg[idx++] = (byte) (mlen >>> 8);
0474:                msg[idx++] = (byte) (mlen & 0xff);
0475:                // ... client_version
0476:                msg[idx++] = (byte) (ver >>> 4);
0477:                msg[idx++] = (byte) (ver & 0x0f);
0478:                // ... random
0479:                /* 
0480:                 * TODO: overwrite the first four bytes of crand with
0481:                 * current time and date in standard 32-bit UNIX format.
0482:                 */
0483:                crand = new byte[32];
0484:                rnd.generateData(crand, (short) 0, (short) 32);
0485:                System.arraycopy(crand, 0, msg, idx, crand.length);
0486:                idx += crand.length;
0487:                // ... session_id
0488:                msg[idx++] = (byte) (len & 0xff);
0489:                if (cSession != null) {
0490:                    System.arraycopy(cSession.id, 0, msg, idx,
0491:                            cSession.id.length);
0492:                    idx += cSession.id.length;
0493:                }
0494:                // ... cipher_suites and compression methods
0495:                System.arraycopy(SUITES_AND_COMP, 0, msg, idx,
0496:                        SUITES_AND_COMP.length);
0497:
0498:                ourMD5.update(msg, 0, msg.length);
0499:                ourSHA.update(msg, 0, msg.length);
0500:
0501:                // Finally, write this handshake record
0502:                rec.wrRec(Record.HNDSHK, msg, 0, msg.length);
0503:            }
0504:
0505:            /**
0506:             * Receives a Server hello handshake message.
0507:             * <P />
0508:             * @return 0 on success, -1 on failure
0509:             * @exception IOException if there is a problem reading the
0510:             * message
0511:             */
0512:            private int rcvSrvrHello() throws IOException {
0513:                int msgLength = getNextMsg(S_HELLO);
0514:                int idx = start + HDR_SIZE;
0515:                int endOfMsg = start + msgLength;
0516:
0517:                /*
0518:                 * Message must be long enough to contain a 4-byte header, 
0519:                 * 2-byte version, a 32-byte random, a 1-byte session Id
0520:                 * length (plus variable lenght session Id), 2 byte cipher
0521:                 * suite, 1 byte compression method.
0522:                 */
0523:                if (msgLength < 42) {
0524:                    return -1;
0525:                }
0526:
0527:                // Get the server version
0528:                if ((rec.inputData[start + idx++] != (ver >>> 4))
0529:                        || (rec.inputData[start + idx++] != (ver & 0x0f))) {
0530:                    return -1;
0531:                }
0532:
0533:                // .. the 32-byte server random
0534:                srand = new byte[32];
0535:                System.arraycopy(rec.inputData, idx, srand, 0, 32);
0536:                idx += 32;
0537:
0538:                // ... the session_Id length in 1 byte (and session_Id)
0539:                int slen = rec.inputData[idx++] & 0xff;
0540:                if (slen != 0) {
0541:                    if (endOfMsg < idx + slen) {
0542:                        return -1;
0543:                    }
0544:
0545:                    sSessionId = new byte[slen];
0546:                    System.arraycopy(rec.inputData, idx, sSessionId, 0, slen);
0547:                    idx += slen;
0548:                }
0549:
0550:                // ... the cipher suite
0551:                /* 
0552:                 * NOTE: this is a hack, it works because for the cipher suites
0553:                 * we support, the second byte directly maps to suite code.
0554:                 */
0555:                idx++;
0556:                negSuite = rec.inputData[idx++];
0557:
0558:                /*
0559:                 * Check the cipher suite and compression method. The compression 
0560:                 * method better be 0x00 since that is the only one we ever propose.
0561:                 *
0562:                 */
0563:
0564:                if ((negSuite != CipherSuites.ARCFOUR_128_SHA)
0565:                        && (negSuite != CipherSuites.ARCFOUR_128_MD5)
0566:                        && (negSuite != CipherSuites.ARCFOUR_40_MD5)
0567:                        &&
0568:                        //Support for new Ciphers        
0569:                        (negSuite != CipherSuites.DES_CBC_SHA)
0570:                        && (negSuite != CipherSuites.TRIPLEDES_CBC_SHA)
0571:                        && (rec.inputData[idx++] != (byte) 0x00)) {
0572:                    return -1;
0573:                }
0574:
0575:                // Update the hash of handshake messages
0576:                ourMD5.update(rec.inputData, start, msgLength);
0577:                ourSHA.update(rec.inputData, start, msgLength);
0578:
0579:                negSuiteName = suiteNames[negSuite];
0580:
0581:                Utils.logln(Utils.LOG_INFO, "Negotiated " + negSuiteName);
0582:                //System.out.println("Negotiated Cipher : "+negSuiteName);
0583:
0584:                return 0;
0585:            }
0586:
0587:            /**
0588:             * Receives a Server certificate message containing a certificate
0589:             * chain starting with the server certificate.
0590:             * <P />
0591:             * @return 0 if a trustworthy server certificate is found, -1 otherwise
0592:             * @exception IOException if there is a problem reading the message
0593:             */
0594:            private int rcvCert() throws IOException {
0595:                int msgLength;
0596:                int endOfMsg;
0597:                int idx;
0598:                int len;
0599:
0600:                msgLength = getNextMsg(CERT);
0601:                endOfMsg = start + msgLength;
0602:
0603:                /*
0604:                 * Message should atleast have a 4-byte header and an empty cert
0605:                 * list with 3-byte length
0606:                 */
0607:                if (msgLength < 7) {
0608:                    return -1;
0609:                }
0610:
0611:                idx = start + HDR_SIZE;
0612:                len = 0;
0613:
0614:                // Check the length ...
0615:                len = ((rec.inputData[idx++] & 0xff) << 16)
0616:                        + ((rec.inputData[idx++] & 0xff) << 8)
0617:                        + (rec.inputData[idx++] & 0xff);
0618:                if ((idx + len) > endOfMsg)
0619:                    return -1;
0620:
0621:                certCnt = 0;
0622:                sKeyUsage = 0;
0623:
0624:                // Parse the certificate chain and get the server's public key
0625:                sKey = parseChain(peerHost, rec.inputData, idx, endOfMsg,
0626:                        SSLStreamConnection.getTrustedCertStore());
0627:
0628:                // Update the hash of handshake messages
0629:                ourMD5.update(rec.inputData, start, msgLength);
0630:                ourSHA.update(rec.inputData, start, msgLength);
0631:
0632:                certCnt = 0;
0633:                return 0;
0634:            }
0635:
0636:            /**
0637:             * Receives a Server key exchange message. For now only RSA key
0638:             * exchange is supported and this message includes temporary
0639:             * RSA public key parameters signed by the server's long-term
0640:             * private key. This message is optional.
0641:             * <P />
0642:             * @return 0 on success, -1 on failure
0643:             * @exception IOException if there is a problem reading the
0644:             * message
0645:             */
0646:            private int rcvSrvrKeyExch() throws IOException {
0647:                int msgLength = getNextMsg(S_KEYEXCH);
0648:                int idx = start + HDR_SIZE;
0649:                int endOfMsg = start + msgLength;
0650:
0651:                /*
0652:                 * NOTE: Based on what we propose, the only key exch is RSA
0653:                 * Also note that the server key exchange is optional and used
0654:                 * only if the public key included in the certificate chain
0655:                 * is unsuitable for encrypting the pre-master secret.
0656:                 */
0657:                if (msgLength == -1) {
0658:                    // We can use the server key to encrypt premaster secret
0659:                    eKey = sKey;
0660:                    /*
0661:                     * Make sure sKey can be used for premaster secret encryption,
0662:                     * i.e. if key usage extensions are present, the key encipherment
0663:                     * bit or the serverAuth bit must be set
0664:                     */
0665:                    if ((sKeyUsage != -1) && ((sKeyUsage & 0x04) != 0x04)
0666:                            && ((sKeyUsage & 0x020000) != 0x020000)) {
0667:                        Utils.logln(Utils.LOG_ERR,
0668:                                "Neither keyEncipherment nor serverAuth "
0669:                                        + "bit is set in server certificate");
0670:
0671:                        throw new CertificateException(sCert,
0672:                                CertificateException.INAPPROPRIATE_KEY_USAGE);
0673:                    }
0674:
0675:                    return 0;
0676:                }
0677:
0678:                /*
0679:                 * Make sure sKey can be used for signing RSA params, 
0680:                 * i.e. if key usage extensions are present, the digitalSignature
0681:                 * bit or serverAuth bit must be set
0682:                 */
0683:                if ((sKeyUsage != -1) && ((sKeyUsage & 0x01) != 0x01)
0684:                        && ((sKeyUsage & 0x020000) != 0x020000)) {
0685:                    Utils.logln(Utils.LOG_ERR,
0686:                            "Neither digitalSignature nor serverAuth "
0687:                                    + "bit is set in server certificate");
0688:                    throw new CertificateException(sCert,
0689:                            CertificateException.INAPPROPRIATE_KEY_USAGE);
0690:                }
0691:
0692:                // read and verify the encryption key parameters
0693:                if (endOfMsg < (idx + 4)) {
0694:                    return -1;
0695:                }
0696:
0697:                // read the modulus length
0698:                int len = ((rec.inputData[idx++] & 0xff) << 16)
0699:                        + (rec.inputData[idx++] & 0xff);
0700:                if (endOfMsg < (idx + len + 2)) {
0701:                    return -1;
0702:                }
0703:
0704:                try {
0705:                    // ... and the modulus
0706:                    /*
0707:                     * Some weird sites (e.g. www.verisign.com) encode a 
0708:                     * 512-bit modulus in 65 (rather than 64 bytes) with the 
0709:                     * first byte set to zero. We accomodate this behavior
0710:                     * by using a special check.
0711:                     */
0712:                    if ((len == 65) && (rec.inputData[idx] == (byte) 0x00)) {
0713:                        eKey = (RSAPublicKey) KeyBuilder.buildKey(
0714:                                KeyBuilder.TYPE_RSA_PUBLIC, (short) (64 << 3),
0715:                                false);
0716:                        eKey.setModulus(rec.inputData, (short) (idx + 1),
0717:                                (short) 64);
0718:                    } else {
0719:                        eKey = (RSAPublicKey) KeyBuilder.buildKey(
0720:                                KeyBuilder.TYPE_RSA_PUBLIC, (short) (len << 3),
0721:                                false);
0722:                        eKey
0723:                                .setModulus(rec.inputData, (short) idx,
0724:                                        (short) len);
0725:                    }
0726:
0727:                    idx += len;
0728:                    // read the exponent length
0729:                    len = ((rec.inputData[idx++] & 0xff) << 16)
0730:                            + (rec.inputData[idx++] & 0xff);
0731:                    if (endOfMsg < (idx + len)) {
0732:                        return -1;
0733:                    }
0734:
0735:                    // ... and the exponent
0736:                    eKey.setExponent(rec.inputData, (short) idx, (short) len);
0737:                } catch (CryptoException ce) {
0738:                    // Utils.logln(Utils.LOG_ERR, "rcvSrvrExch caught " + ce);
0739:                    return -1;
0740:                }
0741:
0742:                idx += len;
0743:
0744:                // mark where ServerRSAparams end
0745:                int end = idx;
0746:
0747:                // Now read the signature length
0748:                len = ((rec.inputData[idx++] & 0xff) << 16)
0749:                        + (rec.inputData[idx++] & 0xff);
0750:                if (endOfMsg < (idx + len)) {
0751:                    return -1;
0752:                }
0753:
0754:                // ... and the signature
0755:                byte[] sig = new byte[len];
0756:                System.arraycopy(rec.inputData, idx, sig, 0, sig.length);
0757:                idx += len;
0758:                if (endOfMsg != idx) {
0759:                    return -1;
0760:                }
0761:
0762:                // Compute the expected hash
0763:                byte[] dat = new byte[MD5_SIZE + SHA_SIZE];
0764:                try {
0765:                    MessageDigest di = MessageDigest.getInstance(
0766:                            MessageDigest.ALG_MD5, false);
0767:                    di.update(crand, 0, crand.length);
0768:                    di.update(srand, 0, srand.length);
0769:                    di.doFinal(rec.inputData, HDR_SIZE, end - HDR_SIZE, dat, 0);
0770:
0771:                    di = MessageDigest
0772:                            .getInstance(MessageDigest.ALG_SHA, false);
0773:                    di.update(crand, 0, crand.length);
0774:                    di.update(srand, 0, srand.length);
0775:                    di.doFinal(rec.inputData, HDR_SIZE, end - HDR_SIZE, dat,
0776:                            MD5_SIZE);
0777:                } catch (Exception e) {
0778:                    throw new RuntimeException("No MD5 or SHA");
0779:                }
0780:
0781:                try {
0782:                    Cipher rsa = Cipher
0783:                            .getInstance(Cipher.ALG_RSA_PKCS1, false);
0784:                    rsa.init(sKey, Cipher.MODE_DECRYPT);
0785:                    byte[] res = new byte[sKey.getSize() >>> 3];
0786:                    int val = rsa.doFinal(sig, 0, sig.length, res, 0);
0787:                    if (!Utils.byteMatch(res, 0, dat, 0, dat.length)) {
0788:                        Utils.logln(Utils.LOG_ERR,
0789:                                "RSA params failed verification");
0790:                        return -1;
0791:                    }
0792:                    // Utils.logln(Utils.LOG_DEBUG, "RSA params verified");
0793:                } catch (Exception e) {
0794:                    throw new IOException("RSA decryption caught " + e);
0795:                }
0796:
0797:                // Update the hash of handshake messages
0798:                ourMD5.update(rec.inputData, start, msgLength);
0799:                ourSHA.update(rec.inputData, start, msgLength);
0800:
0801:                return 0;
0802:            }
0803:
0804:            /**
0805:             * Receives a Certificate request message. This message is optional.
0806:             * <P />
0807:             * @return 0 (this method always completes successfully)
0808:             * @exception IOException if there is a problem reading the
0809:             * message
0810:             */
0811:            private int rcvCertReq() throws IOException {
0812:                int msgLength = getNextMsg(CERT_REQ);
0813:                if (msgLength == -1) {
0814:                    return 0; // certificate request is optional
0815:                }
0816:
0817:                /*
0818:                 * We do not support client-side certificates so if we see
0819:                 * a request for a certificate, remember it here so we can
0820:                 * complain later
0821:                 */
0822:                gotCertReq = (byte) 1;
0823:
0824:                // Update the hash of handshake messages
0825:                ourMD5.update(rec.inputData, start, msgLength);
0826:                ourSHA.update(rec.inputData, start, msgLength);
0827:
0828:                // NOTE: We return zero without attempting to parse the message body.
0829:                return 0;
0830:            }
0831:
0832:            /**
0833:             * Receives a Server hello done message.
0834:             * <P />
0835:             * @return 0 on success, -1 on error
0836:             * @exception IOException if there is a problem reading the
0837:             * message
0838:             */
0839:            private int rcvSrvrHelloDone() throws IOException {
0840:                int msgLength = getNextMsg(S_DONE);
0841:
0842:                // A server_hello_done message has no body, just the header
0843:                if (msgLength != HDR_SIZE) {
0844:                    return -1;
0845:                }
0846:
0847:                // Update the hash of handshake messages
0848:                ourMD5.update(rec.inputData, start, msgLength);
0849:                ourSHA.update(rec.inputData, start, msgLength);
0850:
0851:                return 0;
0852:            }
0853:
0854:            /**
0855:             * Sends a Client key exchange message. For now, only RSA key 
0856:             * exchange is supported and this message contains a pre-master
0857:             * secret encrypted with the RSA public key of the server.
0858:             * <P />
0859:             * @exception IOException if there is a problem writing to the 
0860:             * record layer
0861:             */
0862:            private void sndKeyExch() throws IOException {
0863:                /*
0864:                 * If we get here, the server agreed to an RSA key exchange
0865:                 * and the RSA public key to be used for encrypting the
0866:                 * pre-master secret is available in eKey.
0867:                 */
0868:                if (gotCertReq == 1) {
0869:                    // Send back an error ... we do not support client auth
0870:                    rec.alert(Record.FATAL, Record.NO_CERT);
0871:                    throw new IOException("No client cert");
0872:                } else { // NOTE: The only possible key exch is RSA
0873:
0874:                    // Generate a 48-byte random pre-master secret
0875:                    preMaster = new byte[48];
0876:
0877:                    rnd.generateData(preMaster, (short) 0, (short) 48);
0878:                    // ... first two bytes must have client version
0879:                    preMaster[0] = (byte) (ver >>> 4);
0880:                    preMaster[1] = (byte) (ver & 0x0f);
0881:
0882:                    // Prepare a message containing the RSA encrypted pre-master
0883:                    int modLen = eKey.getSize() >>> 3;
0884:                    byte[] msg = new byte[HDR_SIZE + modLen];
0885:                    int idx = 0;
0886:                    // Fill the type
0887:                    msg[idx++] = C_KEYEXCH;
0888:                    // ... message length
0889:                    msg[idx++] = (byte) (modLen >>> 16);
0890:                    msg[idx++] = (byte) (modLen >>> 8);
0891:                    msg[idx++] = (byte) (modLen & 0xff);
0892:
0893:                    // ... the encrypted pre-master secret
0894:                    try {
0895:                        Cipher rsa = Cipher.getInstance(Cipher.ALG_RSA_PKCS1,
0896:                                false);
0897:                        rsa.init(eKey, Cipher.MODE_ENCRYPT);
0898:                        int val = rsa.doFinal(preMaster, 0, 48, msg, idx);
0899:                        if (val != modLen)
0900:                            throw new IOException("RSA result too short");
0901:                    } catch (Exception e) {
0902:                        //throw new IOException("premaster encryption caught " + e);
0903:                        e.printStackTrace();
0904:                        throw new IOException("premaster encryption caught "
0905:                                + e);
0906:                    }
0907:
0908:                    // Update the hash of handshake messages
0909:                    ourMD5.update(msg, 0, msg.length);
0910:                    ourSHA.update(msg, 0, msg.length);
0911:
0912:                    rec.wrRec(Record.HNDSHK, msg, 0, msg.length);
0913:                }
0914:            }
0915:
0916:            /**
0917:             * Derives the master key based on the pre-master secret and
0918:             * random values exchanged in the client and server hello messages.
0919:             * <P />
0920:             * @exception IOException if there is a problem during the computation
0921:             */
0922:            private void mkMaster() throws IOException {
0923:                byte[] expansion[] = { { (byte) 0x41 }, // 'A'
0924:                        { (byte) 0x42, (byte) 0x42 }, // 'BB'
0925:                        { (byte) 0x43, (byte) 0x43, (byte) 0x43 }, // 'CCC'
0926:                };
0927:
0928:                MessageDigest md = null;
0929:                MessageDigest sd = null;
0930:
0931:                /* 
0932:                 * First, we compute the 48-byte (three MD5 outputs) master secret
0933:                 * 
0934:                 * master_secret = 
0935:                 *   MD5(pre_master + SHA('A' + pre_master +
0936:                 *                         ClientHello.random + ServerHello.random)) +
0937:                 *   MD5(pre_master + SHA('BB' + pre_master +
0938:                 *                         ClientHello.random + ServerHello.random)) +
0939:                 *   MD5(pre_master + SHA('CCC' + pre_master +
0940:                 *                         ClientHello.random + ServerHello.random));
0941:                 * 
0942:                 * To simplify things, we use
0943:                 *   tmp = pre_master + ClientHello.random + ServerHello.random;
0944:                 */
0945:                byte[] tmp = new byte[preMaster.length + crand.length
0946:                        + srand.length];
0947:                System.arraycopy(preMaster, 0, tmp, 0, preMaster.length);
0948:                System.arraycopy(crand, 0, tmp, preMaster.length, crand.length);
0949:                System.arraycopy(srand, 0, tmp,
0950:                        preMaster.length + crand.length, srand.length);
0951:                try {
0952:                    md = MessageDigest
0953:                            .getInstance(MessageDigest.ALG_MD5, false);
0954:                    sd = MessageDigest
0955:                            .getInstance(MessageDigest.ALG_SHA, false);
0956:                } catch (Exception e) {
0957:                    /*
0958:                     * We should never catch this here (if these are missing,
0959:                     * we will catch this exception in the constructor)
0960:                     */
0961:                    throw new IOException("No MD5 or SHA");
0962:                }
0963:                master = new byte[48];
0964:
0965:                for (int i = 0; i < 3; i++) {
0966:                    md.update(preMaster, 0, preMaster.length);
0967:                    sd.update(expansion[i], 0, expansion[i].length);
0968:                    byte[] res = new byte[SHA_SIZE];
0969:                    sd.doFinal(tmp, 0, tmp.length, res, 0);
0970:                    md.doFinal(res, 0, res.length, master, i << 4);
0971:                }
0972:            }
0973:
0974:            /**
0975:             * Sends a ChangeCipherSpec protocol message (this is not really
0976:             * a handshake protocol message).
0977:             * <P />
0978:             * @exception IOException if there is a problem writing to the 
0979:             * record layer
0980:             */
0981:            private void sndChangeCipher() throws IOException {
0982:                byte[] msg = new byte[1];
0983:                // change cipher spec consists of a single byte with value 1    
0984:                msg[0] = (byte) 0x01;
0985:                rec.wrRec(Record.CCS, msg, 0, 1); // msg.length is 1
0986:            }
0987:
0988:            /**
0989:             * Computes the content of a Finished message.
0990:             * <P />
0991:             * @param who the role (either Record.CLIENT or
0992:             * Record.SERVER) for which the finish message is computed
0993:             * @return a byte array containing the hash of all handshake 
0994:             * messages seen so far
0995:             * @exception IOException if handshake digests could not be computed
0996:             */
0997:            private byte[] computeFinished(byte who) throws IOException {
0998:                byte[] sender[] = { { 0x53, 0x52, 0x56, 0x52 }, // for server
0999:                        { 0x43, 0x4c, 0x4e, 0x54 } // for client
1000:                };
1001:                byte[] msg = new byte[MD5_SIZE + SHA_SIZE];
1002:                byte[] tmp = null;
1003:
1004:                try {
1005:                    // long t1 = System.currentTimeMillis();
1006:                    MessageDigest d = (MessageDigest) ourMD5.clone();
1007:                    d.update(sender[who], 0, 4);
1008:                    d.update(master, 0, master.length);
1009:                    tmp = new byte[MD5_SIZE];
1010:                    // MD5 padding length is 48     
1011:                    d.doFinal(Record.PAD1, 0, 48, tmp, 0);
1012:                    d.update(master, 0, master.length);
1013:                    d.update(Record.PAD2, 0, 48);
1014:                    d.doFinal(tmp, 0, MD5_SIZE, msg, 0);
1015:
1016:                    d = (MessageDigest) ourSHA.clone();
1017:                    d.update(sender[who], 0, 4);
1018:                    d.update(master, 0, master.length);
1019:                    tmp = new byte[SHA_SIZE];
1020:                    // SHA padding length is 40
1021:                    d.doFinal(rec.PAD1, 0, 40, tmp, 0);
1022:                    d.update(master, 0, master.length);
1023:                    d.update(Record.PAD2, 0, 40);
1024:                    d.doFinal(tmp, 0, SHA_SIZE, msg, MD5_SIZE);
1025:
1026:                    return msg;
1027:                } catch (Exception e) {
1028:                    throw new IOException("MessageDigest not cloneable");
1029:                }
1030:            }
1031:
1032:            /**
1033:             * Sends a Finished message.
1034:             * <P />
1035:             * @exception IOException if there is a problem writing to the 
1036:             * record layer
1037:             */
1038:            private void sndFinished() throws IOException {
1039:                // HDR_SIZE + MD5_SIZE + SHA_SIZE is 40
1040:                byte[] msg = new byte[40];
1041:
1042:                System.arraycopy(FINISH_PREFIX, 0, msg, 0, 4);
1043:                // MD5_SIZE + SHA_SIZE is 36
1044:                System.arraycopy(computeFinished(role), 0, msg, 4, 36);
1045:
1046:                // Update the hash of handshake messages
1047:                ourMD5.update(msg, 0, msg.length);
1048:                ourSHA.update(msg, 0, msg.length);
1049:
1050:                rec.wrRec(Record.HNDSHK, msg, 0, msg.length);
1051:            }
1052:
1053:            /**
1054:             * Receives a ChangeCipherSpec protocol message (this is
1055:             * not a handshake message).
1056:             * <P />
1057:             * @return 0 on success, -1 on error
1058:             * @exception IOException if there is a problem reading the
1059:             * message
1060:             */
1061:            private int rcvChangeCipher() throws IOException {
1062:                /* 
1063:                 * We make sure that there are no unread handshake messages
1064:                 * in the internal store when we get here.
1065:                 */
1066:                if (cnt != 0) {
1067:                    Utils
1068:                            .logln(Utils.LOG_ERR,
1069:                                    "Unread handshake mesg in store");
1070:                    return -1;
1071:                }
1072:
1073:                /*
1074:                 * Note that CCS is not a handshake message (it is its own protocol)
1075:                 * The record layer header is 5 bytes and the CCS body is one
1076:                 * byte with value 0x01.
1077:                 */
1078:                rec.rdRec(Record.CCS);
1079:                if ((rec.inputData == null) || (rec.inputData.length != 1)
1080:                        || (rec.inputData[0] != (byte) 0x01)) {
1081:                    return -1;
1082:                }
1083:
1084:                return 0;
1085:            }
1086:
1087:            /**
1088:             * Receives a Finished message and verifies that it contains
1089:             * the correct hash of handshake messages.
1090:             * <P />
1091:             * @return 0 on success, -1 on error
1092:             * @exception IOException if there is a problem reading the
1093:             * message
1094:             */
1095:            private int rcvFinished() throws IOException {
1096:                int msgLength = getNextMsg(FINISH);
1097:                if (msgLength != 40) {
1098:                    return -1;
1099:                }
1100:
1101:                // Compute the expected hash
1102:                byte[] expected = computeFinished((byte) (1 - role));
1103:
1104:                if (!Utils.byteMatch(rec.inputData, start + HDR_SIZE, expected,
1105:                        0, expected.length)) {
1106:                    return -1;
1107:                } else {
1108:                    // Update the hash of handshake messages
1109:                    ourMD5.update(rec.inputData, start, msgLength);
1110:                    ourSHA.update(rec.inputData, start, msgLength);
1111:                    // now = System.currentTimeMillis();
1112:                    return 0;
1113:                }
1114:            }
1115:
1116:            /**
1117:             * Initiates an SSL handshake with the peer specified previously
1118:             * in the constructor. 
1119:             * <P />
1120:             * @param aswho role played in the handshake (for now only
1121:             * Record.CLIENT is supported)
1122:             * @exception IOException if the handshake fails for some reason
1123:             */
1124:            // TODO: Allow handshake parameters such as ver, cipher suites 
1125:            // and compression methods to be passed as arguments.
1126:            void doHandShake(byte aswho) throws IOException {
1127:                long t1 = System.currentTimeMillis();
1128:                int code = 0;
1129:
1130:                ver = (byte) 0x30; // TODO: This is hardcoded for now
1131:                role = aswho;
1132:
1133:                byte val = 0;
1134:                sndHello3();
1135:
1136:                if (rcvSrvrHello() < 0) {
1137:                    complain("Bad ServerHello");
1138:                }
1139:                ;
1140:
1141:                if ((sSessionId == null)
1142:                        || (cSession == null)
1143:                        || (sSessionId.length != cSession.id.length)
1144:                        || !Utils.byteMatch(sSessionId, 0, cSession.id, 0,
1145:                                sSessionId.length)) {
1146:                    // Session not resumed
1147:
1148:                    try {
1149:                        code = rcvCert();
1150:                    } catch (CertificateException e) {
1151:                        complain(e);
1152:                    }
1153:
1154:                    if (code < 0) {
1155:                        complain("Corrupt server certificate message");
1156:                    }
1157:
1158:                    // ... get server_key_exchange (optional)
1159:                    try {
1160:                        code = rcvSrvrKeyExch();
1161:                    } catch (CertificateException e) {
1162:                        complain(e);
1163:                    }
1164:
1165:                    if (code < 0) {
1166:                        complain("Bad ServerKeyExchange");
1167:                    }
1168:
1169:                    // ... get certificate_request (optional)
1170:                    rcvCertReq();
1171:                    if (rcvSrvrHelloDone() < 0) {
1172:                        complain("Bad ServerHelloDone");
1173:                    }
1174:
1175:                    // ... send client_key_exchange
1176:                    sndKeyExch();
1177:                    mkMaster();
1178:                    try {
1179:                        rec.init(crand, srand, negSuite, master);
1180:                    } catch (Exception e) {
1181:                        complain("Record.init() caught " + e);
1182:                    }
1183:
1184:                    // ... send change_cipher_spec
1185:                    sndChangeCipher();
1186:                    // ... send finished
1187:                    sndFinished();
1188:
1189:                    // ... get change_cipher_spec
1190:                    if (rcvChangeCipher() < 0) {
1191:                        complain("Bad ChangeCipherSpec");
1192:                    }
1193:
1194:                    // ... get finished
1195:                    if (rcvFinished() < 0) {
1196:                        complain("Bad Finished");
1197:                    }
1198:                } else {
1199:                    /*
1200:                     * The server agreed to resume a session.
1201:                     * Get the needed values from the previous session
1202:                     * now since the references could be overwritten if a
1203:                     * concurrent connection is made to this host and port.
1204:                     */
1205:                    master = cSession.master;
1206:                    sCert = cSession.cert;
1207:
1208:                    try {
1209:                        rec.init(crand, srand, negSuite, master);
1210:                    } catch (Exception e) {
1211:                        complain("Record.init() caught " + e);
1212:                    }
1213:
1214:                    // ... get change_cipher_spec
1215:                    if (rcvChangeCipher() < 0) {
1216:                        complain("Bad ChangeCipherSpec");
1217:                    }
1218:
1219:                    // ... get finished
1220:                    if (rcvFinished() < 0) {
1221:                        complain("Bad Finished");
1222:                    }
1223:
1224:                    // ... send change_cipher_spec
1225:                    sndChangeCipher();
1226:                    // ... send finished
1227:                    sndFinished();
1228:                }
1229:
1230:                Session.add(peerHost, peerPort, sSessionId, master, sCert);
1231:
1232:                // Zero out the premaster and master secrets
1233:                if (preMaster != null) {
1234:                    // premaster can be null if we resumed an SSL session
1235:                    for (int i = 0; i < preMaster.length; i++) {
1236:                        preMaster[i] = 0;
1237:                    }
1238:                }
1239:
1240:                for (int i = 0; i < master.length; i++) {
1241:                    master[i] = 0;
1242:                }
1243:            }
1244:
1245:            /**
1246:             * Sends a fatal alert indicating handshake_failure and marks
1247:             * the corresponding SSL session is non-resumable.
1248:             * <p />
1249:             * @param msg string containing the exception message to be reported
1250:             * @exception IOException with the specified string
1251:             */
1252:            private void complain(String msg) throws IOException {
1253:                complain(new IOException(msg));
1254:            }
1255:
1256:            /**
1257:             * Sends a fatal alert indicating handshake_failure and marks
1258:             * the corresponding SSL session is non-resumable.
1259:             * <p />
1260:             * @param e the IOException to be reported
1261:             * @exception IOException 
1262:             */
1263:            private void complain(IOException e) throws IOException {
1264:                try {
1265:                    rec.alert(Record.FATAL, Record.HNDSHK_FAIL);
1266:                    if (sSessionId != null) {
1267:                        Session.del(peerHost, peerPort, sSessionId);
1268:                    }
1269:                } finally {
1270:                    throw e;
1271:                }
1272:            }
1273:
1274:            void setCipherSuites(byte[] cipherSuites) {
1275:                this .SUITES_AND_COMP = cipherSuites;
1276:            }
1277:
1278:        }
1279:
1280:        /**
1281:         * This class implements methods to maintain resumable SSL
1282:         * sessions.
1283:         */
1284:        // visible within the package
1285:        class Session {
1286:            /**  Maximum number of cached resumable sessions. */
1287:            private static final byte MAX_SESSIONS = 4;
1288:
1289:            /**
1290:             * Stores the last index where a session was overwritten, we
1291:             * try to do a round-robin selection of places to overwrite
1292:             */
1293:            private static int delIdx = 0;
1294:
1295:            /*
1296:             * A session is uniquely identified by the combination of 
1297:             * host, port and session identifier. The master secret is
1298:             * included in the cached session information.
1299:             */
1300:            /** Target host name. */
1301:            String host;
1302:            /** Target port number. */
1303:            int port;
1304:            /** Session identifier. */
1305:            byte[] id;
1306:            /** Master secret. */
1307:            byte[] master;
1308:            /** Target Certificate. */
1309:            X509Certificate cert;
1310:
1311:            /** A cache of currently resumable sessions. */
1312:            private static Session[] sessions = new Session[MAX_SESSIONS];
1313:
1314:            /**
1315:             * Gets the master secret associated with a resumable session.
1316:             * The session is uniquely identified by the combination of the
1317:             * host, port.
1318:             *
1319:             * @param h host name of peer
1320:             * @param p port number of peer
1321:             *
1322:             * @return matching session
1323:             */
1324:            static synchronized Session get(String h, int p) {
1325:                for (int i = 0; i < MAX_SESSIONS; i++) {
1326:                    if ((sessions[i] == null) || (sessions[i].id == null))
1327:                        continue;
1328:
1329:                    if (sessions[i].host.compareTo(h) == 0
1330:                            && sessions[i].port == p) {
1331:                        return sessions[i];
1332:                    }
1333:                }
1334:
1335:                return null;
1336:            }
1337:
1338:            /**
1339:             * Adds a new session with the specified parameters to the cache
1340:             * of resumable sessions. At any given time, this class maintains
1341:             * at most one resusumable session for any host/port pair.
1342:             * <P />
1343:             * @param h host name of peer
1344:             * @param p port number of peer
1345:             * @param id session identifier
1346:             * @param mas master secret
1347:             * @param cert certificate of peer
1348:             */
1349:            static synchronized void add(String h, int p, byte[] id,
1350:                    byte[] mas, X509Certificate cert) {
1351:                // TODO: This will change if we stop using linear arrays
1352:                int idx = MAX_SESSIONS;
1353:                for (int i = 0; i < MAX_SESSIONS; i++) {
1354:                    if ((sessions[i] == null) || (sessions[i].id == null)) {
1355:                        idx = i; // possible candidate for overwriting
1356:                        continue;
1357:                    }
1358:
1359:                    if ((sessions[i].host.compareTo(h) == 0)
1360:                            && (sessions[i].port == p)) { // preferred candidate
1361:                        idx = i;
1362:                        break;
1363:                    }
1364:                }
1365:
1366:                /*
1367:                 * If all else is taken, overwrite the one specified by 
1368:                 * delIdx and move delIdx over to the next one. Simulates FIFO.
1369:                 */
1370:                if (idx == MAX_SESSIONS) {
1371:                    idx = delIdx;
1372:                    delIdx++;
1373:                    if (delIdx == MAX_SESSIONS)
1374:                        delIdx = 0;
1375:                }
1376:
1377:                if (sessions[idx] == null) {
1378:                    sessions[idx] = new Session();
1379:                }
1380:
1381:                sessions[idx].id = id;
1382:
1383:                /*
1384:                 * Since the master will change after this method, we need to
1385:                 * copy it, to preserve its current value for later.
1386:                 */
1387:                sessions[idx].master = new byte[mas.length];
1388:                System.arraycopy(mas, 0, sessions[idx].master, 0, mas.length);
1389:
1390:                sessions[idx].host = new String(h); // "h" will be a substring of URL
1391:                sessions[idx].port = p;
1392:                sessions[idx].cert = cert;
1393:            }
1394:
1395:            /**
1396:             * Deletes the session identified by the specfied parameters
1397:             * from the cache of resumable sessions.
1398:             * <P />
1399:             * @param h host name of peer
1400:             * @param p port number of peer
1401:             * @param sid session identifier
1402:             */
1403:            static synchronized void del(String h, int p, byte[] sid) {
1404:                for (int i = 0; i < MAX_SESSIONS; i++) {
1405:                    if ((sessions[i] == null) || (sessions[i].id == null))
1406:                        continue;
1407:
1408:                    if (Utils.byteMatch(sessions[i].id, 0, sid, 0, sid.length)
1409:                            && (sessions[i].host.compareTo(h) == 0)
1410:                            && (sessions[i].port == p)) {
1411:                        sessions[i].id = null;
1412:                        sessions[i].master = null;
1413:                        sessions[i].host = null;
1414:                        sessions[i].cert = null;
1415:                        break;
1416:                    }
1417:                }
1418:            }
1419:
1420:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.