rocket-js 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/.gitignore +0 -11
  2. data/Rakefile +33 -47
  3. data/lib/rocket/js.rb +0 -2
  4. data/lib/rocket/js/builder.rb +2 -2
  5. data/lib/rocket/js/cli.rb +1 -1
  6. data/rocket-js.gemspec +23 -80
  7. data/src/vendor/web-socket-js/FABridge.js +604 -0
  8. data/src/vendor/web-socket-js/README.txt +109 -0
  9. data/src/vendor/web-socket-js/WebSocketMain.swf +0 -0
  10. data/src/vendor/web-socket-js/WebSocketMainInsecure.zip +0 -0
  11. data/src/vendor/web-socket-js/flash-src/WebSocket.as +473 -0
  12. data/src/vendor/web-socket-js/flash-src/WebSocketMain.as +88 -0
  13. data/src/vendor/web-socket-js/flash-src/WebSocketMainInsecure.as +19 -0
  14. data/src/vendor/web-socket-js/flash-src/WebSocketStateEvent.as +32 -0
  15. data/src/vendor/web-socket-js/flash-src/bridge/FABridge.as +943 -0
  16. data/src/vendor/web-socket-js/flash-src/build.sh +10 -0
  17. data/src/vendor/web-socket-js/flash-src/com/adobe/net/proxies/RFC2817Socket.as +204 -0
  18. data/src/vendor/web-socket-js/flash-src/com/gsolo/encryption/MD5.as +375 -0
  19. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/Crypto.as +287 -0
  20. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/MozillaRootCertificates.as +3235 -0
  21. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509Certificate.as +218 -0
  22. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/cert/X509CertificateCollection.as +57 -0
  23. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/HMAC.as +82 -0
  24. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHMAC.as +27 -0
  25. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/IHash.as +21 -0
  26. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MAC.as +137 -0
  27. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD2.as +124 -0
  28. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/MD5.as +204 -0
  29. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA1.as +106 -0
  30. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA224.as +28 -0
  31. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHA256.as +115 -0
  32. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/hash/SHABase.as +71 -0
  33. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/ARC4.as +90 -0
  34. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/IPRNG.as +20 -0
  35. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/Random.as +119 -0
  36. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/prng/TLSPRF.as +142 -0
  37. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/rsa/RSAKey.as +339 -0
  38. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/AESKey.as +2797 -0
  39. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/BlowFishKey.as +375 -0
  40. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CBCMode.as +55 -0
  41. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFB8Mode.as +61 -0
  42. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CFBMode.as +64 -0
  43. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/CTRMode.as +58 -0
  44. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/DESKey.as +365 -0
  45. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ECBMode.as +86 -0
  46. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ICipher.as +21 -0
  47. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IMode.as +15 -0
  48. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IPad.as +32 -0
  49. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IStreamCipher.as +21 -0
  50. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/ISymmetricKey.as +35 -0
  51. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/IVMode.as +110 -0
  52. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/NullPad.as +34 -0
  53. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/OFBMode.as +52 -0
  54. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/PKCS5.as +44 -0
  55. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SSLPad.as +44 -0
  56. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/SimpleIVMode.as +60 -0
  57. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TLSPad.as +42 -0
  58. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/TripleDESKey.as +88 -0
  59. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/XTeaKey.as +94 -0
  60. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/aeskey.pl +29 -0
  61. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/symmetric/dump.txt +2304 -0
  62. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/AESKeyTest.as +1220 -0
  63. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ARC4Test.as +58 -0
  64. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BigIntegerTest.as +39 -0
  65. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/BlowFishKeyTest.as +148 -0
  66. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CBCModeTest.as +160 -0
  67. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFB8ModeTest.as +71 -0
  68. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CFBModeTest.as +98 -0
  69. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/CTRModeTest.as +109 -0
  70. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/DESKeyTest.as +112 -0
  71. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ECBModeTest.as +151 -0
  72. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/HMACTest.as +184 -0
  73. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/ITestHarness.as +20 -0
  74. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD2Test.as +56 -0
  75. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/MD5Test.as +58 -0
  76. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/OFBModeTest.as +101 -0
  77. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/RSAKeyTest.as +92 -0
  78. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA1Test.as +198 -0
  79. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA224Test.as +58 -0
  80. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/SHA256Test.as +60 -0
  81. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TLSPRFTest.as +51 -0
  82. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TestCase.as +42 -0
  83. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/TripleDESKeyTest.as +59 -0
  84. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tests/XTeaKeyTest.as +66 -0
  85. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/BulkCiphers.as +102 -0
  86. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/CipherSuites.as +117 -0
  87. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/IConnectionState.as +14 -0
  88. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/ISecurityParameters.as +29 -0
  89. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/KeyExchanges.as +24 -0
  90. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/MACs.as +38 -0
  91. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLConnectionState.as +171 -0
  92. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLEvent.as +26 -0
  93. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/SSLSecurityParameters.as +340 -0
  94. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConfig.as +70 -0
  95. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSConnectionState.as +151 -0
  96. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEngine.as +895 -0
  97. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSError.as +39 -0
  98. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSEvent.as +27 -0
  99. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSecurityParameters.as +197 -0
  100. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocket.as +370 -0
  101. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSSocketEvent.as +26 -0
  102. data/src/vendor/web-socket-js/flash-src/com/hurlant/crypto/tls/TLSTest.as +180 -0
  103. data/src/vendor/web-socket-js/flash-src/com/hurlant/math/BarrettReduction.as +90 -0
  104. data/src/vendor/web-socket-js/flash-src/com/hurlant/math/BigInteger.as +1543 -0
  105. data/src/vendor/web-socket-js/flash-src/com/hurlant/math/ClassicReduction.as +35 -0
  106. data/src/vendor/web-socket-js/flash-src/com/hurlant/math/IReduction.as +11 -0
  107. data/src/vendor/web-socket-js/flash-src/com/hurlant/math/MontgomeryReduction.as +85 -0
  108. data/src/vendor/web-socket-js/flash-src/com/hurlant/math/NullReduction.as +34 -0
  109. data/src/vendor/web-socket-js/flash-src/com/hurlant/math/bi_internal.as +11 -0
  110. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/ArrayUtil.as +25 -0
  111. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/Base64.as +189 -0
  112. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/Hex.as +66 -0
  113. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/Memory.as +28 -0
  114. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/ByteString.as +43 -0
  115. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/DER.as +210 -0
  116. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/IAsn1Type.as +21 -0
  117. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/Integer.as +44 -0
  118. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/OID.as +35 -0
  119. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/ObjectIdentifier.as +112 -0
  120. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/PEM.as +118 -0
  121. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/PrintableString.as +49 -0
  122. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/Sequence.as +90 -0
  123. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/Set.as +27 -0
  124. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/Type.as +94 -0
  125. data/src/vendor/web-socket-js/flash-src/com/hurlant/util/der/UTCTime.as +60 -0
  126. data/src/vendor/web-socket-js/sample.html +76 -0
  127. data/src/vendor/web-socket-js/swfobject.js +4 -0
  128. data/src/vendor/web-socket-js/web_socket.js +388 -0
  129. metadata +163 -30
  130. data/lib/rocket/js/version.rb +0 -14
  131. data/rocket-0.0.1.min.js +0 -45
@@ -0,0 +1,895 @@
1
+ /**
2
+ * TLSEngine
3
+ *
4
+ * A TLS protocol implementation.
5
+ * See comment below for some details.
6
+ * Copyright (c) 2007 Henri Torgemane
7
+ *
8
+ * Patched(heavily) by Bobby Parker (shortwave@gmail.com)
9
+ *
10
+ * See LICENSE.txt for full license information.
11
+ */
12
+ package com.hurlant.crypto.tls {
13
+ import com.hurlant.crypto.cert.X509Certificate;
14
+ import com.hurlant.crypto.cert.X509CertificateCollection;
15
+ import com.hurlant.crypto.prng.Random;
16
+ import com.hurlant.util.ArrayUtil;
17
+ import com.hurlant.util.Hex;
18
+
19
+ import flash.events.Event;
20
+ import flash.events.EventDispatcher;
21
+ import flash.events.ProgressEvent;
22
+ import flash.utils.ByteArray;
23
+ import flash.utils.IDataInput;
24
+ import flash.utils.IDataOutput;
25
+ import flash.utils.clearTimeout;
26
+ import flash.utils.setTimeout;
27
+ import com.hurlant.crypto.prng.ARC4;
28
+
29
+
30
+ [Event(name="close", type="flash.events.Event")]
31
+ [Event(name="socketData", type="flash.events.ProgressEvent")]
32
+ [Event(name="ready", type="com.hurlant.crypto.tls.TLSEvent")]
33
+ [Event(name="data", type="com.hurlant.crypto.tls.TLSEvent")]
34
+
35
+ /**
36
+ * The heart of the TLS protocol.
37
+ * This class can work in server or client mode.
38
+ *
39
+ * This doesn't fully implement the TLS protocol.
40
+ *
41
+ * Things missing that I'd like to add:
42
+ * - support for client-side certificates
43
+ * - general code clean-up to make sure we don't have gaping securite holes
44
+ *
45
+ * Things that aren't there that I won't add:
46
+ * - support for "export" cypher suites (deprecated in later TLS versions)
47
+ * - support for "anon" cypher suites (deprecated in later TLS versions)
48
+ *
49
+ * Things that I'm unsure about adding later:
50
+ * - compression. Compressing encrypted streams is barely worth the CPU cycles.
51
+ * - diffie-hellman based key exchange mechanisms. Nifty, but would we miss it?
52
+ *
53
+ * @author henri
54
+ *
55
+ */
56
+ public class TLSEngine extends EventDispatcher {
57
+
58
+ public static const SERVER:uint = 0;
59
+ public static const CLIENT:uint = 1;
60
+ public var protocol_version:uint;
61
+
62
+
63
+
64
+ private static const PROTOCOL_HANDSHAKE:uint = 22;
65
+ private static const PROTOCOL_ALERT:uint = 21;
66
+ private static const PROTOCOL_CHANGE_CIPHER_SPEC:uint = 20;
67
+ private static const PROTOCOL_APPLICATION_DATA:uint = 23;
68
+
69
+
70
+ private static const STATE_NEW:uint = 0; // brand new. nothing happened yet
71
+ private static const STATE_NEGOTIATING:uint = 1; // we're figuring out what to use
72
+ private static const STATE_READY:uint = 2; // we're ready for AppData stuff to go over us.
73
+ private static const STATE_CLOSED:uint = 3; // we're done done.
74
+
75
+ private var _entity:uint; // SERVER | CLIENT
76
+ private var _config:TLSConfig;
77
+
78
+ private var _state:uint;
79
+
80
+ private var _securityParameters:ISecurityParameters;
81
+
82
+ private var _currentReadState:IConnectionState;
83
+ private var _currentWriteState:IConnectionState;
84
+ private var _pendingReadState:IConnectionState;
85
+ private var _pendingWriteState:IConnectionState;
86
+
87
+ private var _handshakePayloads:ByteArray;
88
+ private var _handshakeRecords:ByteArray; // For client-side certificate verify
89
+
90
+ private var _iStream:IDataInput;
91
+ private var _oStream:IDataOutput;
92
+
93
+ // temporary store for X509 certs received by this engine.
94
+ private var _store:X509CertificateCollection;
95
+ // the main certificate received from the other side.
96
+ private var _otherCertificate:X509Certificate;
97
+
98
+ public function get peerCertificate() : X509Certificate {
99
+ return _otherCertificate;
100
+ }
101
+ // If this isn't null, we expect this identity to be found in the Cert's Subject CN.
102
+ private var _otherIdentity:String;
103
+
104
+ // The client-side cert
105
+ private var _myCertficate:X509Certificate;
106
+ // My Identity
107
+ private var _myIdentity:String;
108
+
109
+ /**
110
+ *
111
+ * @param config A TLSConfig instance describing how we're supposed to work
112
+ * @param iStream An input stream to read TLS data from
113
+ * @param oStream An output stream to write TLS data to
114
+ * @param otherIdentity An optional identifier. If set, this will be checked against the Subject CN of the other side's certificate.
115
+ *
116
+ */
117
+ function TLSEngine(config:TLSConfig, iStream:IDataInput, oStream:IDataOutput, otherIdentity:String = null) {
118
+ _entity = config.entity;
119
+ _config = config;
120
+ _iStream = iStream;
121
+ _oStream = oStream;
122
+ _otherIdentity = otherIdentity;
123
+
124
+ _state = STATE_NEW;
125
+
126
+ // Pick the right set of callbacks
127
+ _entityHandshakeHandlers = _entity == CLIENT ? handshakeHandlersClient : handshakeHandlersServer;
128
+
129
+ // setting up new security parameters needs to be controlled by...something.
130
+ if (_config.version == SSLSecurityParameters.PROTOCOL_VERSION) {
131
+ _securityParameters = new SSLSecurityParameters(_entity);
132
+ } else {
133
+ _securityParameters = new TLSSecurityParameters(_entity, _config.certificate, _config.privateKey);
134
+ }
135
+ protocol_version = _config.version;
136
+
137
+ // So this...why is it here, other than to preclude a possible null pointer situation?
138
+ var states:Object = _securityParameters.getConnectionStates();
139
+
140
+ _currentReadState = states.read;
141
+ _currentWriteState = states.write;
142
+
143
+ _handshakePayloads = new ByteArray;
144
+
145
+ _store = new X509CertificateCollection;
146
+ }
147
+
148
+ /**
149
+ * This starts the TLS negotiation for a TLS Client.
150
+ *
151
+ * This is a no-op for a TLS Server.
152
+ *
153
+ */
154
+ public function start():void {
155
+ if (_entity == CLIENT) {
156
+ try {
157
+ startHandshake();
158
+ } catch (e:TLSError) {
159
+ handleTLSError(e);
160
+ }
161
+ }
162
+ }
163
+
164
+
165
+ public function dataAvailable(e:* = null):void {
166
+ if (_state == STATE_CLOSED) return; // ignore
167
+ try {
168
+ parseRecord(_iStream);
169
+ } catch (e:TLSError) {
170
+ handleTLSError(e);
171
+ }
172
+ }
173
+
174
+ public function close(e:TLSError = null):void {
175
+ if (_state == STATE_CLOSED) return; // ignore
176
+ // ok. send an Alert to let the peer know
177
+ var rec:ByteArray = new ByteArray;
178
+ if (e==null && _state != STATE_READY) {
179
+ // use canceled while handshaking. be nice about it
180
+ rec[0] = 1;
181
+ rec[1] = TLSError.user_canceled;
182
+ sendRecord(PROTOCOL_ALERT, rec);
183
+ }
184
+ rec[0] = 2;
185
+ if (e == null) {
186
+ rec[1] = TLSError.close_notify;
187
+ } else {
188
+ rec[1] = e.errorID;
189
+ trace("TLSEngine shutdown triggered by "+e);
190
+ }
191
+ sendRecord(PROTOCOL_ALERT, rec);
192
+
193
+ _state = STATE_CLOSED;
194
+ dispatchEvent(new Event(Event.CLOSE));
195
+ }
196
+
197
+ private var _packetQueue:Array = [];
198
+ private function parseRecord(stream:IDataInput):void {
199
+ var p:ByteArray;
200
+ while(_state!=STATE_CLOSED && stream.bytesAvailable>4) {
201
+
202
+ if (_packetQueue.length>0) {
203
+ var packet:Object = _packetQueue.shift();
204
+ p = packet.data;
205
+ if (stream.bytesAvailable+p.length>=packet.length) {
206
+ // we have a whole packet. put together.
207
+ stream.readBytes(p, p.length, packet.length-p.length);
208
+ parseOneRecord(packet.type, packet.length, p);
209
+ // do another loop to parse any leftover record
210
+ continue;
211
+ } else {
212
+ // not enough. grab the data and park it.
213
+ stream.readBytes(p, p.length, stream.bytesAvailable);
214
+ _packetQueue.push(packet);
215
+ continue;
216
+ }
217
+ }
218
+
219
+
220
+ var type:uint = stream.readByte();
221
+ var ver:uint = stream.readShort();
222
+ var length:uint = stream.readShort();
223
+ if (length>16384+2048) { // support compression and encryption overhead.
224
+ throw new TLSError("Excessive TLS Record length: "+length, TLSError.record_overflow);
225
+ }
226
+ // Can pretty much assume that if I'm here, I've got a default config, so let's use it.
227
+ if (ver != _securityParameters.version ) {
228
+ throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
229
+ }
230
+
231
+ p = new ByteArray;
232
+ var actualLength:uint = Math.min(stream.bytesAvailable, length);
233
+ stream.readBytes(p, 0, actualLength);
234
+ if (actualLength == length) {
235
+ parseOneRecord(type, length, p);
236
+ } else {
237
+ _packetQueue.push({type:type, length:length, data:p});
238
+ }
239
+ }
240
+ }
241
+
242
+
243
+ // Protocol handler map, provides a mapping of protocol types to individual packet handlers
244
+ private var protocolHandlers:Object = { 23 : parseApplicationData, // PROTOCOL_APPLICATION_DATA
245
+ 22 : parseHandshake, // PROTOCOL_HANDSHAKE
246
+ 21 : parseAlert, // PROTOCOL_ALERT
247
+ 20 : parseChangeCipherSpec }; // PROTOCOL_CHANGE_CIPHER_SPEC
248
+
249
+ /**
250
+ * Modified to support the notion of a handler map(see above ), since it makes for better clarity (IMHO of course).
251
+ */
252
+ private function parseOneRecord(type:uint, length:uint, p:ByteArray):void {
253
+ p = _currentReadState.decrypt(type, length, p);
254
+ if (p.length>16384) {
255
+ throw new TLSError("Excessive Decrypted TLS Record length: "+p.length, TLSError.record_overflow);
256
+ }
257
+ if (protocolHandlers.hasOwnProperty( type )) {
258
+ while( p != null)
259
+ p = protocolHandlers[ type ]( p );
260
+ } else {
261
+ throw new TLSError("Unsupported TLS Record Content Type: "+type.toString( 16 ), TLSError.unexpected_message);
262
+ }
263
+ }
264
+
265
+ ///////// handshake handling
266
+ // session identifier
267
+ // peer certificate
268
+ // compression method
269
+ // cipher spec
270
+ // master secret
271
+ // is resumable
272
+ private static const HANDSHAKE_HELLO_REQUEST:uint = 0;
273
+ private static const HANDSHAKE_CLIENT_HELLO:uint = 1;
274
+ private static const HANDSHAKE_SERVER_HELLO:uint = 2;
275
+ private static const HANDSHAKE_CERTIFICATE:uint = 11;
276
+ private static const HANDSHAKE_SERVER_KEY_EXCHANGE:uint = 12;
277
+ private static const HANDSHAKE_CERTIFICATE_REQUEST:uint = 13;
278
+ private static const HANDSHAKE_HELLO_DONE:uint = 14;
279
+ private static const HANDSHAKE_CERTIFICATE_VERIFY:uint = 15;
280
+ private static const HANDSHAKE_CLIENT_KEY_EXCHANGE:uint = 16;
281
+ private static const HANDSHAKE_FINISHED:uint = 20;
282
+
283
+ // Server handshake handler map
284
+ private var handshakeHandlersServer:Object = { 0 : notifyStateError, // HANDSHAKE_HELLO_REQUEST
285
+ 1 : parseHandshakeClientHello, // HANDSHAKE_CLIENT_HELLO
286
+ 2 : notifyStateError, // HANDSHAKE_SERVER_HELLO
287
+ 11 : loadCertificates, // HANDSHAKE_CERTIFICATE
288
+ 12 : notifyStateError, // HANDSHAKE_SERVER_KEY_EXCHANGE
289
+ 13 : notifyStateError, // HANDSHAKE_CERTIFICATE_REQUEST
290
+ 14 : notifyStateError, // HANDSHAKE_HELLO_DONE
291
+ 15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
292
+ 16 : parseHandshakeClientKeyExchange, // HANDSHAKE_CLIENT_KEY_EXCHANGE
293
+ 20 : verifyHandshake // HANDSHAKE_FINISHED
294
+ };
295
+
296
+ // Client handshake handler map
297
+ private var handshakeHandlersClient:Object = { 0 : parseHandshakeHello, // HANDSHAKE_HELLO_REQUEST
298
+ 1 : notifyStateError, // HANDSHAKE_CLIENT_HELLO
299
+ 2 : parseHandshakeServerHello, // HANDSHAKE_SERVER_HELLO
300
+ 11 : loadCertificates, // HANDSHAKE_CERTIFICATE
301
+ 12 : parseServerKeyExchange, // HANDSHAKE_SERVER_KEY_EXCHANGE
302
+ 13 : setStateRespondWithCertificate, // HANDSHAKE_CERTIFICATE
303
+ 14 : sendClientAck, // HANDSHAKE_HELLO_DONE
304
+ 15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
305
+ 16 : notifyStateError, // HANDSHAKE_CLIENT_KEY_EXCHANGE
306
+ 20 : verifyHandshake // HANDSHAKE_FINISHED
307
+ };
308
+ private var _entityHandshakeHandlers:Object;
309
+ private var _handshakeCanContinue:Boolean = true; // For handling cases where I might need to pause processing during a handshake (cert issues, etc.).
310
+ private var _handshakeQueue:Array = [];
311
+ /**
312
+ * The handshake is always started by the client.
313
+ */
314
+ private function startHandshake():void {
315
+ _state = STATE_NEGOTIATING;
316
+ // reset some other handshake state. XXX
317
+ sendClientHello();
318
+ }
319
+
320
+ /**
321
+ * Handle the incoming handshake packet.
322
+ *
323
+ */
324
+ private function parseHandshake(p:ByteArray):ByteArray {
325
+
326
+ if (p.length<4) {
327
+ trace("Handshake packet is way too short. bailing.");
328
+ return null;
329
+ }
330
+
331
+ p.position = 0;
332
+
333
+ var rec:ByteArray = p;
334
+ var type:uint = rec.readUnsignedByte();
335
+ var tmp:uint = rec.readUnsignedByte();
336
+ var length:uint = (tmp<<16) | rec.readUnsignedShort();
337
+ if (length+4>p.length) {
338
+ // partial read.
339
+ trace("Handshake packet is incomplete. bailing.");
340
+ return null;
341
+ }
342
+
343
+ // we need to copy the record, to have a valid FINISHED exchange.
344
+ if (type!=HANDSHAKE_FINISHED) {
345
+ _handshakePayloads.writeBytes(p, 0, length+4);
346
+ }
347
+
348
+ // Surf the handler map and find the right handler for this handshake packet type.
349
+ // I modified the individual handlers so they encapsulate all possible knowledge
350
+ // about the incoming packet type, so no previous handling or massaging of the data
351
+ // is required, as was the case using the switch statement. BP
352
+ if (_entityHandshakeHandlers.hasOwnProperty( type )) {
353
+ if (_entityHandshakeHandlers[ type ] is Function)
354
+ _entityHandshakeHandlers[ type ]( rec );
355
+ } else {
356
+ throw new TLSError( "Unimplemented or unknown handshake type!", TLSError.internal_error );
357
+ }
358
+
359
+ // Get set up for the next packet.
360
+ if (length+4<p.length) {
361
+ var n:ByteArray = new ByteArray;
362
+ n.writeBytes(p,length+4, p.length-(length+4));
363
+ return n;
364
+ } else {
365
+ return null;
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Throw an error when the detected handshake state isn't a valid state for the given entity type (client vs. server, etc. ).
371
+ * This really should abort the handshake, since there's no case in which a server should EVER be confused about the type of entity it is. BP
372
+ */
373
+ private function notifyStateError( rec:ByteArray ) : void {
374
+ throw new TLSError( "Invalid handshake state for a TLS Entity type of " + _entity, TLSError.internal_error );
375
+ }
376
+
377
+ /**
378
+ * two unimplemented functions
379
+ */
380
+ private function parseClientKeyExchange( rec:ByteArray ) : void {
381
+ throw new TLSError( "ClientKeyExchange is currently unimplemented!", TLSError.internal_error );
382
+ }
383
+
384
+ private function parseServerKeyExchange( rec:ByteArray ) : void {
385
+ throw new TLSError( "ServerKeyExchange is currently unimplemented!", TLSError.internal_error );
386
+ }
387
+
388
+ /**
389
+ * Test the server's Finished message for validity against the data we know about. Only slightly rewritten. BP
390
+ */
391
+ private function verifyHandshake( rec:ByteArray):void {
392
+ // Get the Finished message
393
+ var verifyData:ByteArray = new ByteArray;
394
+ // This, in the vain hope that noboby is using SSL 2 anymore
395
+ if (_securityParameters.version == SSLSecurityParameters.PROTOCOL_VERSION) {
396
+ rec.readBytes(verifyData, 0, 36); // length should be (in fact, better be) 16 + 20 (md5-size + sha1-size)
397
+ } else { // presuming TLS
398
+ rec.readBytes(verifyData, 0, 12);
399
+ }
400
+
401
+ var data:ByteArray = _securityParameters.computeVerifyData(1-_entity, _handshakePayloads);
402
+
403
+ if (ArrayUtil.equals(verifyData, data)) {
404
+ _state = STATE_READY;
405
+ dispatchEvent(new TLSEvent(TLSEvent.READY));
406
+ } else {
407
+ throw new TLSError("Invalid Finished mac.", TLSError.bad_record_mac);
408
+ }
409
+ }
410
+
411
+ // enforceClient/enforceServer removed in favor of state-driven function maps
412
+
413
+ /**
414
+ * Handle a HANDSHAKE_HELLO
415
+ */
416
+ private function parseHandshakeHello( rec:ByteArray ) : void {
417
+ if (_state != STATE_READY) {
418
+ trace("Received an HELLO_REQUEST before being in state READY. ignoring.");
419
+ return;
420
+ }
421
+ _handshakePayloads = new ByteArray;
422
+ startHandshake();
423
+ }
424
+
425
+ /**
426
+ * Handle a HANDSHAKE_CLIENT_KEY_EXCHANGE
427
+ */
428
+ private function parseHandshakeClientKeyExchange(rec:ByteArray):void {
429
+ if (_securityParameters.useRSA) {
430
+ // skip 2 bytes for length.
431
+ var len:uint = rec.readShort();
432
+ var cipher:ByteArray = new ByteArray;
433
+ rec.readBytes(cipher, 0, len);
434
+ var preMasterSecret:ByteArray = new ByteArray;
435
+ _config.privateKey.decrypt(cipher, preMasterSecret, len);
436
+ _securityParameters.setPreMasterSecret(preMasterSecret);
437
+
438
+ // now is a good time to get our pending states
439
+ var o:Object = _securityParameters.getConnectionStates();
440
+ _pendingReadState = o.read;
441
+ _pendingWriteState = o.write;
442
+
443
+ } else {
444
+ throw new TLSError("parseHandshakeClientKeyExchange not implemented for DH modes.", TLSError.internal_error);
445
+ }
446
+
447
+ }
448
+
449
+ /**
450
+ * Handle HANDSHAKE_SERVER_HELLO - client-side
451
+ */
452
+ private function parseHandshakeServerHello( rec:IDataInput ) : void {
453
+
454
+ var ver:uint = rec.readShort();
455
+ if (ver != _securityParameters.version) {
456
+ throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
457
+ }
458
+ var random:ByteArray = new ByteArray;
459
+ rec.readBytes(random, 0, 32);
460
+ var session_length:uint = rec.readByte();
461
+ var session:ByteArray = new ByteArray;
462
+ if (session_length > 0) {
463
+ // some implementations don't assign a session ID
464
+ rec.readBytes(session, 0, session_length);
465
+ }
466
+
467
+ _securityParameters.setCipher(rec.readShort());
468
+ _securityParameters.setCompression(rec.readByte());
469
+ _securityParameters.setServerRandom(random);
470
+ }
471
+
472
+ /**
473
+ * Handle HANDSHAKE_CLIENT_HELLO - server side
474
+ */
475
+ private function parseHandshakeClientHello( rec:IDataInput ) : void {
476
+ var ret:Object;
477
+ var ver:uint = rec.readShort();
478
+ if (ver != _securityParameters.version) {
479
+ throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
480
+ }
481
+
482
+ var random:ByteArray = new ByteArray;
483
+ rec.readBytes(random, 0, 32);
484
+ var session_length:uint = rec.readByte();
485
+ var session:ByteArray = new ByteArray;
486
+ if (session_length > 0) {
487
+ // some implementations don't assign a session ID
488
+ rec.readBytes(session, 0, session_length);
489
+ }
490
+ var suites:Array = [];
491
+
492
+ var suites_length:uint = rec.readShort();
493
+ for (var i:uint=0;i<suites_length/2;i++) {
494
+ suites.push(rec.readShort());
495
+ }
496
+
497
+ var compressions:Array = [];
498
+
499
+ var comp_length:uint = rec.readByte();
500
+ for (i=0;i<comp_length;i++) {
501
+ compressions.push(rec.readByte());
502
+ }
503
+
504
+ ret = {random:random, session:session, suites:suites, compressions:compressions};
505
+
506
+ var sofar:uint = 2+32+1+session_length+2+suites_length+1+comp_length;
507
+ var extensions:Array = [];
508
+ if (sofar<length) {
509
+ // we have extensions. great.
510
+ var ext_total_length:uint = rec.readShort();
511
+ while (ext_total_length>0) {
512
+ var ext_type:uint = rec.readShort();
513
+ var ext_length:uint = rec.readShort();
514
+ var ext_data:ByteArray = new ByteArray;
515
+ rec.readBytes(ext_data, 0, ext_length);
516
+ ext_total_length -= 4+ext_length;
517
+ extensions.push({type:ext_type, length:ext_length, data:ext_data});
518
+ }
519
+ }
520
+ ret.ext = extensions;
521
+
522
+ sendServerHello(ret);
523
+ sendCertificate();
524
+ // TODO: Modify to handle case of requesting a certificate from the client, for "client authentication",
525
+ // and testing purposes, will probably never actually need it.
526
+ sendServerHelloDone();
527
+ }
528
+
529
+ private function sendClientHello():void {
530
+ var rec:ByteArray = new ByteArray;
531
+ // version - modified to support version attribute from ISecurityParameters
532
+ rec.writeShort(_securityParameters.version);
533
+ // random
534
+ var prng:Random = new Random;
535
+ var clientRandom:ByteArray = new ByteArray;
536
+ prng.nextBytes(clientRandom, 32);
537
+ _securityParameters.setClientRandom(clientRandom);
538
+ rec.writeBytes(clientRandom,0,32);
539
+ // session
540
+ rec.writeByte(32);
541
+ prng.nextBytes(rec, 32);
542
+ // Cipher suites
543
+ var cs:Array = _config.cipherSuites;
544
+ rec.writeShort(2* cs.length);
545
+ for (var i:int=0;i<cs.length;i++) {
546
+ rec.writeShort(cs[i]);
547
+ }
548
+ // Compression
549
+ cs = _config.compressions;
550
+ rec.writeByte(cs.length);
551
+ for (i=0;i<cs.length;i++) {
552
+ rec.writeByte(cs[i]);
553
+ }
554
+ // no extensions, yet.
555
+ rec.position = 0;
556
+ sendHandshake(HANDSHAKE_CLIENT_HELLO, rec.length, rec);
557
+ }
558
+
559
+ private function findMatch(a1:Array, a2:Array):int {
560
+ for (var i:int=0;i<a1.length;i++) {
561
+ var e:uint = a1[i];
562
+ if (a2.indexOf(e)>-1) {
563
+ return e;
564
+ }
565
+ }
566
+ return -1;
567
+ }
568
+
569
+ private function sendServerHello(v:Object):void {
570
+ var cipher:int = findMatch(_config.cipherSuites, v.suites);
571
+ if (cipher == -1) {
572
+ throw new TLSError("No compatible cipher found.", TLSError.handshake_failure);
573
+ }
574
+ _securityParameters.setCipher(cipher);
575
+
576
+ var comp:int = findMatch(_config.compressions, v.compressions);
577
+ if (comp == 01) {
578
+ throw new TLSError("No compatible compression method found.", TLSError.handshake_failure);
579
+ }
580
+ _securityParameters.setCompression(comp);
581
+ _securityParameters.setClientRandom(v.random);
582
+
583
+
584
+ var rec:ByteArray = new ByteArray;
585
+ rec.writeShort(_securityParameters.version);
586
+ var prng:Random = new Random;
587
+ var serverRandom:ByteArray = new ByteArray;
588
+ prng.nextBytes(serverRandom, 32);
589
+ _securityParameters.setServerRandom(serverRandom);
590
+ rec.writeBytes(serverRandom,0,32);
591
+ // session
592
+ rec.writeByte(32);
593
+ prng.nextBytes(rec, 32);
594
+ // Cipher suite
595
+ rec.writeShort(v.suites[0]);
596
+ // Compression
597
+ rec.writeByte(v.compressions[0]);
598
+ rec.position = 0;
599
+ sendHandshake(HANDSHAKE_SERVER_HELLO, rec.length, rec);
600
+ }
601
+
602
+ private var sendClientCert:Boolean = false;
603
+ private function setStateRespondWithCertificate( r:ByteArray = null) : void {
604
+ sendClientCert = true;
605
+ }
606
+
607
+ private function sendCertificate( r:ByteArray = null ):void {
608
+ var cert:ByteArray = _config.certificate;
609
+ var len:uint;
610
+ var len2:uint;
611
+ var rec:ByteArray = new ByteArray;
612
+ // Look for a certficate chain, if we have one, send it, if we don't, send an empty record.
613
+ if (cert != null) {
614
+ len = cert.length;
615
+ len2 = cert.length + 3;
616
+ rec.writeByte(len2>>16);
617
+ rec.writeShort(len2&65535);
618
+ rec.writeByte(len>>16);
619
+ rec.writeShort(len&65535);
620
+ rec.writeBytes(cert);
621
+ } else {
622
+ rec.writeShort( 0 );
623
+ rec.writeByte( 0 );
624
+ }
625
+ rec.position = 0;
626
+ sendHandshake(HANDSHAKE_CERTIFICATE, rec.length, rec);
627
+ }
628
+
629
+ private function sendCertificateVerify():void {
630
+ var rec:ByteArray = new ByteArray();
631
+ // Encrypt the handshake payloads here
632
+ var data:ByteArray = _securityParameters.computeCertificateVerify(_entity, _handshakePayloads);
633
+ data.position=0;
634
+ sendHandshake(HANDSHAKE_CERTIFICATE_VERIFY, data.length, data);
635
+ }
636
+
637
+ private function sendServerHelloDone():void {
638
+ var rec:ByteArray = new ByteArray;
639
+ sendHandshake(HANDSHAKE_HELLO_DONE, rec.length, rec);
640
+ }
641
+
642
+ private function sendClientKeyExchange():void {
643
+ if (_securityParameters.useRSA) {
644
+ var p:ByteArray = new ByteArray;
645
+ p.writeShort(_securityParameters.version);
646
+ var prng:Random = new Random;
647
+ prng.nextBytes(p, 46);
648
+ p.position = 0;
649
+
650
+ var preMasterSecret:ByteArray = new ByteArray;
651
+ preMasterSecret.writeBytes(p, 0, p.length);
652
+ preMasterSecret.position = 0;
653
+ _securityParameters.setPreMasterSecret(preMasterSecret);
654
+
655
+ var enc_key:ByteArray = new ByteArray;
656
+ _otherCertificate.getPublicKey().encrypt(preMasterSecret, enc_key, preMasterSecret.length);
657
+
658
+ enc_key.position = 0;
659
+ var rec:ByteArray = new ByteArray;
660
+
661
+ // TLS requires the size of the premaster key be sent BUT
662
+ // SSL 3.0 does not
663
+ if (_securityParameters.version > 0x0300) {
664
+ rec.writeShort(enc_key.length);
665
+ }
666
+ rec.writeBytes(enc_key, 0, enc_key.length);
667
+
668
+ rec.position=0;
669
+
670
+ sendHandshake(HANDSHAKE_CLIENT_KEY_EXCHANGE, rec.length, rec);
671
+
672
+ // now is a good time to get our pending states
673
+ var o:Object = _securityParameters.getConnectionStates();
674
+ _pendingReadState = o.read;
675
+ _pendingWriteState = o.write;
676
+
677
+ } else {
678
+ throw new TLSError("Non-RSA Client Key Exchange not implemented.", TLSError.internal_error);
679
+ }
680
+ }
681
+ private function sendFinished():void {
682
+ var data:ByteArray = _securityParameters.computeVerifyData(_entity, _handshakePayloads);
683
+ data.position=0;
684
+ sendHandshake(HANDSHAKE_FINISHED, data.length, data);
685
+ }
686
+
687
+ private function sendHandshake(type:uint, len:uint, payload:IDataInput):void {
688
+ var rec:ByteArray = new ByteArray;
689
+ rec.writeByte(type);
690
+ rec.writeByte(0);
691
+ rec.writeShort(len);
692
+ payload.readBytes(rec, rec.position, len);
693
+ _handshakePayloads.writeBytes(rec, 0, rec.length);
694
+ sendRecord(PROTOCOL_HANDSHAKE, rec);
695
+ }
696
+
697
+ private function sendChangeCipherSpec():void {
698
+ var rec:ByteArray = new ByteArray;
699
+ rec[0] = 1;
700
+ sendRecord(PROTOCOL_CHANGE_CIPHER_SPEC, rec);
701
+
702
+ // right after, switch the cipher for writing.
703
+ _currentWriteState = _pendingWriteState;
704
+ _pendingWriteState = null;
705
+ }
706
+
707
+ public function sendApplicationData(data:ByteArray, offset:uint=0, length:uint=0):void {
708
+ var rec:ByteArray = new ByteArray;
709
+ var len:uint = length;
710
+ // BIG FAT WARNING: Patch from Arlen Cuss ALA As3crypto group on Google code.
711
+ // This addresses data overflow issues when the packet size hits the max length boundary.
712
+ if (len == 0) len = data.length;
713
+ while (len>16384) {
714
+ rec.position = 0;
715
+ rec.writeBytes(data, offset, 16384);
716
+ rec.position = 0;
717
+ sendRecord(PROTOCOL_APPLICATION_DATA, rec);
718
+ offset += 16384;
719
+ len -= 16384;
720
+ }
721
+ rec.position = 0;
722
+ rec.writeBytes(data, offset, len);
723
+ // trace("Data I'm sending..." + Hex.fromArray( data ));
724
+ rec.position = 0;
725
+ sendRecord(PROTOCOL_APPLICATION_DATA, rec);
726
+ }
727
+ private function sendRecord(type:uint, payload:ByteArray):void {
728
+ // encrypt
729
+ payload = _currentWriteState.encrypt(type, payload);
730
+
731
+ _oStream.writeByte(type);
732
+ _oStream.writeShort(_securityParameters.version);
733
+ _oStream.writeShort(payload.length);
734
+ _oStream.writeBytes(payload, 0, payload.length);
735
+
736
+ scheduleWrite();
737
+ }
738
+
739
+ private var _writeScheduler:uint;
740
+ private function scheduleWrite():void {
741
+ if (_writeScheduler!=0) return;
742
+ _writeScheduler = setTimeout(commitWrite, 0);
743
+ }
744
+ private function commitWrite():void {
745
+ clearTimeout(_writeScheduler);
746
+ _writeScheduler = 0;
747
+ if (_state != STATE_CLOSED) {
748
+ dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA));
749
+ }
750
+ }
751
+
752
+ private function sendClientAck( rec:ByteArray ):void {
753
+ if ( _handshakeCanContinue ) {
754
+ // If I have a pending cert request, send it
755
+ if (sendClientCert)
756
+ sendCertificate();
757
+ // send a client key exchange
758
+ sendClientKeyExchange();
759
+ // Send the certificate verify, if we have one
760
+ if (_config.certificate != null)
761
+ sendCertificateVerify();
762
+ // send a change cipher spec
763
+ sendChangeCipherSpec();
764
+ // send a finished
765
+ sendFinished();
766
+ }
767
+ }
768
+
769
+ /**
770
+ * Vaguely gross function that parses a RSA key out of a certificate.
771
+ *
772
+ * As long as that certificate looks just the way we expect it to.
773
+ *
774
+ */
775
+ private function loadCertificates( rec:ByteArray ):void {
776
+ var tmp:uint = rec.readByte();
777
+ var certs_len:uint = (tmp<<16) | rec.readShort();
778
+ var certs:Array = [];
779
+
780
+ while (certs_len>0) {
781
+ tmp = rec.readByte();
782
+ var cert_len:uint = (tmp<<16) | rec.readShort();
783
+ var cert:ByteArray = new ByteArray;
784
+ rec.readBytes(cert, 0, cert_len);
785
+ certs.push(cert);
786
+ certs_len -= 3 + cert_len;
787
+ }
788
+
789
+ var firstCert:X509Certificate = null;
790
+ for (var i:int=0;i<certs.length;i++) {
791
+ var x509:X509Certificate = new X509Certificate(certs[i]);
792
+ _store.addCertificate(x509);
793
+ if (firstCert==null) {
794
+ firstCert = x509;
795
+ }
796
+ }
797
+
798
+
799
+ // Test first for trust override parameters
800
+ // This nice trust override stuff comes from Joey Parrish via As3crypto forums
801
+ var certTrusted:Boolean;
802
+ if (_config.trustAllCertificates) {
803
+ certTrusted = true; // Blatantly trust everything
804
+ } else if (_config.trustSelfSignedCertificates ) {
805
+ // Self-signed certs
806
+ certTrusted = firstCert.isSelfSigned(new Date);
807
+ } else {
808
+ // Certs with a signer in the CA store - realistically, I should setup an event chain to handle this
809
+ certTrusted = firstCert.isSigned(_store, _config.CAStore );
810
+ }
811
+
812
+ // Good so far
813
+ if (certTrusted) {
814
+ // ok, that's encouraging. now for the hostname match.
815
+ if (_otherIdentity==null || _config.ignoreCommonNameMismatch ) {
816
+ // we don't care who we're talking with. groovy.
817
+ _otherCertificate = firstCert;
818
+ } else {
819
+ // use regex to handle wildcard certs
820
+ var commonName:String = firstCert.getCommonName();
821
+ // replace all regex special characters with escaped version, except for asterisk
822
+ // replace the asterisk with a regex sequence to match one or more non-dot characters
823
+ var commonNameRegex:RegExp = new RegExp( commonName.replace(/[\^\\\-$.[\]|()?+{}]/g, "\\$&").replace(/\*/g, "[^.]+"), "gi");
824
+ if (commonNameRegex.exec(_otherIdentity)) {
825
+ _otherCertificate = firstCert;
826
+ } else {
827
+ if (_config.promptUserForAcceptCert ) {
828
+ _handshakeCanContinue = false;
829
+ dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
830
+ } else {
831
+ throw new TLSError("Invalid common name: "+firstCert.getCommonName()+", expected "+_otherIdentity, TLSError.bad_certificate);
832
+ }
833
+ }
834
+ }
835
+
836
+ } else {
837
+ // Let's ask the user if we can accept this cert. I'm not certain of the behaviour in case of timeouts,
838
+ // so I probably need to handle the case by killing and restarting the connection rather than continuing if it becomes
839
+ // an issue. We shall see. BP
840
+ if (_config.promptUserForAcceptCert) {
841
+ _handshakeCanContinue = false;
842
+ dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
843
+ } else {
844
+ // Cannot continue, die.
845
+ throw new TLSError("Cannot verify certificate", TLSError.bad_certificate);
846
+ }
847
+ }
848
+ }
849
+
850
+ // Accept the peer cert, and keep going
851
+ public function acceptPeerCertificate() : void {
852
+ _handshakeCanContinue = true;
853
+ sendClientAck( null );
854
+ }
855
+
856
+ // Step off biotch! No trust for you!
857
+ public function rejectPeerCertificate() : void {
858
+ throw new TLSError("Peer certificate not accepted!", TLSError.bad_certificate);
859
+ }
860
+
861
+
862
+ private function parseAlert(p:ByteArray):void {
863
+ //throw new Error("Alert not implemented.");
864
+ // 7.2
865
+ trace("GOT ALERT! type="+p[1]);
866
+ close();
867
+ }
868
+ private function parseChangeCipherSpec(p:ByteArray):void {
869
+ p.readUnsignedByte();
870
+ if (_pendingReadState==null) {
871
+ throw new TLSError("Not ready to Change Cipher Spec, damnit.", TLSError.unexpected_message);
872
+ }
873
+ _currentReadState = _pendingReadState;
874
+ _pendingReadState = null;
875
+ // 7.1
876
+ }
877
+ private function parseApplicationData(p:ByteArray):void {
878
+ if (_state != STATE_READY) {
879
+ throw new TLSError("Too soon for data!", TLSError.unexpected_message);
880
+ return;
881
+ }
882
+ dispatchEvent(new TLSEvent(TLSEvent.DATA, p));
883
+ }
884
+
885
+ private function handleTLSError(e:TLSError):void {
886
+ // basic rules to keep things simple:
887
+ // - Make a good faith attempt at notifying peers
888
+ // - TLSErrors are always fatal.
889
+ // BP: Meh...not always. Common Name mismatches appear to be common on servers. Instead of closing, let's pause, and ask for confirmation
890
+ // before we tear the connection down.
891
+
892
+ close(e);
893
+ }
894
+ }
895
+ }