2 * TLSSecurityParameters
\r
4 * This class encapsulates all the security parameters that get negotiated
\r
5 * during the TLS handshake. It also holds all the key derivation methods.
\r
6 * Copyright (c) 2007 Henri Torgemane
\r
8 * Patched by Bobby Parker (sh0rtwave@gmail.com)
\r
10 * See LICENSE.txt for full license information.
\r
12 package com.hurlant.crypto.tls {
\r
13 import com.hurlant.crypto.hash.MD5;
\r
14 import com.hurlant.crypto.hash.SHA1;
\r
15 import com.hurlant.crypto.prng.TLSPRF;
\r
16 import com.hurlant.util.Hex;
\r
18 import flash.utils.ByteArray;
19 import com.hurlant.crypto.rsa.RSAKey;
\r
21 public class TLSSecurityParameters implements ISecurityParameters {
\r
24 public static const COMPRESSION_NULL:uint = 0;
\r
26 // This is probably not smart. Revise this to use all settings from TLSConfig, since this shouldn't really know about
\r
27 // user settings, those are best handled from the engine at a session level.
\r
28 public static var IGNORE_CN_MISMATCH:Boolean = true;
\r
29 public static var ENABLE_USER_CLIENT_CERTIFICATE:Boolean = false;
\r
30 public static var USER_CERTIFICATE:String;
\r
33 private var cert:ByteArray; // Local Cert
\r
34 private var key:RSAKey; // local key
\r
35 private var entity:uint; // SERVER | CLIENT
\r
36 private var bulkCipher:uint; // BULK_CIPHER_*
\r
37 private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER
\r
38 private var keySize:uint;
\r
39 private var keyMaterialLength:uint;
\r
40 private var IVSize:uint;
\r
41 private var macAlgorithm:uint; // MAC_*
\r
42 private var hashSize:uint;
\r
43 private var compression:uint; // COMPRESSION_NULL
\r
44 private var masterSecret:ByteArray; // 48 bytes
\r
45 private var clientRandom:ByteArray; // 32 bytes
\r
46 private var serverRandom:ByteArray; // 32 bytes
\r
47 private var ignoreCNMismatch:Boolean = true;
\r
48 private var trustAllCerts:Boolean = false;
\r
49 private var trustSelfSigned:Boolean = false;
\r
50 public static const PROTOCOL_VERSION:uint = 0x0301;
51 private var tlsDebug:Boolean = false;
\r
54 // not strictly speaking part of this, but yeah.
\r
55 public var keyExchange:uint;
\r
56 public function TLSSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:RSAKey = null) {
\r
57 this.entity = entity;
\r
63 public function get version() : uint {
\r
64 return PROTOCOL_VERSION;
\r
67 public function reset():void {
\r
68 bulkCipher = BulkCiphers.NULL;
\r
69 cipherType = BulkCiphers.BLOCK_CIPHER;
\r
70 macAlgorithm = MACs.NULL;
\r
71 compression = COMPRESSION_NULL;
\r
72 masterSecret = null;
\r
75 public function getBulkCipher():uint {
\r
78 public function getCipherType():uint {
\r
81 public function getMacAlgorithm():uint {
\r
82 return macAlgorithm;
\r
85 public function setCipher(cipher:uint):void {
\r
86 bulkCipher = CipherSuites.getBulkCipher(cipher);
\r
87 cipherType = BulkCiphers.getType(bulkCipher);
\r
88 keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); // 8
\r
89 keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5
\r
90 IVSize = BulkCiphers.getIVSize(bulkCipher);
\r
92 keyExchange = CipherSuites.getKeyExchange(cipher);
\r
94 macAlgorithm = CipherSuites.getMac(cipher);
\r
95 hashSize = MACs.getHashSize(macAlgorithm);
\r
97 public function setCompression(algo:uint):void {
\r
100 public function setPreMasterSecret(secret:ByteArray):void {
\r
101 // compute master_secret
\r
102 var seed:ByteArray = new ByteArray;
\r
103 seed.writeBytes(clientRandom, 0, clientRandom.length);
\r
104 seed.writeBytes(serverRandom, 0, serverRandom.length);
\r
105 var prf:TLSPRF = new TLSPRF(secret, "master secret", seed);
\r
106 masterSecret = new ByteArray;
\r
107 prf.nextBytes(masterSecret, 48);
\r
109 trace("Master Secret: " + Hex.fromArray( masterSecret, true ));
\r
111 public function setClientRandom(secret:ByteArray):void {
\r
112 clientRandom = secret;
\r
114 public function setServerRandom(secret:ByteArray):void {
\r
115 serverRandom = secret;
\r
118 public function get useRSA():Boolean {
\r
119 return KeyExchanges.useRSA(keyExchange);
\r
122 public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {
\r
123 var seed:ByteArray = new ByteArray;
\r
124 var md5:MD5 = new MD5;
\r
126 trace("Handshake value: " + Hex.fromArray(handshakeMessages, true ));
\r
127 seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());
\r
128 var sha:SHA1 = new SHA1;
\r
129 seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());
\r
131 trace("Seed in: " + Hex.fromArray(seed, true ));
\r
132 var prf:TLSPRF = new TLSPRF(masterSecret, (side==TLSEngine.CLIENT) ? "client finished" : "server finished", seed);
\r
133 var out:ByteArray = new ByteArray;
\r
134 prf.nextBytes(out, 12);
\r
136 trace("Finished out: " + Hex.fromArray(out, true ));
\r
141 // client side certficate check - This is probably incorrect somehow
\r
142 public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {
\r
143 var seed:ByteArray = new ByteArray;
\r
144 var md5:MD5 = new MD5;
\r
145 seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());
\r
146 var sha:SHA1 = new SHA1;
\r
147 seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());
\r
149 // Now that I have my hashes of existing handshake messages (which I'm not sure about the length of yet) then
\r
150 // Sign that with my private key
\r
152 var out:ByteArray = new ByteArray();
\r
153 key.sign( seed, out, seed.bytesAvailable);
\r
158 public function getConnectionStates():Object {
\r
159 if (masterSecret != null) {
\r
160 var seed:ByteArray = new ByteArray;
\r
161 seed.writeBytes(serverRandom, 0, serverRandom.length);
\r
162 seed.writeBytes(clientRandom, 0, clientRandom.length);
\r
163 var prf:TLSPRF = new TLSPRF(masterSecret, "key expansion", seed);
\r
165 var client_write_MAC:ByteArray = new ByteArray;
\r
166 prf.nextBytes(client_write_MAC, hashSize);
\r
167 var server_write_MAC:ByteArray = new ByteArray;
\r
168 prf.nextBytes(server_write_MAC, hashSize);
\r
169 var client_write_key:ByteArray = new ByteArray;
\r
170 prf.nextBytes(client_write_key, keyMaterialLength);
\r
171 var server_write_key:ByteArray = new ByteArray;
\r
172 prf.nextBytes(server_write_key, keyMaterialLength);
\r
173 var client_write_IV:ByteArray = new ByteArray;
\r
174 prf.nextBytes(client_write_IV, IVSize);
\r
175 var server_write_IV:ByteArray = new ByteArray;
\r
176 prf.nextBytes(server_write_IV, IVSize);
\r
178 var client_write:TLSConnectionState = new TLSConnectionState(
\r
179 bulkCipher, cipherType, macAlgorithm,
\r
180 client_write_MAC, client_write_key, client_write_IV);
\r
181 var server_write:TLSConnectionState = new TLSConnectionState(
\r
182 bulkCipher, cipherType, macAlgorithm,
\r
183 server_write_MAC, server_write_key, server_write_IV);
\r
185 if (entity == TLSEngine.CLIENT) {
\r
186 return {read:server_write, write:client_write};
\r
188 return {read:client_write, write:server_write};
\r
192 return {read:new TLSConnectionState, write:new TLSConnectionState};
\r