Source Code Cross Referenced for Handshake.java in  » 6.0-JDK-Modules » j2me » com » sun » midp » ssl » 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 » 6.0 JDK Modules » j2me » com.sun.midp.ssl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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