Source Code Cross Referenced for TlsProtocolHandler.java in  » Security » Bouncy-Castle » org » bouncycastle » crypto » tls » 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 » Security » Bouncy Castle » org.bouncycastle.crypto.tls 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package org.bouncycastle.crypto.tls;
0002:
0003:        import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
0004:        import org.bouncycastle.crypto.InvalidCipherTextException;
0005:        import org.bouncycastle.crypto.encodings.PKCS1Encoding;
0006:        import org.bouncycastle.crypto.engines.RSABlindedEngine;
0007:        import org.bouncycastle.crypto.params.ParametersWithRandom;
0008:        import org.bouncycastle.crypto.params.RSAKeyParameters;
0009:        import org.bouncycastle.crypto.prng.ThreadedSeedGenerator;
0010:
0011:        import java.io.ByteArrayInputStream;
0012:        import java.io.ByteArrayOutputStream;
0013:        import java.io.IOException;
0014:        import java.io.InputStream;
0015:        import java.io.OutputStream;
0016:        import java.math.BigInteger;
0017:        import java.security.SecureRandom;
0018:
0019:        /**
0020:         * An implementation of all high level protocols in TLS 1.0.
0021:         */
0022:        public class TlsProtocolHandler {
0023:
0024:            private static final short RL_CHANGE_CIPHER_SPEC = 20;
0025:
0026:            private static final short RL_ALERT = 21;
0027:
0028:            private static final short RL_HANDSHAKE = 22;
0029:
0030:            private static final short RL_APPLICATION_DATA = 23;
0031:
0032:            /*
0033:             hello_request(0), client_hello(1), server_hello(2),
0034:             certificate(11), server_key_exchange (12),
0035:             certificate_request(13), server_hello_done(14),
0036:             certificate_verify(15), client_key_exchange(16),
0037:             finished(20), (255)
0038:             */
0039:
0040:            private static final short HP_HELLO_REQUEST = 0;
0041:
0042:            private static final short HP_CLIENT_HELLO = 1;
0043:
0044:            private static final short HP_SERVER_HELLO = 2;
0045:
0046:            private static final short HP_CERTIFICATE = 11;
0047:
0048:            private static final short HP_SERVER_KEY_EXCHANGE = 12;
0049:
0050:            private static final short HP_CERTIFICATE_REQUEST = 13;
0051:
0052:            private static final short HP_SERVER_HELLO_DONE = 14;
0053:
0054:            private static final short HP_CERTIFICATE_VERIFY = 15;
0055:
0056:            private static final short HP_CLIENT_KEY_EXCHANGE = 16;
0057:
0058:            private static final short HP_FINISHED = 20;
0059:
0060:            /*
0061:             * Our Connection states
0062:             */
0063:
0064:            private static final short CS_CLIENT_HELLO_SEND = 1;
0065:
0066:            private static final short CS_SERVER_HELLO_RECEIVED = 2;
0067:
0068:            private static final short CS_SERVER_CERTIFICATE_RECEIVED = 3;
0069:
0070:            private static final short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4;
0071:
0072:            private static final short CS_SERVER_HELLO_DONE_RECEIVED = 5;
0073:
0074:            private static final short CS_CLIENT_KEY_EXCHANGE_SEND = 6;
0075:
0076:            private static final short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 7;
0077:
0078:            private static final short CS_CLIENT_FINISHED_SEND = 8;
0079:
0080:            private static final short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 9;
0081:
0082:            private static final short CS_DONE = 10;
0083:
0084:            protected static final short AP_close_notify = 0;
0085:            protected static final short AP_unexpected_message = 10;
0086:            protected static final short AP_bad_record_mac = 20;
0087:            protected static final short AP_decryption_failed = 21;
0088:            protected static final short AP_record_overflow = 22;
0089:            protected static final short AP_decompression_failure = 30;
0090:            protected static final short AP_handshake_failure = 40;
0091:            protected static final short AP_bad_certificate = 42;
0092:            protected static final short AP_unsupported_certificate = 43;
0093:            protected static final short AP_certificate_revoked = 44;
0094:            protected static final short AP_certificate_expired = 45;
0095:            protected static final short AP_certificate_unknown = 46;
0096:            protected static final short AP_illegal_parameter = 47;
0097:            protected static final short AP_unknown_ca = 48;
0098:            protected static final short AP_access_denied = 49;
0099:            protected static final short AP_decode_error = 50;
0100:            protected static final short AP_decrypt_error = 51;
0101:            protected static final short AP_export_restriction = 60;
0102:            protected static final short AP_protocol_version = 70;
0103:            protected static final short AP_insufficient_security = 71;
0104:            protected static final short AP_internal_error = 80;
0105:            protected static final short AP_user_canceled = 90;
0106:            protected static final short AP_no_renegotiation = 100;
0107:
0108:            protected static final short AL_warning = 1;
0109:            protected static final short AL_fatal = 2;
0110:
0111:            private static final byte[] emptybuf = new byte[0];
0112:
0113:            private static final String TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
0114:
0115:            /*
0116:             * Queues for data from some protocolls.
0117:             */
0118:
0119:            private ByteQueue applicationDataQueue = new ByteQueue();
0120:
0121:            private ByteQueue changeCipherSpecQueue = new ByteQueue();
0122:
0123:            private ByteQueue alertQueue = new ByteQueue();
0124:
0125:            private ByteQueue handshakeQueue = new ByteQueue();
0126:
0127:            /*
0128:             * The Record Stream we use
0129:             */
0130:
0131:            private RecordStream rs;
0132:
0133:            private SecureRandom random;
0134:
0135:            /*
0136:             * The public rsa-key of the server.
0137:             */
0138:
0139:            private RSAKeyParameters serverRsaKey = null;
0140:
0141:            private TlsInputStream tlsInputStream = null;
0142:            private TlsOuputStream tlsOutputStream = null;
0143:
0144:            private boolean closed = false;
0145:            private boolean failedWithError = false;
0146:            private boolean appDataReady = false;
0147:
0148:            private byte[] clientRandom;
0149:            private byte[] serverRandom;
0150:            private byte[] ms;
0151:
0152:            private TlsCipherSuite choosenCipherSuite = null;
0153:
0154:            private BigInteger Yc;
0155:            private byte[] pms;
0156:
0157:            private CertificateVerifyer verifyer = null;
0158:
0159:            public TlsProtocolHandler(InputStream is, OutputStream os) {
0160:                /*
0161:                 * We use our threaded seed generator to generate a good random
0162:                 * seed. If the user has a better random seed, he should use
0163:                 * the constructor with a SecureRandom.
0164:                 */
0165:                ThreadedSeedGenerator tsg = new ThreadedSeedGenerator();
0166:                this .random = new SecureRandom();
0167:                /*
0168:                 * Hopefully, 20 bytes in fast mode are good enough.
0169:                 */
0170:                this .random.setSeed(tsg.generateSeed(20, true));
0171:
0172:                this .rs = new RecordStream(this , is, os);
0173:            }
0174:
0175:            public TlsProtocolHandler(InputStream is, OutputStream os,
0176:                    SecureRandom sr) {
0177:                this .random = sr;
0178:                this .rs = new RecordStream(this , is, os);
0179:            }
0180:
0181:            private short connection_state;
0182:
0183:            protected void processData(short protocol, byte[] buf, int offset,
0184:                    int len) throws IOException {
0185:                /*
0186:                 * Have a look at the protocol type, and add it to the correct queue.
0187:                 */
0188:                switch (protocol) {
0189:                case RL_CHANGE_CIPHER_SPEC:
0190:                    changeCipherSpecQueue.addData(buf, offset, len);
0191:                    processChangeCipherSpec();
0192:                    break;
0193:                case RL_ALERT:
0194:                    alertQueue.addData(buf, offset, len);
0195:                    processAlert();
0196:                    break;
0197:                case RL_HANDSHAKE:
0198:                    handshakeQueue.addData(buf, offset, len);
0199:                    processHandshake();
0200:                    break;
0201:                case RL_APPLICATION_DATA:
0202:                    if (!appDataReady) {
0203:                        this .failWithError(AL_fatal, AP_unexpected_message);
0204:                    }
0205:                    applicationDataQueue.addData(buf, offset, len);
0206:                    processApplicationData();
0207:                    break;
0208:                default:
0209:                    /*
0210:                     * Uh, we don't know this protocol.
0211:                     *
0212:                     * RFC2246 defines on page 13, that we should ignore this.
0213:                     */
0214:
0215:                }
0216:            }
0217:
0218:            private void processHandshake() throws IOException {
0219:                boolean read;
0220:                do {
0221:                    read = false;
0222:
0223:                    /*
0224:                     * We need the first 4 bytes, they contain type and length of
0225:                     * the message.
0226:                     */
0227:                    if (handshakeQueue.size() >= 4) {
0228:                        byte[] beginning = new byte[4];
0229:                        handshakeQueue.read(beginning, 0, 4, 0);
0230:                        ByteArrayInputStream bis = new ByteArrayInputStream(
0231:                                beginning);
0232:                        short type = TlsUtils.readUint8(bis);
0233:                        int len = TlsUtils.readUint24(bis);
0234:
0235:                        /*
0236:                         * Check if we have enough bytes in the buffer to read
0237:                         * the full message.
0238:                         */
0239:                        if (handshakeQueue.size() >= (len + 4)) {
0240:                            /*
0241:                             * Read the message.
0242:                             */
0243:                            byte[] buf = new byte[len];
0244:                            handshakeQueue.read(buf, 0, len, 4);
0245:                            handshakeQueue.removeData(len + 4);
0246:
0247:                            /*
0248:                             * If it is not a finished message, update our hashes
0249:                             * we prepare for the finish message.
0250:                             */
0251:                            if (type != HP_FINISHED) {
0252:                                rs.hash1.update(beginning, 0, 4);
0253:                                rs.hash2.update(beginning, 0, 4);
0254:                                rs.hash1.update(buf, 0, len);
0255:                                rs.hash2.update(buf, 0, len);
0256:                            }
0257:
0258:                            /*
0259:                             * Now, parse the message.
0260:                             */
0261:                            ByteArrayInputStream is = new ByteArrayInputStream(
0262:                                    buf);
0263:
0264:                            /*
0265:                             * Check the type.
0266:                             */
0267:                            switch (type) {
0268:                            case HP_CERTIFICATE:
0269:                                switch (connection_state) {
0270:                                case CS_SERVER_HELLO_RECEIVED:
0271:                                    /*
0272:                                     * Parse the certificates.
0273:                                     */
0274:                                    Certificate cert = Certificate.parse(is);
0275:                                    assertEmpty(is);
0276:
0277:                                    /*
0278:                                     * Verify them.
0279:                                     */
0280:                                    if (!this .verifyer.isValid(cert.getCerts())) {
0281:                                        this .failWithError(AL_fatal,
0282:                                                AP_user_canceled);
0283:                                    }
0284:
0285:                                    /*
0286:                                     * We only support RSA certificates. Lets hope
0287:                                     * this is one.
0288:                                     */
0289:                                    RSAPublicKeyStructure rsaKey = null;
0290:                                    try {
0291:                                        rsaKey = RSAPublicKeyStructure
0292:                                                .getInstance(cert.certs[0]
0293:                                                        .getTBSCertificate()
0294:                                                        .getSubjectPublicKeyInfo()
0295:                                                        .getPublicKey());
0296:                                    } catch (Exception e) {
0297:                                        /*
0298:                                         * Sorry, we have to fail ;-(
0299:                                         */
0300:                                        this .failWithError(AL_fatal,
0301:                                                AP_unsupported_certificate);
0302:                                    }
0303:
0304:                                    /*
0305:                                     * Parse the servers public RSA key.
0306:                                     */
0307:                                    this .serverRsaKey = new RSAKeyParameters(
0308:                                            false, rsaKey.getModulus(), rsaKey
0309:                                                    .getPublicExponent());
0310:
0311:                                    connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
0312:                                    read = true;
0313:                                    break;
0314:                                default:
0315:                                    this .failWithError(AL_fatal,
0316:                                            AP_unexpected_message);
0317:                                }
0318:                                break;
0319:                            case HP_FINISHED:
0320:                                switch (connection_state) {
0321:                                case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
0322:                                    /*
0323:                                     * Read the checksum from the finished message,
0324:                                     * it has always 12 bytes.
0325:                                     */
0326:                                    byte[] receivedChecksum = new byte[12];
0327:                                    TlsUtils.readFully(receivedChecksum, is);
0328:                                    assertEmpty(is);
0329:
0330:                                    /*
0331:                                     * Calculate our owne checksum.
0332:                                     */
0333:                                    byte[] checksum = new byte[12];
0334:                                    byte[] md5andsha1 = new byte[16 + 20];
0335:                                    rs.hash2.doFinal(md5andsha1, 0);
0336:                                    TlsUtils.PRF(this .ms, TlsUtils
0337:                                            .toByteArray("server finished"),
0338:                                            md5andsha1, checksum);
0339:
0340:                                    /*
0341:                                     * Compare both checksums.
0342:                                     */
0343:                                    for (int i = 0; i < receivedChecksum.length; i++) {
0344:                                        if (receivedChecksum[i] != checksum[i]) {
0345:                                            /*
0346:                                             * Wrong checksum in the finished message.
0347:                                             */
0348:                                            this .failWithError(AL_fatal,
0349:                                                    AP_handshake_failure);
0350:                                        }
0351:                                    }
0352:
0353:                                    connection_state = CS_DONE;
0354:
0355:                                    /*
0356:                                     * We are now ready to receive application data.
0357:                                     */
0358:                                    this .appDataReady = true;
0359:                                    read = true;
0360:                                    break;
0361:                                default:
0362:                                    this .failWithError(AL_fatal,
0363:                                            AP_unexpected_message);
0364:                                }
0365:                                break;
0366:                            case HP_SERVER_HELLO:
0367:                                switch (connection_state) {
0368:                                case CS_CLIENT_HELLO_SEND:
0369:                                    /*
0370:                                     * Read the server hello message
0371:                                     */
0372:                                    TlsUtils.checkVersion(is, this );
0373:
0374:                                    /*
0375:                                     * Read the server random
0376:                                     */
0377:                                    this .serverRandom = new byte[32];
0378:                                    TlsUtils.readFully(this .serverRandom, is);
0379:
0380:                                    /*
0381:                                     * Currenty, we don't support session ids
0382:                                     */
0383:                                    short sessionIdLength = TlsUtils
0384:                                            .readUint8(is);
0385:                                    byte[] sessionId = new byte[sessionIdLength];
0386:                                    TlsUtils.readFully(sessionId, is);
0387:
0388:                                    /*
0389:                                     * Find out which ciphersuite the server has
0390:                                     * choosen. If we don't support this ciphersuite,
0391:                                     * the TlsCipherSuiteManager will throw an
0392:                                     * exception.
0393:                                     */
0394:                                    this .choosenCipherSuite = TlsCipherSuiteManager
0395:                                            .getCipherSuite(TlsUtils
0396:                                                    .readUint16(is), this );
0397:
0398:                                    /*
0399:                                     * We support only the null compression which
0400:                                     * means no compression.
0401:                                     */
0402:                                    short compressionMethod = TlsUtils
0403:                                            .readUint8(is);
0404:                                    if (compressionMethod != 0) {
0405:                                        this 
0406:                                                .failWithError(
0407:                                                        TlsProtocolHandler.AL_fatal,
0408:                                                        TlsProtocolHandler.AP_illegal_parameter);
0409:                                    }
0410:                                    assertEmpty(is);
0411:
0412:                                    connection_state = CS_SERVER_HELLO_RECEIVED;
0413:                                    read = true;
0414:                                    break;
0415:                                default:
0416:                                    this .failWithError(AL_fatal,
0417:                                            AP_unexpected_message);
0418:                                }
0419:                                break;
0420:                            case HP_SERVER_HELLO_DONE:
0421:                                switch (connection_state) {
0422:
0423:                                case CS_SERVER_CERTIFICATE_RECEIVED:
0424:                                    /*
0425:                                     * There was no server key exchange message, check
0426:                                     * that we are doing RSA key exchange.
0427:                                     */
0428:                                    if (this .choosenCipherSuite
0429:                                            .getKeyExchangeAlgorithm() != TlsCipherSuite.KE_RSA) {
0430:                                        this .failWithError(AL_fatal,
0431:                                                AP_unexpected_message);
0432:                                    }
0433:
0434:                                    /*
0435:                                     * NB: Fall through to next case label to continue RSA key exchange
0436:                                     */
0437:
0438:                                case CS_SERVER_KEY_EXCHANGE_RECEIVED:
0439:
0440:                                    assertEmpty(is);
0441:                                    connection_state = CS_SERVER_HELLO_DONE_RECEIVED;
0442:
0443:                                    /*
0444:                                     * Send the client key exchange message, depending
0445:                                     * on the key exchange we are using in our
0446:                                     * ciphersuite.
0447:                                     */
0448:                                    short ke = this .choosenCipherSuite
0449:                                            .getKeyExchangeAlgorithm();
0450:
0451:                                    switch (ke) {
0452:                                    case TlsCipherSuite.KE_RSA:
0453:                                        /*
0454:                                         * We are doing RSA key exchange. We will
0455:                                         * choose a pre master secret and send it
0456:                                         * rsa encrypted to the server.
0457:                                         *
0458:                                         * Prepare pre master secret.
0459:                                         */
0460:                                        pms = new byte[48];
0461:                                        pms[0] = 3;
0462:                                        pms[1] = 1;
0463:                                        for (int i = 2; i < 48; i++) {
0464:                                            pms[i] = (byte) random.nextInt();
0465:                                        }
0466:
0467:                                        /*
0468:                                         * Encode the pms and send it to the server.
0469:                                         *
0470:                                         * Prepare an PKCS1Encoding with good random
0471:                                         * padding.
0472:                                         */
0473:                                        RSABlindedEngine rsa = new RSABlindedEngine();
0474:                                        PKCS1Encoding encoding = new PKCS1Encoding(
0475:                                                rsa);
0476:                                        encoding.init(true,
0477:                                                new ParametersWithRandom(
0478:                                                        this .serverRsaKey,
0479:                                                        this .random));
0480:                                        byte[] encrypted = null;
0481:                                        try {
0482:                                            encrypted = encoding.processBlock(
0483:                                                    pms, 0, pms.length);
0484:                                        } catch (InvalidCipherTextException e) {
0485:                                            /*
0486:                                             * This should never happen, only during decryption.
0487:                                             */
0488:                                            this .failWithError(AL_fatal,
0489:                                                    AP_internal_error);
0490:                                        }
0491:
0492:                                        /*
0493:                                         * Send the encrypted pms.
0494:                                         */
0495:                                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
0496:                                        TlsUtils.writeUint8(
0497:                                                HP_CLIENT_KEY_EXCHANGE, bos);
0498:                                        TlsUtils.writeUint24(
0499:                                                encrypted.length + 2, bos);
0500:                                        TlsUtils.writeUint16(encrypted.length,
0501:                                                bos);
0502:                                        bos.write(encrypted);
0503:                                        byte[] message = bos.toByteArray();
0504:
0505:                                        rs.writeMessage((short) RL_HANDSHAKE,
0506:                                                message, 0, message.length);
0507:                                        break;
0508:                                    case TlsCipherSuite.KE_DHE_RSA:
0509:                                        /*
0510:                                         * Send the Client Key Exchange message for
0511:                                         * DHE key exchange.
0512:                                         */
0513:                                        byte[] YcByte = this .Yc.toByteArray();
0514:                                        ByteArrayOutputStream DHbos = new ByteArrayOutputStream();
0515:                                        TlsUtils.writeUint8(
0516:                                                HP_CLIENT_KEY_EXCHANGE, DHbos);
0517:                                        TlsUtils.writeUint24(YcByte.length + 2,
0518:                                                DHbos);
0519:                                        TlsUtils.writeUint16(YcByte.length,
0520:                                                DHbos);
0521:                                        DHbos.write(YcByte);
0522:                                        byte[] DHmessage = DHbos.toByteArray();
0523:
0524:                                        rs.writeMessage((short) RL_HANDSHAKE,
0525:                                                DHmessage, 0, DHmessage.length);
0526:
0527:                                        break;
0528:                                    default:
0529:                                        /*
0530:                                         * Proble during handshake, we don't know
0531:                                         * how to thandle this key exchange method.
0532:                                         */
0533:                                        this .failWithError(AL_fatal,
0534:                                                AP_unexpected_message);
0535:
0536:                                    }
0537:
0538:                                    connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;
0539:
0540:                                    /*
0541:                                     * Now, we send change cipher state
0542:                                     */
0543:                                    byte[] cmessage = new byte[1];
0544:                                    cmessage[0] = 1;
0545:                                    rs.writeMessage(
0546:                                            (short) RL_CHANGE_CIPHER_SPEC,
0547:                                            cmessage, 0, cmessage.length);
0548:
0549:                                    connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;
0550:
0551:                                    /*
0552:                                     * Calculate the ms
0553:                                     */
0554:                                    this .ms = new byte[48];
0555:                                    byte[] random = new byte[clientRandom.length
0556:                                            + serverRandom.length];
0557:                                    System.arraycopy(clientRandom, 0, random,
0558:                                            0, clientRandom.length);
0559:                                    System.arraycopy(serverRandom, 0, random,
0560:                                            clientRandom.length,
0561:                                            serverRandom.length);
0562:                                    TlsUtils.PRF(pms, TlsUtils
0563:                                            .toByteArray("master secret"),
0564:                                            random, this .ms);
0565:
0566:                                    /*
0567:                                     * Initialize our cipher suite
0568:                                     */
0569:                                    rs.writeSuite = this .choosenCipherSuite;
0570:                                    rs.writeSuite.init(this .ms, clientRandom,
0571:                                            serverRandom);
0572:
0573:                                    /*
0574:                                     * Send our finished message.
0575:                                     */
0576:                                    byte[] checksum = new byte[12];
0577:                                    byte[] md5andsha1 = new byte[16 + 20];
0578:                                    rs.hash1.doFinal(md5andsha1, 0);
0579:                                    TlsUtils.PRF(this .ms, TlsUtils
0580:                                            .toByteArray("client finished"),
0581:                                            md5andsha1, checksum);
0582:
0583:                                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
0584:                                    TlsUtils.writeUint8(HP_FINISHED, bos);
0585:                                    TlsUtils.writeUint24(12, bos);
0586:                                    bos.write(checksum);
0587:                                    byte[] message = bos.toByteArray();
0588:
0589:                                    rs.writeMessage((short) RL_HANDSHAKE,
0590:                                            message, 0, message.length);
0591:
0592:                                    this .connection_state = CS_CLIENT_FINISHED_SEND;
0593:                                    read = true;
0594:                                    break;
0595:                                default:
0596:                                    this .failWithError(AL_fatal,
0597:                                            AP_handshake_failure);
0598:                                }
0599:                                break;
0600:                            case HP_SERVER_KEY_EXCHANGE:
0601:                                switch (connection_state) {
0602:                                case CS_SERVER_CERTIFICATE_RECEIVED:
0603:                                    /*
0604:                                     * Check that we are doing DHE key exchange
0605:                                     */
0606:                                    if (this .choosenCipherSuite
0607:                                            .getKeyExchangeAlgorithm() != TlsCipherSuite.KE_DHE_RSA) {
0608:                                        this .failWithError(AL_fatal,
0609:                                                AP_unexpected_message);
0610:                                    }
0611:
0612:                                    /*
0613:                                     * Parse the Structure
0614:                                     */
0615:                                    int pLength = TlsUtils.readUint16(is);
0616:                                    byte[] pByte = new byte[pLength];
0617:                                    TlsUtils.readFully(pByte, is);
0618:
0619:                                    int gLength = TlsUtils.readUint16(is);
0620:                                    byte[] gByte = new byte[gLength];
0621:                                    TlsUtils.readFully(gByte, is);
0622:
0623:                                    int YsLength = TlsUtils.readUint16(is);
0624:                                    byte[] YsByte = new byte[YsLength];
0625:                                    TlsUtils.readFully(YsByte, is);
0626:
0627:                                    int sigLength = TlsUtils.readUint16(is);
0628:                                    byte[] sigByte = new byte[sigLength];
0629:                                    TlsUtils.readFully(sigByte, is);
0630:
0631:                                    this .assertEmpty(is);
0632:
0633:                                    /*
0634:                                     * Verify the Signature.
0635:                                     *
0636:                                     * First, calculate the hash.
0637:                                     */
0638:                                    CombinedHash sigDigest = new CombinedHash();
0639:                                    ByteArrayOutputStream signedData = new ByteArrayOutputStream();
0640:                                    TlsUtils.writeUint16(pLength, signedData);
0641:                                    signedData.write(pByte);
0642:                                    TlsUtils.writeUint16(gLength, signedData);
0643:                                    signedData.write(gByte);
0644:                                    TlsUtils.writeUint16(YsLength, signedData);
0645:                                    signedData.write(YsByte);
0646:                                    byte[] signed = signedData.toByteArray();
0647:
0648:                                    sigDigest.update(this .clientRandom, 0,
0649:                                            this .clientRandom.length);
0650:                                    sigDigest.update(this .serverRandom, 0,
0651:                                            this .serverRandom.length);
0652:                                    sigDigest.update(signed, 0, signed.length);
0653:                                    byte[] hash = new byte[sigDigest
0654:                                            .getDigestSize()];
0655:                                    sigDigest.doFinal(hash, 0);
0656:
0657:                                    /*
0658:                                     * Now, do the RSA operation
0659:                                     */
0660:                                    RSABlindedEngine rsa = new RSABlindedEngine();
0661:                                    PKCS1Encoding encoding = new PKCS1Encoding(
0662:                                            rsa);
0663:                                    encoding.init(false, this .serverRsaKey);
0664:
0665:                                    /*
0666:                                     * The data which was signed
0667:                                     */
0668:                                    byte[] sigHash = null;
0669:
0670:                                    try {
0671:                                        sigHash = encoding.processBlock(
0672:                                                sigByte, 0, sigByte.length);
0673:                                    } catch (InvalidCipherTextException e) {
0674:                                        this .failWithError(AL_fatal,
0675:                                                AP_bad_certificate);
0676:                                    }
0677:
0678:                                    /*
0679:                                     * Check if the data which was signed is equal to
0680:                                     * the hash we calculated.
0681:                                     */
0682:                                    if (sigHash.length != hash.length) {
0683:                                        this .failWithError(AL_fatal,
0684:                                                AP_bad_certificate);
0685:                                    }
0686:
0687:                                    for (int i = 0; i < sigHash.length; i++) {
0688:                                        if (sigHash[i] != hash[i]) {
0689:                                            this .failWithError(AL_fatal,
0690:                                                    AP_bad_certificate);
0691:                                        }
0692:                                    }
0693:
0694:                                    /*
0695:                                     * OK, Signature was correct.
0696:                                     *
0697:                                     * Do the DH calculation.
0698:                                     */
0699:                                    BigInteger p = new BigInteger(1, pByte);
0700:                                    BigInteger g = new BigInteger(1, gByte);
0701:                                    BigInteger Ys = new BigInteger(1, YsByte);
0702:                                    BigInteger x = new BigInteger(
0703:                                            p.bitLength() - 1, this .random);
0704:                                    Yc = g.modPow(x, p);
0705:                                    this .pms = (Ys.modPow(x, p)).toByteArray();
0706:
0707:                                    /*
0708:                                     * Remove leading zero byte, if present.
0709:                                     */
0710:                                    if (this .pms[0] == 0) {
0711:                                        byte[] tmp = new byte[this .pms.length - 1];
0712:                                        System.arraycopy(this .pms, 1, tmp, 0,
0713:                                                tmp.length);
0714:                                        this .pms = tmp;
0715:                                    }
0716:
0717:                                    this .connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
0718:                                    read = true;
0719:                                    break;
0720:                                default:
0721:                                    this .failWithError(AL_fatal,
0722:                                            AP_unexpected_message);
0723:                                }
0724:                                break;
0725:                            case HP_HELLO_REQUEST:
0726:                            case HP_CLIENT_KEY_EXCHANGE:
0727:                            case HP_CERTIFICATE_REQUEST:
0728:                            case HP_CERTIFICATE_VERIFY:
0729:                            case HP_CLIENT_HELLO:
0730:                            default:
0731:                                // We do not support this!
0732:                                this .failWithError(AL_fatal,
0733:                                        AP_unexpected_message);
0734:                                break;
0735:
0736:                            }
0737:
0738:                        }
0739:                    }
0740:                } while (read);
0741:
0742:            }
0743:
0744:            private void processApplicationData() {
0745:                /*
0746:                 * There is nothing we need to do here.
0747:                 * 
0748:                 * This function could be used for callbacks when application
0749:                 * data arrives in the future.
0750:                 */
0751:            }
0752:
0753:            private void processAlert() throws IOException {
0754:                while (alertQueue.size() >= 2) {
0755:                    /*
0756:                     * An alert is always 2 bytes. Read the alert.
0757:                     */
0758:                    byte[] tmp = new byte[2];
0759:                    alertQueue.read(tmp, 0, 2, 0);
0760:                    alertQueue.removeData(2);
0761:                    short level = tmp[0];
0762:                    short description = tmp[1];
0763:                    if (level == AL_fatal) {
0764:                        /*
0765:                         * This is a fatal error.
0766:                         */
0767:                        this .failedWithError = true;
0768:                        this .closed = true;
0769:                        /*
0770:                         * Now try to close the stream, ignore errors.
0771:                         */
0772:                        try {
0773:                            rs.close();
0774:                        } catch (Exception e) {
0775:
0776:                        }
0777:                        throw new IOException(TLS_ERROR_MESSAGE);
0778:                    } else {
0779:                        /*
0780:                         * This is just a warning.
0781:                         */
0782:                        if (description == AP_close_notify) {
0783:                            /*
0784:                             * Close notify
0785:                             */
0786:                            this .failWithError(AL_warning, AP_close_notify);
0787:                        }
0788:                        /*
0789:                         * If it is just a warning, we continue.
0790:                         */
0791:                    }
0792:                }
0793:
0794:            }
0795:
0796:            /**
0797:             * This method is called, when a change cipher spec message is received.
0798:             *
0799:             * @throws IOException If the message has an invalid content or the
0800:             *                     handshake is not in the correct state.
0801:             */
0802:            private void processChangeCipherSpec() throws IOException {
0803:                while (changeCipherSpecQueue.size() > 0) {
0804:                    /*
0805:                     * A change cipher spec message is only one byte with the value 1.
0806:                     */
0807:                    byte[] b = new byte[1];
0808:                    changeCipherSpecQueue.read(b, 0, 1, 0);
0809:                    changeCipherSpecQueue.removeData(1);
0810:                    if (b[0] != 1) {
0811:                        /*
0812:                         * This should never happen.
0813:                         */
0814:                        this .failWithError(AL_fatal, AP_unexpected_message);
0815:
0816:                    } else {
0817:                        /*
0818:                         * Check if we are in the correct connection state.
0819:                         */
0820:                        if (this .connection_state == CS_CLIENT_FINISHED_SEND) {
0821:                            rs.readSuite = rs.writeSuite;
0822:                            this .connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED;
0823:                        } else {
0824:                            /*
0825:                             * We are not in the correct connection state.
0826:                             */
0827:                            this .failWithError(AL_fatal, AP_handshake_failure);
0828:                        }
0829:
0830:                    }
0831:                }
0832:
0833:            }
0834:
0835:            /**
0836:             * Connects to the remote system.
0837:             *
0838:             * @param verifyer Will be used when a certificate is received to verify
0839:             *                 that this certificate is accepted by the client.
0840:             * @throws IOException If handshake was not successfull.
0841:             */
0842:            public void connect(CertificateVerifyer verifyer)
0843:                    throws IOException {
0844:                this .verifyer = verifyer;
0845:
0846:                /*
0847:                 * Send Client hello
0848:                 *
0849:                 * First, generate some random data.
0850:                 */
0851:                this .clientRandom = new byte[32];
0852:                int t = (int) (System.currentTimeMillis() / 1000);
0853:                this .clientRandom[0] = (byte) (t >> 24);
0854:                this .clientRandom[1] = (byte) (t >> 16);
0855:                this .clientRandom[2] = (byte) (t >> 8);
0856:                this .clientRandom[3] = (byte) t;
0857:
0858:                for (int i = 4; i < clientRandom.length; i++) {
0859:                    this .clientRandom[i] = (byte) random.nextInt();
0860:                }
0861:
0862:                ByteArrayOutputStream os = new ByteArrayOutputStream();
0863:                TlsUtils.writeVersion(os);
0864:                os.write(this .clientRandom);
0865:
0866:                /*
0867:                 * Length of Session id
0868:                 */
0869:                TlsUtils.writeUint8((short) 0, os);
0870:
0871:                /*
0872:                 * Cipher suites
0873:                 */
0874:                TlsCipherSuiteManager.writeCipherSuites(os);
0875:
0876:                /*
0877:                 * Compression methods, just the null method.
0878:                 */
0879:                byte[] compressionMethods = new byte[] { 0x00 };
0880:                TlsUtils.writeUint8((short) compressionMethods.length, os);
0881:                os.write(compressionMethods);
0882:
0883:                ByteArrayOutputStream bos = new ByteArrayOutputStream();
0884:                TlsUtils.writeUint8(HP_CLIENT_HELLO, bos);
0885:                TlsUtils.writeUint24(os.size(), bos);
0886:                bos.write(os.toByteArray());
0887:                byte[] message = bos.toByteArray();
0888:                rs.writeMessage(RL_HANDSHAKE, message, 0, message.length);
0889:                connection_state = CS_CLIENT_HELLO_SEND;
0890:
0891:                /*
0892:                 * We will now read data, until we have completed the handshake.
0893:                 */
0894:                while (connection_state != CS_DONE) {
0895:                    rs.readData();
0896:                }
0897:
0898:                this .tlsInputStream = new TlsInputStream(this );
0899:                this .tlsOutputStream = new TlsOuputStream(this );
0900:            }
0901:
0902:            /**
0903:             * Read data from the network. The method will return immed, if there is
0904:             * still some data left in the buffer, or block untill some application
0905:             * data has been read from the network.
0906:             *
0907:             * @param buf    The buffer where the data will be copied to.
0908:             * @param offset The position where the data will be placed in the buffer.
0909:             * @param len    The maximum number of bytes to read.
0910:             * @return The number of bytes read.
0911:             * @throws IOException If something goes wrong during reading data.
0912:             */
0913:            protected int readApplicationData(byte[] buf, int offset, int len)
0914:                    throws IOException {
0915:                while (applicationDataQueue.size() == 0) {
0916:                    /*
0917:                     * We need to read some data.
0918:                     */
0919:                    if (this .failedWithError) {
0920:                        /*
0921:                         * Something went terribly wrong, we should throw an IOException
0922:                         */
0923:                        throw new IOException(TLS_ERROR_MESSAGE);
0924:                    }
0925:                    if (this .closed) {
0926:                        /*
0927:                         * Connection has been closed, there is no more data to read.
0928:                         */
0929:                        return -1;
0930:                    }
0931:
0932:                    try {
0933:                        rs.readData();
0934:                    } catch (IOException e) {
0935:                        if (!this .closed) {
0936:                            this .failWithError(AL_fatal, AP_internal_error);
0937:                        }
0938:                        throw e;
0939:                    } catch (RuntimeException e) {
0940:                        if (!this .closed) {
0941:                            this .failWithError(AL_fatal, AP_internal_error);
0942:                        }
0943:                        throw e;
0944:                    }
0945:                }
0946:                len = Math.min(len, applicationDataQueue.size());
0947:                applicationDataQueue.read(buf, offset, len, 0);
0948:                applicationDataQueue.removeData(len);
0949:                return len;
0950:            }
0951:
0952:            /**
0953:             * Send some application data to the remote system.
0954:             * <p/>
0955:             * The method will handle fragmentation internally.
0956:             *
0957:             * @param buf    The buffer with the data.
0958:             * @param offset The position in the buffer where the data is placed.
0959:             * @param len    The length of the data.
0960:             * @throws IOException If something goes wrong during sending.
0961:             */
0962:            protected void writeData(byte[] buf, int offset, int len)
0963:                    throws IOException {
0964:                if (this .failedWithError) {
0965:                    throw new IOException(TLS_ERROR_MESSAGE);
0966:                }
0967:                if (this .closed) {
0968:                    throw new IOException(
0969:                            "Sorry, connection has been closed, you cannot write more data");
0970:                }
0971:
0972:                /*
0973:                 * Protect against known IV attack!
0974:                 *
0975:                 * DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT
0976:                 * YOU ARE DOING HERE.
0977:                 */
0978:                rs.writeMessage(RL_APPLICATION_DATA, emptybuf, 0, 0);
0979:
0980:                do {
0981:                    /*
0982:                     * We are only allowed to write fragments up to 2^14 bytes.
0983:                     */
0984:                    int toWrite = Math.min(len, 1 << 14);
0985:
0986:                    try {
0987:                        rs.writeMessage(RL_APPLICATION_DATA, buf, offset,
0988:                                toWrite);
0989:                    } catch (IOException e) {
0990:                        if (!closed) {
0991:                            this .failWithError(AL_fatal, AP_internal_error);
0992:                        }
0993:                        throw e;
0994:                    } catch (RuntimeException e) {
0995:                        if (!closed) {
0996:                            this .failWithError(AL_fatal, AP_internal_error);
0997:                        }
0998:                        throw e;
0999:                    }
1000:
1001:                    offset += toWrite;
1002:                    len -= toWrite;
1003:                } while (len > 0);
1004:
1005:            }
1006:
1007:            /** @deprecated use 'getOutputStream' instead */
1008:            public TlsOuputStream getTlsOuputStream() {
1009:                return this .tlsOutputStream;
1010:            }
1011:
1012:            /**
1013:             * @return An OutputStream which can be used to send data.
1014:             */
1015:            public OutputStream getOutputStream() {
1016:                return this .tlsOutputStream;
1017:            }
1018:
1019:            /** @deprecated use 'getInputStream' instead */
1020:            public TlsInputStream getTlsInputStream() {
1021:                return this .tlsInputStream;
1022:            }
1023:
1024:            /**
1025:             * @return An InputStream which can be used to read data.
1026:             */
1027:            public InputStream getInputStream() {
1028:                return this .tlsInputStream;
1029:            }
1030:
1031:            /**
1032:             * Terminate this connection whith an alert.
1033:             * <p/>
1034:             * Can be used for normal closure too.
1035:             *
1036:             * @param alertLevel       The level of the alert, an be AL_fatal or AL_warning.
1037:             * @param alertDescription The exact alert message.
1038:             * @throws IOException If alert was fatal.
1039:             */
1040:            protected void failWithError(short alertLevel,
1041:                    short alertDescription) throws IOException {
1042:                /*
1043:                 * Check if the connection is still open.
1044:                 */
1045:                if (!closed) {
1046:                    /*
1047:                     * Prepare the message
1048:                     */
1049:                    byte[] error = new byte[2];
1050:                    error[0] = (byte) alertLevel;
1051:                    error[1] = (byte) alertDescription;
1052:                    this .closed = true;
1053:
1054:                    if (alertLevel == AL_fatal) {
1055:                        /*
1056:                         * This is a fatal message.
1057:                         */
1058:                        this .failedWithError = true;
1059:                    }
1060:                    rs.writeMessage(RL_ALERT, error, 0, 2);
1061:                    rs.close();
1062:                    if (alertLevel == AL_fatal) {
1063:                        throw new IOException(TLS_ERROR_MESSAGE);
1064:                    }
1065:
1066:                } else {
1067:                    throw new IOException(TLS_ERROR_MESSAGE);
1068:                }
1069:
1070:            }
1071:
1072:            /**
1073:             * Closes this connection.
1074:             *
1075:             * @throws IOException If something goes wrong during closing.
1076:             */
1077:            public void close() throws IOException {
1078:                if (!closed) {
1079:                    this .failWithError((short) 1, (short) 0);
1080:                }
1081:            }
1082:
1083:            /**
1084:             * Make sure the InputStream is now empty. Fail otherwise.
1085:             *
1086:             * @param is The InputStream to check.
1087:             * @throws IOException If is is not empty.
1088:             */
1089:            protected void assertEmpty(ByteArrayInputStream is)
1090:                    throws IOException {
1091:                if (is.available() > 0) {
1092:                    this .failWithError(AL_fatal, AP_decode_error);
1093:                }
1094:            }
1095:
1096:            protected void flush() throws IOException {
1097:                rs.flush();
1098:            }
1099:
1100:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.