xref: /inferno-os/appl/lib/crypt/ssl3.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth#
2*37da2899SCharles.Forsyth# SSL 3.0 protocol
3*37da2899SCharles.Forsyth#
4*37da2899SCharles.Forsythimplement SSL3;
5*37da2899SCharles.Forsyth
6*37da2899SCharles.Forsythinclude "sys.m";
7*37da2899SCharles.Forsyth	sys					: Sys;
8*37da2899SCharles.Forsyth
9*37da2899SCharles.Forsythinclude "keyring.m";
10*37da2899SCharles.Forsyth	keyring					: Keyring;
11*37da2899SCharles.Forsyth	IPint, DigestState			: import keyring;
12*37da2899SCharles.Forsyth
13*37da2899SCharles.Forsythinclude "security.m";
14*37da2899SCharles.Forsyth	random					: Random;
15*37da2899SCharles.Forsyth	ssl					: SSL;
16*37da2899SCharles.Forsyth
17*37da2899SCharles.Forsythinclude "daytime.m";
18*37da2899SCharles.Forsyth	daytime					: Daytime;
19*37da2899SCharles.Forsyth
20*37da2899SCharles.Forsythinclude "asn1.m";
21*37da2899SCharles.Forsyth	asn1					: ASN1;
22*37da2899SCharles.Forsyth
23*37da2899SCharles.Forsythinclude "pkcs.m";
24*37da2899SCharles.Forsyth	pkcs					: PKCS;
25*37da2899SCharles.Forsyth	DHParams, DHPublicKey, DHPrivateKey,
26*37da2899SCharles.Forsyth	RSAParams, RSAKey,
27*37da2899SCharles.Forsyth	DSSPrivateKey, DSSPublicKey		: import PKCS;
28*37da2899SCharles.Forsyth
29*37da2899SCharles.Forsythinclude "x509.m";
30*37da2899SCharles.Forsyth	x509					: X509;
31*37da2899SCharles.Forsyth	Signed,	Certificate, SubjectPKInfo	: import x509;
32*37da2899SCharles.Forsyth
33*37da2899SCharles.Forsythinclude "sslsession.m";
34*37da2899SCharles.Forsyth	sslsession				: SSLsession;
35*37da2899SCharles.Forsyth	Session					: import sslsession;
36*37da2899SCharles.Forsyth
37*37da2899SCharles.Forsythinclude "ssl3.m";
38*37da2899SCharles.Forsyth
39*37da2899SCharles.Forsyth#
40*37da2899SCharles.Forsyth# debug mode
41*37da2899SCharles.Forsyth#
42*37da2899SCharles.ForsythSSL_DEBUG					: con 0;
43*37da2899SCharles.Forsythlogfd						: ref Sys->FD;
44*37da2899SCharles.Forsyth
45*37da2899SCharles.Forsyth#
46*37da2899SCharles.Forsyth# version {major, minor}
47*37da2899SCharles.Forsyth#
48*37da2899SCharles.ForsythSSL_VERSION_2_0					:= array [] of {byte 0, byte 16r02};
49*37da2899SCharles.ForsythSSL_VERSION_3_0					:= array [] of {byte 16r03, byte 0};
50*37da2899SCharles.Forsyth
51*37da2899SCharles.Forsyth
52*37da2899SCharles.Forsyth# SSL Record Protocol
53*37da2899SCharles.Forsyth
54*37da2899SCharles.ForsythSSL_CHANGE_CIPHER_SPEC 				: con 20;
55*37da2899SCharles.Forsyth	SSL_ALERT				: con 21;
56*37da2899SCharles.Forsyth	SSL_HANDSHAKE 				: con 22;
57*37da2899SCharles.Forsyth	SSL_APPLICATION_DATA 			: con 23;
58*37da2899SCharles.Forsyth	SSL_V2HANDSHAKE				: con 0; # escape to sslv2
59*37da2899SCharles.Forsyth
60*37da2899SCharles.Forsyth# SSL Application Protocol consists of alert protocol, change cipher spec protocol
61*37da2899SCharles.Forsyth# v2 and v3 handshake protocol and application data protocol. The v2 handshake
62*37da2899SCharles.Forsyth# protocol is included only for backward compatibility
63*37da2899SCharles.Forsyth
64*37da2899SCharles.ForsythProtocol: adt {
65*37da2899SCharles.Forsyth	pick {
66*37da2899SCharles.Forsyth	pAlert =>
67*37da2899SCharles.Forsyth		alert				: ref Alert;
68*37da2899SCharles.Forsyth	pChangeCipherSpec =>
69*37da2899SCharles.Forsyth		change_cipher_spec		: ref ChangeCipherSpec;
70*37da2899SCharles.Forsyth	pHandshake =>
71*37da2899SCharles.Forsyth		handshake			: ref Handshake;
72*37da2899SCharles.Forsyth	pV2Handshake =>
73*37da2899SCharles.Forsyth		handshake			: ref V2Handshake;
74*37da2899SCharles.Forsyth	pApplicationData =>
75*37da2899SCharles.Forsyth		data				: array of byte;
76*37da2899SCharles.Forsyth	}
77*37da2899SCharles.Forsyth
78*37da2899SCharles.Forsyth	decode: fn(r: ref Record, ctx: ref Context): (ref Protocol, string);
79*37da2899SCharles.Forsyth	encode: fn(p: self ref Protocol, vers: array of byte): (ref Record, string);
80*37da2899SCharles.Forsyth	tostring: fn(p: self ref Protocol): string;
81*37da2899SCharles.Forsyth};
82*37da2899SCharles.Forsyth
83*37da2899SCharles.Forsyth#
84*37da2899SCharles.Forsyth# ssl alert protocol
85*37da2899SCharles.Forsyth#
86*37da2899SCharles.ForsythSSL_WARNING	 				: con 1;
87*37da2899SCharles.Forsyth	SSL_FATAL				: con 2;
88*37da2899SCharles.Forsyth
89*37da2899SCharles.ForsythSSL_CLOSE_NOTIFY				: con 0;
90*37da2899SCharles.Forsyth	SSL_UNEXPECTED_MESSAGE			: con 10;
91*37da2899SCharles.Forsyth	SSL_BAD_RECORD_MAC			: con 20;
92*37da2899SCharles.Forsyth	SSL_DECOMPRESSION_FAILURE		: con 30;
93*37da2899SCharles.Forsyth	SSL_HANDSHAKE_FAILURE 			: con 40;
94*37da2899SCharles.Forsyth	SSL_NO_CERTIFICATE			: con 41;
95*37da2899SCharles.Forsyth	SSL_BAD_CERTIFICATE 			: con 42;
96*37da2899SCharles.Forsyth	SSL_UNSUPPORTED_CERTIFICATE 		: con 43;
97*37da2899SCharles.Forsyth	SSL_CERTIFICATE_REVOKED			: con 44;
98*37da2899SCharles.Forsyth	SSL_CERTIFICATE_EXPIRED			: con 45;
99*37da2899SCharles.Forsyth	SSL_CERTIFICATE_UNKNOWN			: con 46;
100*37da2899SCharles.Forsyth	SSL_ILLEGAL_PARAMETER 			: con 47;
101*37da2899SCharles.Forsyth
102*37da2899SCharles.ForsythAlert: adt {
103*37da2899SCharles.Forsyth	level 					: int;
104*37da2899SCharles.Forsyth	description 				: int;
105*37da2899SCharles.Forsyth
106*37da2899SCharles.Forsyth	tostring: fn(a: self ref Alert): string;
107*37da2899SCharles.Forsyth};
108*37da2899SCharles.Forsyth
109*37da2899SCharles.Forsyth#
110*37da2899SCharles.Forsyth# ssl change cipher spec protocol
111*37da2899SCharles.Forsyth#
112*37da2899SCharles.ForsythChangeCipherSpec: adt {
113*37da2899SCharles.Forsyth	value					: int;
114*37da2899SCharles.Forsyth};
115*37da2899SCharles.Forsyth
116*37da2899SCharles.Forsyth#
117*37da2899SCharles.Forsyth# ssl handshake protocol
118*37da2899SCharles.Forsyth#
119*37da2899SCharles.ForsythSSL_HANDSHAKE_HELLO_REQUEST	 		: con 0;
120*37da2899SCharles.Forsyth	SSL_HANDSHAKE_CLIENT_HELLO 		: con 1;
121*37da2899SCharles.Forsyth	SSL_HANDSHAKE_SERVER_HELLO 		: con 2;
122*37da2899SCharles.Forsyth	SSL_HANDSHAKE_CERTIFICATE 		: con 11;
123*37da2899SCharles.Forsyth	SSL_HANDSHAKE_SERVER_KEY_EXCHANGE 	: con 12;
124*37da2899SCharles.Forsyth	SSL_HANDSHAKE_CERTIFICATE_REQUEST 	: con 13;
125*37da2899SCharles.Forsyth	SSL_HANDSHAKE_SERVER_HELLO_DONE 	: con 14;
126*37da2899SCharles.Forsyth	SSL_HANDSHAKE_CERTIFICATE_VERIFY 	: con 15;
127*37da2899SCharles.Forsyth	SSL_HANDSHAKE_CLIENT_KEY_EXCHANGE 	: con 16;
128*37da2899SCharles.Forsyth	SSL_HANDSHAKE_FINISHED	 		: con 20;
129*37da2899SCharles.Forsyth
130*37da2899SCharles.ForsythHandshake: adt {
131*37da2899SCharles.Forsyth	pick {
132*37da2899SCharles.Forsyth       	HelloRequest =>
133*37da2899SCharles.Forsyth        ClientHello =>
134*37da2899SCharles.Forsyth		version 			: array of byte; # [2]
135*37da2899SCharles.Forsyth		random 				: array of byte; # [32]
136*37da2899SCharles.Forsyth		session_id 			: array of byte; # <0..32>
137*37da2899SCharles.Forsyth		suites	 			: array of byte; # [2] x
138*37da2899SCharles.Forsyth		compressions			: array of byte; # [1] x
139*37da2899SCharles.Forsyth        ServerHello =>
140*37da2899SCharles.Forsyth		version 			: array of byte; # [2]
141*37da2899SCharles.Forsyth		random 				: array of byte; # [32]
142*37da2899SCharles.Forsyth		session_id 			: array of byte; # <0..32>
143*37da2899SCharles.Forsyth		suite	 			: array of byte; # [2]
144*37da2899SCharles.Forsyth		compression			: byte; # [1]
145*37da2899SCharles.Forsyth	Certificate =>
146*37da2899SCharles.Forsyth		cert_list 			: list of array of byte; # X509 cert chain
147*37da2899SCharles.Forsyth	ServerKeyExchange =>
148*37da2899SCharles.Forsyth		xkey				: array of byte; # exchange_keys
149*37da2899SCharles.Forsyth        CertificateRequest =>
150*37da2899SCharles.Forsyth		cert_types 			: array of byte;
151*37da2899SCharles.Forsyth		dn_list 			: list of array of byte; # DN list
152*37da2899SCharles.Forsyth	ServerHelloDone =>
153*37da2899SCharles.Forsyth        CertificateVerify =>
154*37da2899SCharles.Forsyth		signature			: array of byte;
155*37da2899SCharles.Forsyth        ClientKeyExchange =>
156*37da2899SCharles.Forsyth		xkey				: array of byte;
157*37da2899SCharles.Forsyth       	Finished =>
158*37da2899SCharles.Forsyth		md5_hash			: array of byte; # [16] Keyring->MD5dlen
159*37da2899SCharles.Forsyth		sha_hash 			: array of byte; # [20] Keyring->SHA1dlen
160*37da2899SCharles.Forsyth	}
161*37da2899SCharles.Forsyth
162*37da2899SCharles.Forsyth	decode: fn(buf: array of byte): (ref Handshake, string);
163*37da2899SCharles.Forsyth	encode: fn(hm: self ref Handshake): (array of byte, string);
164*37da2899SCharles.Forsyth	tostring: fn(hm: self ref Handshake): string;
165*37da2899SCharles.Forsyth};
166*37da2899SCharles.Forsyth
167*37da2899SCharles.Forsyth# cipher suites and cipher specs (default, not all supported)
168*37da2899SCharles.Forsyth#	- key exchange, signature, encrypt and digest algorithms
169*37da2899SCharles.Forsyth
170*37da2899SCharles.ForsythSSL3_Suites := array [] of {
171*37da2899SCharles.Forsyth	NULL_WITH_NULL_NULL => 			array [] of {byte 0, byte 16r00},
172*37da2899SCharles.Forsyth
173*37da2899SCharles.Forsyth	RSA_WITH_NULL_MD5 => 			array [] of {byte 0, byte 16r01},
174*37da2899SCharles.Forsyth	RSA_WITH_NULL_SHA => 			array [] of {byte 0, byte 16r02},
175*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_RC4_40_MD5 => 		array [] of {byte 0, byte 16r03},
176*37da2899SCharles.Forsyth	RSA_WITH_RC4_128_MD5 => 		array [] of {byte 0, byte 16r04},
177*37da2899SCharles.Forsyth	RSA_WITH_RC4_128_SHA => 		array [] of {byte 0, byte 16r05},
178*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_RC2_CBC_40_MD5 => 	array [] of {byte 0, byte 16r06},
179*37da2899SCharles.Forsyth	RSA_WITH_IDEA_CBC_SHA => 		array [] of {byte 0, byte 16r07},
180*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_DES40_CBC_SHA => 	array [] of {byte 0, byte 16r08},
181*37da2899SCharles.Forsyth	RSA_WITH_DES_CBC_SHA => 		array [] of {byte 0, byte 16r09},
182*37da2899SCharles.Forsyth	RSA_WITH_3DES_EDE_CBC_SHA => 		array [] of {byte 0, byte 16r0A},
183*37da2899SCharles.Forsyth
184*37da2899SCharles.Forsyth	DH_DSS_EXPORT_WITH_DES40_CBC_SHA => 	array [] of {byte 0, byte 16r0B},
185*37da2899SCharles.Forsyth	DH_DSS_WITH_DES_CBC_SHA => 		array [] of {byte 0, byte 16r0C},
186*37da2899SCharles.Forsyth	DH_DSS_WITH_3DES_EDE_CBC_SHA => 	array [] of {byte 0, byte 16r0D},
187*37da2899SCharles.Forsyth	DH_RSA_EXPORT_WITH_DES40_CBC_SHA => 	array [] of {byte 0, byte 16r0E},
188*37da2899SCharles.Forsyth	DH_RSA_WITH_DES_CBC_SHA => 		array [] of {byte 0, byte 16r0F},
189*37da2899SCharles.Forsyth	DH_RSA_WITH_3DES_EDE_CBC_SHA => 	array [] of {byte 0, byte 16r10},
190*37da2899SCharles.Forsyth	DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =>	array [] of {byte 0, byte 16r11},
191*37da2899SCharles.Forsyth	DHE_DSS_WITH_DES_CBC_SHA => 		array [] of {byte 0, byte 16r12},
192*37da2899SCharles.Forsyth	DHE_DSS_WITH_3DES_EDE_CBC_SHA => 	array [] of {byte 0, byte 16r13},
193*37da2899SCharles.Forsyth	DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =>	array [] of {byte 0, byte 16r14},
194*37da2899SCharles.Forsyth	DHE_RSA_WITH_DES_CBC_SHA => 		array [] of {byte 0, byte 16r15},
195*37da2899SCharles.Forsyth	DHE_RSA_WITH_3DES_EDE_CBC_SHA => 	array [] of {byte 0, byte 16r16},
196*37da2899SCharles.Forsyth
197*37da2899SCharles.Forsyth	DH_anon_EXPORT_WITH_RC4_40_MD5 => 	array [] of {byte 0, byte 16r17},
198*37da2899SCharles.Forsyth	DH_anon_WITH_RC4_128_MD5 => 		array [] of {byte 0, byte 16r18},
199*37da2899SCharles.Forsyth	DH_anon_EXPORT_WITH_DES40_CBC_SHA =>	array [] of {byte 0, byte 16r19},
200*37da2899SCharles.Forsyth	DH_anon_WITH_DES_CBC_SHA => 		array [] of {byte 0, byte 16r1A},
201*37da2899SCharles.Forsyth	DH_anon_WITH_3DES_EDE_CBC_SHA => 	array [] of {byte 0, byte 16r1B},
202*37da2899SCharles.Forsyth
203*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_NULL_SHA => 		array [] of {byte 0, byte 16r1C},
204*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA =>	array [] of {byte 0, byte 16r1D},
205*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_RC4_128_SHA => 	array [] of {byte 0, byte 16r1E},
206*37da2899SCharles.Forsyth};
207*37da2899SCharles.Forsyth
208*37da2899SCharles.Forsyth#
209*37da2899SCharles.Forsyth# key exchange algorithms
210*37da2899SCharles.Forsyth#
211*37da2899SCharles.ForsythDHmodlen					: con 512; # default length
212*37da2899SCharles.Forsyth
213*37da2899SCharles.Forsyth
214*37da2899SCharles.Forsyth#
215*37da2899SCharles.Forsyth# certificate types
216*37da2899SCharles.Forsyth#
217*37da2899SCharles.ForsythSSL_RSA_sign 					: con 1;
218*37da2899SCharles.Forsyth	SSL_DSS_sign 				: con 2;
219*37da2899SCharles.Forsyth	SSL_RSA_fixed_DH			: con 3;
220*37da2899SCharles.Forsyth	SSL_DSS_fixed_DH			: con 4;
221*37da2899SCharles.Forsyth	SSL_RSA_emhemeral_DH 			: con 5;
222*37da2899SCharles.Forsyth	SSL_DSS_empemeral_DH 			: con 6;
223*37da2899SCharles.Forsyth	SSL_FORTEZZA_MISSI			: con 20;
224*37da2899SCharles.Forsyth
225*37da2899SCharles.Forsyth#
226*37da2899SCharles.Forsyth# cipher definitions
227*37da2899SCharles.Forsyth#
228*37da2899SCharles.ForsythSSL_EXPORT_TRUE 				: con 0;
229*37da2899SCharles.Forsyth	SSL_EXPORT_FALSE 			: con 1;
230*37da2899SCharles.Forsyth
231*37da2899SCharles.ForsythSSL_NULL_CIPHER,
232*37da2899SCharles.Forsyth	SSL_RC4,
233*37da2899SCharles.Forsyth	SSL_RC2_CBC,
234*37da2899SCharles.Forsyth	SSL_IDEA_CBC,
235*37da2899SCharles.Forsyth	SSL_DES_CBC,
236*37da2899SCharles.Forsyth	SSL_3DES_EDE_CBC,
237*37da2899SCharles.Forsyth	SSL_FORTEZZA_CBC			: con iota;
238*37da2899SCharles.Forsyth
239*37da2899SCharles.ForsythSSL_STREAM_CIPHER,
240*37da2899SCharles.Forsyth	SSL_BLOCK_CIPHER			: con iota;
241*37da2899SCharles.Forsyth
242*37da2899SCharles.ForsythSSL_NULL_MAC,
243*37da2899SCharles.Forsyth	SSL_MD5,
244*37da2899SCharles.Forsyth	SSL_SHA					: con iota;
245*37da2899SCharles.Forsyth
246*37da2899SCharles.Forsyth#
247*37da2899SCharles.Forsyth# MAC paddings
248*37da2899SCharles.Forsyth#
249*37da2899SCharles.ForsythSSL_MAX_MAC_PADDING 				: con 48;
250*37da2899SCharles.ForsythSSL_MAC_PAD1 := array [] of {
251*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
252*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
253*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
254*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
255*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
256*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
257*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
258*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
259*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
260*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
261*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
262*37da2899SCharles.Forsyth	byte 16r36, byte 16r36, byte 16r36, byte 16r36,
263*37da2899SCharles.Forsyth};
264*37da2899SCharles.ForsythSSL_MAC_PAD2 := array [] of {
265*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
266*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
267*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
268*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
269*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
270*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
271*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
272*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
273*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
274*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
275*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
276*37da2899SCharles.Forsyth	byte 16r5c, byte 16r5c, byte 16r5c, byte 16r5c,
277*37da2899SCharles.Forsyth};
278*37da2899SCharles.Forsyth
279*37da2899SCharles.Forsyth#
280*37da2899SCharles.Forsyth# finished messages
281*37da2899SCharles.Forsyth#
282*37da2899SCharles.ForsythSSL_CLIENT_SENDER := array [] of {
283*37da2899SCharles.Forsyth	byte 16r43, byte 16r4C, byte 16r4E, byte 16r54};
284*37da2899SCharles.ForsythSSL_SERVER_SENDER := array [] of {
285*37da2899SCharles.Forsyth	byte 16r53, byte 16r52, byte 16r56, byte 16r52};
286*37da2899SCharles.Forsyth
287*37da2899SCharles.Forsyth#
288*37da2899SCharles.Forsyth# a default distiguished names
289*37da2899SCharles.Forsyth#
290*37da2899SCharles.ForsythRSA_COMMERCIAL_CA_ROOT_SUBJECT_NAME := array [] of {
291*37da2899SCharles.Forsyth	byte 16r30, byte 16r5F, byte 16r31, byte 16r0B,
292*37da2899SCharles.Forsyth	byte 16r30, byte 16r09, byte 16r06, byte 16r03,
293*37da2899SCharles.Forsyth	byte 16r55, byte 16r04, byte 16r06, byte 16r13,
294*37da2899SCharles.Forsyth	byte 16r02, byte 16r55, byte 16r53, byte 16r31,
295*37da2899SCharles.Forsyth	byte 16r20, byte 16r30, byte 16r1E, byte 16r06,
296*37da2899SCharles.Forsyth	byte 16r03, byte 16r55, byte 16r04, byte 16r0A,
297*37da2899SCharles.Forsyth	byte 16r13, byte 16r17, byte 16r52, byte 16r53,
298*37da2899SCharles.Forsyth	byte 16r41, byte 16r20, byte 16r44, byte 16r61,
299*37da2899SCharles.Forsyth	byte 16r74, byte 16r61, byte 16r20, byte 16r53,
300*37da2899SCharles.Forsyth	byte 16r65, byte 16r63, byte 16r75, byte 16r72,
301*37da2899SCharles.Forsyth	byte 16r69, byte 16r74, byte 16r79, byte 16r2C,
302*37da2899SCharles.Forsyth	byte 16r20, byte 16r49, byte 16r6E, byte 16r63,
303*37da2899SCharles.Forsyth	byte 16r2E, byte 16r31, byte 16r2E, byte 16r30,
304*37da2899SCharles.Forsyth	byte 16r2C, byte 16r06, byte 16r03, byte 16r55,
305*37da2899SCharles.Forsyth	byte 16r04, byte 16r0B, byte 16r13, byte 16r25,
306*37da2899SCharles.Forsyth	byte 16r53, byte 16r65, byte 16r63, byte 16r75,
307*37da2899SCharles.Forsyth	byte 16r72, byte 16r65, byte 16r20, byte 16r53,
308*37da2899SCharles.Forsyth	byte 16r65, byte 16r72, byte 16r76, byte 16r65,
309*37da2899SCharles.Forsyth	byte 16r72, byte 16r20, byte 16r43, byte 16r65,
310*37da2899SCharles.Forsyth	byte 16r72, byte 16r74, byte 16r69, byte 16r66,
311*37da2899SCharles.Forsyth	byte 16r69, byte 16r63, byte 16r61, byte 16r74,
312*37da2899SCharles.Forsyth	byte 16r69, byte 16r6F, byte 16r6E, byte 16r20,
313*37da2899SCharles.Forsyth	byte 16r41, byte 16r75, byte 16r74, byte 16r68,
314*37da2899SCharles.Forsyth	byte 16r6F, byte 16r72, byte 16r69, byte 16r74,
315*37da2899SCharles.Forsyth	byte 16r79,
316*37da2899SCharles.Forsyth};
317*37da2899SCharles.Forsyth
318*37da2899SCharles.Forsyth# SSL internal status
319*37da2899SCharles.ForsythUSE_DEVSSL,
320*37da2899SCharles.Forsyth	SSL3_RECORD,
321*37da2899SCharles.Forsyth	SSL3_HANDSHAKE,
322*37da2899SCharles.Forsyth	SSL2_HANDSHAKE,
323*37da2899SCharles.Forsyth	CLIENT_SIDE,
324*37da2899SCharles.Forsyth	SESSION_RESUMABLE,
325*37da2899SCharles.Forsyth	CLIENT_AUTH,
326*37da2899SCharles.Forsyth	CERT_REQUEST,
327*37da2899SCharles.Forsyth	CERT_SENT,
328*37da2899SCharles.Forsyth	CERT_RECEIVED,
329*37da2899SCharles.Forsyth	OUT_READY,
330*37da2899SCharles.Forsyth	IN_READY				: con  1 << iota;
331*37da2899SCharles.Forsyth
332*37da2899SCharles.Forsyth# SSL internal state
333*37da2899SCharles.ForsythSTATE_EXIT,
334*37da2899SCharles.Forsyth	STATE_CHANGE_CIPHER_SPEC,
335*37da2899SCharles.Forsyth	STATE_HELLO_REQUEST,
336*37da2899SCharles.Forsyth	STATE_CLIENT_HELLO,
337*37da2899SCharles.Forsyth	STATE_SERVER_HELLO,
338*37da2899SCharles.Forsyth	STATE_CLIENT_KEY_EXCHANGE,
339*37da2899SCharles.Forsyth	STATE_SERVER_KEY_EXCHANGE,
340*37da2899SCharles.Forsyth	STATE_SERVER_HELLO_DONE,
341*37da2899SCharles.Forsyth	STATE_CLIENT_CERTIFICATE,
342*37da2899SCharles.Forsyth	STATE_SERVER_CERTIFICATE,
343*37da2899SCharles.Forsyth	STATE_CERTIFICATE_VERIFY,
344*37da2899SCharles.Forsyth	STATE_FINISHED				: con iota;
345*37da2899SCharles.Forsyth
346*37da2899SCharles.Forsyth#
347*37da2899SCharles.Forsyth# load necessary modules
348*37da2899SCharles.Forsyth#
349*37da2899SCharles.Forsythinit(): string
350*37da2899SCharles.Forsyth{
351*37da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
352*37da2899SCharles.Forsyth	if(sys == nil)
353*37da2899SCharles.Forsyth		return "ssl3: load sys module failed";
354*37da2899SCharles.Forsyth	logfd = sys->fildes(1);
355*37da2899SCharles.Forsyth
356*37da2899SCharles.Forsyth	keyring = load Keyring Keyring->PATH;
357*37da2899SCharles.Forsyth	if(keyring == nil)
358*37da2899SCharles.Forsyth		return "ssl3: load keyring module failed";
359*37da2899SCharles.Forsyth
360*37da2899SCharles.Forsyth	random = load Random Random->PATH;
361*37da2899SCharles.Forsyth	if(random == nil)
362*37da2899SCharles.Forsyth		return "ssl3: load random module failed";
363*37da2899SCharles.Forsyth
364*37da2899SCharles.Forsyth	daytime = load Daytime Daytime->PATH;
365*37da2899SCharles.Forsyth	if(daytime == nil)
366*37da2899SCharles.Forsyth		return "ssl3: load Daytime module failed";
367*37da2899SCharles.Forsyth
368*37da2899SCharles.Forsyth	pkcs = load PKCS PKCS->PATH;
369*37da2899SCharles.Forsyth	if(pkcs == nil)
370*37da2899SCharles.Forsyth		return "ssl3: load pkcs module failed";
371*37da2899SCharles.Forsyth	pkcs->init();
372*37da2899SCharles.Forsyth
373*37da2899SCharles.Forsyth	x509 = load X509 X509->PATH;
374*37da2899SCharles.Forsyth	if(x509 == nil)
375*37da2899SCharles.Forsyth		return "ssl3: load x509 module failed";
376*37da2899SCharles.Forsyth	x509->init();
377*37da2899SCharles.Forsyth
378*37da2899SCharles.Forsyth	ssl = load SSL SSL->PATH;
379*37da2899SCharles.Forsyth	if(ssl == nil)
380*37da2899SCharles.Forsyth		return "ssl3: load SSL module failed";
381*37da2899SCharles.Forsyth	sslsession = load SSLsession SSLsession->PATH;
382*37da2899SCharles.Forsyth	if(sslsession == nil)
383*37da2899SCharles.Forsyth		return "ssl3: load sslsession module failed";
384*37da2899SCharles.Forsyth	e := sslsession->init();
385*37da2899SCharles.Forsyth	if(e != nil)
386*37da2899SCharles.Forsyth		return "ssl3: sslsession init failed: "+e;
387*37da2899SCharles.Forsyth
388*37da2899SCharles.Forsyth	return "";
389*37da2899SCharles.Forsyth}
390*37da2899SCharles.Forsyth
391*37da2899SCharles.Forsythlog(s: string)
392*37da2899SCharles.Forsyth{
393*37da2899SCharles.Forsyth	a := array of byte (s + "\n");
394*37da2899SCharles.Forsyth	sys->write(logfd, a, len a);
395*37da2899SCharles.Forsyth}
396*37da2899SCharles.Forsyth
397*37da2899SCharles.Forsyth#
398*37da2899SCharles.Forsyth# protocol context
399*37da2899SCharles.Forsyth#
400*37da2899SCharles.Forsyth
401*37da2899SCharles.ForsythContext.new(): ref Context
402*37da2899SCharles.Forsyth{
403*37da2899SCharles.Forsyth	ctx := ref Context;
404*37da2899SCharles.Forsyth
405*37da2899SCharles.Forsyth	ctx.c = nil;
406*37da2899SCharles.Forsyth	ctx.session = nil;
407*37da2899SCharles.Forsyth	ctx.local_info = nil;
408*37da2899SCharles.Forsyth
409*37da2899SCharles.Forsyth	ctx.sha_state = nil;
410*37da2899SCharles.Forsyth	ctx.md5_state = nil;
411*37da2899SCharles.Forsyth
412*37da2899SCharles.Forsyth	ctx.status = 0;
413*37da2899SCharles.Forsyth	ctx.state = 0;
414*37da2899SCharles.Forsyth
415*37da2899SCharles.Forsyth	ctx.client_random = array [32] of byte;
416*37da2899SCharles.Forsyth	ctx.server_random = array [32] of byte;
417*37da2899SCharles.Forsyth
418*37da2899SCharles.Forsyth	ctx.cw_mac = nil;
419*37da2899SCharles.Forsyth	ctx.sw_mac = nil;
420*37da2899SCharles.Forsyth	ctx.cw_key = nil;
421*37da2899SCharles.Forsyth	ctx.sw_key = nil;
422*37da2899SCharles.Forsyth	ctx.cw_IV = nil;
423*37da2899SCharles.Forsyth	ctx.sw_IV = nil;
424*37da2899SCharles.Forsyth
425*37da2899SCharles.Forsyth	ctx.in_queue = RecordQueue.new();
426*37da2899SCharles.Forsyth	ctx.in_queue.data = ref Record(0, nil, array [1<<15] of byte) :: nil;
427*37da2899SCharles.Forsyth	ctx.out_queue = RecordQueue.new();
428*37da2899SCharles.Forsyth
429*37da2899SCharles.Forsyth	# set session resumable as default
430*37da2899SCharles.Forsyth	ctx.status |= SESSION_RESUMABLE;
431*37da2899SCharles.Forsyth
432*37da2899SCharles.Forsyth	return ctx;
433*37da2899SCharles.Forsyth}
434*37da2899SCharles.Forsyth
435*37da2899SCharles.ForsythContext.client(ctx: self ref Context, fd: ref Sys->FD, peername: string, ver: int, info: ref Authinfo)
436*37da2899SCharles.Forsyth	: (string, int)
437*37da2899SCharles.Forsyth{
438*37da2899SCharles.Forsyth	if(SSL_DEBUG)
439*37da2899SCharles.Forsyth		log(sys->sprint("ssl3: Context.Client peername=%s ver=%d\n", peername, ver));
440*37da2899SCharles.Forsyth	if ((ckstr := cksuites(info.suites)) != nil)
441*37da2899SCharles.Forsyth		return (ckstr, ver);
442*37da2899SCharles.Forsyth	# the order is important
443*37da2899SCharles.Forsyth	ctx.local_info = info;
444*37da2899SCharles.Forsyth	ctx.state = STATE_HELLO_REQUEST;
445*37da2899SCharles.Forsyth	e := ctx.connect(fd);
446*37da2899SCharles.Forsyth	if(e != "")
447*37da2899SCharles.Forsyth		return (e, ver);
448*37da2899SCharles.Forsyth	ctx.session = sslsession->get_session_byname(peername);
449*37da2899SCharles.Forsyth
450*37da2899SCharles.Forsyth	# Request to resume an SSL 3.0 session should use an SSL 3.0 client hello
451*37da2899SCharles.Forsyth	if(ctx.session.session_id != nil) {
452*37da2899SCharles.Forsyth		if((ctx.session.version[0] == SSL_VERSION_3_0[0]) &&
453*37da2899SCharles.Forsyth			(ctx.session.version[1] == SSL_VERSION_3_0[1])) {
454*37da2899SCharles.Forsyth			ver = 3;
455*37da2899SCharles.Forsyth			ctx.status |= SSL3_HANDSHAKE;
456*37da2899SCharles.Forsyth			ctx.status &= ~SSL2_HANDSHAKE;
457*37da2899SCharles.Forsyth		}
458*37da2899SCharles.Forsyth	}
459*37da2899SCharles.Forsyth	e = ctx.set_version(ver);
460*37da2899SCharles.Forsyth	if(e != "")
461*37da2899SCharles.Forsyth		return (e, ver);
462*37da2899SCharles.Forsyth	reset_client_random(ctx);
463*37da2899SCharles.Forsyth	ctx.status |= CLIENT_SIDE;
464*37da2899SCharles.Forsyth	e = do_protocol(ctx);
465*37da2899SCharles.Forsyth	if(e != nil)
466*37da2899SCharles.Forsyth		return (e, ver);
467*37da2899SCharles.Forsyth
468*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD)
469*37da2899SCharles.Forsyth		ver = 3;
470*37da2899SCharles.Forsyth	else
471*37da2899SCharles.Forsyth		ver = 2;
472*37da2899SCharles.Forsyth	return (nil, ver);
473*37da2899SCharles.Forsyth}
474*37da2899SCharles.Forsyth
475*37da2899SCharles.ForsythContext.server(ctx: self ref Context, fd: ref Sys->FD, info: ref Authinfo, client_auth: int)
476*37da2899SCharles.Forsyth	: string
477*37da2899SCharles.Forsyth{
478*37da2899SCharles.Forsyth	if ((ckstr := cksuites(info.suites)) != nil)
479*37da2899SCharles.Forsyth		return ckstr;
480*37da2899SCharles.Forsyth	ctx.local_info = info;
481*37da2899SCharles.Forsyth	if(client_auth)
482*37da2899SCharles.Forsyth		ctx.status |= CLIENT_AUTH;
483*37da2899SCharles.Forsyth	ctx.state = STATE_CLIENT_HELLO;
484*37da2899SCharles.Forsyth	e := ctx.connect(fd);
485*37da2899SCharles.Forsyth	if(e != "")
486*37da2899SCharles.Forsyth		return e;
487*37da2899SCharles.Forsyth	reset_server_random(ctx);
488*37da2899SCharles.Forsyth	e = ctx.set_version(3); # set ssl device to version 3
489*37da2899SCharles.Forsyth	if(e != "")
490*37da2899SCharles.Forsyth		return e;
491*37da2899SCharles.Forsyth	ctx.status &= ~CLIENT_SIDE;
492*37da2899SCharles.Forsyth	e = do_protocol(ctx);
493*37da2899SCharles.Forsyth	if(e != nil)
494*37da2899SCharles.Forsyth		return e;
495*37da2899SCharles.Forsyth
496*37da2899SCharles.Forsyth	return "";
497*37da2899SCharles.Forsyth}
498*37da2899SCharles.Forsyth
499*37da2899SCharles.Forsyth
500*37da2899SCharles.ForsythContext.use_devssl(ctx: self ref Context)
501*37da2899SCharles.Forsyth{
502*37da2899SCharles.Forsyth	if(!(ctx.status & IN_READY) && !(ctx.status & OUT_READY))
503*37da2899SCharles.Forsyth		ctx.status |= USE_DEVSSL;
504*37da2899SCharles.Forsyth}
505*37da2899SCharles.Forsyth
506*37da2899SCharles.ForsythContext.set_version(ctx: self ref Context, vers: int): string
507*37da2899SCharles.Forsyth{
508*37da2899SCharles.Forsyth	err := "";
509*37da2899SCharles.Forsyth
510*37da2899SCharles.Forsyth	if(ctx.c == nil) {
511*37da2899SCharles.Forsyth		err = "no connection provided";
512*37da2899SCharles.Forsyth	}
513*37da2899SCharles.Forsyth	else {
514*37da2899SCharles.Forsyth		if(SSL_DEBUG)
515*37da2899SCharles.Forsyth			log("ssl3: record version = " + string vers);
516*37da2899SCharles.Forsyth
517*37da2899SCharles.Forsyth		if(vers == 2) {
518*37da2899SCharles.Forsyth			ctx.status &= ~SSL3_RECORD;
519*37da2899SCharles.Forsyth			ctx.status &= ~SSL3_HANDSHAKE;
520*37da2899SCharles.Forsyth			ctx.status |= SSL2_HANDSHAKE;
521*37da2899SCharles.Forsyth			if (ctx.session != nil)
522*37da2899SCharles.Forsyth				ctx.session.version = SSL_VERSION_2_0;
523*37da2899SCharles.Forsyth		}
524*37da2899SCharles.Forsyth		else if(vers == 3) { # may be sslv2 handshake using ssl3 record
525*37da2899SCharles.Forsyth			ctx.status |= SSL3_RECORD;
526*37da2899SCharles.Forsyth			ctx.status |= SSL3_HANDSHAKE;
527*37da2899SCharles.Forsyth			ctx.status &= ~SSL2_HANDSHAKE; # tmp test only
528*37da2899SCharles.Forsyth			if (ctx.session != nil)
529*37da2899SCharles.Forsyth				ctx.session.version = SSL_VERSION_3_0;
530*37da2899SCharles.Forsyth		}
531*37da2899SCharles.Forsyth		else if(vers == 23) { # may be sslv2 handshake using ssl3 record
532*37da2899SCharles.Forsyth			ctx.status &= ~SSL3_RECORD;
533*37da2899SCharles.Forsyth			ctx.status |= SSL3_HANDSHAKE;
534*37da2899SCharles.Forsyth			ctx.status |= SSL2_HANDSHAKE;
535*37da2899SCharles.Forsyth			vers = 2;
536*37da2899SCharles.Forsyth		}
537*37da2899SCharles.Forsyth		else
538*37da2899SCharles.Forsyth			err = "unsupported ssl device version";
539*37da2899SCharles.Forsyth
540*37da2899SCharles.Forsyth		if((err == "") && (ctx.status & USE_DEVSSL)) {
541*37da2899SCharles.Forsyth			if(sys->fprint(ctx.c.cfd, "ver %d", vers) < 0)
542*37da2899SCharles.Forsyth				err = sys->sprint("ssl3: set ssl device version failed: %r");
543*37da2899SCharles.Forsyth		}
544*37da2899SCharles.Forsyth	}
545*37da2899SCharles.Forsyth
546*37da2899SCharles.Forsyth	return err;
547*37da2899SCharles.Forsyth}
548*37da2899SCharles.Forsyth
549*37da2899SCharles.ForsythContext.connect(ctx: self ref Context, fd: ref Sys->FD): string
550*37da2899SCharles.Forsyth{
551*37da2899SCharles.Forsyth	err := "";
552*37da2899SCharles.Forsyth
553*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL)
554*37da2899SCharles.Forsyth		(err, ctx.c) = ssl->connect(fd);
555*37da2899SCharles.Forsyth	else {
556*37da2899SCharles.Forsyth		ctx.c = ref Sys->Connection(fd, nil, "");
557*37da2899SCharles.Forsyth		ctx.in_queue.sequence_numbers[0] = 0;
558*37da2899SCharles.Forsyth		ctx.out_queue.sequence_numbers[1] = 0;
559*37da2899SCharles.Forsyth	}
560*37da2899SCharles.Forsyth
561*37da2899SCharles.Forsyth	return err;
562*37da2899SCharles.Forsyth}
563*37da2899SCharles.Forsyth
564*37da2899SCharles.ForsythContext.read(ctx: self ref Context, a: array of byte, n: int): int
565*37da2899SCharles.Forsyth{
566*37da2899SCharles.Forsyth	if(ctx.state != STATE_EXIT || !(ctx.status & IN_READY)) {
567*37da2899SCharles.Forsyth		if(SSL_DEBUG)
568*37da2899SCharles.Forsyth			log("ssl3: read not ready\n");
569*37da2899SCharles.Forsyth		return -1;
570*37da2899SCharles.Forsyth	}
571*37da2899SCharles.Forsyth
572*37da2899SCharles.Forsyth	if(ctx.out_queue.data != nil)
573*37da2899SCharles.Forsyth		record_write_queue(ctx);
574*37da2899SCharles.Forsyth
575*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL) {
576*37da2899SCharles.Forsyth		fd := ctx.c.dfd;
577*37da2899SCharles.Forsyth		if(ctx.status & SSL3_RECORD) {
578*37da2899SCharles.Forsyth			buf := array [n+3] of byte;
579*37da2899SCharles.Forsyth			m := sys->read(fd, buf, n+3); # header + n bytes
580*37da2899SCharles.Forsyth			if(m < 3) {
581*37da2899SCharles.Forsyth				if(SSL_DEBUG)
582*37da2899SCharles.Forsyth					log(sys->sprint("ssl3: read failure: %r"));
583*37da2899SCharles.Forsyth				return -1;
584*37da2899SCharles.Forsyth			}
585*37da2899SCharles.Forsyth
586*37da2899SCharles.Forsyth			if(buf[1] != SSL_VERSION_3_0[0] || buf[2] != SSL_VERSION_3_0[1]) {
587*37da2899SCharles.Forsyth				if(SSL_DEBUG)
588*37da2899SCharles.Forsyth					log("ssl3: not ssl version 3 data: header = [" + bastr(buf[0:3]) + "]");
589*37da2899SCharles.Forsyth				return -1;
590*37da2899SCharles.Forsyth			}
591*37da2899SCharles.Forsyth
592*37da2899SCharles.Forsyth			a[0:] = buf[3:m];
593*37da2899SCharles.Forsyth
594*37da2899SCharles.Forsyth			content_type := int buf[0];
595*37da2899SCharles.Forsyth			case content_type {
596*37da2899SCharles.Forsyth			SSL_APPLICATION_DATA =>
597*37da2899SCharles.Forsyth				break;
598*37da2899SCharles.Forsyth			SSL_ALERT =>
599*37da2899SCharles.Forsyth				if(SSL_DEBUG)
600*37da2899SCharles.Forsyth					log("ssl3: expect application data, got alert: [" + bastr(buf[3:m]) +"]");
601*37da2899SCharles.Forsyth				return 0;
602*37da2899SCharles.Forsyth			SSL_HANDSHAKE =>
603*37da2899SCharles.Forsyth				if(SSL_DEBUG)
604*37da2899SCharles.Forsyth					log("ssl3: expect application data, got handshake message");
605*37da2899SCharles.Forsyth				return 0;
606*37da2899SCharles.Forsyth			SSL_CHANGE_CIPHER_SPEC =>
607*37da2899SCharles.Forsyth				if(SSL_DEBUG)
608*37da2899SCharles.Forsyth					log("ssl3: dynamic change cipher spec not supported yet");
609*37da2899SCharles.Forsyth				return 0;
610*37da2899SCharles.Forsyth			}
611*37da2899SCharles.Forsyth			return m-3;
612*37da2899SCharles.Forsyth		}
613*37da2899SCharles.Forsyth		else
614*37da2899SCharles.Forsyth			return sys->read(fd, a, n);
615*37da2899SCharles.Forsyth	}
616*37da2899SCharles.Forsyth	else {
617*37da2899SCharles.Forsyth		q := ctx.in_queue;
618*37da2899SCharles.Forsyth		got := 0;
619*37da2899SCharles.Forsyth		if(q.fragment) {
620*37da2899SCharles.Forsyth			d := (hd q.data).data;
621*37da2899SCharles.Forsyth			m := q.e - q.b;
622*37da2899SCharles.Forsyth			i := q.e - q.fragment;
623*37da2899SCharles.Forsyth			if(q.fragment > n) {
624*37da2899SCharles.Forsyth				a[0:] = d[i:i+n];
625*37da2899SCharles.Forsyth				q.fragment -= n;
626*37da2899SCharles.Forsyth				got = n;
627*37da2899SCharles.Forsyth			}
628*37da2899SCharles.Forsyth			else {
629*37da2899SCharles.Forsyth				a[0:] = d[i:q.e];
630*37da2899SCharles.Forsyth				got = q.fragment;
631*37da2899SCharles.Forsyth				q.fragment = 0;
632*37da2899SCharles.Forsyth			}
633*37da2899SCharles.Forsyth		}
634*37da2899SCharles.Forsythout:
635*37da2899SCharles.Forsyth		while(got < n) {
636*37da2899SCharles.Forsyth			err := q.read(ctx, ctx.c.dfd);
637*37da2899SCharles.Forsyth			if(err != "") {
638*37da2899SCharles.Forsyth				if(SSL_DEBUG)
639*37da2899SCharles.Forsyth					log("ssl3: read: " + err);
640*37da2899SCharles.Forsyth				break;
641*37da2899SCharles.Forsyth			}
642*37da2899SCharles.Forsyth			r := hd q.data;
643*37da2899SCharles.Forsyth			if(ctx.status & SSL3_RECORD) {
644*37da2899SCharles.Forsyth				case r.content_type {
645*37da2899SCharles.Forsyth				SSL_APPLICATION_DATA =>
646*37da2899SCharles.Forsyth					break;
647*37da2899SCharles.Forsyth				SSL_ALERT =>
648*37da2899SCharles.Forsyth					if(SSL_DEBUG)
649*37da2899SCharles.Forsyth						log("ssl3: read: got alert\n\t\t" + bastr(r.data[q.b:q.e]));
650*37da2899SCharles.Forsyth					# delete session id
651*37da2899SCharles.Forsyth					ctx.session.session_id = nil;
652*37da2899SCharles.Forsyth					ctx.status &= ~IN_READY;
653*37da2899SCharles.Forsyth					break out;
654*37da2899SCharles.Forsyth				SSL_CHANGE_CIPHER_SPEC =>
655*37da2899SCharles.Forsyth					if(SSL_DEBUG)
656*37da2899SCharles.Forsyth						log("ssl3: read: got change cipher spec\n");
657*37da2899SCharles.Forsyth				SSL_HANDSHAKE =>
658*37da2899SCharles.Forsyth					if(SSL_DEBUG)
659*37da2899SCharles.Forsyth						log("ssl3: read: got handshake data\n");
660*37da2899SCharles.Forsyth					#do_handshake(ctx, r); # ?
661*37da2899SCharles.Forsyth				* =>
662*37da2899SCharles.Forsyth					if(SSL_DEBUG)
663*37da2899SCharles.Forsyth						log("ssl3: read: unknown data\n");
664*37da2899SCharles.Forsyth				}
665*37da2899SCharles.Forsyth			}
666*37da2899SCharles.Forsyth
667*37da2899SCharles.Forsyth			if((n - got) <= (q.e - q.b)) {
668*37da2899SCharles.Forsyth				a[got:] = r.data[q.b:q.b+n-got];
669*37da2899SCharles.Forsyth				q.fragment = q.e - q.b - n + got;
670*37da2899SCharles.Forsyth				got = n;
671*37da2899SCharles.Forsyth			}
672*37da2899SCharles.Forsyth			else {
673*37da2899SCharles.Forsyth				a[got:] = r.data[q.b:q.e];
674*37da2899SCharles.Forsyth				q.fragment = 0;
675*37da2899SCharles.Forsyth				got += q.e - q.b;
676*37da2899SCharles.Forsyth			}
677*37da2899SCharles.Forsyth		}
678*37da2899SCharles.Forsyth		if(SSL_DEBUG)
679*37da2899SCharles.Forsyth			log(sys->sprint("ssl3: read: returning %d bytes\n", got));
680*37da2899SCharles.Forsyth		return got;
681*37da2899SCharles.Forsyth	}
682*37da2899SCharles.Forsyth}
683*37da2899SCharles.Forsyth
684*37da2899SCharles.ForsythContext.write(ctx: self ref Context, a: array of byte, n: int): int
685*37da2899SCharles.Forsyth{
686*37da2899SCharles.Forsyth	if(ctx.state != STATE_EXIT || !(ctx.status & OUT_READY))
687*37da2899SCharles.Forsyth		return-1;
688*37da2899SCharles.Forsyth
689*37da2899SCharles.Forsyth	if(ctx.out_queue.data != nil)
690*37da2899SCharles.Forsyth		record_write_queue(ctx);
691*37da2899SCharles.Forsyth
692*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL) {
693*37da2899SCharles.Forsyth		if(ctx.status & SSL3_RECORD) {
694*37da2899SCharles.Forsyth			buf := array [n+3] of byte;
695*37da2899SCharles.Forsyth			buf[0] = byte SSL_APPLICATION_DATA;
696*37da2899SCharles.Forsyth			buf[1:] = SSL_VERSION_3_0;
697*37da2899SCharles.Forsyth			buf[3:] = a[0:n];
698*37da2899SCharles.Forsyth			n = sys->write(ctx.c.dfd, buf, n+3);
699*37da2899SCharles.Forsyth			if(n > 0)
700*37da2899SCharles.Forsyth				n -= 3;
701*37da2899SCharles.Forsyth		}
702*37da2899SCharles.Forsyth		else
703*37da2899SCharles.Forsyth			n = sys->write(ctx.c.dfd, a, n);
704*37da2899SCharles.Forsyth	}
705*37da2899SCharles.Forsyth	else {
706*37da2899SCharles.Forsyth		q := ctx.out_queue;
707*37da2899SCharles.Forsyth		v := SSL_VERSION_2_0;
708*37da2899SCharles.Forsyth		if(ctx.status&SSL3_RECORD)
709*37da2899SCharles.Forsyth			v = SSL_VERSION_3_0;
710*37da2899SCharles.Forsyth		for(i := 0; i < n;){
711*37da2899SCharles.Forsyth			m := n-i;
712*37da2899SCharles.Forsyth			if(m > q.length)
713*37da2899SCharles.Forsyth				m = q.length;
714*37da2899SCharles.Forsyth			r := ref Record(SSL_APPLICATION_DATA, v, a[i:i+m]);
715*37da2899SCharles.Forsyth			record_write(r, ctx); # return error?
716*37da2899SCharles.Forsyth			i += m;
717*37da2899SCharles.Forsyth		}
718*37da2899SCharles.Forsyth	}
719*37da2899SCharles.Forsyth	return n;
720*37da2899SCharles.Forsyth}
721*37da2899SCharles.Forsyth
722*37da2899SCharles.Forsythdevssl_read(ctx: ref Context): (ref Record, string)
723*37da2899SCharles.Forsyth{
724*37da2899SCharles.Forsyth	buf := array [Sys->ATOMICIO] of byte;
725*37da2899SCharles.Forsyth	r: ref Record;
726*37da2899SCharles.Forsyth	c := ctx.c;
727*37da2899SCharles.Forsyth
728*37da2899SCharles.Forsyth	n := sys->read(c.dfd, buf, 3);
729*37da2899SCharles.Forsyth	if(n < 0)
730*37da2899SCharles.Forsyth		return (nil, sys->sprint("record read: read failure: %r"));
731*37da2899SCharles.Forsyth
732*37da2899SCharles.Forsyth	# in case of undetermined, do auto record version detection
733*37da2899SCharles.Forsyth	if((ctx.state == SSL2_STATE_SERVER_HELLO) &&
734*37da2899SCharles.Forsyth		(ctx.status & SSL2_HANDSHAKE) && (ctx.status & SSL3_HANDSHAKE)) {
735*37da2899SCharles.Forsyth
736*37da2899SCharles.Forsyth		fstatus := sys->open(ctx.c.dir + "/status", Sys->OREAD);
737*37da2899SCharles.Forsyth		if(fstatus == nil)
738*37da2899SCharles.Forsyth			return (nil, "open status: " + sys->sprint("%r"));
739*37da2899SCharles.Forsyth		status := array [64] of byte;
740*37da2899SCharles.Forsyth		nbyte := sys->read(fstatus, status, len status);
741*37da2899SCharles.Forsyth		if(nbyte != 1)
742*37da2899SCharles.Forsyth			return (nil, "read status: " + sys->sprint("%r"));
743*37da2899SCharles.Forsyth
744*37da2899SCharles.Forsyth		ver := int status[0];
745*37da2899SCharles.Forsyth
746*37da2899SCharles.Forsyth		if(SSL_DEBUG)
747*37da2899SCharles.Forsyth			log("ssl3: auto record version detect as: " + string ver);
748*37da2899SCharles.Forsyth
749*37da2899SCharles.Forsyth		# assert ctx.status & SSL2_RECORD true ? before reset
750*37da2899SCharles.Forsyth		if(ver == 2) {
751*37da2899SCharles.Forsyth			ctx.status &= ~SSL3_RECORD;
752*37da2899SCharles.Forsyth			ctx.status |= SSL2_HANDSHAKE;
753*37da2899SCharles.Forsyth			ctx.status &= ~SSL3_HANDSHAKE;
754*37da2899SCharles.Forsyth		}
755*37da2899SCharles.Forsyth		else {
756*37da2899SCharles.Forsyth			ctx.status |= SSL3_RECORD;
757*37da2899SCharles.Forsyth		}
758*37da2899SCharles.Forsyth	}
759*37da2899SCharles.Forsyth
760*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD) {
761*37da2899SCharles.Forsyth		if(n < 3)
762*37da2899SCharles.Forsyth			return (nil, sys->sprint("record read: read failure: %r"));
763*37da2899SCharles.Forsyth
764*37da2899SCharles.Forsyth		# assert only major version number
765*37da2899SCharles.Forsyth		if(buf[1] != SSL_VERSION_3_0[0])
766*37da2899SCharles.Forsyth			return (nil, "record read: version mismatch");
767*37da2899SCharles.Forsyth
768*37da2899SCharles.Forsyth		case int buf[0] {
769*37da2899SCharles.Forsyth		SSL_ALERT =>
770*37da2899SCharles.Forsyth			n = sys->read(c.dfd, buf, 5); # read in header plus rest
771*37da2899SCharles.Forsyth			if(n != 5)
772*37da2899SCharles.Forsyth				return (nil, sys->sprint("read alert failed: %r"));
773*37da2899SCharles.Forsyth			r = ref Record(SSL_ALERT, SSL_VERSION_3_0, buf[3:5]);
774*37da2899SCharles.Forsyth
775*37da2899SCharles.Forsyth		SSL_CHANGE_CIPHER_SPEC =>
776*37da2899SCharles.Forsyth			n = sys->read(c.dfd, buf, 4); # read in header plus rest
777*37da2899SCharles.Forsyth			if(n != 4)
778*37da2899SCharles.Forsyth				return (nil, sys->sprint("read change_cipher_spec failed: %r"));
779*37da2899SCharles.Forsyth			r = ref Record(SSL_CHANGE_CIPHER_SPEC, SSL_VERSION_3_0, buf[3:4]);
780*37da2899SCharles.Forsyth
781*37da2899SCharles.Forsyth		SSL_HANDSHAKE =>
782*37da2899SCharles.Forsyth			n = sys->read(c.dfd, buf, 7); # header + msg length
783*37da2899SCharles.Forsyth			if(n != 7)
784*37da2899SCharles.Forsyth				return (nil, sys->sprint("read handshake header + msg length failed: %r"));
785*37da2899SCharles.Forsyth			m := int_decode(buf[4:7]);
786*37da2899SCharles.Forsyth			if(m < 0)
787*37da2899SCharles.Forsyth				return (nil, "read handshake failed: unexpected length");
788*37da2899SCharles.Forsyth			data := array [m+4] of byte;
789*37da2899SCharles.Forsyth			data[0:] = buf[3:7]; # msg type + length
790*37da2899SCharles.Forsyth			if(m != 0) {
791*37da2899SCharles.Forsyth				# need exact m bytes (exclude header), otherwise failure
792*37da2899SCharles.Forsyth				remain := m;
793*37da2899SCharles.Forsyth				now := 4;
794*37da2899SCharles.Forsyth				while(remain > 0) {
795*37da2899SCharles.Forsyth					n = sys->read(c.dfd, buf, remain+3); # header + msg
796*37da2899SCharles.Forsyth					if(n < 3 || int buf[0] != SSL_HANDSHAKE)
797*37da2899SCharles.Forsyth						return (nil, sys->sprint("read handshake msg body failed: %r"));
798*37da2899SCharles.Forsyth					sys->print("expect %d, got %d bytes\n", m, n-3);
799*37da2899SCharles.Forsyth					remain -= n - 3;
800*37da2899SCharles.Forsyth					data[now:] = buf[3:n];
801*37da2899SCharles.Forsyth					now += n - 3;
802*37da2899SCharles.Forsyth				}
803*37da2899SCharles.Forsyth			}
804*37da2899SCharles.Forsyth
805*37da2899SCharles.Forsyth			r = ref Record(SSL_HANDSHAKE, SSL_VERSION_3_0, data);
806*37da2899SCharles.Forsyth		* =>
807*37da2899SCharles.Forsyth			return (nil, "trying to read unknown protocol message");
808*37da2899SCharles.Forsyth		}
809*37da2899SCharles.Forsyth
810*37da2899SCharles.Forsyth		if(SSL_DEBUG)
811*37da2899SCharles.Forsyth			log("ssl3: record_read: \n\theader = \n\t\t" + bastr(buf[0:3])
812*37da2899SCharles.Forsyth			+ "\n\tdata = \n\t\t" + bastr(r.data) + "\n");
813*37da2899SCharles.Forsyth	}
814*37da2899SCharles.Forsyth	# v2 record layer
815*37da2899SCharles.Forsyth	else {
816*37da2899SCharles.Forsyth		# assume the handshake record size less than Sys->ATOMICIO
817*37da2899SCharles.Forsyth		# in most case, this is ok
818*37da2899SCharles.Forsyth		if(n == 3) {
819*37da2899SCharles.Forsyth			n = sys->read(c.dfd, buf[3:], Sys->ATOMICIO - 3);
820*37da2899SCharles.Forsyth			if(n < 0)
821*37da2899SCharles.Forsyth				return (nil, sys->sprint("v2 record read: read failure: %r"));
822*37da2899SCharles.Forsyth		}
823*37da2899SCharles.Forsyth
824*37da2899SCharles.Forsyth		r = ref Record(SSL_V2HANDSHAKE, SSL_VERSION_2_0, buf[0:n+3]);
825*37da2899SCharles.Forsyth
826*37da2899SCharles.Forsyth		if(SSL_DEBUG)
827*37da2899SCharles.Forsyth			log("ssl3: v2 record_read: \n\tdata = \n\t\t" + bastr(r.data) + "\n");
828*37da2899SCharles.Forsyth	}
829*37da2899SCharles.Forsyth
830*37da2899SCharles.Forsyth	return (r, nil);
831*37da2899SCharles.Forsyth}
832*37da2899SCharles.Forsyth
833*37da2899SCharles.Forsythrecord_read(ctx: ref Context): (ref Record, string)
834*37da2899SCharles.Forsyth{
835*37da2899SCharles.Forsyth	q := ctx.in_queue;
836*37da2899SCharles.Forsyth	if(q.fragment == 0) {
837*37da2899SCharles.Forsyth		err := q.read(ctx, ctx.c.dfd);
838*37da2899SCharles.Forsyth		if(err != "")
839*37da2899SCharles.Forsyth			return (nil, err);
840*37da2899SCharles.Forsyth		q.fragment = q.e - q.b;
841*37da2899SCharles.Forsyth	}
842*37da2899SCharles.Forsyth
843*37da2899SCharles.Forsyth	r := hd q.data;
844*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD) {
845*37da2899SCharles.Forsyth		# confirm only major version number
846*37da2899SCharles.Forsyth		if(r.version[0] != SSL_VERSION_3_0[0])
847*37da2899SCharles.Forsyth			return (nil, "record read: not v3 record");
848*37da2899SCharles.Forsyth
849*37da2899SCharles.Forsyth		case r.content_type {
850*37da2899SCharles.Forsyth		SSL_ALERT =>
851*37da2899SCharles.Forsyth			a := array [2] of byte;
852*37da2899SCharles.Forsyth			n := fetch_data(ctx, a, 2);
853*37da2899SCharles.Forsyth			if(n != 2)
854*37da2899SCharles.Forsyth				return (nil, "read alert failed");
855*37da2899SCharles.Forsyth			r = ref Record(SSL_ALERT, SSL_VERSION_3_0, a);
856*37da2899SCharles.Forsyth
857*37da2899SCharles.Forsyth		SSL_CHANGE_CIPHER_SPEC =>
858*37da2899SCharles.Forsyth			a := array [1] of byte;
859*37da2899SCharles.Forsyth			n := fetch_data(ctx, a, 1);
860*37da2899SCharles.Forsyth			if(n != 1)
861*37da2899SCharles.Forsyth				return (nil, "read change_cipher_spec failed");
862*37da2899SCharles.Forsyth			r = ref Record(SSL_CHANGE_CIPHER_SPEC, SSL_VERSION_3_0, a);
863*37da2899SCharles.Forsyth
864*37da2899SCharles.Forsyth		SSL_HANDSHAKE =>
865*37da2899SCharles.Forsyth			a := array [4] of byte;
866*37da2899SCharles.Forsyth			n := fetch_data(ctx, a, 4);
867*37da2899SCharles.Forsyth			if(n != 4)
868*37da2899SCharles.Forsyth				return (nil, "read message length failed");
869*37da2899SCharles.Forsyth			m := int_decode(a[1:]);
870*37da2899SCharles.Forsyth			if(m < 0)
871*37da2899SCharles.Forsyth				return (nil, "unexpected handshake message length");
872*37da2899SCharles.Forsyth			b := array [m+4] of byte;
873*37da2899SCharles.Forsyth			b[0:] = a;
874*37da2899SCharles.Forsyth			n = fetch_data(ctx, b[4:], m);
875*37da2899SCharles.Forsyth			if(n != m)
876*37da2899SCharles.Forsyth				return (nil, "read message body failed");
877*37da2899SCharles.Forsyth			r = ref Record(SSL_HANDSHAKE, SSL_VERSION_3_0, b);
878*37da2899SCharles.Forsyth		* =>
879*37da2899SCharles.Forsyth			return (nil, "trying to read unknown protocol message");
880*37da2899SCharles.Forsyth		}
881*37da2899SCharles.Forsyth	}
882*37da2899SCharles.Forsyth	# v2 record layer
883*37da2899SCharles.Forsyth	else {
884*37da2899SCharles.Forsyth		r = ref Record(SSL_V2HANDSHAKE, SSL_VERSION_2_0, r.data[q.b:q.e]);
885*37da2899SCharles.Forsyth		q.fragment = 0;
886*37da2899SCharles.Forsyth	}
887*37da2899SCharles.Forsyth
888*37da2899SCharles.Forsyth	return (r, nil);
889*37da2899SCharles.Forsyth}
890*37da2899SCharles.Forsyth
891*37da2899SCharles.Forsythfetch_data(ctx: ref Context, a: array of byte, n: int): int
892*37da2899SCharles.Forsyth{
893*37da2899SCharles.Forsyth	q := ctx.in_queue;
894*37da2899SCharles.Forsyth	r := hd q.data;
895*37da2899SCharles.Forsyth
896*37da2899SCharles.Forsyth	got := 0;
897*37da2899SCharles.Forsyth	cnt := -1;
898*37da2899SCharles.Forsythout:
899*37da2899SCharles.Forsyth	while(got < n) {
900*37da2899SCharles.Forsyth		if(q.fragment) {
901*37da2899SCharles.Forsyth			cnt = r.content_type;
902*37da2899SCharles.Forsyth			i := q.e - q.fragment;
903*37da2899SCharles.Forsyth			if(n-got <= q.fragment) {
904*37da2899SCharles.Forsyth				a[got:] = r.data[i:i+n-got];
905*37da2899SCharles.Forsyth				q.fragment -= n - got;
906*37da2899SCharles.Forsyth				got = n;
907*37da2899SCharles.Forsyth			}
908*37da2899SCharles.Forsyth			else {
909*37da2899SCharles.Forsyth				a[got:] = r.data[i:q.e];
910*37da2899SCharles.Forsyth				got += q.fragment;
911*37da2899SCharles.Forsyth				q.fragment = 0;
912*37da2899SCharles.Forsyth			}
913*37da2899SCharles.Forsyth		}
914*37da2899SCharles.Forsyth		else {
915*37da2899SCharles.Forsyth			err := q.read(ctx, ctx.c.dfd);
916*37da2899SCharles.Forsyth			if(err != "")
917*37da2899SCharles.Forsyth				break out;
918*37da2899SCharles.Forsyth			if(cnt == -1)
919*37da2899SCharles.Forsyth				cnt = r.content_type;
920*37da2899SCharles.Forsyth			if(ctx.status & SSL3_RECORD) {
921*37da2899SCharles.Forsyth				case r.content_type {
922*37da2899SCharles.Forsyth				SSL_APPLICATION_DATA =>
923*37da2899SCharles.Forsyth					break;
924*37da2899SCharles.Forsyth				* =>
925*37da2899SCharles.Forsyth					if(cnt != r.content_type)
926*37da2899SCharles.Forsyth						break out;
927*37da2899SCharles.Forsyth				}
928*37da2899SCharles.Forsyth			}
929*37da2899SCharles.Forsyth			else {
930*37da2899SCharles.Forsyth				r.content_type = SSL_V2HANDSHAKE;
931*37da2899SCharles.Forsyth			}
932*37da2899SCharles.Forsyth		}
933*37da2899SCharles.Forsyth	}
934*37da2899SCharles.Forsyth	return got;
935*37da2899SCharles.Forsyth}
936*37da2899SCharles.Forsyth
937*37da2899SCharles.Forsythrecord_write(r: ref Record, ctx: ref Context)
938*37da2899SCharles.Forsyth{
939*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL) {
940*37da2899SCharles.Forsyth		buf: array of byte;
941*37da2899SCharles.Forsyth		n: int;
942*37da2899SCharles.Forsyth		c := ctx.c;
943*37da2899SCharles.Forsyth
944*37da2899SCharles.Forsyth		if(ctx.status & SSL3_RECORD) {
945*37da2899SCharles.Forsyth			buf = array [3 + len r.data] of byte;
946*37da2899SCharles.Forsyth			buf[0] = byte r.content_type;
947*37da2899SCharles.Forsyth			buf[1:] = r.version;
948*37da2899SCharles.Forsyth			buf[3:] = r.data;
949*37da2899SCharles.Forsyth			n = sys->write(c.dfd, buf, len buf);
950*37da2899SCharles.Forsyth			if(n < 0 || n != len buf) {
951*37da2899SCharles.Forsyth				if(SSL_DEBUG)
952*37da2899SCharles.Forsyth					log(sys->sprint("ssl3: v3 record write error: %d %r", n));
953*37da2899SCharles.Forsyth				return; # don't terminated until alerts being read
954*37da2899SCharles.Forsyth			}
955*37da2899SCharles.Forsyth		}
956*37da2899SCharles.Forsyth		else {
957*37da2899SCharles.Forsyth			buf = r.data;
958*37da2899SCharles.Forsyth			n = sys->write(c.dfd, buf, len buf);
959*37da2899SCharles.Forsyth			if(n < 0 || n != len buf) {
960*37da2899SCharles.Forsyth				if(SSL_DEBUG)
961*37da2899SCharles.Forsyth					log(sys->sprint("ssl3: v2 record write error: %d %r", n));
962*37da2899SCharles.Forsyth				return; # don't terminated until alerts being read
963*37da2899SCharles.Forsyth			}
964*37da2899SCharles.Forsyth		}
965*37da2899SCharles.Forsyth	}
966*37da2899SCharles.Forsyth	else
967*37da2899SCharles.Forsyth		ctx.out_queue.write(ctx, ctx.c.dfd, r);
968*37da2899SCharles.Forsyth
969*37da2899SCharles.Forsyth	# if(SSL_DEBUG)
970*37da2899SCharles.Forsyth	#	log("ssl3: record_write: \n\t\t" + bastr(buf) + "\n");
971*37da2899SCharles.Forsyth}
972*37da2899SCharles.Forsyth
973*37da2899SCharles.ForsythRecordQueue.new(): ref RecordQueue
974*37da2899SCharles.Forsyth{
975*37da2899SCharles.Forsyth	q := ref RecordQueue(
976*37da2899SCharles.Forsyth		ref MacState.null(0),
977*37da2899SCharles.Forsyth		ref CipherState.null(1),
978*37da2899SCharles.Forsyth		1 << 15,
979*37da2899SCharles.Forsyth		array [2] of { * => 0},
980*37da2899SCharles.Forsyth		nil,
981*37da2899SCharles.Forsyth		0,
982*37da2899SCharles.Forsyth		0, # b
983*37da2899SCharles.Forsyth		0  # e
984*37da2899SCharles.Forsyth	);
985*37da2899SCharles.Forsyth	return q;
986*37da2899SCharles.Forsyth}
987*37da2899SCharles.Forsyth
988*37da2899SCharles.ForsythRecordQueue.read(q: self ref RecordQueue, ctx: ref Context, fd: ref Sys->FD): string
989*37da2899SCharles.Forsyth{
990*37da2899SCharles.Forsyth	r := hd q.data;
991*37da2899SCharles.Forsyth	a := r.data;
992*37da2899SCharles.Forsyth	if(ensure(fd, a, 2) < 0)
993*37da2899SCharles.Forsyth		return "no more data";
994*37da2899SCharles.Forsyth	# auto record version detection
995*37da2899SCharles.Forsyth	m, h, pad: int = 0;
996*37da2899SCharles.Forsyth	if(int a[0] < 20 || int a[0] > 23) {
997*37da2899SCharles.Forsyth		ctx.status &= ~SSL3_RECORD;
998*37da2899SCharles.Forsyth		if(int a[0] & 16r80) {
999*37da2899SCharles.Forsyth			h = 2;
1000*37da2899SCharles.Forsyth			m = ((int a[0] & 16r7f) << 8) | int a[1];
1001*37da2899SCharles.Forsyth			pad = 0;
1002*37da2899SCharles.Forsyth		} else {
1003*37da2899SCharles.Forsyth			h = 3;
1004*37da2899SCharles.Forsyth			m = ((int a[0] & 16r3f) << 8) | int a[1];
1005*37da2899SCharles.Forsyth			if(ensure(fd, a[2:], 1) < 0)
1006*37da2899SCharles.Forsyth				return "bad v2 record";
1007*37da2899SCharles.Forsyth			pad = int a[2];
1008*37da2899SCharles.Forsyth			if(pad > m)
1009*37da2899SCharles.Forsyth				return "bad v2 pad";
1010*37da2899SCharles.Forsyth		}
1011*37da2899SCharles.Forsyth		r.content_type = SSL_V2HANDSHAKE;
1012*37da2899SCharles.Forsyth		r.version = SSL_VERSION_2_0;
1013*37da2899SCharles.Forsyth	}
1014*37da2899SCharles.Forsyth	else {
1015*37da2899SCharles.Forsyth		ctx.status |= SSL3_RECORD;
1016*37da2899SCharles.Forsyth		h = 5;
1017*37da2899SCharles.Forsyth		if(ensure(fd, a[2:], 3) < 0)
1018*37da2899SCharles.Forsyth			return "bad v3 record";
1019*37da2899SCharles.Forsyth		m = ((int a[3]) << 8) | int a[4];
1020*37da2899SCharles.Forsyth		r.content_type = int a[0];
1021*37da2899SCharles.Forsyth		r.version = a[1:3];
1022*37da2899SCharles.Forsyth	}
1023*37da2899SCharles.Forsyth	if(ensure(fd, a[h:], m) < 0)
1024*37da2899SCharles.Forsyth#		return "data too short";
1025*37da2899SCharles.Forsyth		return sys->sprint("data too short wanted %d", m);
1026*37da2899SCharles.Forsyth	if(SSL_DEBUG) {
1027*37da2899SCharles.Forsyth		log("ssl3: record read\n\tbefore decrypt\n\t\t" + bastr(a[0:m+h]));
1028*37da2899SCharles.Forsyth		log(sys->sprint("SSL3=%d\n", ctx.status & SSL3_RECORD));
1029*37da2899SCharles.Forsyth	}
1030*37da2899SCharles.Forsyth
1031*37da2899SCharles.Forsyth	# decrypt (data, pad, mac)
1032*37da2899SCharles.Forsyth	pick dec := q.cipherState {
1033*37da2899SCharles.Forsyth	null =>
1034*37da2899SCharles.Forsyth	rc4 =>
1035*37da2899SCharles.Forsyth		keyring->rc4(dec.es, a[h:], m);
1036*37da2899SCharles.Forsyth		if (SSL_DEBUG) log("rc4 1");
1037*37da2899SCharles.Forsyth	descbc =>
1038*37da2899SCharles.Forsyth		keyring->descbc(dec.es, a[h:], m, 1);
1039*37da2899SCharles.Forsyth		if (SSL_DEBUG) log("descbc 1");
1040*37da2899SCharles.Forsyth	ideacbc =>
1041*37da2899SCharles.Forsyth		keyring->ideacbc(dec.es, a[h:], m, 1);
1042*37da2899SCharles.Forsyth		if (SSL_DEBUG) log("ideacbc 1");
1043*37da2899SCharles.Forsyth	* =>
1044*37da2899SCharles.Forsyth	}
1045*37da2899SCharles.Forsyth
1046*37da2899SCharles.Forsyth	if(SSL_DEBUG)
1047*37da2899SCharles.Forsyth		log("ssl3: record read\n\tafter decrypt\n\t\t" + bastr(a[0:m]));
1048*37da2899SCharles.Forsyth
1049*37da2899SCharles.Forsyth	idata, imac, ipad: int = 0;
1050*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD) {
1051*37da2899SCharles.Forsyth		if(q.cipherState.block_size > 1){
1052*37da2899SCharles.Forsyth			pad = int a[h + m - 1];
1053*37da2899SCharles.Forsyth			if(pad >= q.cipherState.block_size)
1054*37da2899SCharles.Forsyth				return "bad v3 pad";
1055*37da2899SCharles.Forsyth			# pad++;
1056*37da2899SCharles.Forsyth			ipad = h+m-pad-1;
1057*37da2899SCharles.Forsyth		}
1058*37da2899SCharles.Forsyth		else
1059*37da2899SCharles.Forsyth			ipad = h+m-pad;
1060*37da2899SCharles.Forsyth		imac = ipad - q.macState.hash_size;
1061*37da2899SCharles.Forsyth		idata = h;
1062*37da2899SCharles.Forsyth	}
1063*37da2899SCharles.Forsyth	else {
1064*37da2899SCharles.Forsyth		imac = h;
1065*37da2899SCharles.Forsyth		idata = imac + q.macState.hash_size;
1066*37da2899SCharles.Forsyth		ipad = h + m - pad;
1067*37da2899SCharles.Forsyth	}
1068*37da2899SCharles.Forsyth	if(tagof q.macState != tagof MacState.null) {
1069*37da2899SCharles.Forsyth		if (ctx.status & SSL3_RECORD)
1070*37da2899SCharles.Forsyth			mac := q.calcmac(ctx, r.content_type, a, idata, imac-idata);
1071*37da2899SCharles.Forsyth		else
1072*37da2899SCharles.Forsyth			mac = q.calcmac(ctx, r.content_type, a, idata, ipad+pad-idata);
1073*37da2899SCharles.Forsyth		if(bytes_cmp(mac, a[imac:imac+len mac]) < 0)
1074*37da2899SCharles.Forsyth			return "bad mac";
1075*37da2899SCharles.Forsyth	}
1076*37da2899SCharles.Forsyth	q.b = idata;
1077*37da2899SCharles.Forsyth	if (ctx.status & SSL3_RECORD)
1078*37da2899SCharles.Forsyth		q.e = imac;
1079*37da2899SCharles.Forsyth	else
1080*37da2899SCharles.Forsyth		q.e = ipad;
1081*37da2899SCharles.Forsyth	q.fragment = q.e - q.b;
1082*37da2899SCharles.Forsyth
1083*37da2899SCharles.Forsyth	if((++q.sequence_numbers[0] == 0) && (ctx.status&SSL3_RECORD))
1084*37da2899SCharles.Forsyth		++q.sequence_numbers[1];
1085*37da2899SCharles.Forsyth
1086*37da2899SCharles.Forsyth	return "";
1087*37da2899SCharles.Forsyth}
1088*37da2899SCharles.Forsyth
1089*37da2899SCharles.Forsythensure(fd: ref Sys->FD, a: array of byte, n: int): int
1090*37da2899SCharles.Forsyth{
1091*37da2899SCharles.Forsyth	i, m: int = 0;
1092*37da2899SCharles.Forsyth	while(i < n) {
1093*37da2899SCharles.Forsyth		m = sys->read(fd, a[i:], n - i);
1094*37da2899SCharles.Forsyth		if(m <= 0) {
1095*37da2899SCharles.Forsyth			return -1;
1096*37da2899SCharles.Forsyth		}
1097*37da2899SCharles.Forsyth		i += m;
1098*37da2899SCharles.Forsyth	}
1099*37da2899SCharles.Forsyth	return n;
1100*37da2899SCharles.Forsyth}
1101*37da2899SCharles.Forsyth
1102*37da2899SCharles.ForsythRecordQueue.write(q: self ref RecordQueue, ctx: ref Context, fd: ref Sys->FD,
1103*37da2899SCharles.Forsyth	r: ref Record): string
1104*37da2899SCharles.Forsyth{
1105*37da2899SCharles.Forsyth	m := len r.data;
1106*37da2899SCharles.Forsyth	h, pad: int = 0;
1107*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD) {
1108*37da2899SCharles.Forsyth		h = 5;
1109*37da2899SCharles.Forsyth		if(q.cipherState.block_size > 1) {
1110*37da2899SCharles.Forsyth			pad = (m+q.macState.hash_size+1)%q.cipherState.block_size;
1111*37da2899SCharles.Forsyth			if (pad)
1112*37da2899SCharles.Forsyth				pad = q.cipherState.block_size - pad;
1113*37da2899SCharles.Forsyth		}
1114*37da2899SCharles.Forsyth	}
1115*37da2899SCharles.Forsyth	else {
1116*37da2899SCharles.Forsyth		h = 2;
1117*37da2899SCharles.Forsyth		if(q.cipherState.block_size > 1) {
1118*37da2899SCharles.Forsyth			pad = m%q.cipherState.block_size;
1119*37da2899SCharles.Forsyth			if(pad) {
1120*37da2899SCharles.Forsyth				pad = q.cipherState.block_size - pad;
1121*37da2899SCharles.Forsyth				h++;
1122*37da2899SCharles.Forsyth			}
1123*37da2899SCharles.Forsyth		}
1124*37da2899SCharles.Forsyth	}
1125*37da2899SCharles.Forsyth
1126*37da2899SCharles.Forsyth	m += pad + q.macState.hash_size;
1127*37da2899SCharles.Forsyth	if ((ctx.status & SSL3_RECORD) && q.cipherState.block_size > 1)
1128*37da2899SCharles.Forsyth		m++;
1129*37da2899SCharles.Forsyth	a := array [h+m] of byte;
1130*37da2899SCharles.Forsyth
1131*37da2899SCharles.Forsyth	idata, imac, ipad: int = 0;
1132*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD) {
1133*37da2899SCharles.Forsyth		a[0] = byte r.content_type;
1134*37da2899SCharles.Forsyth		a[1:] = r.version;
1135*37da2899SCharles.Forsyth		a[3] = byte (m >> 8);			#CJL - netscape ssl3 traces do not show top bit set
1136*37da2899SCharles.Forsyth#		a[3] = byte ((m >> 8) | 16r80);	#CJL
1137*37da2899SCharles.Forsyth#		a[3] = byte (m | 16r8000) >> 8;
1138*37da2899SCharles.Forsyth		a[4] = byte m;
1139*37da2899SCharles.Forsyth		idata = h;
1140*37da2899SCharles.Forsyth		imac = idata + len r.data;
1141*37da2899SCharles.Forsyth		ipad = imac + q.macState.hash_size;
1142*37da2899SCharles.Forsyth		if (q.cipherState.block_size > 1)
1143*37da2899SCharles.Forsyth			a[h+m-1] = byte pad;
1144*37da2899SCharles.Forsyth	}
1145*37da2899SCharles.Forsyth	else {
1146*37da2899SCharles.Forsyth		if(pad) {
1147*37da2899SCharles.Forsyth			a[0] = byte m >> 8;
1148*37da2899SCharles.Forsyth			a[2] = byte pad;
1149*37da2899SCharles.Forsyth		}
1150*37da2899SCharles.Forsyth		else
1151*37da2899SCharles.Forsyth			a[0] = byte ((m >> 8) | 16r80);
1152*37da2899SCharles.Forsyth		a[1] = byte m;
1153*37da2899SCharles.Forsyth		imac = h;
1154*37da2899SCharles.Forsyth		idata = imac + q.macState.hash_size;
1155*37da2899SCharles.Forsyth		ipad = idata + len r.data;
1156*37da2899SCharles.Forsyth	}
1157*37da2899SCharles.Forsyth	a[idata:] = r.data;
1158*37da2899SCharles.Forsyth	if(pad)
1159*37da2899SCharles.Forsyth		a[ipad:] = array [pad] of { * => byte (pad-1)};
1160*37da2899SCharles.Forsyth
1161*37da2899SCharles.Forsyth	if(tagof q.macState != tagof MacState.null) {
1162*37da2899SCharles.Forsyth		if (ctx.status & SSL3_RECORD)
1163*37da2899SCharles.Forsyth			a[imac:] = q.calcmac(ctx, r.content_type, a, idata, len r.data);
1164*37da2899SCharles.Forsyth		else
1165*37da2899SCharles.Forsyth			a[imac:] = q.calcmac(ctx, r.content_type, a, idata, ipad+pad-idata);
1166*37da2899SCharles.Forsyth	}
1167*37da2899SCharles.Forsyth
1168*37da2899SCharles.Forsyth	 if(SSL_DEBUG) {
1169*37da2899SCharles.Forsyth		log("ssl3: record write\n\tbefore encrypt\n\t\t" + bastr(a));
1170*37da2899SCharles.Forsyth		log(sys->sprint("SSL3=%d\n", ctx.status & SSL3_RECORD));
1171*37da2899SCharles.Forsyth	}
1172*37da2899SCharles.Forsyth
1173*37da2899SCharles.Forsyth	# encrypt (data, pad, mac)
1174*37da2899SCharles.Forsyth	pick enc := q.cipherState {
1175*37da2899SCharles.Forsyth	null =>
1176*37da2899SCharles.Forsyth	rc4 =>
1177*37da2899SCharles.Forsyth		keyring->rc4(enc.es, a[h:], m);
1178*37da2899SCharles.Forsyth		if (SSL_DEBUG) log("rc4 0");
1179*37da2899SCharles.Forsyth	descbc =>
1180*37da2899SCharles.Forsyth		keyring->descbc(enc.es, a[h:], m, 0);
1181*37da2899SCharles.Forsyth		if (SSL_DEBUG) log(sys->sprint("descbc 0 %d", m));
1182*37da2899SCharles.Forsyth	ideacbc =>
1183*37da2899SCharles.Forsyth		keyring->ideacbc(enc.es, a[h:], m, 0);
1184*37da2899SCharles.Forsyth		if (SSL_DEBUG) log(sys->sprint("ideacbc 0 %d", m));
1185*37da2899SCharles.Forsyth	* =>
1186*37da2899SCharles.Forsyth	}
1187*37da2899SCharles.Forsyth
1188*37da2899SCharles.Forsyth	 if(SSL_DEBUG)
1189*37da2899SCharles.Forsyth		log("ssl3: record write\n\tafter encrypt\n\t\t" + bastr(a));
1190*37da2899SCharles.Forsyth
1191*37da2899SCharles.Forsyth	if(sys->write(fd, a, h+m) < 0)
1192*37da2899SCharles.Forsyth		return sys->sprint("ssl3: record write: %r");
1193*37da2899SCharles.Forsyth
1194*37da2899SCharles.Forsyth	if((++q.sequence_numbers[0] == 0) && (ctx.status&SSL3_RECORD))
1195*37da2899SCharles.Forsyth		++q.sequence_numbers[1];
1196*37da2899SCharles.Forsyth
1197*37da2899SCharles.Forsyth	return "";
1198*37da2899SCharles.Forsyth}
1199*37da2899SCharles.Forsyth
1200*37da2899SCharles.ForsythRecordQueue.calcmac(q: self ref RecordQueue, ctx: ref Context, cntype: int, a: array of byte,
1201*37da2899SCharles.Forsyth	ofs, n: int) : array of byte
1202*37da2899SCharles.Forsyth{
1203*37da2899SCharles.Forsyth	digest, b: array of byte;
1204*37da2899SCharles.Forsyth
1205*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD) {
1206*37da2899SCharles.Forsyth		b = array [11] of byte;
1207*37da2899SCharles.Forsyth		i := putn(b, 0, q.sequence_numbers[1], 4);
1208*37da2899SCharles.Forsyth		i = putn(b, i, q.sequence_numbers[0], 4);
1209*37da2899SCharles.Forsyth		b[i++] = byte cntype;
1210*37da2899SCharles.Forsyth		putn(b, i, n, 2);
1211*37da2899SCharles.Forsyth	}
1212*37da2899SCharles.Forsyth	else {
1213*37da2899SCharles.Forsyth		b = array [4] of byte;
1214*37da2899SCharles.Forsyth		putn(b, 0, q.sequence_numbers[0], 4);
1215*37da2899SCharles.Forsyth	}
1216*37da2899SCharles.Forsyth
1217*37da2899SCharles.Forsyth	# if(SSL_DEBUG)
1218*37da2899SCharles.Forsyth	#	log("ssl3: record mac\n\tother =\n\t\t" + bastr(b));
1219*37da2899SCharles.Forsyth
1220*37da2899SCharles.Forsyth	pick ms := q.macState {
1221*37da2899SCharles.Forsyth	md5 =>
1222*37da2899SCharles.Forsyth		digest = array [Keyring->MD5dlen] of byte;
1223*37da2899SCharles.Forsyth		ds0 := ms.ds[0].copy();
1224*37da2899SCharles.Forsyth		if(ctx.status & SSL3_RECORD) {
1225*37da2899SCharles.Forsyth			keyring->md5(b, len b, nil, ds0);
1226*37da2899SCharles.Forsyth			keyring->md5(a[ofs:], n, digest, ds0);
1227*37da2899SCharles.Forsyth			ds1 := ms.ds[1].copy();
1228*37da2899SCharles.Forsyth			keyring->md5(digest, len digest, digest, ds1);
1229*37da2899SCharles.Forsyth		}
1230*37da2899SCharles.Forsyth		else {
1231*37da2899SCharles.Forsyth			keyring->md5(a[ofs:], n, nil, ds0);
1232*37da2899SCharles.Forsyth			keyring->md5(b, len b, digest, ds0);
1233*37da2899SCharles.Forsyth		}
1234*37da2899SCharles.Forsyth	sha =>
1235*37da2899SCharles.Forsyth		digest = array [Keyring->SHA1dlen] of byte;
1236*37da2899SCharles.Forsyth		ds0 := ms.ds[0].copy();
1237*37da2899SCharles.Forsyth		if(ctx.status & SSL3_RECORD) {
1238*37da2899SCharles.Forsyth			keyring->sha1(b, len b, nil, ds0);
1239*37da2899SCharles.Forsyth			keyring->sha1(a[ofs:], n, digest, ds0);
1240*37da2899SCharles.Forsyth			ds1 := ms.ds[1].copy();
1241*37da2899SCharles.Forsyth			keyring->sha1(digest, len digest, digest, ds1);
1242*37da2899SCharles.Forsyth		}
1243*37da2899SCharles.Forsyth		else {
1244*37da2899SCharles.Forsyth			keyring->sha1(a[ofs:], n, nil, ds0);
1245*37da2899SCharles.Forsyth			keyring->sha1(b, len b, digest, ds0);
1246*37da2899SCharles.Forsyth		}
1247*37da2899SCharles.Forsyth	}
1248*37da2899SCharles.Forsyth	return digest;
1249*37da2899SCharles.Forsyth}
1250*37da2899SCharles.Forsyth
1251*37da2899SCharles.Forsythset_queues(ctx: ref Context): string
1252*37da2899SCharles.Forsyth{
1253*37da2899SCharles.Forsyth	sw: array of byte;
1254*37da2899SCharles.Forsyth	if(ctx.sw_key != nil) {
1255*37da2899SCharles.Forsyth		sw = array [len ctx.sw_key + len ctx.sw_IV] of byte;
1256*37da2899SCharles.Forsyth		sw[0:] = ctx.sw_key;
1257*37da2899SCharles.Forsyth		sw[len ctx.sw_key:] = ctx.sw_IV;
1258*37da2899SCharles.Forsyth	}
1259*37da2899SCharles.Forsyth	cw: array of byte;
1260*37da2899SCharles.Forsyth	if(ctx.cw_key != nil) {
1261*37da2899SCharles.Forsyth		cw = array [len ctx.cw_key + len ctx.cw_IV] of byte;
1262*37da2899SCharles.Forsyth		cw[0:] = ctx.cw_key;
1263*37da2899SCharles.Forsyth		cw[len ctx.cw_key:] = ctx.cw_IV;
1264*37da2899SCharles.Forsyth	}
1265*37da2899SCharles.Forsyth
1266*37da2899SCharles.Forsyth	err := "";
1267*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL) {
1268*37da2899SCharles.Forsyth		err = set_secrets(ctx.c, ctx.sw_mac, ctx.cw_mac, sw, cw);
1269*37da2899SCharles.Forsyth		if(err == "")
1270*37da2899SCharles.Forsyth			err = set_cipher_algs(ctx);
1271*37da2899SCharles.Forsyth	}
1272*37da2899SCharles.Forsyth	else {
1273*37da2899SCharles.Forsyth		err = set_out_queue(ctx);
1274*37da2899SCharles.Forsyth		if(err == "")
1275*37da2899SCharles.Forsyth			err = set_in_queue(ctx);
1276*37da2899SCharles.Forsyth	}
1277*37da2899SCharles.Forsyth
1278*37da2899SCharles.Forsyth	return err;
1279*37da2899SCharles.Forsyth}
1280*37da2899SCharles.Forsyth
1281*37da2899SCharles.Forsythset_in_queue(ctx: ref Context): string
1282*37da2899SCharles.Forsyth{
1283*37da2899SCharles.Forsyth	sw: array of byte;
1284*37da2899SCharles.Forsyth	if(ctx.sw_key != nil) {
1285*37da2899SCharles.Forsyth		sw = array [len ctx.sw_key + len ctx.sw_IV] of byte;
1286*37da2899SCharles.Forsyth		sw[0:] = ctx.sw_key;
1287*37da2899SCharles.Forsyth		sw[len ctx.sw_key:] = ctx.sw_IV;
1288*37da2899SCharles.Forsyth	}
1289*37da2899SCharles.Forsyth
1290*37da2899SCharles.Forsyth	err := "";
1291*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL) {
1292*37da2899SCharles.Forsyth		err = set_secrets(ctx.c, ctx.sw_mac, nil, sw, nil);
1293*37da2899SCharles.Forsyth		if(err == "")
1294*37da2899SCharles.Forsyth			err = set_cipher_algs(ctx);
1295*37da2899SCharles.Forsyth	}
1296*37da2899SCharles.Forsyth	else
1297*37da2899SCharles.Forsyth		err = set_queue(ctx, ctx.in_queue, ctx.sw_mac, sw);
1298*37da2899SCharles.Forsyth
1299*37da2899SCharles.Forsyth	return err;
1300*37da2899SCharles.Forsyth}
1301*37da2899SCharles.Forsyth
1302*37da2899SCharles.Forsythset_out_queue(ctx: ref Context): string
1303*37da2899SCharles.Forsyth{
1304*37da2899SCharles.Forsyth	cw: array of byte;
1305*37da2899SCharles.Forsyth	if(ctx.cw_key != nil) {
1306*37da2899SCharles.Forsyth		cw = array [len ctx.cw_key + len ctx.cw_IV] of byte;
1307*37da2899SCharles.Forsyth		cw[0:] = ctx.cw_key;
1308*37da2899SCharles.Forsyth		cw[len ctx.cw_key:] = ctx.cw_IV;
1309*37da2899SCharles.Forsyth	}
1310*37da2899SCharles.Forsyth
1311*37da2899SCharles.Forsyth	err := "";
1312*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL) {
1313*37da2899SCharles.Forsyth		err = set_secrets(ctx.c, nil, ctx.cw_mac, nil, cw);
1314*37da2899SCharles.Forsyth		if(err == "")
1315*37da2899SCharles.Forsyth			err = set_cipher_algs(ctx);
1316*37da2899SCharles.Forsyth	}
1317*37da2899SCharles.Forsyth	else
1318*37da2899SCharles.Forsyth		err = set_queue(ctx, ctx.out_queue, ctx.cw_mac, cw);
1319*37da2899SCharles.Forsyth
1320*37da2899SCharles.Forsyth	return err;
1321*37da2899SCharles.Forsyth}
1322*37da2899SCharles.Forsyth
1323*37da2899SCharles.Forsythset_queue(ctx: ref Context, q: ref RecordQueue, mac, key: array of byte): string
1324*37da2899SCharles.Forsyth{
1325*37da2899SCharles.Forsyth	e := "";
1326*37da2899SCharles.Forsyth
1327*37da2899SCharles.Forsyth	case ctx.sel_ciph.mac_algorithm {
1328*37da2899SCharles.Forsyth	SSL_NULL_MAC =>
1329*37da2899SCharles.Forsyth		q.macState = ref MacState.null(0);
1330*37da2899SCharles.Forsyth	SSL_MD5 =>
1331*37da2899SCharles.Forsyth		ds: array of ref DigestState;
1332*37da2899SCharles.Forsyth		if(ctx.status & SSL3_RECORD) {
1333*37da2899SCharles.Forsyth			ds = array [2] of ref DigestState;
1334*37da2899SCharles.Forsyth			ds[0] = keyring->md5(mac, len mac, nil, nil);
1335*37da2899SCharles.Forsyth			ds[1] = keyring->md5(mac, len mac, nil, nil);
1336*37da2899SCharles.Forsyth			ds[0] = keyring->md5(SSL_MAC_PAD1, 48, nil, ds[0]);
1337*37da2899SCharles.Forsyth			ds[1] = keyring->md5(SSL_MAC_PAD2, 48, nil, ds[1]);
1338*37da2899SCharles.Forsyth		}
1339*37da2899SCharles.Forsyth		else {
1340*37da2899SCharles.Forsyth			ds = array [1] of ref DigestState;
1341*37da2899SCharles.Forsyth			ds[0] = keyring->md5(mac, len mac, nil, nil);
1342*37da2899SCharles.Forsyth		}
1343*37da2899SCharles.Forsyth		q.macState = ref MacState.md5(Keyring->MD5dlen, ds);
1344*37da2899SCharles.Forsyth	SSL_SHA =>
1345*37da2899SCharles.Forsyth		ds: array of ref DigestState;
1346*37da2899SCharles.Forsyth		if(ctx.status & SSL3_RECORD) {
1347*37da2899SCharles.Forsyth			ds = array [2] of ref DigestState;
1348*37da2899SCharles.Forsyth			ds[0] = keyring->sha1(mac, len mac, nil, nil);
1349*37da2899SCharles.Forsyth			ds[1] = keyring->sha1(mac, len mac, nil, nil);
1350*37da2899SCharles.Forsyth			ds[0] = keyring->sha1(SSL_MAC_PAD1, 40, nil, ds[0]);
1351*37da2899SCharles.Forsyth			ds[1] = keyring->sha1(SSL_MAC_PAD2, 40, nil, ds[1]);
1352*37da2899SCharles.Forsyth		}
1353*37da2899SCharles.Forsyth		else {
1354*37da2899SCharles.Forsyth			ds = array [1] of ref DigestState;
1355*37da2899SCharles.Forsyth			ds[0] = keyring->sha1(mac, len mac, nil, nil);
1356*37da2899SCharles.Forsyth		}
1357*37da2899SCharles.Forsyth		q.macState = ref MacState.sha(Keyring->SHA1dlen, ds);
1358*37da2899SCharles.Forsyth	* =>
1359*37da2899SCharles.Forsyth		e = "ssl3: digest method: unknown";
1360*37da2899SCharles.Forsyth	}
1361*37da2899SCharles.Forsyth
1362*37da2899SCharles.Forsyth	case ctx.sel_ciph.bulk_cipher_algorithm {
1363*37da2899SCharles.Forsyth	SSL_NULL_CIPHER =>
1364*37da2899SCharles.Forsyth		q.cipherState = ref CipherState.null(1);
1365*37da2899SCharles.Forsyth	SSL_RC4 =>
1366*37da2899SCharles.Forsyth		if (SSL_DEBUG) log("rc4setup");
1367*37da2899SCharles.Forsyth		rcs := keyring->rc4setup(key);
1368*37da2899SCharles.Forsyth		q.cipherState = ref CipherState.rc4(1, rcs);
1369*37da2899SCharles.Forsyth	SSL_DES_CBC =>
1370*37da2899SCharles.Forsyth		dcs : ref keyring->DESstate;
1371*37da2899SCharles.Forsyth
1372*37da2899SCharles.Forsyth		if (SSL_DEBUG) log(sys->sprint("dessetup %d", len key));
1373*37da2899SCharles.Forsyth		if (len key >= 16)
1374*37da2899SCharles.Forsyth			dcs = keyring->dessetup(key[0:8], key[8:16]);
1375*37da2899SCharles.Forsyth		else if (len key >= 8)
1376*37da2899SCharles.Forsyth			dcs = keyring->dessetup(key[0:8], nil);
1377*37da2899SCharles.Forsyth		else
1378*37da2899SCharles.Forsyth			e = "ssl3: bad DES key length";
1379*37da2899SCharles.Forsyth		q.cipherState = ref CipherState.descbc(8, dcs);
1380*37da2899SCharles.Forsyth	SSL_IDEA_CBC =>
1381*37da2899SCharles.Forsyth		ics : ref keyring->IDEAstate;
1382*37da2899SCharles.Forsyth
1383*37da2899SCharles.Forsyth		if (SSL_DEBUG) log(sys->sprint("ideasetup %d", len key));
1384*37da2899SCharles.Forsyth		if (len key >= 24)
1385*37da2899SCharles.Forsyth			ics = keyring->ideasetup(key[0:16], key[16:24]);
1386*37da2899SCharles.Forsyth		else if (len key >= 16)
1387*37da2899SCharles.Forsyth			ics = keyring->ideasetup(key[0:16], nil);
1388*37da2899SCharles.Forsyth		else
1389*37da2899SCharles.Forsyth			e = "ssl3: bad IDEA key length";
1390*37da2899SCharles.Forsyth		q.cipherState = ref CipherState.ideacbc(8, ics);
1391*37da2899SCharles.Forsyth	SSL_RC2_CBC or
1392*37da2899SCharles.Forsyth	SSL_3DES_EDE_CBC or
1393*37da2899SCharles.Forsyth	SSL_FORTEZZA_CBC =>
1394*37da2899SCharles.Forsyth		e = "ssl3: unsupported cipher";
1395*37da2899SCharles.Forsyth	* =>
1396*37da2899SCharles.Forsyth		e = "ssl3: unknown cipher";
1397*37da2899SCharles.Forsyth	}
1398*37da2899SCharles.Forsyth
1399*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD) {
1400*37da2899SCharles.Forsyth		q.length = 1 << 14;
1401*37da2899SCharles.Forsyth		if(tagof q.macState != tagof MacState.null)
1402*37da2899SCharles.Forsyth			q.length += 2048;
1403*37da2899SCharles.Forsyth	}
1404*37da2899SCharles.Forsyth	else {
1405*37da2899SCharles.Forsyth		if(q.cipherState.block_size > 1) {
1406*37da2899SCharles.Forsyth			q.length = (1<<14) - q.macState.hash_size - 1;
1407*37da2899SCharles.Forsyth			q.length -= q.length % q.cipherState.block_size;
1408*37da2899SCharles.Forsyth		}
1409*37da2899SCharles.Forsyth		else
1410*37da2899SCharles.Forsyth			q.length = (1<<15) - q.macState.hash_size - 1;
1411*37da2899SCharles.Forsyth	}
1412*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD)
1413*37da2899SCharles.Forsyth		q.sequence_numbers[0] = q.sequence_numbers[1] = 0;
1414*37da2899SCharles.Forsyth
1415*37da2899SCharles.Forsyth	return e;
1416*37da2899SCharles.Forsyth}
1417*37da2899SCharles.Forsyth
1418*37da2899SCharles.Forsythset_cipher_algs(ctx: ref Context) : string
1419*37da2899SCharles.Forsyth{
1420*37da2899SCharles.Forsyth	e: string;
1421*37da2899SCharles.Forsyth
1422*37da2899SCharles.Forsyth	algspec := "alg";
1423*37da2899SCharles.Forsyth
1424*37da2899SCharles.Forsyth	case enc := ctx.sel_ciph.bulk_cipher_algorithm {
1425*37da2899SCharles.Forsyth	SSL_NULL_CIPHER =>
1426*37da2899SCharles.Forsyth		algspec += " clear";
1427*37da2899SCharles.Forsyth	SSL_RC4 => 	# stream cipher
1428*37da2899SCharles.Forsyth		algspec += " rc4_128";
1429*37da2899SCharles.Forsyth	SSL_DES_CBC => # block cipher
1430*37da2899SCharles.Forsyth		algspec += " descbc";
1431*37da2899SCharles.Forsyth	SSL_IDEA_CBC => # block cipher
1432*37da2899SCharles.Forsyth		algspec += " ideacbc";
1433*37da2899SCharles.Forsyth	SSL_RC2_CBC or
1434*37da2899SCharles.Forsyth	SSL_3DES_EDE_CBC or
1435*37da2899SCharles.Forsyth	SSL_FORTEZZA_CBC =>
1436*37da2899SCharles.Forsyth		e = "ssl3: encrypt method: unsupported";
1437*37da2899SCharles.Forsyth	* =>
1438*37da2899SCharles.Forsyth		e = "ssl3: encrypt method: unknown";
1439*37da2899SCharles.Forsyth	}
1440*37da2899SCharles.Forsyth
1441*37da2899SCharles.Forsyth	case mac := ctx.sel_ciph.mac_algorithm {
1442*37da2899SCharles.Forsyth	SSL_NULL_MAC =>
1443*37da2899SCharles.Forsyth		algspec += " clear";
1444*37da2899SCharles.Forsyth	SSL_MD5 =>
1445*37da2899SCharles.Forsyth		algspec += " md5";
1446*37da2899SCharles.Forsyth	SSL_SHA =>
1447*37da2899SCharles.Forsyth		algspec += " sha1";
1448*37da2899SCharles.Forsyth	* =>
1449*37da2899SCharles.Forsyth		e = "ssl3: digest method: unknown";
1450*37da2899SCharles.Forsyth	}
1451*37da2899SCharles.Forsyth
1452*37da2899SCharles.Forsyth	e = set_ctl(ctx.c, algspec);
1453*37da2899SCharles.Forsyth	if(e != "") {
1454*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1455*37da2899SCharles.Forsyth			log("failed to set cipher algs: " + e);
1456*37da2899SCharles.Forsyth	}
1457*37da2899SCharles.Forsyth
1458*37da2899SCharles.Forsyth	return e;
1459*37da2899SCharles.Forsyth}
1460*37da2899SCharles.Forsyth
1461*37da2899SCharles.Forsythset_ctl(c: ref Sys->Connection, s: string): string
1462*37da2899SCharles.Forsyth{
1463*37da2899SCharles.Forsyth	a := array of byte s;
1464*37da2899SCharles.Forsyth	if(sys->write(c.cfd, a, len a) < 0)
1465*37da2899SCharles.Forsyth		return sys->sprint("error writing sslctl: %r");
1466*37da2899SCharles.Forsyth
1467*37da2899SCharles.Forsyth	if(SSL_DEBUG)
1468*37da2899SCharles.Forsyth		log("ssl3: set cipher algorithm:\n\t\t" + s + "\n");
1469*37da2899SCharles.Forsyth
1470*37da2899SCharles.Forsyth	return "";
1471*37da2899SCharles.Forsyth}
1472*37da2899SCharles.Forsyth
1473*37da2899SCharles.Forsythset_secrets(c: ref Sys->Connection, min, mout, sin, sout: array of byte) : string
1474*37da2899SCharles.Forsyth{
1475*37da2899SCharles.Forsyth	fmin := sys->open(c.dir + "/macin", Sys->OWRITE);
1476*37da2899SCharles.Forsyth	fmout := sys->open(c.dir + "/macout", Sys->OWRITE);
1477*37da2899SCharles.Forsyth	fsin := sys->open(c.dir + "/secretin", Sys->OWRITE);
1478*37da2899SCharles.Forsyth	fsout := sys->open(c.dir + "/secretout", Sys->OWRITE);
1479*37da2899SCharles.Forsyth	if(fmin == nil || fmout == nil || fsin == nil || fsout == nil)
1480*37da2899SCharles.Forsyth		return sys->sprint("can't open ssl secret files: %r\n");
1481*37da2899SCharles.Forsyth
1482*37da2899SCharles.Forsyth	if(sin != nil) {
1483*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1484*37da2899SCharles.Forsyth			log("ssl3: set encryption secret and IV\n\tsecretin:\n\t\t" + bastr(sin) + "\n");
1485*37da2899SCharles.Forsyth		if(sys->write(fsin, sin, len sin) < 0)
1486*37da2899SCharles.Forsyth			return sys->sprint("error writing secretin: %r");
1487*37da2899SCharles.Forsyth	}
1488*37da2899SCharles.Forsyth	if(sout != nil) {
1489*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1490*37da2899SCharles.Forsyth			log("ssl3: set encryption secret and IV\n\tsecretout:\n\t\t" + bastr(sout) + "\n");
1491*37da2899SCharles.Forsyth		if(sys->write(fsout, sout, len sout) < 0)
1492*37da2899SCharles.Forsyth			return sys->sprint("error writing secretout: %r");
1493*37da2899SCharles.Forsyth	}
1494*37da2899SCharles.Forsyth	if(min != nil) {
1495*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1496*37da2899SCharles.Forsyth			log("ssl3: set digest secret\n\tmacin:\n\t\t" + bastr(min) + "\n");
1497*37da2899SCharles.Forsyth		if(sys->write(fmin, min, len min) < 0)
1498*37da2899SCharles.Forsyth			return sys->sprint("error writing macin: %r");
1499*37da2899SCharles.Forsyth	}
1500*37da2899SCharles.Forsyth	if(mout != nil) {
1501*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1502*37da2899SCharles.Forsyth			log("ssl3: set digest secret\n\tmacout:\n\t\t" + bastr(mout) + "\n");
1503*37da2899SCharles.Forsyth		if(sys->write(fmout, mout, len mout) < 0)
1504*37da2899SCharles.Forsyth			return sys->sprint("error writing macout: %r");
1505*37da2899SCharles.Forsyth	}
1506*37da2899SCharles.Forsyth
1507*37da2899SCharles.Forsyth	return "";
1508*37da2899SCharles.Forsyth}
1509*37da2899SCharles.Forsyth
1510*37da2899SCharles.Forsyth#
1511*37da2899SCharles.Forsyth# description must be alert description
1512*37da2899SCharles.Forsyth#
1513*37da2899SCharles.Forsythfatal(description: int, debug_msg: string, ctx: ref Context)
1514*37da2899SCharles.Forsyth{
1515*37da2899SCharles.Forsyth	if(SSL_DEBUG)
1516*37da2899SCharles.Forsyth		log("ssl3: " + debug_msg);
1517*37da2899SCharles.Forsyth
1518*37da2899SCharles.Forsyth	# TODO: use V2Handshake.Error for v2
1519*37da2899SCharles.Forsyth	alert_enque(ref Alert(SSL_FATAL, description), ctx);
1520*37da2899SCharles.Forsyth
1521*37da2899SCharles.Forsyth	# delete session id
1522*37da2899SCharles.Forsyth	ctx.session.session_id = nil;
1523*37da2899SCharles.Forsyth
1524*37da2899SCharles.Forsyth	ctx.state = STATE_EXIT;
1525*37da2899SCharles.Forsyth}
1526*37da2899SCharles.Forsyth
1527*37da2899SCharles.Forsythalert_enque(a: ref Alert, ctx: ref Context)
1528*37da2899SCharles.Forsyth{
1529*37da2899SCharles.Forsyth	p := ref Protocol.pAlert(a);
1530*37da2899SCharles.Forsyth
1531*37da2899SCharles.Forsyth	protocol_write(p, ctx);
1532*37da2899SCharles.Forsyth}
1533*37da2899SCharles.Forsyth
1534*37da2899SCharles.Forsyth# clean up out queue before switch cipher. this is why
1535*37da2899SCharles.Forsyth# change cipher spec differs from handshake message by ssl spec
1536*37da2899SCharles.Forsyth
1537*37da2899SCharles.Forsythccs_enque(cs: ref ChangeCipherSpec, ctx: ref Context)
1538*37da2899SCharles.Forsyth{
1539*37da2899SCharles.Forsyth	p := ref Protocol.pChangeCipherSpec(cs);
1540*37da2899SCharles.Forsyth
1541*37da2899SCharles.Forsyth	protocol_write(p, ctx);
1542*37da2899SCharles.Forsyth
1543*37da2899SCharles.Forsyth	record_write_queue(ctx);
1544*37da2899SCharles.Forsyth	ctx.out_queue.data = nil;
1545*37da2899SCharles.Forsyth}
1546*37da2899SCharles.Forsyth
1547*37da2899SCharles.Forsythhandshake_enque(h: ref Handshake, ctx: ref Context)
1548*37da2899SCharles.Forsyth{
1549*37da2899SCharles.Forsyth	p := ref Protocol.pHandshake(h);
1550*37da2899SCharles.Forsyth
1551*37da2899SCharles.Forsyth	protocol_write(p, ctx);
1552*37da2899SCharles.Forsyth}
1553*37da2899SCharles.Forsyth
1554*37da2899SCharles.Forsythprotocol_write(p: ref Protocol, ctx: ref Context)
1555*37da2899SCharles.Forsyth{
1556*37da2899SCharles.Forsyth	record_version := SSL_VERSION_2_0;
1557*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD)
1558*37da2899SCharles.Forsyth		record_version = SSL_VERSION_3_0;
1559*37da2899SCharles.Forsyth	(r, e) := p.encode(record_version);
1560*37da2899SCharles.Forsyth	if(e != "") {
1561*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1562*37da2899SCharles.Forsyth			log("ssl3: protocol_write: " + e);
1563*37da2899SCharles.Forsyth		exit;
1564*37da2899SCharles.Forsyth	}
1565*37da2899SCharles.Forsyth
1566*37da2899SCharles.Forsyth	# Note: only for sslv3
1567*37da2899SCharles.Forsyth	if((ctx.status&SSL2_HANDSHAKE) && (ctx.status&SSL3_HANDSHAKE)) {
1568*37da2899SCharles.Forsyth		if(ctx.state == STATE_HELLO_REQUEST) {
1569*37da2899SCharles.Forsyth			e = update_handshake_hash(ctx, r);
1570*37da2899SCharles.Forsyth			if(e != "") {
1571*37da2899SCharles.Forsyth				if(SSL_DEBUG)
1572*37da2899SCharles.Forsyth					log("ssl3: protocol_write: " + e);
1573*37da2899SCharles.Forsyth				exit;
1574*37da2899SCharles.Forsyth			}
1575*37da2899SCharles.Forsyth		}
1576*37da2899SCharles.Forsyth	}
1577*37da2899SCharles.Forsyth	if((ctx.status&SSL3_HANDSHAKE) && (r.content_type == SSL_HANDSHAKE)) {
1578*37da2899SCharles.Forsyth		e = update_handshake_hash(ctx, r);
1579*37da2899SCharles.Forsyth		if(e != "") {
1580*37da2899SCharles.Forsyth			if(SSL_DEBUG)
1581*37da2899SCharles.Forsyth				log("ssl3: protocol_write: " + e);
1582*37da2899SCharles.Forsyth			exit;
1583*37da2899SCharles.Forsyth		}
1584*37da2899SCharles.Forsyth	}
1585*37da2899SCharles.Forsyth
1586*37da2899SCharles.Forsyth	ctx.out_queue.data = r :: ctx.out_queue.data;
1587*37da2899SCharles.Forsyth}
1588*37da2899SCharles.Forsyth
1589*37da2899SCharles.Forsyth#feed_data(ctx: ref Context, a: array of byte, n: int): int
1590*37da2899SCharles.Forsyth#{
1591*37da2899SCharles.Forsyth#
1592*37da2899SCharles.Forsyth#}
1593*37da2899SCharles.Forsyth
1594*37da2899SCharles.Forsyth# FIFO
1595*37da2899SCharles.Forsythrecord_write_queue(ctx: ref Context)
1596*37da2899SCharles.Forsyth{
1597*37da2899SCharles.Forsyth	write_queue : list of ref Record;
1598*37da2899SCharles.Forsyth
1599*37da2899SCharles.Forsyth	wq := ctx.out_queue.data;
1600*37da2899SCharles.Forsyth	while(wq != nil) {
1601*37da2899SCharles.Forsyth		write_queue = hd wq :: write_queue;
1602*37da2899SCharles.Forsyth		wq = tl wq;
1603*37da2899SCharles.Forsyth	}
1604*37da2899SCharles.Forsyth
1605*37da2899SCharles.Forsyth	wq = write_queue;
1606*37da2899SCharles.Forsyth	while(wq != nil) {
1607*37da2899SCharles.Forsyth		record_write(hd wq, ctx);
1608*37da2899SCharles.Forsyth		wq = tl wq;
1609*37da2899SCharles.Forsyth	}
1610*37da2899SCharles.Forsyth}
1611*37da2899SCharles.Forsyth
1612*37da2899SCharles.Forsyth# Possible combinations are v2 only, v3 only and both (undetermined). The v2 only must be
1613*37da2899SCharles.Forsyth# v2 handshake and v2 record layer. The v3 only must be v3 handshake and v3 record layer.
1614*37da2899SCharles.Forsyth# If both v2 and v3 are supported, it may be v2 handshake and v2 record layer, or v3
1615*37da2899SCharles.Forsyth# handshake and v3 record layer, or v2 handshake and v3 record layer. In the case of
1616*37da2899SCharles.Forsyth# both, the client should send a v2 client hello message with handshake protocol version v3.
1617*37da2899SCharles.Forsyth
1618*37da2899SCharles.Forsythdo_protocol(ctx: ref Context): string
1619*37da2899SCharles.Forsyth{
1620*37da2899SCharles.Forsyth	r: ref Record;
1621*37da2899SCharles.Forsyth	in: ref Protocol;
1622*37da2899SCharles.Forsyth	e: string = nil;
1623*37da2899SCharles.Forsyth
1624*37da2899SCharles.Forsyth	while(ctx.state != STATE_EXIT) {
1625*37da2899SCharles.Forsyth
1626*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1627*37da2899SCharles.Forsyth			log("ssl3: state = " + state_info(ctx));
1628*37da2899SCharles.Forsyth
1629*37da2899SCharles.Forsyth		# init a new handshake
1630*37da2899SCharles.Forsyth		if(ctx.state == STATE_HELLO_REQUEST) {
1631*37da2899SCharles.Forsyth			# v2 and v3
1632*37da2899SCharles.Forsyth			if((ctx.status&SSL2_HANDSHAKE) && (ctx.status&SSL3_HANDSHAKE)) {
1633*37da2899SCharles.Forsyth				ch := ref V2Handshake.ClientHello(
1634*37da2899SCharles.Forsyth						SSL_VERSION_3_0,
1635*37da2899SCharles.Forsyth						v3tov2specs(ctx.local_info.suites),
1636*37da2899SCharles.Forsyth						ctx.session.session_id,
1637*37da2899SCharles.Forsyth						ctx.client_random
1638*37da2899SCharles.Forsyth					);
1639*37da2899SCharles.Forsyth				v2handshake_enque(ch, ctx);
1640*37da2899SCharles.Forsyth				in = ref Protocol.pV2Handshake(ch);
1641*37da2899SCharles.Forsyth			}
1642*37da2899SCharles.Forsyth			# v3 only
1643*37da2899SCharles.Forsyth			else if(ctx.status&SSL3_HANDSHAKE) {
1644*37da2899SCharles.Forsyth				in = ref Protocol.pHandshake(ref Handshake.HelloRequest());
1645*37da2899SCharles.Forsyth			}
1646*37da2899SCharles.Forsyth			# v2 only
1647*37da2899SCharles.Forsyth			else if(ctx.status&SSL2_HANDSHAKE) {
1648*37da2899SCharles.Forsyth				ch := ref V2Handshake.ClientHello(
1649*37da2899SCharles.Forsyth						SSL_VERSION_2_0,
1650*37da2899SCharles.Forsyth						v3tov2specs(ctx.local_info.suites),
1651*37da2899SCharles.Forsyth						ctx.session.session_id,
1652*37da2899SCharles.Forsyth						ctx.client_random[32-SSL2_CHALLENGE_LENGTH:32]
1653*37da2899SCharles.Forsyth					);
1654*37da2899SCharles.Forsyth				v2handshake_enque(ch, ctx);
1655*37da2899SCharles.Forsyth				in = ref Protocol.pV2Handshake(ch);
1656*37da2899SCharles.Forsyth			}
1657*37da2899SCharles.Forsyth			# unknown version
1658*37da2899SCharles.Forsyth			else {
1659*37da2899SCharles.Forsyth				e = "unknown ssl device version";
1660*37da2899SCharles.Forsyth				fatal(SSL_CLOSE_NOTIFY, "ssl3: " + e, ctx);
1661*37da2899SCharles.Forsyth				continue;
1662*37da2899SCharles.Forsyth			}
1663*37da2899SCharles.Forsyth		}
1664*37da2899SCharles.Forsyth
1665*37da2899SCharles.Forsyth		if(in == nil) {
1666*37da2899SCharles.Forsyth			(r, in, e) = protocol_read(ctx);
1667*37da2899SCharles.Forsyth			if(e != "") {
1668*37da2899SCharles.Forsyth				fatal(SSL_CLOSE_NOTIFY, "ssl3: " + e, ctx);
1669*37da2899SCharles.Forsyth				continue;
1670*37da2899SCharles.Forsyth			}
1671*37da2899SCharles.Forsyth			if(SSL_DEBUG)
1672*37da2899SCharles.Forsyth				log("ssl3: protocol_read: ------\n" + in.tostring());
1673*37da2899SCharles.Forsyth		}
1674*37da2899SCharles.Forsyth
1675*37da2899SCharles.Forsyth		pick p := in {
1676*37da2899SCharles.Forsyth		pAlert =>
1677*37da2899SCharles.Forsyth			do_alert(p.alert, ctx);
1678*37da2899SCharles.Forsyth
1679*37da2899SCharles.Forsyth		pChangeCipherSpec =>
1680*37da2899SCharles.Forsyth			if(ctx.state != STATE_CHANGE_CIPHER_SPEC) {
1681*37da2899SCharles.Forsyth				e += "ChangeCipherSpec";
1682*37da2899SCharles.Forsyth				break;
1683*37da2899SCharles.Forsyth			}
1684*37da2899SCharles.Forsyth			do_change_cipher_spec(ctx);
1685*37da2899SCharles.Forsyth
1686*37da2899SCharles.Forsyth		pHandshake =>
1687*37da2899SCharles.Forsyth			if(!(ctx.status & SSL3_HANDSHAKE)) {
1688*37da2899SCharles.Forsyth				e = "Wrong Handshake";
1689*37da2899SCharles.Forsyth				break;
1690*37da2899SCharles.Forsyth			}
1691*37da2899SCharles.Forsyth			if((ctx.status & SSL3_RECORD) &&
1692*37da2899SCharles.Forsyth				(ctx.state == SSL2_STATE_SERVER_HELLO)) {
1693*37da2899SCharles.Forsyth				ctx.state = STATE_SERVER_HELLO;
1694*37da2899SCharles.Forsyth				ctx.status &= ~SSL2_HANDSHAKE;
1695*37da2899SCharles.Forsyth			}
1696*37da2899SCharles.Forsyth			e = do_handshake(p.handshake, ctx);
1697*37da2899SCharles.Forsyth
1698*37da2899SCharles.Forsyth		pV2Handshake =>
1699*37da2899SCharles.Forsyth			if(ctx.state != STATE_HELLO_REQUEST) {
1700*37da2899SCharles.Forsyth				if(!(ctx.status & SSL2_HANDSHAKE)) {
1701*37da2899SCharles.Forsyth					e = "Wrong Handshake";
1702*37da2899SCharles.Forsyth					break;
1703*37da2899SCharles.Forsyth				}
1704*37da2899SCharles.Forsyth				e = do_v2handshake(p.handshake, ctx);
1705*37da2899SCharles.Forsyth			}
1706*37da2899SCharles.Forsyth			else
1707*37da2899SCharles.Forsyth				ctx.state = SSL2_STATE_SERVER_HELLO;
1708*37da2899SCharles.Forsyth
1709*37da2899SCharles.Forsyth
1710*37da2899SCharles.Forsyth		* =>
1711*37da2899SCharles.Forsyth			e = "unknown protocol message";
1712*37da2899SCharles.Forsyth		}
1713*37da2899SCharles.Forsyth
1714*37da2899SCharles.Forsyth		if(e != nil) {
1715*37da2899SCharles.Forsyth			e = "do_protocol: wrong protocol side or protocol message: " + e;
1716*37da2899SCharles.Forsyth			fatal(SSL_UNEXPECTED_MESSAGE, e, ctx);
1717*37da2899SCharles.Forsyth		}
1718*37da2899SCharles.Forsyth
1719*37da2899SCharles.Forsyth		in = nil;
1720*37da2899SCharles.Forsyth
1721*37da2899SCharles.Forsyth		record_write_queue(ctx);
1722*37da2899SCharles.Forsyth		ctx.out_queue.data = nil;
1723*37da2899SCharles.Forsyth	}
1724*37da2899SCharles.Forsyth
1725*37da2899SCharles.Forsyth	return e;
1726*37da2899SCharles.Forsyth}
1727*37da2899SCharles.Forsyth
1728*37da2899SCharles.Forsythstate_info(ctx: ref Context): string
1729*37da2899SCharles.Forsyth{
1730*37da2899SCharles.Forsyth	info: string;
1731*37da2899SCharles.Forsyth
1732*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD)
1733*37da2899SCharles.Forsyth		info = "\n\tRecord Version 3: ";
1734*37da2899SCharles.Forsyth	else
1735*37da2899SCharles.Forsyth		info = "\n\tRecord Version 2: ";
1736*37da2899SCharles.Forsyth
1737*37da2899SCharles.Forsyth	if(ctx.status & SSL2_HANDSHAKE) {
1738*37da2899SCharles.Forsyth
1739*37da2899SCharles.Forsyth		if(ctx.status & SSL3_HANDSHAKE) {
1740*37da2899SCharles.Forsyth			info += "\n\tHandshake Version Undetermined: Client Hello";
1741*37da2899SCharles.Forsyth		}
1742*37da2899SCharles.Forsyth		else {
1743*37da2899SCharles.Forsyth			info += "\n\tHandshake Version 2: ";
1744*37da2899SCharles.Forsyth
1745*37da2899SCharles.Forsyth			case ctx.state {
1746*37da2899SCharles.Forsyth			SSL2_STATE_CLIENT_HELLO =>
1747*37da2899SCharles.Forsyth				info += "Client Hello";
1748*37da2899SCharles.Forsyth			SSL2_STATE_SERVER_HELLO =>
1749*37da2899SCharles.Forsyth				info += "Server Hello";
1750*37da2899SCharles.Forsyth			SSL2_STATE_CLIENT_MASTER_KEY =>
1751*37da2899SCharles.Forsyth				info += "Client Master Key";
1752*37da2899SCharles.Forsyth			SSL2_STATE_SERVER_VERIFY =>
1753*37da2899SCharles.Forsyth				info += "Server Verify";
1754*37da2899SCharles.Forsyth			SSL2_STATE_REQUEST_CERTIFICATE =>
1755*37da2899SCharles.Forsyth				info += "Request Certificate";
1756*37da2899SCharles.Forsyth			SSL2_STATE_CLIENT_CERTIFICATE =>
1757*37da2899SCharles.Forsyth				info += "Client Certificate";
1758*37da2899SCharles.Forsyth			SSL2_STATE_CLIENT_FINISHED =>
1759*37da2899SCharles.Forsyth				info += "Client Finished";
1760*37da2899SCharles.Forsyth			SSL2_STATE_SERVER_FINISHED =>
1761*37da2899SCharles.Forsyth				info += "Server Finished";
1762*37da2899SCharles.Forsyth			SSL2_STATE_ERROR =>
1763*37da2899SCharles.Forsyth				info += "Error";
1764*37da2899SCharles.Forsyth			}
1765*37da2899SCharles.Forsyth		}
1766*37da2899SCharles.Forsyth	}
1767*37da2899SCharles.Forsyth	else {
1768*37da2899SCharles.Forsyth		info = "\n\tHandshake Version 3: ";
1769*37da2899SCharles.Forsyth
1770*37da2899SCharles.Forsyth		case ctx.state {
1771*37da2899SCharles.Forsyth		STATE_EXIT =>
1772*37da2899SCharles.Forsyth			info += "Exit";
1773*37da2899SCharles.Forsyth
1774*37da2899SCharles.Forsyth		STATE_CHANGE_CIPHER_SPEC =>
1775*37da2899SCharles.Forsyth			info += "Change Cipher Spec";
1776*37da2899SCharles.Forsyth
1777*37da2899SCharles.Forsyth		STATE_HELLO_REQUEST =>
1778*37da2899SCharles.Forsyth			info += "Hello Request";
1779*37da2899SCharles.Forsyth
1780*37da2899SCharles.Forsyth		STATE_CLIENT_HELLO =>
1781*37da2899SCharles.Forsyth			info += "Client Hello";
1782*37da2899SCharles.Forsyth
1783*37da2899SCharles.Forsyth		STATE_SERVER_HELLO =>
1784*37da2899SCharles.Forsyth			info += "Server Hello";
1785*37da2899SCharles.Forsyth
1786*37da2899SCharles.Forsyth		STATE_CLIENT_KEY_EXCHANGE =>
1787*37da2899SCharles.Forsyth			info += "Client Key Exchange";
1788*37da2899SCharles.Forsyth
1789*37da2899SCharles.Forsyth		STATE_SERVER_KEY_EXCHANGE =>
1790*37da2899SCharles.Forsyth			info += "Server Key Exchange";
1791*37da2899SCharles.Forsyth
1792*37da2899SCharles.Forsyth		STATE_SERVER_HELLO_DONE =>
1793*37da2899SCharles.Forsyth			info += "Server Hello Done";
1794*37da2899SCharles.Forsyth
1795*37da2899SCharles.Forsyth		STATE_CLIENT_CERTIFICATE =>
1796*37da2899SCharles.Forsyth			info += "Client Certificate";
1797*37da2899SCharles.Forsyth
1798*37da2899SCharles.Forsyth		STATE_SERVER_CERTIFICATE =>
1799*37da2899SCharles.Forsyth			info += "Server Certificate";
1800*37da2899SCharles.Forsyth
1801*37da2899SCharles.Forsyth		STATE_CERTIFICATE_VERIFY =>
1802*37da2899SCharles.Forsyth			info += "Certificate Verify";
1803*37da2899SCharles.Forsyth
1804*37da2899SCharles.Forsyth		STATE_FINISHED =>
1805*37da2899SCharles.Forsyth			info += "Finished";
1806*37da2899SCharles.Forsyth		}
1807*37da2899SCharles.Forsyth	}
1808*37da2899SCharles.Forsyth
1809*37da2899SCharles.Forsyth	if(ctx.status & CLIENT_AUTH)
1810*37da2899SCharles.Forsyth		info += ": Client Auth";
1811*37da2899SCharles.Forsyth	if(ctx.status & CERT_REQUEST)
1812*37da2899SCharles.Forsyth		info += ": Cert Request";
1813*37da2899SCharles.Forsyth	if(ctx.status & CERT_SENT)
1814*37da2899SCharles.Forsyth		info += ": Cert Sent";
1815*37da2899SCharles.Forsyth	if(ctx.status & CERT_RECEIVED)
1816*37da2899SCharles.Forsyth		info += ": Cert Received";
1817*37da2899SCharles.Forsyth
1818*37da2899SCharles.Forsyth	return info;
1819*37da2899SCharles.Forsyth}
1820*37da2899SCharles.Forsyth
1821*37da2899SCharles.Forsythreset_client_random(ctx: ref Context)
1822*37da2899SCharles.Forsyth{
1823*37da2899SCharles.Forsyth	ctx.client_random[0:] = int_encode(ctx.session.connection_time, 4);
1824*37da2899SCharles.Forsyth	ctx.client_random[4:] = random->randombuf(Random->NotQuiteRandom, 28);
1825*37da2899SCharles.Forsyth}
1826*37da2899SCharles.Forsyth
1827*37da2899SCharles.Forsythreset_server_random(ctx: ref Context)
1828*37da2899SCharles.Forsyth{
1829*37da2899SCharles.Forsyth	ctx.server_random[0:] = int_encode(ctx.session.connection_time, 4);
1830*37da2899SCharles.Forsyth	ctx.server_random[4:] = random->randombuf(Random->NotQuiteRandom, 28);
1831*37da2899SCharles.Forsyth}
1832*37da2899SCharles.Forsyth
1833*37da2899SCharles.Forsythupdate_handshake_hash(ctx: ref Context, r: ref Record): string
1834*37da2899SCharles.Forsyth{
1835*37da2899SCharles.Forsyth	err := "";
1836*37da2899SCharles.Forsyth
1837*37da2899SCharles.Forsyth	ctx.sha_state = keyring->sha1(r.data, len r.data, nil, ctx.sha_state);
1838*37da2899SCharles.Forsyth	ctx.md5_state = keyring->md5(r.data, len r.data, nil, ctx.md5_state);
1839*37da2899SCharles.Forsyth	if(ctx.sha_state == nil || ctx.md5_state == nil)
1840*37da2899SCharles.Forsyth		err = "update handshake hash failed";
1841*37da2899SCharles.Forsyth
1842*37da2899SCharles.Forsyth	# if(SSL_DEBUG)
1843*37da2899SCharles.Forsyth	#	log("ssl3: update_handshake_hash\n\tmessage_data =\n\t\t" + bastr(r.data) + "\n");
1844*37da2899SCharles.Forsyth
1845*37da2899SCharles.Forsyth	return err;
1846*37da2899SCharles.Forsyth}
1847*37da2899SCharles.Forsyth
1848*37da2899SCharles.Forsyth# Note:
1849*37da2899SCharles.Forsyth#	this depends on the record protocol
1850*37da2899SCharles.Forsythprotocol_read(ctx: ref Context): (ref Record, ref Protocol, string)
1851*37da2899SCharles.Forsyth{
1852*37da2899SCharles.Forsyth	p: ref Protocol;
1853*37da2899SCharles.Forsyth	r: ref Record;
1854*37da2899SCharles.Forsyth	e: string;
1855*37da2899SCharles.Forsyth
1856*37da2899SCharles.Forsyth	vers := SSL_VERSION_2_0;
1857*37da2899SCharles.Forsyth	if(ctx.status & SSL3_RECORD)
1858*37da2899SCharles.Forsyth		vers = SSL_VERSION_3_0;
1859*37da2899SCharles.Forsyth	if(ctx.status & USE_DEVSSL)
1860*37da2899SCharles.Forsyth		(r, e) = devssl_read(ctx);
1861*37da2899SCharles.Forsyth	else
1862*37da2899SCharles.Forsyth		(r, e) = record_read(ctx);
1863*37da2899SCharles.Forsyth	if(e != "")
1864*37da2899SCharles.Forsyth		return (nil, nil, e);
1865*37da2899SCharles.Forsyth
1866*37da2899SCharles.Forsyth	(p, e) = Protocol.decode(r, ctx);
1867*37da2899SCharles.Forsyth	if(e != "")
1868*37da2899SCharles.Forsyth		return (r, nil, e);
1869*37da2899SCharles.Forsyth
1870*37da2899SCharles.Forsyth	return (r, p, nil);
1871*37da2899SCharles.Forsyth}
1872*37da2899SCharles.Forsyth
1873*37da2899SCharles.Forsyth# Alert messages with a level of fatal result in the immediate
1874*37da2899SCharles.Forsyth# termination of the connection and zero out session.
1875*37da2899SCharles.Forsyth
1876*37da2899SCharles.Forsythdo_alert(a: ref Alert, ctx: ref Context)
1877*37da2899SCharles.Forsyth{
1878*37da2899SCharles.Forsyth	case a.level {
1879*37da2899SCharles.Forsyth	SSL_FATAL =>
1880*37da2899SCharles.Forsyth
1881*37da2899SCharles.Forsyth		case a.description {
1882*37da2899SCharles.Forsyth		SSL_UNEXPECTED_MESSAGE =>
1883*37da2899SCharles.Forsyth
1884*37da2899SCharles.Forsyth			# should never be observed in communication
1885*37da2899SCharles.Forsyth			# between proper implementations.
1886*37da2899SCharles.Forsyth			break;
1887*37da2899SCharles.Forsyth
1888*37da2899SCharles.Forsyth		SSL_HANDSHAKE_FAILURE =>
1889*37da2899SCharles.Forsyth
1890*37da2899SCharles.Forsyth			# unable to negotiate an acceptable set of security
1891*37da2899SCharles.Forsyth			# parameters given the options available.
1892*37da2899SCharles.Forsyth			break;
1893*37da2899SCharles.Forsyth
1894*37da2899SCharles.Forsyth		* =>
1895*37da2899SCharles.Forsyth			break;
1896*37da2899SCharles.Forsyth		}
1897*37da2899SCharles.Forsyth
1898*37da2899SCharles.Forsyth		ctx.session.session_id = nil;
1899*37da2899SCharles.Forsyth		ctx.state = STATE_EXIT;
1900*37da2899SCharles.Forsyth
1901*37da2899SCharles.Forsyth	SSL_WARNING =>
1902*37da2899SCharles.Forsyth
1903*37da2899SCharles.Forsyth		case a.description {
1904*37da2899SCharles.Forsyth		SSL_CLOSE_NOTIFY =>
1905*37da2899SCharles.Forsyth
1906*37da2899SCharles.Forsyth			if(SSL_DEBUG)
1907*37da2899SCharles.Forsyth				log("ssl3: do_alert SSL_WARNING:SSL_CLOSE_NOTIFY\n");
1908*37da2899SCharles.Forsyth			# notifies the recipient that the sender will not
1909*37da2899SCharles.Forsyth			# send any more messages on this connection.
1910*37da2899SCharles.Forsyth
1911*37da2899SCharles.Forsyth			ctx.state = STATE_EXIT;
1912*37da2899SCharles.Forsyth			fatal(SSL_CLOSE_NOTIFY, "ssl3: response close notify", ctx);
1913*37da2899SCharles.Forsyth
1914*37da2899SCharles.Forsyth		SSL_NO_CERTIFICATE =>
1915*37da2899SCharles.Forsyth
1916*37da2899SCharles.Forsyth			# A no_certificate alert message may be sent in
1917*37da2899SCharles.Forsyth			# response to a certification request if no
1918*37da2899SCharles.Forsyth			# appropriate certificate is available.
1919*37da2899SCharles.Forsyth
1920*37da2899SCharles.Forsyth			if(ctx.state == STATE_CLIENT_CERTIFICATE) {
1921*37da2899SCharles.Forsyth				hm := ref Handshake.Certificate(ctx.local_info.certs);
1922*37da2899SCharles.Forsyth				handshake_enque(hm, ctx);
1923*37da2899SCharles.Forsyth			}
1924*37da2899SCharles.Forsyth
1925*37da2899SCharles.Forsyth		SSL_BAD_CERTIFICATE or
1926*37da2899SCharles.Forsyth
1927*37da2899SCharles.Forsyth			# A certificate was corrupt, contained signatures
1928*37da2899SCharles.Forsyth			# that did not verify correctly, etc.
1929*37da2899SCharles.Forsyth
1930*37da2899SCharles.Forsyth		SSL_UNSUPPORTED_CERTIFICATE or
1931*37da2899SCharles.Forsyth
1932*37da2899SCharles.Forsyth			# A certificate was of an unsupported type.
1933*37da2899SCharles.Forsyth
1934*37da2899SCharles.Forsyth		SSL_CERTIFICATE_REVOKED or
1935*37da2899SCharles.Forsyth
1936*37da2899SCharles.Forsyth			# A certificate was revoked by its signer.
1937*37da2899SCharles.Forsyth
1938*37da2899SCharles.Forsyth		SSL_CERTIFICATE_EXPIRED or
1939*37da2899SCharles.Forsyth
1940*37da2899SCharles.Forsyth			# A certificate has expired or is not currently
1941*37da2899SCharles.Forsyth			# valid.
1942*37da2899SCharles.Forsyth
1943*37da2899SCharles.Forsyth		SSL_CERTIFICATE_UNKNOWN =>
1944*37da2899SCharles.Forsyth
1945*37da2899SCharles.Forsyth			# Some other (unspecified) issue arose in
1946*37da2899SCharles.Forsyth			# processing the certificate, rendering it
1947*37da2899SCharles.Forsyth			# unacceptable.
1948*37da2899SCharles.Forsyth			break;
1949*37da2899SCharles.Forsyth
1950*37da2899SCharles.Forsyth		* =>
1951*37da2899SCharles.Forsyth			ctx.session.session_id = nil;
1952*37da2899SCharles.Forsyth			fatal(SSL_ILLEGAL_PARAMETER, "ssl3: unknown alert description", ctx);
1953*37da2899SCharles.Forsyth		}
1954*37da2899SCharles.Forsyth
1955*37da2899SCharles.Forsyth	* =>
1956*37da2899SCharles.Forsyth		ctx.session.session_id = nil;
1957*37da2899SCharles.Forsyth		fatal(SSL_ILLEGAL_PARAMETER, "ssl3: unknown alert level received", ctx);
1958*37da2899SCharles.Forsyth	}
1959*37da2899SCharles.Forsyth}
1960*37da2899SCharles.Forsyth
1961*37da2899SCharles.Forsyth# notify the receiving party that subsequent records will
1962*37da2899SCharles.Forsyth# be protected under the just-negotiated CipherSpec and keys.
1963*37da2899SCharles.Forsyth
1964*37da2899SCharles.Forsythdo_change_cipher_spec(ctx: ref Context)
1965*37da2899SCharles.Forsyth{
1966*37da2899SCharles.Forsyth	# calculate and set new keys
1967*37da2899SCharles.Forsyth	if(!(ctx.status & IN_READY)) {
1968*37da2899SCharles.Forsyth		e := set_in_queue(ctx);
1969*37da2899SCharles.Forsyth		if(e != "") {
1970*37da2899SCharles.Forsyth			fatal(SSL_CLOSE_NOTIFY, "do_change_cipher_spec: setup new cipher failed", ctx);
1971*37da2899SCharles.Forsyth			return;
1972*37da2899SCharles.Forsyth		}
1973*37da2899SCharles.Forsyth		ctx.status |= IN_READY;
1974*37da2899SCharles.Forsyth
1975*37da2899SCharles.Forsyth		if(SSL_DEBUG)
1976*37da2899SCharles.Forsyth			log("ssl3: set in cipher done\n");
1977*37da2899SCharles.Forsyth	}
1978*37da2899SCharles.Forsyth
1979*37da2899SCharles.Forsyth	ctx.state = STATE_FINISHED;
1980*37da2899SCharles.Forsyth}
1981*37da2899SCharles.Forsyth
1982*37da2899SCharles.Forsyth
1983*37da2899SCharles.Forsyth# process and advance handshake messages, update internal stack and switch to next
1984*37da2899SCharles.Forsyth# expected state(s).
1985*37da2899SCharles.Forsyth
1986*37da2899SCharles.Forsythdo_handshake(handshake: ref Handshake, ctx: ref Context) : string
1987*37da2899SCharles.Forsyth{
1988*37da2899SCharles.Forsyth	e := "";
1989*37da2899SCharles.Forsyth
1990*37da2899SCharles.Forsyth	pick h := handshake {
1991*37da2899SCharles.Forsyth	HelloRequest =>
1992*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) || ctx.state != STATE_HELLO_REQUEST) {
1993*37da2899SCharles.Forsyth			e = "HelloRequest";
1994*37da2899SCharles.Forsyth			break;
1995*37da2899SCharles.Forsyth		}
1996*37da2899SCharles.Forsyth		do_hello_request(ctx);
1997*37da2899SCharles.Forsyth
1998*37da2899SCharles.Forsyth	ClientHello =>
1999*37da2899SCharles.Forsyth		if((ctx.status & CLIENT_SIDE) || ctx.state != STATE_CLIENT_HELLO) {
2000*37da2899SCharles.Forsyth			e = "ClientHello";
2001*37da2899SCharles.Forsyth			break;
2002*37da2899SCharles.Forsyth		}
2003*37da2899SCharles.Forsyth		do_client_hello(h, ctx);
2004*37da2899SCharles.Forsyth
2005*37da2899SCharles.Forsyth	ServerHello =>
2006*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) || ctx.state != STATE_SERVER_HELLO) {
2007*37da2899SCharles.Forsyth			e = "ServerHello";
2008*37da2899SCharles.Forsyth			break;
2009*37da2899SCharles.Forsyth		}
2010*37da2899SCharles.Forsyth		do_server_hello(h, ctx);
2011*37da2899SCharles.Forsyth
2012*37da2899SCharles.Forsyth	ClientKeyExchange =>
2013*37da2899SCharles.Forsyth		if((ctx.status & CLIENT_SIDE) || ctx.state != STATE_CLIENT_KEY_EXCHANGE) {
2014*37da2899SCharles.Forsyth			e = "ClientKeyExchange";
2015*37da2899SCharles.Forsyth			break;
2016*37da2899SCharles.Forsyth		}
2017*37da2899SCharles.Forsyth		do_client_keyex(h, ctx);
2018*37da2899SCharles.Forsyth
2019*37da2899SCharles.Forsyth	ServerKeyExchange =>
2020*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) ||
2021*37da2899SCharles.Forsyth			(ctx.state != STATE_SERVER_KEY_EXCHANGE && ctx.state != STATE_SERVER_HELLO_DONE)) {
2022*37da2899SCharles.Forsyth			e = "ServerKeyExchange";
2023*37da2899SCharles.Forsyth			break;
2024*37da2899SCharles.Forsyth		}
2025*37da2899SCharles.Forsyth		do_server_keyex(h, ctx);
2026*37da2899SCharles.Forsyth
2027*37da2899SCharles.Forsyth	ServerHelloDone =>
2028*37da2899SCharles.Forsyth		# diff from SSLRef, to support variant impl
2029*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) ||
2030*37da2899SCharles.Forsyth			(ctx.state != STATE_SERVER_HELLO_DONE && ctx.state != STATE_SERVER_KEY_EXCHANGE)) {
2031*37da2899SCharles.Forsyth			e = "ServerHelloDone";
2032*37da2899SCharles.Forsyth			break;
2033*37da2899SCharles.Forsyth		}
2034*37da2899SCharles.Forsyth		do_server_done(ctx);
2035*37da2899SCharles.Forsyth
2036*37da2899SCharles.Forsyth	Certificate =>
2037*37da2899SCharles.Forsyth		if(ctx.status & CLIENT_SIDE) {
2038*37da2899SCharles.Forsyth			if(ctx.state != STATE_SERVER_CERTIFICATE) {
2039*37da2899SCharles.Forsyth				e = "ServerCertificate";
2040*37da2899SCharles.Forsyth				break;
2041*37da2899SCharles.Forsyth			}
2042*37da2899SCharles.Forsyth			do_server_cert(h, ctx);
2043*37da2899SCharles.Forsyth		}
2044*37da2899SCharles.Forsyth		else {
2045*37da2899SCharles.Forsyth			if(ctx.state != STATE_CLIENT_CERTIFICATE) {
2046*37da2899SCharles.Forsyth				e = "ClientCertificate";
2047*37da2899SCharles.Forsyth				break;
2048*37da2899SCharles.Forsyth			}
2049*37da2899SCharles.Forsyth			do_client_cert(h, ctx); # server_side
2050*37da2899SCharles.Forsyth		}
2051*37da2899SCharles.Forsyth
2052*37da2899SCharles.Forsyth	CertificateRequest =>
2053*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) || ctx.state != STATE_SERVER_HELLO_DONE
2054*37da2899SCharles.Forsyth			|| ctx.state != STATE_SERVER_KEY_EXCHANGE) {
2055*37da2899SCharles.Forsyth			e = "CertificateRequest";
2056*37da2899SCharles.Forsyth			break;
2057*37da2899SCharles.Forsyth		}
2058*37da2899SCharles.Forsyth		do_cert_request(h, ctx);
2059*37da2899SCharles.Forsyth
2060*37da2899SCharles.Forsyth	CertificateVerify =>
2061*37da2899SCharles.Forsyth		if((ctx.status & CLIENT_SIDE) || ctx.state != STATE_CERTIFICATE_VERIFY) {
2062*37da2899SCharles.Forsyth			e = "CertificateVerify";
2063*37da2899SCharles.Forsyth			break;
2064*37da2899SCharles.Forsyth		}
2065*37da2899SCharles.Forsyth		do_cert_verify(h, ctx);
2066*37da2899SCharles.Forsyth
2067*37da2899SCharles.Forsyth	Finished =>
2068*37da2899SCharles.Forsyth		if(ctx.status & CLIENT_SIDE) {
2069*37da2899SCharles.Forsyth			if(ctx.state != STATE_FINISHED) {
2070*37da2899SCharles.Forsyth				e = "ClientFinished";
2071*37da2899SCharles.Forsyth				break;
2072*37da2899SCharles.Forsyth			}
2073*37da2899SCharles.Forsyth			do_finished(SSL_CLIENT_SENDER, ctx);
2074*37da2899SCharles.Forsyth		}
2075*37da2899SCharles.Forsyth		else {
2076*37da2899SCharles.Forsyth			if(ctx.state != STATE_FINISHED) {
2077*37da2899SCharles.Forsyth				e = "ServerFinished";
2078*37da2899SCharles.Forsyth				break;
2079*37da2899SCharles.Forsyth			}
2080*37da2899SCharles.Forsyth			do_finished(SSL_SERVER_SENDER, ctx);
2081*37da2899SCharles.Forsyth		}
2082*37da2899SCharles.Forsyth
2083*37da2899SCharles.Forsyth	* =>
2084*37da2899SCharles.Forsyth		e = "unknown handshake message";
2085*37da2899SCharles.Forsyth	}
2086*37da2899SCharles.Forsyth
2087*37da2899SCharles.Forsyth	if(e != nil)
2088*37da2899SCharles.Forsyth		e = "do_handshake: " + e;
2089*37da2899SCharles.Forsyth
2090*37da2899SCharles.Forsyth	return e;
2091*37da2899SCharles.Forsyth}
2092*37da2899SCharles.Forsyth
2093*37da2899SCharles.Forsyth# [client side]
2094*37da2899SCharles.Forsyth# The hello request message may be sent by server at any time, but will be ignored by
2095*37da2899SCharles.Forsyth# the client if the handshake protocol is already underway. It is simple notification
2096*37da2899SCharles.Forsyth# that the client should begin the negotiation process anew by sending a client hello
2097*37da2899SCharles.Forsyth# message.
2098*37da2899SCharles.Forsyth
2099*37da2899SCharles.Forsythdo_hello_request(ctx: ref Context)
2100*37da2899SCharles.Forsyth{
2101*37da2899SCharles.Forsyth	# start from new handshake digest state
2102*37da2899SCharles.Forsyth	ctx.sha_state = ctx.md5_state = nil;
2103*37da2899SCharles.Forsyth
2104*37da2899SCharles.Forsyth	# Note:
2105*37da2899SCharles.Forsyth	# 	sending ctx.local_info.suites instead of ctx.session.suite,
2106*37da2899SCharles.Forsyth	#	if session is resumable by server, ctx.session.suite will be used.
2107*37da2899SCharles.Forsyth	handshake_enque(
2108*37da2899SCharles.Forsyth		ref Handshake.ClientHello(
2109*37da2899SCharles.Forsyth			ctx.session.version,
2110*37da2899SCharles.Forsyth			ctx.client_random,
2111*37da2899SCharles.Forsyth			ctx.session.session_id,
2112*37da2899SCharles.Forsyth			ctx.local_info.suites,
2113*37da2899SCharles.Forsyth			ctx.local_info.comprs
2114*37da2899SCharles.Forsyth		),
2115*37da2899SCharles.Forsyth		ctx
2116*37da2899SCharles.Forsyth	);
2117*37da2899SCharles.Forsyth
2118*37da2899SCharles.Forsyth	ctx.state = STATE_SERVER_HELLO;
2119*37da2899SCharles.Forsyth}
2120*37da2899SCharles.Forsyth
2121*37da2899SCharles.Forsyth# [client side]
2122*37da2899SCharles.Forsyth# Processes the received server hello handshake message and determines if the session
2123*37da2899SCharles.Forsyth# is resumable. (The client sends a client hello using the session id of the session
2124*37da2899SCharles.Forsyth# to be resumed. The server then checks its session cache for a match. If a match is
2125*37da2899SCharles.Forsyth# FOUND, and the server is WILLING to re-establish the connection under the specified
2126*37da2899SCharles.Forsyth# session state, it will send a server hello with the SAME session id value.) If the
2127*37da2899SCharles.Forsyth# session is resumed, at this point both client and server must send change cipher
2128*37da2899SCharles.Forsyth# spec messages. If the session is not resumable, the client and server perform
2129*37da2899SCharles.Forsyth# a full handshake. (On the server side, if a session id match is not found, the
2130*37da2899SCharles.Forsyth# server generates a new session id or if the server is not willing to resume, the
2131*37da2899SCharles.Forsyth# server uses a null session id).
2132*37da2899SCharles.Forsyth
2133*37da2899SCharles.Forsythdo_server_hello(hm: ref Handshake.ServerHello, ctx: ref Context)
2134*37da2899SCharles.Forsyth{
2135*37da2899SCharles.Forsyth	# trying to resume
2136*37da2899SCharles.Forsyth	if(bytes_cmp(ctx.session.session_id, hm.session_id) == 0) {
2137*37da2899SCharles.Forsyth
2138*37da2899SCharles.Forsyth		if(SSL_DEBUG)
2139*37da2899SCharles.Forsyth			log("ssl3: session resumed\n");
2140*37da2899SCharles.Forsyth
2141*37da2899SCharles.Forsyth		ctx.status |= SESSION_RESUMABLE;
2142*37da2899SCharles.Forsyth		# avoid version attack
2143*37da2899SCharles.Forsyth		if(ctx.session.version[0] != hm.version[0] ||
2144*37da2899SCharles.Forsyth			ctx.session.version[1] != hm.version[1]) {
2145*37da2899SCharles.Forsyth			fatal(SSL_CLOSE_NOTIFY,	"do_server_hello: version mismatch", ctx);
2146*37da2899SCharles.Forsyth			return;
2147*37da2899SCharles.Forsyth		}
2148*37da2899SCharles.Forsyth
2149*37da2899SCharles.Forsyth		ctx.server_random = hm.random;
2150*37da2899SCharles.Forsyth
2151*37da2899SCharles.Forsyth		# uses the retrieved session suite by server (should be same by client)
2152*37da2899SCharles.Forsyth		(ciph, keyx, sign, e)
2153*37da2899SCharles.Forsyth			:= suite_to_spec(hm.suite, SSL3_Suites);
2154*37da2899SCharles.Forsyth		if(e != nil) {
2155*37da2899SCharles.Forsyth			fatal(SSL_UNEXPECTED_MESSAGE, "server hello: suite not found", ctx);
2156*37da2899SCharles.Forsyth			return;
2157*37da2899SCharles.Forsyth		}
2158*37da2899SCharles.Forsyth		ctx.sel_ciph = ciph;
2159*37da2899SCharles.Forsyth		ctx.sel_keyx = keyx;
2160*37da2899SCharles.Forsyth		ctx.sel_sign = sign;
2161*37da2899SCharles.Forsyth		ctx.sel_cmpr = int ctx.session.compression; # not supported by ssl3 yet
2162*37da2899SCharles.Forsyth
2163*37da2899SCharles.Forsyth		# calculate keys
2164*37da2899SCharles.Forsyth		(ctx.cw_mac, ctx.sw_mac, ctx.cw_key, ctx.sw_key, ctx.cw_IV, ctx.sw_IV)
2165*37da2899SCharles.Forsyth			= calc_keys(ctx.sel_ciph, ctx.session.master_secret,
2166*37da2899SCharles.Forsyth			ctx.client_random, ctx.server_random);
2167*37da2899SCharles.Forsyth
2168*37da2899SCharles.Forsyth
2169*37da2899SCharles.Forsyth		ctx.state = STATE_CHANGE_CIPHER_SPEC;
2170*37da2899SCharles.Forsyth	}
2171*37da2899SCharles.Forsyth	else {
2172*37da2899SCharles.Forsyth		ctx.status &= ~SESSION_RESUMABLE;
2173*37da2899SCharles.Forsyth
2174*37da2899SCharles.Forsyth		# On the server side, if a session id match is not found, the
2175*37da2899SCharles.Forsyth		# server generates a new session id or if the server is not willing
2176*37da2899SCharles.Forsyth		# to resume, the server uses an empty session id and cannot be
2177*37da2899SCharles.Forsyth		# cached by both client and server.
2178*37da2899SCharles.Forsyth
2179*37da2899SCharles.Forsyth		ctx.session.session_id = hm.session_id;
2180*37da2899SCharles.Forsyth		ctx.session.version = hm.version;
2181*37da2899SCharles.Forsyth		ctx.server_random = hm.random;
2182*37da2899SCharles.Forsyth
2183*37da2899SCharles.Forsyth		if(SSL_DEBUG)
2184*37da2899SCharles.Forsyth			log("ssl3: do_server_hello:\n\tselected cipher suite =\n\t\t"
2185*37da2899SCharles.Forsyth			+ cipher_suite_info(hm.suite, SSL3_Suites) + "\n");
2186*37da2899SCharles.Forsyth
2187*37da2899SCharles.Forsyth		(ciph, keyx, sign, e) := suite_to_spec(hm.suite, SSL3_Suites);
2188*37da2899SCharles.Forsyth		if(e != nil) {
2189*37da2899SCharles.Forsyth			fatal(SSL_UNEXPECTED_MESSAGE, "server hello: suite not found", ctx);
2190*37da2899SCharles.Forsyth			return;
2191*37da2899SCharles.Forsyth		}
2192*37da2899SCharles.Forsyth
2193*37da2899SCharles.Forsyth		ctx.sel_ciph = ciph;
2194*37da2899SCharles.Forsyth		ctx.sel_keyx = keyx;
2195*37da2899SCharles.Forsyth		ctx.sel_sign = sign;
2196*37da2899SCharles.Forsyth		ctx.sel_cmpr = int hm.compression; # not supported by ssl3 yet
2197*37da2899SCharles.Forsyth
2198*37da2899SCharles.Forsyth		# next state is determined by selected key exchange and signature methods
2199*37da2899SCharles.Forsyth		# the ctx.sel_keyx and ctx.sel_sign are completed by the following handshake
2200*37da2899SCharles.Forsyth		# Certificate and/or ServerKeyExchange
2201*37da2899SCharles.Forsyth
2202*37da2899SCharles.Forsyth		if(tagof ctx.sel_keyx == tagof KeyExAlg.DH &&
2203*37da2899SCharles.Forsyth			tagof ctx.sel_sign == tagof SigAlg.anon)
2204*37da2899SCharles.Forsyth			ctx.state = STATE_SERVER_KEY_EXCHANGE;
2205*37da2899SCharles.Forsyth		else
2206*37da2899SCharles.Forsyth			ctx.state = STATE_SERVER_CERTIFICATE;
2207*37da2899SCharles.Forsyth	}
2208*37da2899SCharles.Forsyth}
2209*37da2899SCharles.Forsyth
2210*37da2899SCharles.Forsyth# [client side]
2211*37da2899SCharles.Forsyth# Processes the received server key exchange message. The server key exchange message
2212*37da2899SCharles.Forsyth# is sent by the server if it has no certificate, has a certificate only used for
2213*37da2899SCharles.Forsyth# signing, or FORTEZZA KEA key exchange is used.
2214*37da2899SCharles.Forsyth
2215*37da2899SCharles.Forsythdo_server_keyex(hm: ref Handshake.ServerKeyExchange, ctx: ref Context)
2216*37da2899SCharles.Forsyth{
2217*37da2899SCharles.Forsyth	# install exchange keys sent by server, this may require public key
2218*37da2899SCharles.Forsyth	# retrieved from certificate sent by Handshake.Certificate message
2219*37da2899SCharles.Forsyth
2220*37da2899SCharles.Forsyth	(err, i) := install_server_xkey(hm.xkey, ctx.sel_keyx);
2221*37da2899SCharles.Forsyth	if(err == "")
2222*37da2899SCharles.Forsyth		err = verify_server_xkey(ctx.client_random, ctx.server_random, hm.xkey, i, ctx.sel_sign);
2223*37da2899SCharles.Forsyth
2224*37da2899SCharles.Forsyth	if(err == "")
2225*37da2899SCharles.Forsyth		ctx.state = STATE_SERVER_HELLO_DONE;
2226*37da2899SCharles.Forsyth	else
2227*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "do_server_keyex: " + err, ctx);
2228*37da2899SCharles.Forsyth}
2229*37da2899SCharles.Forsyth
2230*37da2899SCharles.Forsyth# [client side]
2231*37da2899SCharles.Forsyth# Processes the received server hello done message by verifying that the server
2232*37da2899SCharles.Forsyth# provided a valid certificate if required and checking that the server hello
2233*37da2899SCharles.Forsyth# parameters are acceptable.
2234*37da2899SCharles.Forsyth
2235*37da2899SCharles.Forsythdo_server_done(ctx: ref Context)
2236*37da2899SCharles.Forsyth{
2237*37da2899SCharles.Forsyth	# On client side, optionally send client cert chain if client_auth
2238*37da2899SCharles.Forsyth	# is required by the server. The server may drop the connection,
2239*37da2899SCharles.Forsyth	# if it does not receive client certificate in the following
2240*37da2899SCharles.Forsyth	# Handshake.ClientCertificate message
2241*37da2899SCharles.Forsyth	if(ctx.status & CLIENT_AUTH) {
2242*37da2899SCharles.Forsyth		if(ctx.local_info.certs != nil) {
2243*37da2899SCharles.Forsyth			handshake_enque(
2244*37da2899SCharles.Forsyth				ref Handshake.Certificate(ctx.local_info.certs),
2245*37da2899SCharles.Forsyth				ctx
2246*37da2899SCharles.Forsyth			);
2247*37da2899SCharles.Forsyth			ctx.status |= CERT_SENT;
2248*37da2899SCharles.Forsyth		}
2249*37da2899SCharles.Forsyth		else {
2250*37da2899SCharles.Forsyth			alert_enque(
2251*37da2899SCharles.Forsyth				ref Alert(SSL_WARNING, SSL_NO_CERTIFICATE),
2252*37da2899SCharles.Forsyth				ctx
2253*37da2899SCharles.Forsyth			);
2254*37da2899SCharles.Forsyth		}
2255*37da2899SCharles.Forsyth	}
2256*37da2899SCharles.Forsyth
2257*37da2899SCharles.Forsyth	# calculate premaster secrect, client exchange keys and update ref KeyExAlg
2258*37da2899SCharles.Forsyth	# of the client side
2259*37da2899SCharles.Forsyth	(x, pm, e) := calc_client_xkey(ctx.sel_keyx);
2260*37da2899SCharles.Forsyth	if(e != "") {
2261*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, e, ctx);
2262*37da2899SCharles.Forsyth		return;
2263*37da2899SCharles.Forsyth	}
2264*37da2899SCharles.Forsyth	handshake_enque(ref Handshake.ClientKeyExchange(x), ctx);
2265*37da2899SCharles.Forsyth
2266*37da2899SCharles.Forsyth	ms := calc_master_secret(pm, ctx.client_random, ctx.server_random);
2267*37da2899SCharles.Forsyth	if(ms == nil) {
2268*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "server hello done: calc master secret failed", ctx);
2269*37da2899SCharles.Forsyth		return;
2270*37da2899SCharles.Forsyth	}
2271*37da2899SCharles.Forsyth	# ctx.premaster_secret = pm;
2272*37da2899SCharles.Forsyth	ctx.session.master_secret = ms;
2273*37da2899SCharles.Forsyth
2274*37da2899SCharles.Forsyth	# sending certificate verifiy message if the client auth is required
2275*37da2899SCharles.Forsyth	# and client certificate has been sent,
2276*37da2899SCharles.Forsyth	if(ctx.status & CERT_SENT) {
2277*37da2899SCharles.Forsyth		sig : array of byte;
2278*37da2899SCharles.Forsyth		(md5_hash, sha_hash)
2279*37da2899SCharles.Forsyth			:= calc_finished(nil, ctx.session.master_secret, ctx.sha_state, ctx.md5_state);
2280*37da2899SCharles.Forsyth		# check type of client cert being sent
2281*37da2899SCharles.Forsyth		pick sk := ctx.local_info.sk {
2282*37da2899SCharles.Forsyth		RSA =>
2283*37da2899SCharles.Forsyth			hashes := array [36] of byte;
2284*37da2899SCharles.Forsyth			hashes[0:] = md5_hash;
2285*37da2899SCharles.Forsyth			hashes[16:] = sha_hash;
2286*37da2899SCharles.Forsyth			#(e, sig) = pkcs->rsa_sign(hashes, sk, PKCS->MD5_WithRSAEncryption);
2287*37da2899SCharles.Forsyth		DSS =>
2288*37da2899SCharles.Forsyth			#(e, sig) = pkcs->dss_sign(sha_hash, sk);
2289*37da2899SCharles.Forsyth		* =>
2290*37da2899SCharles.Forsyth			e = "unknown sign";
2291*37da2899SCharles.Forsyth		}
2292*37da2899SCharles.Forsyth		if(e != "") {
2293*37da2899SCharles.Forsyth			fatal(SSL_HANDSHAKE_FAILURE, "server hello done: sign cert verify failed", ctx);
2294*37da2899SCharles.Forsyth			return;
2295*37da2899SCharles.Forsyth		}
2296*37da2899SCharles.Forsyth		handshake_enque(ref Handshake.CertificateVerify(sig), ctx);
2297*37da2899SCharles.Forsyth	}
2298*37da2899SCharles.Forsyth
2299*37da2899SCharles.Forsyth	ccs_enque(ref ChangeCipherSpec(1), ctx);
2300*37da2899SCharles.Forsyth	(ctx.cw_mac, ctx.sw_mac, ctx.cw_key, ctx.sw_key, ctx.cw_IV, ctx.sw_IV)
2301*37da2899SCharles.Forsyth		= calc_keys(ctx.sel_ciph, ctx.session.master_secret,
2302*37da2899SCharles.Forsyth		ctx.client_random, ctx.server_random);
2303*37da2899SCharles.Forsyth
2304*37da2899SCharles.Forsyth	# set cipher on write channel
2305*37da2899SCharles.Forsyth	e = set_out_queue(ctx);
2306*37da2899SCharles.Forsyth	if(e != nil) {
2307*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "do_server_done: " + e, ctx);
2308*37da2899SCharles.Forsyth		return;
2309*37da2899SCharles.Forsyth	}
2310*37da2899SCharles.Forsyth	ctx.status |= OUT_READY;
2311*37da2899SCharles.Forsyth
2312*37da2899SCharles.Forsyth	if(SSL_DEBUG)
2313*37da2899SCharles.Forsyth		log("ssl3: set out cipher done\n");
2314*37da2899SCharles.Forsyth	(mh, sh) := calc_finished(SSL_CLIENT_SENDER, ctx.session.master_secret,
2315*37da2899SCharles.Forsyth		ctx.sha_state, ctx.md5_state);
2316*37da2899SCharles.Forsyth# sending out the Finished msg causes MS https servers to hangup
2317*37da2899SCharles.Forsyth#sys->print("RETURNING FROM DO_SERVER_DONE\n");
2318*37da2899SCharles.Forsyth#return;
2319*37da2899SCharles.Forsyth	handshake_enque(ref Handshake.Finished(mh, sh), ctx);
2320*37da2899SCharles.Forsyth
2321*37da2899SCharles.Forsyth	ctx.state = STATE_CHANGE_CIPHER_SPEC;
2322*37da2899SCharles.Forsyth}
2323*37da2899SCharles.Forsyth
2324*37da2899SCharles.Forsyth# [client side]
2325*37da2899SCharles.Forsyth# Process the received certificate message.
2326*37da2899SCharles.Forsyth# Note:
2327*37da2899SCharles.Forsyth#	according to current US export law, RSA moduli larger than 512 bits
2328*37da2899SCharles.Forsyth# 	may not be used for key exchange in software exported from US. With
2329*37da2899SCharles.Forsyth# 	this message, larger RSA keys may be used as signature only
2330*37da2899SCharles.Forsyth# 	certificates to sign temporary shorter RSA keys for key exchange.
2331*37da2899SCharles.Forsyth
2332*37da2899SCharles.Forsythdo_server_cert(hm: ref Handshake.Certificate, ctx: ref Context)
2333*37da2899SCharles.Forsyth{
2334*37da2899SCharles.Forsyth	if(hm.cert_list == nil) {
2335*37da2899SCharles.Forsyth		fatal(SSL_UNEXPECTED_MESSAGE, "nil peer certificate", ctx);
2336*37da2899SCharles.Forsyth		return;
2337*37da2899SCharles.Forsyth	}
2338*37da2899SCharles.Forsyth
2339*37da2899SCharles.Forsyth	# server's certificate is the last one in the chain (reverse required)
2340*37da2899SCharles.Forsyth	cl := hm.cert_list;
2341*37da2899SCharles.Forsyth	ctx.session.peer_certs = nil;
2342*37da2899SCharles.Forsyth	while(cl != nil) {
2343*37da2899SCharles.Forsyth		ctx.session.peer_certs = hd cl::ctx.session.peer_certs;
2344*37da2899SCharles.Forsyth		cl = tl cl;
2345*37da2899SCharles.Forsyth	}
2346*37da2899SCharles.Forsyth
2347*37da2899SCharles.Forsyth	# TODO: verify certificate chain
2348*37da2899SCharles.Forsyth	#	check if in the acceptable dnlist
2349*37da2899SCharles.Forsyth	# ctx.sel_keyx.peer_pk = x509->verify_chain(ctx.session.peer_certs);
2350*37da2899SCharles.Forsyth	if(SSL_DEBUG)
2351*37da2899SCharles.Forsyth		log("ssl3: number certificates got: " + string len ctx.session.peer_certs);
2352*37da2899SCharles.Forsyth	peer_cert := hd ctx.session.peer_certs;
2353*37da2899SCharles.Forsyth	(e, signed) := x509->Signed.decode(peer_cert);
2354*37da2899SCharles.Forsyth	if(e != "") {
2355*37da2899SCharles.Forsyth		if(SSL_DEBUG)
2356*37da2899SCharles.Forsyth			log("ss3: server certificate: " + e);
2357*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "server certificate: " + e, ctx);
2358*37da2899SCharles.Forsyth		return;
2359*37da2899SCharles.Forsyth	}
2360*37da2899SCharles.Forsyth
2361*37da2899SCharles.Forsyth	srv_cert: ref Certificate;
2362*37da2899SCharles.Forsyth	(e, srv_cert) = x509->Certificate.decode(signed.tobe_signed);
2363*37da2899SCharles.Forsyth	if(e != "") {
2364*37da2899SCharles.Forsyth		if(SSL_DEBUG)
2365*37da2899SCharles.Forsyth			log("ss3: server certificate: " + e);
2366*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "server certificate: " + e, ctx);
2367*37da2899SCharles.Forsyth		return;
2368*37da2899SCharles.Forsyth	}
2369*37da2899SCharles.Forsyth	if(SSL_DEBUG)
2370*37da2899SCharles.Forsyth		log("ssl3: " + srv_cert.tostring());
2371*37da2899SCharles.Forsyth
2372*37da2899SCharles.Forsyth	# extract and determine byte of user certificate
2373*37da2899SCharles.Forsyth	id: int;
2374*37da2899SCharles.Forsyth	peer_pk: ref X509->PublicKey;
2375*37da2899SCharles.Forsyth	(e, id, peer_pk) = srv_cert.subject_pkinfo.getPublicKey();
2376*37da2899SCharles.Forsyth	if(e != "") {
2377*37da2899SCharles.Forsyth		if(SSL_DEBUG)
2378*37da2899SCharles.Forsyth			log("ss3: server certificate: " + e);
2379*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "server certificate:" + e, ctx);
2380*37da2899SCharles.Forsyth		return;
2381*37da2899SCharles.Forsyth	}
2382*37da2899SCharles.Forsyth
2383*37da2899SCharles.Forsyth	pick key := peer_pk {
2384*37da2899SCharles.Forsyth	RSA =>
2385*37da2899SCharles.Forsyth		# TODO: to allow checking X509v3 KeyUsage extension
2386*37da2899SCharles.Forsyth		if((0 && key.pk.modulus.bits() > 512 && ctx.sel_ciph.is_exportable)
2387*37da2899SCharles.Forsyth			|| id == PKCS->id_pkcs_md2WithRSAEncryption
2388*37da2899SCharles.Forsyth			|| id == PKCS->id_pkcs_md4WithRSAEncryption
2389*37da2899SCharles.Forsyth			|| id == PKCS->id_pkcs_md5WithRSAEncryption) {
2390*37da2899SCharles.Forsyth			pick sign := ctx.sel_sign {
2391*37da2899SCharles.Forsyth			anon =>
2392*37da2899SCharles.Forsyth				break;
2393*37da2899SCharles.Forsyth			RSA =>
2394*37da2899SCharles.Forsyth				break;
2395*37da2899SCharles.Forsyth			* =>
2396*37da2899SCharles.Forsyth				# error
2397*37da2899SCharles.Forsyth			}
2398*37da2899SCharles.Forsyth			if(ctx.local_info.sk == nil)
2399*37da2899SCharles.Forsyth				ctx.sel_sign = ref SigAlg.RSA(nil, key.pk);
2400*37da2899SCharles.Forsyth			else {
2401*37da2899SCharles.Forsyth				pick mysk := ctx.local_info.sk {
2402*37da2899SCharles.Forsyth				RSA =>
2403*37da2899SCharles.Forsyth					ctx.sel_sign = ref SigAlg.RSA(mysk.sk, key.pk);
2404*37da2899SCharles.Forsyth				* =>
2405*37da2899SCharles.Forsyth					ctx.sel_sign = ref SigAlg.RSA(nil, key.pk);
2406*37da2899SCharles.Forsyth				}
2407*37da2899SCharles.Forsyth			}
2408*37da2899SCharles.Forsyth			# key exchange may be tmp RSA, emhemeral DH depending on cipher suite
2409*37da2899SCharles.Forsyth			ctx.state = STATE_SERVER_KEY_EXCHANGE;
2410*37da2899SCharles.Forsyth		}
2411*37da2899SCharles.Forsyth		# TODO: allow id == PKCS->id_rsa
2412*37da2899SCharles.Forsyth		else if(id == PKCS->id_pkcs_rsaEncryption) {
2413*37da2899SCharles.Forsyth			pick sign := ctx.sel_sign {
2414*37da2899SCharles.Forsyth			anon =>
2415*37da2899SCharles.Forsyth				break;
2416*37da2899SCharles.Forsyth			* =>
2417*37da2899SCharles.Forsyth				# error
2418*37da2899SCharles.Forsyth			}
2419*37da2899SCharles.Forsyth			ctx.sel_sign = ref SigAlg.anon();
2420*37da2899SCharles.Forsyth			pick keyx := ctx.sel_keyx {
2421*37da2899SCharles.Forsyth			RSA =>
2422*37da2899SCharles.Forsyth				keyx.peer_pk = key.pk;
2423*37da2899SCharles.Forsyth			* =>
2424*37da2899SCharles.Forsyth				# error
2425*37da2899SCharles.Forsyth			}
2426*37da2899SCharles.Forsyth			ctx.state = STATE_SERVER_HELLO_DONE;
2427*37da2899SCharles.Forsyth		}
2428*37da2899SCharles.Forsyth		else {
2429*37da2899SCharles.Forsyth			# error
2430*37da2899SCharles.Forsyth		}
2431*37da2899SCharles.Forsyth	DSS =>
2432*37da2899SCharles.Forsyth		pick sign := ctx.sel_sign {
2433*37da2899SCharles.Forsyth		DSS =>
2434*37da2899SCharles.Forsyth			sign.peer_pk = key.pk;
2435*37da2899SCharles.Forsyth			break;
2436*37da2899SCharles.Forsyth		* =>
2437*37da2899SCharles.Forsyth			# error
2438*37da2899SCharles.Forsyth		}
2439*37da2899SCharles.Forsyth		# should be key exchagne such as emhemeral DH
2440*37da2899SCharles.Forsyth		ctx.state = STATE_SERVER_KEY_EXCHANGE;
2441*37da2899SCharles.Forsyth	DH =>
2442*37da2899SCharles.Forsyth		# fixed DH signed in certificate either by RSA or DSS???
2443*37da2899SCharles.Forsyth		pick keyx := ctx.sel_keyx {
2444*37da2899SCharles.Forsyth		DH =>
2445*37da2899SCharles.Forsyth			keyx.peer_pk = key.pk;
2446*37da2899SCharles.Forsyth		* =>
2447*37da2899SCharles.Forsyth			# error
2448*37da2899SCharles.Forsyth		}
2449*37da2899SCharles.Forsyth		ctx.state = STATE_SERVER_KEY_EXCHANGE;
2450*37da2899SCharles.Forsyth	}
2451*37da2899SCharles.Forsyth
2452*37da2899SCharles.Forsyth	if(e != nil) {
2453*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "do_server_cert: " + e, ctx);
2454*37da2899SCharles.Forsyth		return;
2455*37da2899SCharles.Forsyth	}
2456*37da2899SCharles.Forsyth}
2457*37da2899SCharles.Forsyth
2458*37da2899SCharles.Forsyth# [client side]
2459*37da2899SCharles.Forsyth# Processes certificate request message. A non-anonymous server can optionally
2460*37da2899SCharles.Forsyth# request a certificate from the client, if appropriate for the selected cipher
2461*37da2899SCharles.Forsyth# suite It is a fatal handshake failure alert for an anonymous server to
2462*37da2899SCharles.Forsyth# request client identification.
2463*37da2899SCharles.Forsyth
2464*37da2899SCharles.Forsyth# TODO: use another module to do x509 certs, lookup and matching rules
2465*37da2899SCharles.Forsyth
2466*37da2899SCharles.Forsythdo_cert_request(hm: ref Handshake.CertificateRequest, ctx: ref Context)
2467*37da2899SCharles.Forsyth{
2468*37da2899SCharles.Forsyth	found := 0;
2469*37da2899SCharles.Forsyth	for(i := 0; i < len hm.cert_types; i++) {
2470*37da2899SCharles.Forsyth		if(ctx.local_info.root_type == int hm.cert_types[i]) {
2471*37da2899SCharles.Forsyth			found = 1;
2472*37da2899SCharles.Forsyth			break;
2473*37da2899SCharles.Forsyth		}
2474*37da2899SCharles.Forsyth	}
2475*37da2899SCharles.Forsyth	if(!found) {
2476*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "do_cert_request: no required type of cert", ctx);
2477*37da2899SCharles.Forsyth		return;
2478*37da2899SCharles.Forsyth	}
2479*37da2899SCharles.Forsyth	if(dn_cmp(ctx.local_info.dns, hm.dn_list) < 0) {
2480*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "do_cert_request: no required dn", ctx);
2481*37da2899SCharles.Forsyth		return;
2482*37da2899SCharles.Forsyth	}
2483*37da2899SCharles.Forsyth	if(ctx.session.peer_certs == nil) {
2484*37da2899SCharles.Forsyth		fatal(SSL_NO_CERTIFICATE, "certificate request: no peer certificates", ctx);
2485*37da2899SCharles.Forsyth		return;
2486*37da2899SCharles.Forsyth	}
2487*37da2899SCharles.Forsyth
2488*37da2899SCharles.Forsyth	ctx.status |= CLIENT_AUTH;
2489*37da2899SCharles.Forsyth}
2490*37da2899SCharles.Forsyth
2491*37da2899SCharles.Forsythdn_cmp(a, b: list of array of byte): int
2492*37da2899SCharles.Forsyth{
2493*37da2899SCharles.Forsyth	return -1;
2494*37da2899SCharles.Forsyth}
2495*37da2899SCharles.Forsyth
2496*37da2899SCharles.Forsyth# [server side]
2497*37da2899SCharles.Forsyth# Process client hello message.
2498*37da2899SCharles.Forsyth
2499*37da2899SCharles.Forsythdo_client_hello(hm: ref Handshake.ClientHello, ctx: ref Context)
2500*37da2899SCharles.Forsyth{
2501*37da2899SCharles.Forsyth	sndm : ref Handshake;
2502*37da2899SCharles.Forsyth	e : string;
2503*37da2899SCharles.Forsyth
2504*37da2899SCharles.Forsyth	if(hm.version[0] != SSL_VERSION_3_0[0] || hm.version[1] != SSL_VERSION_3_0[1]) {
2505*37da2899SCharles.Forsyth		fatal(SSL_UNEXPECTED_MESSAGE, "client hello: version mismatch", ctx);
2506*37da2899SCharles.Forsyth		return;
2507*37da2899SCharles.Forsyth	}
2508*37da2899SCharles.Forsyth	# else SSL_VERSION_2_0
2509*37da2899SCharles.Forsyth
2510*37da2899SCharles.Forsyth	if(hm.session_id != nil) { # trying to resume
2511*37da2899SCharles.Forsyth		if(ctx.status & SESSION_RESUMABLE) {
2512*37da2899SCharles.Forsyth			s := sslsession->get_session_byid(hm.session_id);
2513*37da2899SCharles.Forsyth			if(s == nil) {
2514*37da2899SCharles.Forsyth				fatal(SSL_UNEXPECTED_MESSAGE, "client hello: retrieve nil session", ctx);
2515*37da2899SCharles.Forsyth				return;
2516*37da2899SCharles.Forsyth			}
2517*37da2899SCharles.Forsyth
2518*37da2899SCharles.Forsyth			if(s.version[0] != hm.version[0] || s.version[1] != hm.version[1]) {
2519*37da2899SCharles.Forsyth				# avoid version attack
2520*37da2899SCharles.Forsyth				fatal(SSL_UNEXPECTED_MESSAGE, "client hello: protocol mismatch", ctx);
2521*37da2899SCharles.Forsyth				return;
2522*37da2899SCharles.Forsyth			}
2523*37da2899SCharles.Forsyth
2524*37da2899SCharles.Forsyth			reset_server_random(ctx);
2525*37da2899SCharles.Forsyth			ctx.client_random = hm.random;
2526*37da2899SCharles.Forsyth
2527*37da2899SCharles.Forsyth			sndm = ref Handshake.ServerHello(s.version, ctx.server_random,
2528*37da2899SCharles.Forsyth				s.session_id, s.suite, s.compression);
2529*37da2899SCharles.Forsyth			handshake_enque(sndm, ctx);
2530*37da2899SCharles.Forsyth
2531*37da2899SCharles.Forsyth			ccs_enque(ref ChangeCipherSpec(1), ctx);
2532*37da2899SCharles.Forsyth			# use existing master_secret, calc keys
2533*37da2899SCharles.Forsyth			(ctx.cw_mac, ctx.sw_mac, ctx.cw_key, ctx.sw_key, ctx.cw_IV, ctx.sw_IV)
2534*37da2899SCharles.Forsyth				= calc_keys(ctx.sel_ciph, ctx.session.master_secret, ctx.client_random,
2535*37da2899SCharles.Forsyth				ctx.server_random);
2536*37da2899SCharles.Forsyth			e = set_out_queue(ctx);
2537*37da2899SCharles.Forsyth			if(e != nil) {
2538*37da2899SCharles.Forsyth				fatal(SSL_CLOSE_NOTIFY,	"client hello: setup new cipher failure", ctx);
2539*37da2899SCharles.Forsyth				return;
2540*37da2899SCharles.Forsyth			}
2541*37da2899SCharles.Forsyth			if(SSL_DEBUG)
2542*37da2899SCharles.Forsyth				log("do_client_hello: set out cipher done\n");
2543*37da2899SCharles.Forsyth
2544*37da2899SCharles.Forsyth			(md5_hash, sha_hash) := calc_finished(SSL_SERVER_SENDER,
2545*37da2899SCharles.Forsyth				s.master_secret, ctx.sha_state, ctx.md5_state);
2546*37da2899SCharles.Forsyth
2547*37da2899SCharles.Forsyth			handshake_enque(ref Handshake.Finished(md5_hash, sha_hash), ctx);
2548*37da2899SCharles.Forsyth
2549*37da2899SCharles.Forsyth			ctx.session = s;
2550*37da2899SCharles.Forsyth			ctx.state = STATE_CHANGE_CIPHER_SPEC;
2551*37da2899SCharles.Forsyth			return;
2552*37da2899SCharles.Forsyth		}
2553*37da2899SCharles.Forsyth
2554*37da2899SCharles.Forsyth		fatal(SSL_CLOSE_NOTIFY,	"client hello: resume session failed", ctx);
2555*37da2899SCharles.Forsyth		return;
2556*37da2899SCharles.Forsyth	}
2557*37da2899SCharles.Forsyth
2558*37da2899SCharles.Forsyth	ctx.session.version = hm.version;
2559*37da2899SCharles.Forsyth	if(ctx.session.peer != nil) {
2560*37da2899SCharles.Forsyth		ctx.session.session_id = random->randombuf(Random->NotQuiteRandom, 32);
2561*37da2899SCharles.Forsyth		if(ctx.session.session_id == nil) {
2562*37da2899SCharles.Forsyth			fatal(SSL_CLOSE_NOTIFY,	"client hello: generate session id failed", ctx);
2563*37da2899SCharles.Forsyth			return;
2564*37da2899SCharles.Forsyth		}
2565*37da2899SCharles.Forsyth	}
2566*37da2899SCharles.Forsyth
2567*37da2899SCharles.Forsyth	suite := find_cipher_suite(hm.suites, ctx.local_info.suites);
2568*37da2899SCharles.Forsyth	if(suite != nil) {
2569*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "client hello: find cipher suite failed", ctx);
2570*37da2899SCharles.Forsyth		return;
2571*37da2899SCharles.Forsyth	}
2572*37da2899SCharles.Forsyth
2573*37da2899SCharles.Forsyth	(ctx.sel_ciph, ctx.sel_keyx, ctx.sel_sign, e) = suite_to_spec(suite, SSL3_Suites);
2574*37da2899SCharles.Forsyth	if(e != nil) {
2575*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, "client hello: find cipher suite failed" + e, ctx);
2576*37da2899SCharles.Forsyth		return;
2577*37da2899SCharles.Forsyth	}
2578*37da2899SCharles.Forsyth
2579*37da2899SCharles.Forsyth	# not supported by ssl3 yet
2580*37da2899SCharles.Forsyth	ctx.sel_cmpr = int hm.compressions[0];
2581*37da2899SCharles.Forsyth	ctx.client_random = hm.random;
2582*37da2899SCharles.Forsyth	ctx.sha_state = nil;
2583*37da2899SCharles.Forsyth	ctx.md5_state = nil;
2584*37da2899SCharles.Forsyth
2585*37da2899SCharles.Forsyth	sndm = ref Handshake.ServerHello(ctx.session.version, ctx.server_random,
2586*37da2899SCharles.Forsyth		ctx.session.session_id, ctx.session.suite, ctx.session.compression);
2587*37da2899SCharles.Forsyth	handshake_enque(sndm, ctx);
2588*37da2899SCharles.Forsyth
2589*37da2899SCharles.Forsyth	# set up keys based on algorithms
2590*37da2899SCharles.Forsyth
2591*37da2899SCharles.Forsyth	if(tagof ctx.sel_keyx != tagof KeyExAlg.DH) {
2592*37da2899SCharles.Forsyth		if(ctx.local_info.certs == nil || ctx.local_info.sk == nil) {
2593*37da2899SCharles.Forsyth			fatal(SSL_HANDSHAKE_FAILURE, "client hello: no local cert or key", ctx);
2594*37da2899SCharles.Forsyth			return;
2595*37da2899SCharles.Forsyth		}
2596*37da2899SCharles.Forsyth
2597*37da2899SCharles.Forsyth		sndm = ref Handshake.Certificate(ctx.local_info.certs);
2598*37da2899SCharles.Forsyth		handshake_enque(sndm, ctx);
2599*37da2899SCharles.Forsyth	}
2600*37da2899SCharles.Forsyth
2601*37da2899SCharles.Forsyth	if(tagof ctx.sel_keyx != tagof KeyExAlg.RSA ||
2602*37da2899SCharles.Forsyth		tagof ctx.sel_sign != tagof SigAlg.anon) {
2603*37da2899SCharles.Forsyth		params, signed_params, xkey: array of byte;
2604*37da2899SCharles.Forsyth		(params, e) = calc_server_xkey(ctx.sel_keyx);
2605*37da2899SCharles.Forsyth		if(e == "")
2606*37da2899SCharles.Forsyth			(signed_params, e) = sign_server_xkey(ctx.sel_sign, params,
2607*37da2899SCharles.Forsyth				ctx.client_random, ctx.server_random);
2608*37da2899SCharles.Forsyth		if(e != "")
2609*37da2899SCharles.Forsyth
2610*37da2899SCharles.Forsyth		n := len params + 2 + len signed_params;
2611*37da2899SCharles.Forsyth		xkey = array [n] of byte;
2612*37da2899SCharles.Forsyth		xkey[0:] = params;
2613*37da2899SCharles.Forsyth		xkey[len params:] = int_encode(len signed_params, 2);
2614*37da2899SCharles.Forsyth		xkey[len params+2:] = signed_params;
2615*37da2899SCharles.Forsyth		handshake_enque(ref Handshake.ServerKeyExchange(xkey), ctx);
2616*37da2899SCharles.Forsyth	}
2617*37da2899SCharles.Forsyth
2618*37da2899SCharles.Forsyth	if(ctx.status & CLIENT_AUTH) {
2619*37da2899SCharles.Forsyth		sndm = ref Handshake.CertificateRequest(ctx.local_info.types, ctx.local_info.dns);
2620*37da2899SCharles.Forsyth		handshake_enque(sndm, ctx);
2621*37da2899SCharles.Forsyth
2622*37da2899SCharles.Forsyth		ctx.status |= CERT_REQUEST;
2623*37da2899SCharles.Forsyth		ctx.state = STATE_CLIENT_CERTIFICATE;
2624*37da2899SCharles.Forsyth	}
2625*37da2899SCharles.Forsyth	else
2626*37da2899SCharles.Forsyth		ctx.state = STATE_CLIENT_KEY_EXCHANGE;
2627*37da2899SCharles.Forsyth
2628*37da2899SCharles.Forsyth	handshake_enque(ref Handshake.ServerHelloDone(), ctx);
2629*37da2899SCharles.Forsyth}
2630*37da2899SCharles.Forsyth
2631*37da2899SCharles.Forsyth# [server side]
2632*37da2899SCharles.Forsyth# Process the received client key exchange message.
2633*37da2899SCharles.Forsyth
2634*37da2899SCharles.Forsythdo_client_keyex(hm: ref Handshake.ClientKeyExchange, ctx: ref Context)
2635*37da2899SCharles.Forsyth{
2636*37da2899SCharles.Forsyth	(premaster_secret, err) := install_client_xkey(hm.xkey, ctx.sel_keyx);
2637*37da2899SCharles.Forsyth	if(err != "") {
2638*37da2899SCharles.Forsyth		fatal(SSL_HANDSHAKE_FAILURE, err, ctx);
2639*37da2899SCharles.Forsyth		return;
2640*37da2899SCharles.Forsyth	}
2641*37da2899SCharles.Forsyth
2642*37da2899SCharles.Forsyth	ctx.session.master_secret = calc_master_secret(premaster_secret,
2643*37da2899SCharles.Forsyth		ctx.client_random, ctx.server_random);
2644*37da2899SCharles.Forsyth
2645*37da2899SCharles.Forsyth	if(ctx.status & CERT_RECEIVED)
2646*37da2899SCharles.Forsyth		ctx.state = STATE_CERTIFICATE_VERIFY;
2647*37da2899SCharles.Forsyth	else
2648*37da2899SCharles.Forsyth		ctx.state = STATE_CHANGE_CIPHER_SPEC;
2649*37da2899SCharles.Forsyth}
2650*37da2899SCharles.Forsyth
2651*37da2899SCharles.Forsyth# [server side]
2652*37da2899SCharles.Forsyth# Process the received certificate message from client.
2653*37da2899SCharles.Forsyth
2654*37da2899SCharles.Forsythdo_client_cert(hm: ref Handshake.Certificate, ctx: ref Context)
2655*37da2899SCharles.Forsyth{
2656*37da2899SCharles.Forsyth	ctx.session.peer_certs = hm.cert_list;
2657*37da2899SCharles.Forsyth
2658*37da2899SCharles.Forsyth	# verify cert chain and determine the type of cert
2659*37da2899SCharles.Forsyth	# ctx.peer_info.sk = x509->verify_chain(ctx.session.peer_certs);
2660*37da2899SCharles.Forsyth	# if(ctx.peer_info.key == nil) {
2661*37da2899SCharles.Forsyth	#	fatal(SSL_HANDSHAKE_FAILURE, "client certificate: cert verify failed", ctx);
2662*37da2899SCharles.Forsyth	#	return;
2663*37da2899SCharles.Forsyth	# }
2664*37da2899SCharles.Forsyth
2665*37da2899SCharles.Forsyth	ctx.status |= CERT_RECEIVED;
2666*37da2899SCharles.Forsyth
2667*37da2899SCharles.Forsyth	ctx.state = STATE_CLIENT_KEY_EXCHANGE;
2668*37da2899SCharles.Forsyth}
2669*37da2899SCharles.Forsyth
2670*37da2899SCharles.Forsyth# [server side]
2671*37da2899SCharles.Forsyth# Process the received certificate verify message from client.
2672*37da2899SCharles.Forsyth
2673*37da2899SCharles.Forsythdo_cert_verify(hm: ref Handshake.CertificateVerify, ctx: ref Context)
2674*37da2899SCharles.Forsyth{
2675*37da2899SCharles.Forsyth	if(ctx.status & CERT_RECEIVED) {
2676*37da2899SCharles.Forsyth		# exp : array of byte;
2677*37da2899SCharles.Forsyth		(md5_hash, sha_hash)
2678*37da2899SCharles.Forsyth			:= calc_finished(nil, ctx.session.master_secret, ctx.sha_state, ctx.md5_state);
2679*37da2899SCharles.Forsyth		ok := 0;
2680*37da2899SCharles.Forsyth		pick upk := ctx.sel_sign {
2681*37da2899SCharles.Forsyth		RSA =>
2682*37da2899SCharles.Forsyth			hashes := array [36] of byte;
2683*37da2899SCharles.Forsyth			hashes[0:] = md5_hash;
2684*37da2899SCharles.Forsyth			hashes[16:] = sha_hash;
2685*37da2899SCharles.Forsyth			ok = pkcs->rsa_verify(hashes, hm.signature, upk.peer_pk, PKCS->MD5_WithRSAEncryption);
2686*37da2899SCharles.Forsyth		DSS =>
2687*37da2899SCharles.Forsyth			ok = pkcs->dss_verify(sha_hash, hm.signature, upk.peer_pk);
2688*37da2899SCharles.Forsyth		}
2689*37da2899SCharles.Forsyth
2690*37da2899SCharles.Forsyth		if(!ok) {
2691*37da2899SCharles.Forsyth			fatal(SSL_HANDSHAKE_FAILURE, "do_cert_verify: client auth failed", ctx);
2692*37da2899SCharles.Forsyth			return;
2693*37da2899SCharles.Forsyth		}
2694*37da2899SCharles.Forsyth	}
2695*37da2899SCharles.Forsyth	else {
2696*37da2899SCharles.Forsyth		alert_enque(ref Alert(SSL_WARNING, SSL_NO_CERTIFICATE), ctx);
2697*37da2899SCharles.Forsyth		return;
2698*37da2899SCharles.Forsyth	}
2699*37da2899SCharles.Forsyth
2700*37da2899SCharles.Forsyth	ctx.state = STATE_CHANGE_CIPHER_SPEC;
2701*37da2899SCharles.Forsyth}
2702*37da2899SCharles.Forsyth
2703*37da2899SCharles.Forsyth# [client or server side]
2704*37da2899SCharles.Forsyth# Process the received finished message either from client or server.
2705*37da2899SCharles.Forsyth
2706*37da2899SCharles.Forsythdo_finished(sender: array of byte, ctx: ref Context)
2707*37da2899SCharles.Forsyth{
2708*37da2899SCharles.Forsyth	# setup write_cipher if not yet
2709*37da2899SCharles.Forsyth	if(!(ctx.status & OUT_READY)) {
2710*37da2899SCharles.Forsyth		ccs_enque(ref ChangeCipherSpec(1), ctx);
2711*37da2899SCharles.Forsyth		e := set_out_queue(ctx);
2712*37da2899SCharles.Forsyth		if(e != nil) {
2713*37da2899SCharles.Forsyth			fatal(SSL_CLOSE_NOTIFY, "do_finished: setup new cipher failed", ctx);
2714*37da2899SCharles.Forsyth			return;
2715*37da2899SCharles.Forsyth		}
2716*37da2899SCharles.Forsyth		ctx.status |= OUT_READY;
2717*37da2899SCharles.Forsyth
2718*37da2899SCharles.Forsyth		if(SSL_DEBUG)
2719*37da2899SCharles.Forsyth			log("ssl3: set out cipher done\n");
2720*37da2899SCharles.Forsyth
2721*37da2899SCharles.Forsyth		(md5_hash, sha_hash) := calc_finished(sender, ctx.session.master_secret,
2722*37da2899SCharles.Forsyth			ctx.sha_state, ctx.md5_state);
2723*37da2899SCharles.Forsyth		handshake_enque(ref Handshake.Finished(md5_hash, sha_hash), ctx);
2724*37da2899SCharles.Forsyth	}
2725*37da2899SCharles.Forsyth
2726*37da2899SCharles.Forsyth	ctx.state = STATE_EXIT; # normal
2727*37da2899SCharles.Forsyth
2728*37da2899SCharles.Forsyth	# clean read queue
2729*37da2899SCharles.Forsyth	ctx.in_queue.fragment = 0;
2730*37da2899SCharles.Forsyth
2731*37da2899SCharles.Forsyth	sslsession->add_session(ctx.session);
2732*37da2899SCharles.Forsyth
2733*37da2899SCharles.Forsyth	if(SSL_DEBUG)
2734*37da2899SCharles.Forsyth		log("ssl3: add session to session database done\n");
2735*37da2899SCharles.Forsyth}
2736*37da2899SCharles.Forsyth
2737*37da2899SCharles.Forsythinstall_client_xkey(a: array of byte, keyx: ref KeyExAlg): (array of byte, string)
2738*37da2899SCharles.Forsyth{
2739*37da2899SCharles.Forsyth	pmaster, x : array of byte;
2740*37da2899SCharles.Forsyth	err := "";
2741*37da2899SCharles.Forsyth	pick kx := keyx {
2742*37da2899SCharles.Forsyth	DH =>
2743*37da2899SCharles.Forsyth		i := 0;
2744*37da2899SCharles.Forsyth		(kx.peer_pk, i) = dh_params_decode(a);
2745*37da2899SCharles.Forsyth		if(kx.peer_pk != nil)
2746*37da2899SCharles.Forsyth			pmaster = pkcs->computeDHAgreedKey(kx.sk.param, kx.sk.sk, kx.peer_pk.pk);
2747*37da2899SCharles.Forsyth		else
2748*37da2899SCharles.Forsyth			err = "decode dh params failed";
2749*37da2899SCharles.Forsyth	RSA =>
2750*37da2899SCharles.Forsyth		(err, x) = pkcs->rsa_decrypt(a, kx.sk, 2);
2751*37da2899SCharles.Forsyth		if(err != "" || len x != 48) {
2752*37da2899SCharles.Forsyth			err = "impl error";
2753*37da2899SCharles.Forsyth		}
2754*37da2899SCharles.Forsyth		else {
2755*37da2899SCharles.Forsyth			if(x[0] != SSL_VERSION_3_0[0] && x[1] != SSL_VERSION_3_0[1])
2756*37da2899SCharles.Forsyth				err = "version wrong: possible version attack";
2757*37da2899SCharles.Forsyth			else
2758*37da2899SCharles.Forsyth				pmaster = x[2:];
2759*37da2899SCharles.Forsyth		}
2760*37da2899SCharles.Forsyth	FORTEZZA_KEA =>
2761*37da2899SCharles.Forsyth		err = "Fortezza unsupported";
2762*37da2899SCharles.Forsyth	}
2763*37da2899SCharles.Forsyth	return (pmaster, err);
2764*37da2899SCharles.Forsyth}
2765*37da2899SCharles.Forsyth
2766*37da2899SCharles.Forsythinstall_server_xkey(a: array of byte, keyx: ref KeyExAlg): (string, int)
2767*37da2899SCharles.Forsyth{
2768*37da2899SCharles.Forsyth	err := "";
2769*37da2899SCharles.Forsyth	i := 0;
2770*37da2899SCharles.Forsyth
2771*37da2899SCharles.Forsyth	pick kx := keyx {
2772*37da2899SCharles.Forsyth	DH =>
2773*37da2899SCharles.Forsyth		(kx.peer_pk, i) = dh_params_decode(a);
2774*37da2899SCharles.Forsyth		if(kx.peer_pk != nil)
2775*37da2899SCharles.Forsyth			kx.peer_params = kx.peer_pk.param;
2776*37da2899SCharles.Forsyth	RSA =>
2777*37da2899SCharles.Forsyth		peer_tmp: ref RSAParams;
2778*37da2899SCharles.Forsyth		(peer_tmp, i, err) = rsa_params_decode(a);
2779*37da2899SCharles.Forsyth		if(err == "") {
2780*37da2899SCharles.Forsyth			modlen := len peer_tmp.modulus.iptobebytes();
2781*37da2899SCharles.Forsyth			kx.peer_pk = ref RSAKey(peer_tmp.modulus, modlen, peer_tmp.exponent);
2782*37da2899SCharles.Forsyth		}
2783*37da2899SCharles.Forsyth	FORTEZZA_KEA =>
2784*37da2899SCharles.Forsyth		return ("Fortezza unsupported", i);
2785*37da2899SCharles.Forsyth	}
2786*37da2899SCharles.Forsyth
2787*37da2899SCharles.Forsyth	return (err, i);
2788*37da2899SCharles.Forsyth}
2789*37da2899SCharles.Forsyth
2790*37da2899SCharles.Forsythverify_server_xkey(crand, srand: array of byte, a: array of byte, i : int, sign: ref SigAlg)
2791*37da2899SCharles.Forsyth	: string
2792*37da2899SCharles.Forsyth{
2793*37da2899SCharles.Forsyth	pick sg := sign {
2794*37da2899SCharles.Forsyth	anon =>
2795*37da2899SCharles.Forsyth	RSA =>
2796*37da2899SCharles.Forsyth		lb := a[0:i]::crand::srand::nil;
2797*37da2899SCharles.Forsyth		(exp, nil, nil) := md5_sha_hash(lb, nil, nil);
2798*37da2899SCharles.Forsyth		ok := pkcs->rsa_verify(exp, a[i+2:], sg.peer_pk, PKCS->MD5_WithRSAEncryption);
2799*37da2899SCharles.Forsyth		if(!ok)
2800*37da2899SCharles.Forsyth			return "RSA sigature verification failed";
2801*37da2899SCharles.Forsyth	DSS =>
2802*37da2899SCharles.Forsyth		lb := a[0:i]::crand::srand::nil;
2803*37da2899SCharles.Forsyth		(exp, nil) := sha_hash(lb, nil);
2804*37da2899SCharles.Forsyth		ok := pkcs->dss_verify(exp, a[i+2:], sg.peer_pk);
2805*37da2899SCharles.Forsyth		if(!ok)
2806*37da2899SCharles.Forsyth			return "DSS sigature verification failed";
2807*37da2899SCharles.Forsyth	}
2808*37da2899SCharles.Forsyth
2809*37da2899SCharles.Forsyth	return "";
2810*37da2899SCharles.Forsyth}
2811*37da2899SCharles.Forsyth
2812*37da2899SCharles.Forsythcalc_client_xkey(keyx: ref KeyExAlg): (array of byte, array of byte, string)
2813*37da2899SCharles.Forsyth{
2814*37da2899SCharles.Forsyth	pm, x : array of byte;
2815*37da2899SCharles.Forsyth	err := "";
2816*37da2899SCharles.Forsyth	pick kx := keyx {
2817*37da2899SCharles.Forsyth	DH =>
2818*37da2899SCharles.Forsyth		# generate our own DH keys based on DH params of peer side
2819*37da2899SCharles.Forsyth		(kx.sk, kx.exch_pk) = pkcs->setupDHAgreement(kx.peer_params);
2820*37da2899SCharles.Forsyth		# TODO: need check type of client cert if(!ctx.status & CLIENT_AUTH)
2821*37da2899SCharles.Forsyth		# 	for implicit case
2822*37da2899SCharles.Forsyth		(x, err) = dh_exchpub_encode(kx.exch_pk);
2823*37da2899SCharles.Forsyth		pm = pkcs->computeDHAgreedKey(kx.sk.param, kx.sk.sk, kx.peer_pk.pk);
2824*37da2899SCharles.Forsyth	RSA =>
2825*37da2899SCharles.Forsyth		pm = array [48] of byte;
2826*37da2899SCharles.Forsyth		pm[0:] = SSL_VERSION_3_0; # against version attack
2827*37da2899SCharles.Forsyth		pm[2:] = random->randombuf(Random->NotQuiteRandom, 46);
2828*37da2899SCharles.Forsyth		(err, x) = pkcs->rsa_encrypt(pm, kx.peer_pk, 2);
2829*37da2899SCharles.Forsyth	FORTEZZA_KEA =>
2830*37da2899SCharles.Forsyth		err = "Fortezza unsupported";
2831*37da2899SCharles.Forsyth	}
2832*37da2899SCharles.Forsyth	if(SSL_DEBUG)
2833*37da2899SCharles.Forsyth		log("ssl3: calc_client_xkey: " + bastr(x));
2834*37da2899SCharles.Forsyth	return (x, pm, err);
2835*37da2899SCharles.Forsyth}
2836*37da2899SCharles.Forsyth
2837*37da2899SCharles.Forsythcalc_server_xkey(keyx: ref KeyExAlg): (array of byte, string)
2838*37da2899SCharles.Forsyth{
2839*37da2899SCharles.Forsyth	params: array of byte;
2840*37da2899SCharles.Forsyth	err: string;
2841*37da2899SCharles.Forsyth	pick kx := keyx {
2842*37da2899SCharles.Forsyth	DH =>
2843*37da2899SCharles.Forsyth		(kx.sk, kx.exch_pk) = pkcs->setupDHAgreement(kx.params);
2844*37da2899SCharles.Forsyth		(params, err) = dh_params_encode(kx.exch_pk);
2845*37da2899SCharles.Forsyth	RSA =>
2846*37da2899SCharles.Forsyth		tmp := ref RSAParams(kx.export_key.modulus, kx.export_key.exponent);
2847*37da2899SCharles.Forsyth		(params, err) = rsa_params_encode(tmp);
2848*37da2899SCharles.Forsyth
2849*37da2899SCharles.Forsyth	FORTEZZA_KEA =>
2850*37da2899SCharles.Forsyth		err = "Fortezza unsupported";
2851*37da2899SCharles.Forsyth	}
2852*37da2899SCharles.Forsyth	return (params, err);
2853*37da2899SCharles.Forsyth}
2854*37da2899SCharles.Forsyth
2855*37da2899SCharles.Forsythsign_server_xkey(sign: ref SigAlg, params, cr, sr: array of byte): (array of byte, string)
2856*37da2899SCharles.Forsyth{
2857*37da2899SCharles.Forsyth	signed_params: array of byte;
2858*37da2899SCharles.Forsyth	err: string;
2859*37da2899SCharles.Forsyth	pick sg := sign {
2860*37da2899SCharles.Forsyth	anon =>
2861*37da2899SCharles.Forsyth	RSA =>
2862*37da2899SCharles.Forsyth		lb := cr::sr::params::nil;
2863*37da2899SCharles.Forsyth		(hashes, nil, nil) := md5_sha_hash(lb, nil, nil);
2864*37da2899SCharles.Forsyth		(err, signed_params) = pkcs->rsa_sign(hashes, sg.sk, PKCS->MD5_WithRSAEncryption);
2865*37da2899SCharles.Forsyth	DSS =>
2866*37da2899SCharles.Forsyth		lb := cr::sr::params::nil;
2867*37da2899SCharles.Forsyth		(hashes, nil) := sha_hash(lb, nil);
2868*37da2899SCharles.Forsyth		(err, signed_params) = pkcs->dss_sign(hashes, sg.sk);
2869*37da2899SCharles.Forsyth	}
2870*37da2899SCharles.Forsyth	return (signed_params, err);
2871*37da2899SCharles.Forsyth}
2872*37da2899SCharles.Forsyth
2873*37da2899SCharles.Forsyth# ssl encoding of DH exchange public key
2874*37da2899SCharles.Forsyth
2875*37da2899SCharles.Forsythdh_exchpub_encode(dh: ref DHPublicKey): (array of byte, string)
2876*37da2899SCharles.Forsyth{
2877*37da2899SCharles.Forsyth	if(dh != nil) {
2878*37da2899SCharles.Forsyth		yb := dh.pk.iptobebytes();
2879*37da2899SCharles.Forsyth		if(yb != nil) {
2880*37da2899SCharles.Forsyth			n := 2 + len yb;
2881*37da2899SCharles.Forsyth			a := array [n] of byte;
2882*37da2899SCharles.Forsyth			i := 0;
2883*37da2899SCharles.Forsyth			a[i:] = int_encode(len yb, 2);
2884*37da2899SCharles.Forsyth			i += 2;
2885*37da2899SCharles.Forsyth			a[i:] = yb;
2886*37da2899SCharles.Forsyth			return (a, nil);
2887*37da2899SCharles.Forsyth		}
2888*37da2899SCharles.Forsyth	}
2889*37da2899SCharles.Forsyth	return (nil, "nil dh params");
2890*37da2899SCharles.Forsyth}
2891*37da2899SCharles.Forsyth
2892*37da2899SCharles.Forsythdh_params_encode(dh: ref DHPublicKey): (array of byte, string)
2893*37da2899SCharles.Forsyth{
2894*37da2899SCharles.Forsyth	if(dh != nil && dh.param != nil) {
2895*37da2899SCharles.Forsyth		pb := dh.param.prime.iptobebytes();
2896*37da2899SCharles.Forsyth		gb := dh.param.base.iptobebytes();
2897*37da2899SCharles.Forsyth		yb := dh.pk.iptobebytes();
2898*37da2899SCharles.Forsyth		if(pb != nil && gb != nil && yb != nil) {
2899*37da2899SCharles.Forsyth			n := 6 + len pb + len gb + len yb;
2900*37da2899SCharles.Forsyth			a := array [n] of byte;
2901*37da2899SCharles.Forsyth			i := 0;
2902*37da2899SCharles.Forsyth			a[i:] = int_encode(len pb, 2);
2903*37da2899SCharles.Forsyth			i += 2;
2904*37da2899SCharles.Forsyth			a[i:] = pb;
2905*37da2899SCharles.Forsyth			i += len pb;
2906*37da2899SCharles.Forsyth			a[i:] = int_encode(len gb, 2);
2907*37da2899SCharles.Forsyth			i += 2;
2908*37da2899SCharles.Forsyth			a[i:] = gb;
2909*37da2899SCharles.Forsyth			i += len gb;
2910*37da2899SCharles.Forsyth			a[i:] = int_encode(len yb, 2);
2911*37da2899SCharles.Forsyth			i += 2;
2912*37da2899SCharles.Forsyth			a[i:] = yb;
2913*37da2899SCharles.Forsyth			i += len yb;
2914*37da2899SCharles.Forsyth			return (a, nil);
2915*37da2899SCharles.Forsyth		}
2916*37da2899SCharles.Forsyth	}
2917*37da2899SCharles.Forsyth	return (nil, "nil dh public key");
2918*37da2899SCharles.Forsyth}
2919*37da2899SCharles.Forsyth
2920*37da2899SCharles.Forsythdh_params_decode(a: array of byte): (ref DHPublicKey, int)
2921*37da2899SCharles.Forsyth{
2922*37da2899SCharles.Forsyth	i := 0;
2923*37da2899SCharles.Forsyth	for(;;) {
2924*37da2899SCharles.Forsyth		n := int_decode(a[i:i+2]);
2925*37da2899SCharles.Forsyth		i += 2;
2926*37da2899SCharles.Forsyth		if(i+n > len a)
2927*37da2899SCharles.Forsyth			break;
2928*37da2899SCharles.Forsyth		p := a[i:i+n];
2929*37da2899SCharles.Forsyth		i += n;
2930*37da2899SCharles.Forsyth		n = int_decode(a[i:i+2]);
2931*37da2899SCharles.Forsyth		i += 2;
2932*37da2899SCharles.Forsyth		if(i+n > len a)
2933*37da2899SCharles.Forsyth			break;
2934*37da2899SCharles.Forsyth		g := a[i:i+n];
2935*37da2899SCharles.Forsyth		i += n;
2936*37da2899SCharles.Forsyth		n = int_decode(a[i:i+2]);
2937*37da2899SCharles.Forsyth		i += 2;
2938*37da2899SCharles.Forsyth		if(i+n > len a)
2939*37da2899SCharles.Forsyth			break;
2940*37da2899SCharles.Forsyth		Ys := a[i:i+n];
2941*37da2899SCharles.Forsyth		i += n;
2942*37da2899SCharles.Forsyth
2943*37da2899SCharles.Forsyth		if(SSL_DEBUG)
2944*37da2899SCharles.Forsyth			log("ssl3: dh_params_decode:" + "\n\tp =\n\t\t" + bastr(p)
2945*37da2899SCharles.Forsyth			+ "\n\tg =\n\t\t" + bastr(g) + "\n\tYs =\n\t\t" + bastr(Ys) + "\n");
2946*37da2899SCharles.Forsyth
2947*37da2899SCharles.Forsyth		# don't care privateValueLength
2948*37da2899SCharles.Forsyth		param := ref DHParams(IPint.bebytestoip(p), IPint.bebytestoip(g), 0);
2949*37da2899SCharles.Forsyth		return (ref DHPublicKey(param, IPint.bebytestoip(Ys)), i);
2950*37da2899SCharles.Forsyth	}
2951*37da2899SCharles.Forsyth	return (nil, i);
2952*37da2899SCharles.Forsyth}
2953*37da2899SCharles.Forsyth
2954*37da2899SCharles.Forsythrsa_params_encode(rsa_params: ref RSAParams): (array of byte, string)
2955*37da2899SCharles.Forsyth{
2956*37da2899SCharles.Forsyth	if(rsa_params != nil) {
2957*37da2899SCharles.Forsyth		mod := rsa_params.modulus.iptobebytes();
2958*37da2899SCharles.Forsyth		exp := rsa_params.exponent.iptobebytes();
2959*37da2899SCharles.Forsyth		if(mod != nil || exp != nil) {
2960*37da2899SCharles.Forsyth			n := 4 + len mod + len exp;
2961*37da2899SCharles.Forsyth			a := array [n] of byte;
2962*37da2899SCharles.Forsyth			i := 0;
2963*37da2899SCharles.Forsyth			a[i:] = int_encode(len mod, 2);
2964*37da2899SCharles.Forsyth			i += 2;
2965*37da2899SCharles.Forsyth			a[i:] = mod;
2966*37da2899SCharles.Forsyth			i += len mod;
2967*37da2899SCharles.Forsyth			a[i:] = int_encode(len exp, 2);
2968*37da2899SCharles.Forsyth			i += 2;
2969*37da2899SCharles.Forsyth			a[i:] = exp;
2970*37da2899SCharles.Forsyth			i += len exp;
2971*37da2899SCharles.Forsyth			return (a, nil);
2972*37da2899SCharles.Forsyth		}
2973*37da2899SCharles.Forsyth	}
2974*37da2899SCharles.Forsyth	return (nil, "nil rsa params");
2975*37da2899SCharles.Forsyth}
2976*37da2899SCharles.Forsyth
2977*37da2899SCharles.Forsythrsa_params_decode(a: array of byte): (ref RSAParams, int, string)
2978*37da2899SCharles.Forsyth{
2979*37da2899SCharles.Forsyth	i := 0;
2980*37da2899SCharles.Forsyth	for(;;) {
2981*37da2899SCharles.Forsyth		if(len a < 2)
2982*37da2899SCharles.Forsyth			break;
2983*37da2899SCharles.Forsyth		n := int_decode(a[i:i+2]);
2984*37da2899SCharles.Forsyth		i += 2;
2985*37da2899SCharles.Forsyth		if(n < 0 || n + i > len a)
2986*37da2899SCharles.Forsyth			break;
2987*37da2899SCharles.Forsyth		mod := a[i:i+n];
2988*37da2899SCharles.Forsyth		i += n;
2989*37da2899SCharles.Forsyth		n = int_decode(a[i:i+2]);
2990*37da2899SCharles.Forsyth		i += 2;
2991*37da2899SCharles.Forsyth		if(n < 0 || n + i > len a)
2992*37da2899SCharles.Forsyth			break;
2993*37da2899SCharles.Forsyth		exp := a[i:i+n];
2994*37da2899SCharles.Forsyth		i += n;
2995*37da2899SCharles.Forsyth		m := i;
2996*37da2899SCharles.Forsyth		modulus := IPint.bebytestoip(mod);
2997*37da2899SCharles.Forsyth		exponent := IPint.bebytestoip(exp);
2998*37da2899SCharles.Forsyth
2999*37da2899SCharles.Forsyth		if(SSL_DEBUG)
3000*37da2899SCharles.Forsyth			log("ssl3: decode RSA params\n\tmodulus = \n\t\t" + bastr(mod)
3001*37da2899SCharles.Forsyth			+ "\n\texponent = \n\t\t" + bastr(exp) + "\n");
3002*37da2899SCharles.Forsyth
3003*37da2899SCharles.Forsyth		if(len a < i+2)
3004*37da2899SCharles.Forsyth			break;
3005*37da2899SCharles.Forsyth		n = int_decode(a[i:i+2]);
3006*37da2899SCharles.Forsyth		i += 2;
3007*37da2899SCharles.Forsyth		if(len a != i + n)
3008*37da2899SCharles.Forsyth			break;
3009*37da2899SCharles.Forsyth		return (ref RSAParams(modulus, exponent), m, nil);
3010*37da2899SCharles.Forsyth	}
3011*37da2899SCharles.Forsyth	return (nil, i, "encoding error");
3012*37da2899SCharles.Forsyth}
3013*37da2899SCharles.Forsyth
3014*37da2899SCharles.Forsyth# md5_hash       MD5(master_secret + pad2 +
3015*37da2899SCharles.Forsyth#                     MD5(handshake_messages + Sender +
3016*37da2899SCharles.Forsyth#                          master_secret + pad1));
3017*37da2899SCharles.Forsyth# sha_hash       SHA(master_secret + pad2 +
3018*37da2899SCharles.Forsyth#                     SHA(handshake_messages + Sender +
3019*37da2899SCharles.Forsyth#                          master_secret + pad1));
3020*37da2899SCharles.Forsyth#
3021*37da2899SCharles.Forsyth# handshake_messages  All of the data from all handshake messages
3022*37da2899SCharles.Forsyth#                     up to but not including this message.  This
3023*37da2899SCharles.Forsyth#                     is only data visible at the handshake layer
3024*37da2899SCharles.Forsyth#                     and does not include record layer headers.
3025*37da2899SCharles.Forsyth#
3026*37da2899SCharles.Forsyth# sender [4], master_secret [48]
3027*37da2899SCharles.Forsyth# pad1 and pad2, 48 bytes for md5, 40 bytes for sha
3028*37da2899SCharles.Forsyth
3029*37da2899SCharles.Forsythcalc_finished(sender, master_secret: array of byte, sha_state, md5_state: ref DigestState)
3030*37da2899SCharles.Forsyth	: (array of byte, array of byte)
3031*37da2899SCharles.Forsyth{
3032*37da2899SCharles.Forsyth	sha_value := array [Keyring->SHA1dlen] of byte;
3033*37da2899SCharles.Forsyth	md5_value := array [Keyring->MD5dlen] of byte;
3034*37da2899SCharles.Forsyth	sha_inner := array [Keyring->SHA1dlen] of byte;
3035*37da2899SCharles.Forsyth	md5_inner := array [Keyring->MD5dlen] of byte;
3036*37da2899SCharles.Forsyth
3037*37da2899SCharles.Forsyth	lb := master_secret::SSL_MAC_PAD1[0:48]::nil;
3038*37da2899SCharles.Forsyth	if(sender != nil)
3039*37da2899SCharles.Forsyth		lb = sender::lb;
3040*37da2899SCharles.Forsyth	(md5_inner, nil) = md5_hash(lb, md5_state);
3041*37da2899SCharles.Forsyth
3042*37da2899SCharles.Forsyth	lb = master_secret::SSL_MAC_PAD1[0:40]::nil;
3043*37da2899SCharles.Forsyth	if(sender != nil)
3044*37da2899SCharles.Forsyth		lb = sender::lb;
3045*37da2899SCharles.Forsyth	(sha_inner, nil) = sha_hash(lb, sha_state);
3046*37da2899SCharles.Forsyth
3047*37da2899SCharles.Forsyth	(md5_value, nil) = md5_hash(master_secret::SSL_MAC_PAD2[0:48]::md5_inner::nil, nil);
3048*37da2899SCharles.Forsyth	(sha_value, nil) = sha_hash(master_secret::SSL_MAC_PAD2[0:40]::sha_inner::nil, nil);
3049*37da2899SCharles.Forsyth
3050*37da2899SCharles.Forsyth	# if(SSL_DEBUG)
3051*37da2899SCharles.Forsyth	#	log("ssl3: calc_finished:"
3052*37da2899SCharles.Forsyth	#	+ "\n\tmd5_inner = \n\t\t" + bastr(md5_inner)
3053*37da2899SCharles.Forsyth	#	+ "\n\tsha_inner = \n\t\t" + bastr(sha_inner)
3054*37da2899SCharles.Forsyth	#	+ "\n\tmd5_value = \n\t\t" + bastr(md5_value)
3055*37da2899SCharles.Forsyth	#	+ "\n\tsha_value = \n\t\t" + bastr(sha_value)
3056*37da2899SCharles.Forsyth	#	+ "\n");
3057*37da2899SCharles.Forsyth
3058*37da2899SCharles.Forsyth	return (md5_value, sha_value);
3059*37da2899SCharles.Forsyth}
3060*37da2899SCharles.Forsyth
3061*37da2899SCharles.Forsyth
3062*37da2899SCharles.Forsyth# master_secret =
3063*37da2899SCharles.Forsyth#	MD5(premaster_secret + SHA('A' + premaster_secret +
3064*37da2899SCharles.Forsyth#		ClientHello.random + ServerHello.random)) +
3065*37da2899SCharles.Forsyth#	MD5(premaster_secret + SHA('BB' + premaster_secret +
3066*37da2899SCharles.Forsyth#		ClientHello.random + ServerHello.random)) +
3067*37da2899SCharles.Forsyth#	MD5(premaster_secret + SHA('CCC' + premaster_secret +
3068*37da2899SCharles.Forsyth#		ClientHello.random + ServerHello.random));
3069*37da2899SCharles.Forsyth
3070*37da2899SCharles.Forsythcalc_master_secret(pm, cr, sr: array of byte): array of byte
3071*37da2899SCharles.Forsyth{
3072*37da2899SCharles.Forsyth	ms := array [48] of byte;
3073*37da2899SCharles.Forsyth	sha_value := array [Keyring->SHA1dlen] of byte;
3074*37da2899SCharles.Forsyth	leader := array [3] of byte;
3075*37da2899SCharles.Forsyth
3076*37da2899SCharles.Forsyth	j := 0;
3077*37da2899SCharles.Forsyth	lb := pm::cr::sr::nil;
3078*37da2899SCharles.Forsyth	for(i := 1; i <= 3; i++) {
3079*37da2899SCharles.Forsyth		leader[0] = leader[1] = leader[2] = byte (16r40 + i);
3080*37da2899SCharles.Forsyth		(sha_value, nil) = sha_hash(leader[0:i]::lb, nil);
3081*37da2899SCharles.Forsyth		(ms[j:], nil) = md5_hash(pm::sha_value::nil, nil);
3082*37da2899SCharles.Forsyth		j += 16; # Keyring->MD5dlen
3083*37da2899SCharles.Forsyth	}
3084*37da2899SCharles.Forsyth
3085*37da2899SCharles.Forsyth	if(SSL_DEBUG)
3086*37da2899SCharles.Forsyth		log("ssl3: calc_master_secret:\n\tmaster_secret = \n\t\t" + bastr(ms) + "\n");
3087*37da2899SCharles.Forsyth
3088*37da2899SCharles.Forsyth	return ms;
3089*37da2899SCharles.Forsyth}
3090*37da2899SCharles.Forsyth
3091*37da2899SCharles.Forsyth
3092*37da2899SCharles.Forsyth# key_block =
3093*37da2899SCharles.Forsyth# 	MD5(master_secret + SHA(`A' + master_secret +
3094*37da2899SCharles.Forsyth#				ServerHello.random + ClientHello.random)) +
3095*37da2899SCharles.Forsyth#       MD5(master_secret + SHA(`BB' + master_secret +
3096*37da2899SCharles.Forsyth#				ServerHello.random + ClientHello.random)) +
3097*37da2899SCharles.Forsyth#       MD5(master_secret + SHA(`CCC' + master_secret +
3098*37da2899SCharles.Forsyth#				ServerHello.random + ClientHello.random)) +
3099*37da2899SCharles.Forsyth#	[...];
3100*37da2899SCharles.Forsyth
3101*37da2899SCharles.Forsythcalc_key_material(n: int, ms, cr, sr: array of byte): array of byte
3102*37da2899SCharles.Forsyth{
3103*37da2899SCharles.Forsyth	key_block := array [n] of byte;
3104*37da2899SCharles.Forsyth	sha_value := array [Keyring->SHA1dlen] of byte; # [20]
3105*37da2899SCharles.Forsyth	md5_value := array [Keyring->MD5dlen] of byte; # [16]
3106*37da2899SCharles.Forsyth	leader := array [10] of byte;
3107*37da2899SCharles.Forsyth
3108*37da2899SCharles.Forsyth	if(n > 16*(len leader)) {
3109*37da2899SCharles.Forsyth		if(SSL_DEBUG)
3110*37da2899SCharles.Forsyth			log(sys->sprint("ssl3: calc key block: key size too long [%d]", n));
3111*37da2899SCharles.Forsyth		return nil;
3112*37da2899SCharles.Forsyth	}
3113*37da2899SCharles.Forsyth
3114*37da2899SCharles.Forsyth	m := n;
3115*37da2899SCharles.Forsyth	i, j, consumed, next : int = 0;
3116*37da2899SCharles.Forsyth	lb := ms::sr::cr::nil;
3117*37da2899SCharles.Forsyth	for(i = 0; m > 0; i++) {
3118*37da2899SCharles.Forsyth		for(j = 0; j <= i; j++)
3119*37da2899SCharles.Forsyth			leader[j] = byte (16r41 + i); # 'A', 'BB', 'CCC', etc.
3120*37da2899SCharles.Forsyth
3121*37da2899SCharles.Forsyth		(sha_value, nil) = sha_hash(leader[0:i+1]::lb, nil);
3122*37da2899SCharles.Forsyth		(md5_value, nil) = md5_hash(ms::sha_value::nil, nil);
3123*37da2899SCharles.Forsyth
3124*37da2899SCharles.Forsyth		consumed = Keyring->MD5dlen;
3125*37da2899SCharles.Forsyth		if(m < Keyring->MD5dlen)
3126*37da2899SCharles.Forsyth			consumed = m;
3127*37da2899SCharles.Forsyth		m -= consumed;
3128*37da2899SCharles.Forsyth
3129*37da2899SCharles.Forsyth		key_block[next:] = md5_value[0:consumed];
3130*37da2899SCharles.Forsyth		next += consumed;
3131*37da2899SCharles.Forsyth	}
3132*37da2899SCharles.Forsyth
3133*37da2899SCharles.Forsyth	if(SSL_DEBUG)
3134*37da2899SCharles.Forsyth		log("ssl3: calc_key_material:" + "\n\tkey_block = \n\t\t" + bastr(key_block) + "\n");
3135*37da2899SCharles.Forsyth
3136*37da2899SCharles.Forsyth	return key_block;
3137*37da2899SCharles.Forsyth}
3138*37da2899SCharles.Forsyth
3139*37da2899SCharles.Forsyth# Then the key_block is partitioned as follows.
3140*37da2899SCharles.Forsyth#
3141*37da2899SCharles.Forsyth#	client_write_MAC_secret[CipherSpec.hash_size]
3142*37da2899SCharles.Forsyth#	server_write_MAC_secret[CipherSpec.hash_size]
3143*37da2899SCharles.Forsyth#	client_write_key[CipherSpec.key_material]
3144*37da2899SCharles.Forsyth#	server_write_key[CipherSpec.key_material]
3145*37da2899SCharles.Forsyth#	client_write_IV[CipherSpec.IV_size] /* non-export ciphers */
3146*37da2899SCharles.Forsyth#	server_write_IV[CipherSpec.IV_size] /* non-export ciphers */
3147*37da2899SCharles.Forsyth#
3148*37da2899SCharles.Forsyth# Any extra key_block material is discarded.
3149*37da2899SCharles.Forsyth#
3150*37da2899SCharles.Forsyth# Exportable encryption algorithms (for which
3151*37da2899SCharles.Forsyth# CipherSpec.is_exportable is true) require additional processing as
3152*37da2899SCharles.Forsyth# follows to derive their final write keys:
3153*37da2899SCharles.Forsyth#
3154*37da2899SCharles.Forsyth#	final_client_write_key = MD5(client_write_key +
3155*37da2899SCharles.Forsyth#					ClientHello.random +
3156*37da2899SCharles.Forsyth#					ServerHello.random);
3157*37da2899SCharles.Forsyth#	final_server_write_key = MD5(server_write_key +
3158*37da2899SCharles.Forsyth#					ServerHello.random +
3159*37da2899SCharles.Forsyth#					ClientHello.random);
3160*37da2899SCharles.Forsyth#
3161*37da2899SCharles.Forsyth# Exportable encryption algorithms derive their IVs from the random
3162*37da2899SCharles.Forsyth# messages:
3163*37da2899SCharles.Forsyth#
3164*37da2899SCharles.Forsyth#	client_write_IV = MD5(ClientHello.random + ServerHello.random);
3165*37da2899SCharles.Forsyth#	server_write_IV = MD5(ServerHello.random + ClientHello.random);
3166*37da2899SCharles.Forsyth
3167*37da2899SCharles.Forsythcalc_keys(ciph: ref CipherSpec, ms, cr, sr: array of byte)
3168*37da2899SCharles.Forsyth	: (array of byte, array of byte, array of byte, array of byte, array of byte, array of byte)
3169*37da2899SCharles.Forsyth{
3170*37da2899SCharles.Forsyth	cw_mac, sw_mac, cw_key, sw_key,	cw_IV, sw_IV: array of byte;
3171*37da2899SCharles.Forsyth
3172*37da2899SCharles.Forsyth	n := ciph.key_material + ciph.hash_size;
3173*37da2899SCharles.Forsyth	if(ciph.is_exportable == SSL_EXPORT_FALSE)
3174*37da2899SCharles.Forsyth		n += ciph.IV_size;
3175*37da2899SCharles.Forsyth	n *= 2;
3176*37da2899SCharles.Forsyth
3177*37da2899SCharles.Forsyth	key_block := calc_key_material(n, ms, cr, sr);
3178*37da2899SCharles.Forsyth
3179*37da2899SCharles.Forsyth	i := 0;
3180*37da2899SCharles.Forsyth	if(ciph.hash_size != 0) {
3181*37da2899SCharles.Forsyth		cw_mac = key_block[i:i+ciph.hash_size];
3182*37da2899SCharles.Forsyth		i += ciph.hash_size;
3183*37da2899SCharles.Forsyth		sw_mac = key_block[i:i+ciph.hash_size];
3184*37da2899SCharles.Forsyth		i += ciph.hash_size;
3185*37da2899SCharles.Forsyth	}
3186*37da2899SCharles.Forsyth
3187*37da2899SCharles.Forsyth	if(ciph.is_exportable == SSL_EXPORT_FALSE) {
3188*37da2899SCharles.Forsyth		if(ciph.key_material != 0) {
3189*37da2899SCharles.Forsyth			cw_key = key_block[i:i+ciph.key_material];
3190*37da2899SCharles.Forsyth			i += ciph.key_material;
3191*37da2899SCharles.Forsyth			sw_key = key_block[i:i+ciph.key_material];
3192*37da2899SCharles.Forsyth			i += ciph.key_material;
3193*37da2899SCharles.Forsyth		}
3194*37da2899SCharles.Forsyth		if(ciph.IV_size != 0) {
3195*37da2899SCharles.Forsyth			cw_IV = key_block[i:i+ciph.IV_size];
3196*37da2899SCharles.Forsyth			i += ciph.IV_size;
3197*37da2899SCharles.Forsyth			sw_IV = key_block[i:i+ciph.IV_size];
3198*37da2899SCharles.Forsyth			i += ciph.IV_size;
3199*37da2899SCharles.Forsyth		}
3200*37da2899SCharles.Forsyth	}
3201*37da2899SCharles.Forsyth	else {
3202*37da2899SCharles.Forsyth		if(ciph.key_material != 0) {
3203*37da2899SCharles.Forsyth			cw_key = key_block[i:i+ciph.key_material];
3204*37da2899SCharles.Forsyth			i += ciph.key_material;
3205*37da2899SCharles.Forsyth			sw_key = key_block[i:i+ciph.key_material];
3206*37da2899SCharles.Forsyth			i += ciph.key_material;
3207*37da2899SCharles.Forsyth			(cw_key, nil) = md5_hash(cw_key::cr::sr::nil, nil);
3208*37da2899SCharles.Forsyth			(sw_key, nil) = md5_hash(sw_key::sr::cr::nil, nil);
3209*37da2899SCharles.Forsyth		}
3210*37da2899SCharles.Forsyth		if(ciph.IV_size != 0) {
3211*37da2899SCharles.Forsyth			(cw_IV, nil) = md5_hash(cr::sr::nil, nil);
3212*37da2899SCharles.Forsyth			(sw_IV, nil) = md5_hash(sr::cr::nil, nil);
3213*37da2899SCharles.Forsyth		}
3214*37da2899SCharles.Forsyth	}
3215*37da2899SCharles.Forsyth
3216*37da2899SCharles.Forsyth	if(SSL_DEBUG)
3217*37da2899SCharles.Forsyth		log("ssl3: calc_keys:"
3218*37da2899SCharles.Forsyth		+ "\n\tclient_write_mac = \n\t\t" + bastr(cw_mac)
3219*37da2899SCharles.Forsyth		+ "\n\tserver_write_mac = \n\t\t" + bastr(sw_mac)
3220*37da2899SCharles.Forsyth		+ "\n\tclient_write_key = \n\t\t" + bastr(cw_key)
3221*37da2899SCharles.Forsyth		+ "\n\tserver_write_key = \n\t\t" + bastr(sw_key)
3222*37da2899SCharles.Forsyth 		+ "\n\tclient_write_IV  = \n\t\t" + bastr(cw_IV)
3223*37da2899SCharles.Forsyth		+ "\n\tserver_write_IV = \n\t\t" + bastr(sw_IV) + "\n");
3224*37da2899SCharles.Forsyth
3225*37da2899SCharles.Forsyth	return (cw_mac, sw_mac, cw_key, sw_key, cw_IV, sw_IV);
3226*37da2899SCharles.Forsyth}
3227*37da2899SCharles.Forsyth
3228*37da2899SCharles.Forsyth#
3229*37da2899SCharles.Forsyth# decode protocol message
3230*37da2899SCharles.Forsyth#
3231*37da2899SCharles.ForsythProtocol.decode(r: ref Record, ctx: ref Context): (ref Protocol, string)
3232*37da2899SCharles.Forsyth{
3233*37da2899SCharles.Forsyth	p : ref Protocol;
3234*37da2899SCharles.Forsyth
3235*37da2899SCharles.Forsyth	case r.content_type {
3236*37da2899SCharles.Forsyth	SSL_ALERT =>
3237*37da2899SCharles.Forsyth		if(len r.data != 2)
3238*37da2899SCharles.Forsyth			return (nil, "alert decode failed");
3239*37da2899SCharles.Forsyth
3240*37da2899SCharles.Forsyth		p = ref Protocol.pAlert(ref Alert(int r.data[0], int r.data[1]));
3241*37da2899SCharles.Forsyth
3242*37da2899SCharles.Forsyth	SSL_CHANGE_CIPHER_SPEC =>
3243*37da2899SCharles.Forsyth		if(len r.data != 1 || r.data[0] != byte 1)
3244*37da2899SCharles.Forsyth			return (nil, "ChangeCipherSpec decode failed");
3245*37da2899SCharles.Forsyth
3246*37da2899SCharles.Forsyth		p = ref Protocol.pChangeCipherSpec(ref ChangeCipherSpec(1));
3247*37da2899SCharles.Forsyth
3248*37da2899SCharles.Forsyth	SSL_HANDSHAKE =>
3249*37da2899SCharles.Forsyth		(hm, e) := Handshake.decode(r.data);
3250*37da2899SCharles.Forsyth		if(e != nil)
3251*37da2899SCharles.Forsyth			return (nil, e);
3252*37da2899SCharles.Forsyth
3253*37da2899SCharles.Forsyth		pick h := hm {
3254*37da2899SCharles.Forsyth		Finished =>
3255*37da2899SCharles.Forsyth			exp_sender := SSL_CLIENT_SENDER;
3256*37da2899SCharles.Forsyth			if(ctx.status & CLIENT_SIDE)
3257*37da2899SCharles.Forsyth				exp_sender = SSL_SERVER_SENDER;
3258*37da2899SCharles.Forsyth
3259*37da2899SCharles.Forsyth			(md5_hash, sha_hash) := calc_finished(exp_sender,
3260*37da2899SCharles.Forsyth				ctx.session.master_secret, ctx.sha_state, ctx.md5_state);
3261*37da2899SCharles.Forsyth
3262*37da2899SCharles.Forsyth			if(SSL_DEBUG)
3263*37da2899SCharles.Forsyth				log("ssl3: handshake_decode: finished"
3264*37da2899SCharles.Forsyth				+ "\n\texpected_md5_hash = \n\t\t" + bastr(md5_hash)
3265*37da2899SCharles.Forsyth				+ "\n\tgot_md5_hash = \n\t\t" + bastr(h.md5_hash)
3266*37da2899SCharles.Forsyth				+ "\n\texpected_sha_hash = \n\t\t" + bastr(sha_hash)
3267*37da2899SCharles.Forsyth				+ "\n\tgot_sha_hash = \n\t\t" + bastr(h.sha_hash) + "\n");
3268*37da2899SCharles.Forsyth
3269*37da2899SCharles.Forsyth			#if(string md5_hash != string h.md5_hash || string sha_hash != string h.sha_hash)
3270*37da2899SCharles.Forsyth			if(bytes_cmp(md5_hash, h.md5_hash) < 0 || bytes_cmp(sha_hash, h.sha_hash) < 0)
3271*37da2899SCharles.Forsyth				return (nil, "finished: sender mismatch");
3272*37da2899SCharles.Forsyth
3273*37da2899SCharles.Forsyth			e = update_handshake_hash(ctx, r);
3274*37da2899SCharles.Forsyth			if(e != nil)
3275*37da2899SCharles.Forsyth				return (nil, e);
3276*37da2899SCharles.Forsyth
3277*37da2899SCharles.Forsyth		CertificateVerify =>
3278*37da2899SCharles.Forsyth
3279*37da2899SCharles.Forsyth			e = update_handshake_hash(ctx, r);
3280*37da2899SCharles.Forsyth			if(e != nil)
3281*37da2899SCharles.Forsyth				return (nil, e);
3282*37da2899SCharles.Forsyth
3283*37da2899SCharles.Forsyth		* =>
3284*37da2899SCharles.Forsyth			e = update_handshake_hash(ctx, r);
3285*37da2899SCharles.Forsyth			if(e != nil)
3286*37da2899SCharles.Forsyth				return (nil, e);
3287*37da2899SCharles.Forsyth		}
3288*37da2899SCharles.Forsyth
3289*37da2899SCharles.Forsyth		p = ref Protocol.pHandshake(hm);
3290*37da2899SCharles.Forsyth
3291*37da2899SCharles.Forsyth	SSL_V2HANDSHAKE =>
3292*37da2899SCharles.Forsyth
3293*37da2899SCharles.Forsyth		(hm, e) := V2Handshake.decode(r.data);
3294*37da2899SCharles.Forsyth		if(e != "")
3295*37da2899SCharles.Forsyth			return (nil, e);
3296*37da2899SCharles.Forsyth
3297*37da2899SCharles.Forsyth		p = ref Protocol.pV2Handshake(hm);
3298*37da2899SCharles.Forsyth
3299*37da2899SCharles.Forsyth	* =>
3300*37da2899SCharles.Forsyth		return (nil, "protocol read: unknown protocol");
3301*37da2899SCharles.Forsyth	}
3302*37da2899SCharles.Forsyth
3303*37da2899SCharles.Forsyth	return (p, nil);
3304*37da2899SCharles.Forsyth
3305*37da2899SCharles.Forsyth}
3306*37da2899SCharles.Forsyth
3307*37da2899SCharles.Forsyth
3308*37da2899SCharles.Forsyth# encode protocol message and return tuple of data record and error message,
3309*37da2899SCharles.Forsyth# may be v2 or v3 record depending on vers.
3310*37da2899SCharles.Forsyth
3311*37da2899SCharles.ForsythProtocol.encode(protocol: self ref Protocol, vers: array of byte): (ref Record, string)
3312*37da2899SCharles.Forsyth{
3313*37da2899SCharles.Forsyth	r: ref Record;
3314*37da2899SCharles.Forsyth	e: string;
3315*37da2899SCharles.Forsyth
3316*37da2899SCharles.Forsyth	pick p := protocol {
3317*37da2899SCharles.Forsyth	pAlert =>
3318*37da2899SCharles.Forsyth		r = ref Record(
3319*37da2899SCharles.Forsyth				SSL_ALERT,
3320*37da2899SCharles.Forsyth				vers,
3321*37da2899SCharles.Forsyth				array [] of {byte p.alert.level, byte p.alert.description}
3322*37da2899SCharles.Forsyth			);
3323*37da2899SCharles.Forsyth
3324*37da2899SCharles.Forsyth	pChangeCipherSpec =>
3325*37da2899SCharles.Forsyth		r = ref Record(
3326*37da2899SCharles.Forsyth				SSL_CHANGE_CIPHER_SPEC,
3327*37da2899SCharles.Forsyth				vers,
3328*37da2899SCharles.Forsyth				array [] of {byte p.change_cipher_spec.value}
3329*37da2899SCharles.Forsyth			);
3330*37da2899SCharles.Forsyth
3331*37da2899SCharles.Forsyth	pHandshake =>
3332*37da2899SCharles.Forsyth		data: array of byte;
3333*37da2899SCharles.Forsyth		(data, e) = p.handshake.encode();
3334*37da2899SCharles.Forsyth		if(e != "")
3335*37da2899SCharles.Forsyth			break;
3336*37da2899SCharles.Forsyth		r = ref Record(
3337*37da2899SCharles.Forsyth				SSL_HANDSHAKE,
3338*37da2899SCharles.Forsyth				vers,
3339*37da2899SCharles.Forsyth				data
3340*37da2899SCharles.Forsyth			);
3341*37da2899SCharles.Forsyth
3342*37da2899SCharles.Forsyth	pV2Handshake =>
3343*37da2899SCharles.Forsyth		data: array of byte;
3344*37da2899SCharles.Forsyth		(data, e) = p.handshake.encode();
3345*37da2899SCharles.Forsyth		if(e != "")
3346*37da2899SCharles.Forsyth			break;
3347*37da2899SCharles.Forsyth		r = ref Record(
3348*37da2899SCharles.Forsyth				SSL_V2HANDSHAKE,
3349*37da2899SCharles.Forsyth				vers,
3350*37da2899SCharles.Forsyth				data
3351*37da2899SCharles.Forsyth			);
3352*37da2899SCharles.Forsyth
3353*37da2899SCharles.Forsyth	* =>
3354*37da2899SCharles.Forsyth		e = "unknown protocol";
3355*37da2899SCharles.Forsyth	}
3356*37da2899SCharles.Forsyth
3357*37da2899SCharles.Forsyth	if(SSL_DEBUG)
3358*37da2899SCharles.Forsyth		log("ssl3: protocol encode\n" + protocol.tostring());
3359*37da2899SCharles.Forsyth
3360*37da2899SCharles.Forsyth	return (r, e);
3361*37da2899SCharles.Forsyth}
3362*37da2899SCharles.Forsyth
3363*37da2899SCharles.Forsyth#
3364*37da2899SCharles.Forsyth# protocol message description
3365*37da2899SCharles.Forsyth#
3366*37da2899SCharles.ForsythProtocol.tostring(protocol: self ref Protocol): string
3367*37da2899SCharles.Forsyth{
3368*37da2899SCharles.Forsyth	info : string;
3369*37da2899SCharles.Forsyth
3370*37da2899SCharles.Forsyth	pick p := protocol {
3371*37da2899SCharles.Forsyth	pAlert =>
3372*37da2899SCharles.Forsyth		info = "\tAlert\n" + p.alert.tostring();
3373*37da2899SCharles.Forsyth
3374*37da2899SCharles.Forsyth	pChangeCipherSpec =>
3375*37da2899SCharles.Forsyth		info = "\tChangeCipherSpec\n";
3376*37da2899SCharles.Forsyth
3377*37da2899SCharles.Forsyth	pHandshake =>
3378*37da2899SCharles.Forsyth		info = "\tHandshake\n" + p.handshake.tostring();
3379*37da2899SCharles.Forsyth
3380*37da2899SCharles.Forsyth	pV2Handshake =>
3381*37da2899SCharles.Forsyth		info = "\tV2Handshake\n" + p.handshake.tostring();
3382*37da2899SCharles.Forsyth
3383*37da2899SCharles.Forsyth	pApplicationData =>
3384*37da2899SCharles.Forsyth		info = "\tApplicationData\n";
3385*37da2899SCharles.Forsyth
3386*37da2899SCharles.Forsyth	* =>
3387*37da2899SCharles.Forsyth		info = "\tUnknownProtocolType\n";
3388*37da2899SCharles.Forsyth	}
3389*37da2899SCharles.Forsyth
3390*37da2899SCharles.Forsyth	return "ssl3: Protocol:\n" + info;
3391*37da2899SCharles.Forsyth}
3392*37da2899SCharles.Forsyth
3393*37da2899SCharles.ForsythHandshake.decode(buf: array of byte): (ref Handshake, string)
3394*37da2899SCharles.Forsyth{
3395*37da2899SCharles.Forsyth	m : ref Handshake;
3396*37da2899SCharles.Forsyth	e : string;
3397*37da2899SCharles.Forsyth
3398*37da2899SCharles.Forsyth	a := buf[4:]; # ignore msg length
3399*37da2899SCharles.Forsyth
3400*37da2899SCharles.Forsyth	i := 0;
3401*37da2899SCharles.Forsyth	case int buf[0] {
3402*37da2899SCharles.Forsyth	SSL_HANDSHAKE_HELLO_REQUEST =>
3403*37da2899SCharles.Forsyth		m = ref Handshake.HelloRequest();
3404*37da2899SCharles.Forsyth
3405*37da2899SCharles.Forsyth        SSL_HANDSHAKE_CLIENT_HELLO =>
3406*37da2899SCharles.Forsyth    		if(len a < 38) {
3407*37da2899SCharles.Forsyth			e = "client hello: unexpected message";
3408*37da2899SCharles.Forsyth			break;
3409*37da2899SCharles.Forsyth		}
3410*37da2899SCharles.Forsyth    		cv := a[i:i+2];
3411*37da2899SCharles.Forsyth		i += 2;
3412*37da2899SCharles.Forsyth		rd := a[i:i+32];
3413*37da2899SCharles.Forsyth		i += 32;
3414*37da2899SCharles.Forsyth		lsi := int a[i++];
3415*37da2899SCharles.Forsyth    		if(len a < 38 + lsi) {
3416*37da2899SCharles.Forsyth			e = "client hello: unexpected message";
3417*37da2899SCharles.Forsyth			break;
3418*37da2899SCharles.Forsyth		}
3419*37da2899SCharles.Forsyth		sid: array of byte;
3420*37da2899SCharles.Forsyth		if(lsi != 0) {
3421*37da2899SCharles.Forsyth			sid = a[i:i+lsi];
3422*37da2899SCharles.Forsyth			i += lsi;
3423*37da2899SCharles.Forsyth		}
3424*37da2899SCharles.Forsyth		else
3425*37da2899SCharles.Forsyth			sid = nil;
3426*37da2899SCharles.Forsyth		lcs := int_decode(a[i:i+2]);
3427*37da2899SCharles.Forsyth		i += 2;
3428*37da2899SCharles.Forsyth		if((lcs & 1) || lcs < 2 || len a < 40 + lsi + lcs) {
3429*37da2899SCharles.Forsyth			e = "client hello: unexpected message";
3430*37da2899SCharles.Forsyth			break;
3431*37da2899SCharles.Forsyth		}
3432*37da2899SCharles.Forsyth		cs := array [lcs/2] of byte;
3433*37da2899SCharles.Forsyth		cs = a[i:i+lcs];
3434*37da2899SCharles.Forsyth		i += lcs;
3435*37da2899SCharles.Forsyth		lcm := int a[i++];
3436*37da2899SCharles.Forsyth		cr := a[i:i+lcm];
3437*37da2899SCharles.Forsyth		i += lcm;
3438*37da2899SCharles.Forsyth		# In the interest of forward compatibility, it is
3439*37da2899SCharles.Forsyth		# permitted for a client hello message to include
3440*37da2899SCharles.Forsyth		# extra data after the compression methods. This
3441*37da2899SCharles.Forsyth		# data must be included in the handshake hashes,
3442*37da2899SCharles.Forsyth		# but otherwise be ignored.
3443*37da2899SCharles.Forsyth		# if(i != len a) {
3444*37da2899SCharles.Forsyth		#	e = "client hello: unexpected message";
3445*37da2899SCharles.Forsyth		#	break;
3446*37da2899SCharles.Forsyth		# }
3447*37da2899SCharles.Forsyth		m = ref Handshake.ClientHello(cv, rd, sid, cs, cr);
3448*37da2899SCharles.Forsyth
3449*37da2899SCharles.Forsyth        SSL_HANDSHAKE_SERVER_HELLO =>
3450*37da2899SCharles.Forsyth		if(len a < 38) {
3451*37da2899SCharles.Forsyth			e = "server hello: unexpected message";
3452*37da2899SCharles.Forsyth			break;
3453*37da2899SCharles.Forsyth		}
3454*37da2899SCharles.Forsyth		sv := a[i:i+2];
3455*37da2899SCharles.Forsyth		i += 2;
3456*37da2899SCharles.Forsyth		rd := a[i:i+32];
3457*37da2899SCharles.Forsyth		i += 32;
3458*37da2899SCharles.Forsyth		lsi := int a[i++];
3459*37da2899SCharles.Forsyth		if(len a < 38 + lsi) {
3460*37da2899SCharles.Forsyth			e = "server hello: unexpected message";
3461*37da2899SCharles.Forsyth			break;
3462*37da2899SCharles.Forsyth		}
3463*37da2899SCharles.Forsyth		sid : array of byte;
3464*37da2899SCharles.Forsyth		if(lsi != 0) {
3465*37da2899SCharles.Forsyth			sid = a[i:i+lsi];
3466*37da2899SCharles.Forsyth			i += lsi;
3467*37da2899SCharles.Forsyth		}
3468*37da2899SCharles.Forsyth		else
3469*37da2899SCharles.Forsyth			sid = nil;
3470*37da2899SCharles.Forsyth		cs := a[i:i+2];
3471*37da2899SCharles.Forsyth		i += 2;
3472*37da2899SCharles.Forsyth		cr := a[i++];
3473*37da2899SCharles.Forsyth		if(i != len a) {
3474*37da2899SCharles.Forsyth			e = "server hello: unexpected message";
3475*37da2899SCharles.Forsyth			break;
3476*37da2899SCharles.Forsyth		}
3477*37da2899SCharles.Forsyth		m = ref Handshake.ServerHello(sv, rd, sid, cs, cr);
3478*37da2899SCharles.Forsyth
3479*37da2899SCharles.Forsyth        SSL_HANDSHAKE_CERTIFICATE =>
3480*37da2899SCharles.Forsyth		n := int_decode(a[i:i+3]);
3481*37da2899SCharles.Forsyth		i += 3;
3482*37da2899SCharles.Forsyth		if(len a != n + 3) {
3483*37da2899SCharles.Forsyth			e = "certificate: unexpected message";
3484*37da2899SCharles.Forsyth			break;
3485*37da2899SCharles.Forsyth		}
3486*37da2899SCharles.Forsyth		cl : list of array of byte;
3487*37da2899SCharles.Forsyth		k : int;
3488*37da2899SCharles.Forsyth		while(i < n) {
3489*37da2899SCharles.Forsyth			k = int_decode(a[i:i+3]);
3490*37da2899SCharles.Forsyth			i += 3;
3491*37da2899SCharles.Forsyth			if(k < 0 || i + k > len a) {
3492*37da2899SCharles.Forsyth				e = "certificate: unexpected message";
3493*37da2899SCharles.Forsyth				break;
3494*37da2899SCharles.Forsyth			}
3495*37da2899SCharles.Forsyth			cl = a[i:i+k] :: cl;
3496*37da2899SCharles.Forsyth			i += k;
3497*37da2899SCharles.Forsyth		}
3498*37da2899SCharles.Forsyth		if(e != nil)
3499*37da2899SCharles.Forsyth			break;
3500*37da2899SCharles.Forsyth		m = ref Handshake.Certificate(cl);
3501*37da2899SCharles.Forsyth
3502*37da2899SCharles.Forsyth        SSL_HANDSHAKE_SERVER_KEY_EXCHANGE =>
3503*37da2899SCharles.Forsyth
3504*37da2899SCharles.Forsyth		m = ref Handshake.ServerKeyExchange(a[i:]);
3505*37da2899SCharles.Forsyth
3506*37da2899SCharles.Forsyth        SSL_HANDSHAKE_CERTIFICATE_REQUEST =>
3507*37da2899SCharles.Forsyth		ln := int_decode(a[i:i+2]);
3508*37da2899SCharles.Forsyth		i += 2;
3509*37da2899SCharles.Forsyth		types := a[i:i+ln];
3510*37da2899SCharles.Forsyth		i += ln;
3511*37da2899SCharles.Forsyth		ln = int_decode(a[i:i+2]);
3512*37da2899SCharles.Forsyth		i += 2;
3513*37da2899SCharles.Forsyth		auths : list of array of byte;
3514*37da2899SCharles.Forsyth		for(j := 0; j < ln; j++) {
3515*37da2899SCharles.Forsyth			ln = int_decode(a[i:i+2]);
3516*37da2899SCharles.Forsyth			i += 2;
3517*37da2899SCharles.Forsyth			auths = a[i:i+ln]::auths;
3518*37da2899SCharles.Forsyth			i += ln;
3519*37da2899SCharles.Forsyth		}
3520*37da2899SCharles.Forsyth		m = ref Handshake.CertificateRequest(types, auths);
3521*37da2899SCharles.Forsyth
3522*37da2899SCharles.Forsyth        SSL_HANDSHAKE_SERVER_HELLO_DONE =>
3523*37da2899SCharles.Forsyth		if(len a != 0) {
3524*37da2899SCharles.Forsyth			e = "server hello done: unexpected message";
3525*37da2899SCharles.Forsyth			break;
3526*37da2899SCharles.Forsyth		}
3527*37da2899SCharles.Forsyth		m = ref Handshake.ServerHelloDone();
3528*37da2899SCharles.Forsyth
3529*37da2899SCharles.Forsyth        SSL_HANDSHAKE_CERTIFICATE_VERIFY =>
3530*37da2899SCharles.Forsyth		ln := int_decode(a[i:i+2]);
3531*37da2899SCharles.Forsyth		i +=2;
3532*37da2899SCharles.Forsyth		sig := a[i:];
3533*37da2899SCharles.Forsyth		i += ln;
3534*37da2899SCharles.Forsyth		if(i != len a) {
3535*37da2899SCharles.Forsyth			e = "certificate verify: unexpected message";
3536*37da2899SCharles.Forsyth			break;
3537*37da2899SCharles.Forsyth		}
3538*37da2899SCharles.Forsyth		m = ref Handshake.CertificateVerify(sig);
3539*37da2899SCharles.Forsyth
3540*37da2899SCharles.Forsyth        SSL_HANDSHAKE_CLIENT_KEY_EXCHANGE =>
3541*37da2899SCharles.Forsyth		m = ref Handshake.ClientKeyExchange(a);
3542*37da2899SCharles.Forsyth
3543*37da2899SCharles.Forsyth        SSL_HANDSHAKE_FINISHED =>
3544*37da2899SCharles.Forsyth		if(len a != Keyring->MD5dlen + Keyring->SHA1dlen) { # 16+20
3545*37da2899SCharles.Forsyth			e = "finished: unexpected message";
3546*37da2899SCharles.Forsyth			break;
3547*37da2899SCharles.Forsyth		}
3548*37da2899SCharles.Forsyth		md5_hash := a[i:i+Keyring->MD5dlen];
3549*37da2899SCharles.Forsyth		i += Keyring->MD5dlen;
3550*37da2899SCharles.Forsyth		sha_hash := a[i:i+Keyring->SHA1dlen];
3551*37da2899SCharles.Forsyth		i += Keyring->SHA1dlen;
3552*37da2899SCharles.Forsyth		if(i != len a) {
3553*37da2899SCharles.Forsyth			e = "finished: unexpected message";
3554*37da2899SCharles.Forsyth			break;
3555*37da2899SCharles.Forsyth		}
3556*37da2899SCharles.Forsyth		m = ref Handshake.Finished(md5_hash, sha_hash);
3557*37da2899SCharles.Forsyth
3558*37da2899SCharles.Forsyth	* =>
3559*37da2899SCharles.Forsyth		e = "unknown message";
3560*37da2899SCharles.Forsyth	}
3561*37da2899SCharles.Forsyth
3562*37da2899SCharles.Forsyth	if(e != nil)
3563*37da2899SCharles.Forsyth		return (nil, "Handshake decode: " + e);
3564*37da2899SCharles.Forsyth
3565*37da2899SCharles.Forsyth	return (m, nil);
3566*37da2899SCharles.Forsyth}
3567*37da2899SCharles.Forsyth
3568*37da2899SCharles.ForsythHandshake.encode(hm: self ref Handshake): (array of byte, string)
3569*37da2899SCharles.Forsyth{
3570*37da2899SCharles.Forsyth	a : array of byte;
3571*37da2899SCharles.Forsyth	n : int;
3572*37da2899SCharles.Forsyth	e : string;
3573*37da2899SCharles.Forsyth
3574*37da2899SCharles.Forsyth	i := 0;
3575*37da2899SCharles.Forsyth	pick m := hm {
3576*37da2899SCharles.Forsyth	HelloRequest =>
3577*37da2899SCharles.Forsyth		a = array [4] of byte;
3578*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_HELLO_REQUEST;
3579*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3580*37da2899SCharles.Forsyth		i += 3;
3581*37da2899SCharles.Forsyth		if(i != 4)
3582*37da2899SCharles.Forsyth			e = "hello request: wrong message length";
3583*37da2899SCharles.Forsyth
3584*37da2899SCharles.Forsyth        ClientHello =>
3585*37da2899SCharles.Forsyth		lsi := len m.session_id;
3586*37da2899SCharles.Forsyth		lcs := len m.suites;
3587*37da2899SCharles.Forsyth		if((lcs &1) || lcs < 2) {
3588*37da2899SCharles.Forsyth			e = "client hello: cipher suites is not multiple of 2 bytes";
3589*37da2899SCharles.Forsyth			break;
3590*37da2899SCharles.Forsyth		}
3591*37da2899SCharles.Forsyth		lcm := len m.compressions;
3592*37da2899SCharles.Forsyth		n = 38 + lsi + lcs + lcm; # 2+32+1+2+1
3593*37da2899SCharles.Forsyth		a = array[n+4] of byte;
3594*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_CLIENT_HELLO;
3595*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3596*37da2899SCharles.Forsyth		i += 3;
3597*37da2899SCharles.Forsyth		a[i:] = m.version;
3598*37da2899SCharles.Forsyth		i += 2;
3599*37da2899SCharles.Forsyth		a[i:] = m.random;
3600*37da2899SCharles.Forsyth		i += 32;
3601*37da2899SCharles.Forsyth		a[i++] = byte lsi;
3602*37da2899SCharles.Forsyth		if(lsi != 0) {
3603*37da2899SCharles.Forsyth			a[i:] = m.session_id;
3604*37da2899SCharles.Forsyth			i += lsi;
3605*37da2899SCharles.Forsyth		}
3606*37da2899SCharles.Forsyth		a[i:] = int_encode(lcs, 2);
3607*37da2899SCharles.Forsyth		i += 2;
3608*37da2899SCharles.Forsyth		a[i:] = m.suites; # not nil
3609*37da2899SCharles.Forsyth		i += lcs;
3610*37da2899SCharles.Forsyth		a[i++] = byte lcm;
3611*37da2899SCharles.Forsyth		a[i:] = m.compressions;	# not nil
3612*37da2899SCharles.Forsyth		i += lcm;
3613*37da2899SCharles.Forsyth		if(i != n+4)
3614*37da2899SCharles.Forsyth			e = "client hello: wrong message length";
3615*37da2899SCharles.Forsyth
3616*37da2899SCharles.Forsyth        ServerHello =>
3617*37da2899SCharles.Forsyth		lsi := len m.session_id;
3618*37da2899SCharles.Forsyth		n = 38 + lsi; # 2+32+1+2+1
3619*37da2899SCharles.Forsyth		a = array [n+4] of byte;
3620*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_SERVER_HELLO;
3621*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3622*37da2899SCharles.Forsyth		i += 3;
3623*37da2899SCharles.Forsyth		a[i:] = m.version;
3624*37da2899SCharles.Forsyth		i += 2;
3625*37da2899SCharles.Forsyth		a[i:] = m.random;
3626*37da2899SCharles.Forsyth		i += 32;
3627*37da2899SCharles.Forsyth		a[i++] = byte lsi;
3628*37da2899SCharles.Forsyth		if(lsi != 0) {
3629*37da2899SCharles.Forsyth			a[i:] = m.session_id;
3630*37da2899SCharles.Forsyth			i += lsi;
3631*37da2899SCharles.Forsyth		}
3632*37da2899SCharles.Forsyth		a[i:] = m.suite; # should be verified, not nil
3633*37da2899SCharles.Forsyth		i += 2;
3634*37da2899SCharles.Forsyth		a[i++] = m.compression; # should be verified, not nil
3635*37da2899SCharles.Forsyth		if(i != n+4)
3636*37da2899SCharles.Forsyth			e = "server hello: wrong message length";
3637*37da2899SCharles.Forsyth
3638*37da2899SCharles.Forsyth        Certificate =>
3639*37da2899SCharles.Forsyth		cl := m.cert_list;
3640*37da2899SCharles.Forsyth		while(cl != nil) {
3641*37da2899SCharles.Forsyth			n += 3 + len hd cl;
3642*37da2899SCharles.Forsyth			cl = tl cl;
3643*37da2899SCharles.Forsyth		}
3644*37da2899SCharles.Forsyth		a = array [n+7] of byte;
3645*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_CERTIFICATE;
3646*37da2899SCharles.Forsyth		a[i:] = int_encode(n+3, 3); # length of record
3647*37da2899SCharles.Forsyth		i += 3;
3648*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3); # total length of cert chain
3649*37da2899SCharles.Forsyth		i += 3;
3650*37da2899SCharles.Forsyth		cl = m.cert_list;
3651*37da2899SCharles.Forsyth		while(cl != nil) {
3652*37da2899SCharles.Forsyth			a[i:] = int_encode(len hd cl, 3);
3653*37da2899SCharles.Forsyth			i += 3;
3654*37da2899SCharles.Forsyth			a[i:] = hd cl;
3655*37da2899SCharles.Forsyth			i += len hd cl;
3656*37da2899SCharles.Forsyth			cl = tl cl;
3657*37da2899SCharles.Forsyth		}
3658*37da2899SCharles.Forsyth		if(i != n+7)
3659*37da2899SCharles.Forsyth			e = "certificate: wrong message length";
3660*37da2899SCharles.Forsyth
3661*37da2899SCharles.Forsyth        ServerKeyExchange =>
3662*37da2899SCharles.Forsyth		n = len m.xkey;
3663*37da2899SCharles.Forsyth		a = array [n+4] of byte;
3664*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_SERVER_KEY_EXCHANGE;
3665*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3666*37da2899SCharles.Forsyth		i += 3;
3667*37da2899SCharles.Forsyth		a[i:] = m.xkey;
3668*37da2899SCharles.Forsyth		i += len m.xkey;
3669*37da2899SCharles.Forsyth		if(i != n+4)
3670*37da2899SCharles.Forsyth			e = "server key exchange: wrong message length";
3671*37da2899SCharles.Forsyth
3672*37da2899SCharles.Forsyth        CertificateRequest =>
3673*37da2899SCharles.Forsyth		ntypes := len m.cert_types;
3674*37da2899SCharles.Forsyth		nauths := len m.dn_list;
3675*37da2899SCharles.Forsyth		n = 1 + ntypes;
3676*37da2899SCharles.Forsyth		dl := m.dn_list;
3677*37da2899SCharles.Forsyth		while(dl != nil) {
3678*37da2899SCharles.Forsyth			n += 2 + len hd dl;
3679*37da2899SCharles.Forsyth			dl = tl dl;
3680*37da2899SCharles.Forsyth		}
3681*37da2899SCharles.Forsyth		n += 2;
3682*37da2899SCharles.Forsyth		a = array [n+4] of byte;
3683*37da2899SCharles.Forsyth		a[i++] =  byte SSL_HANDSHAKE_CERTIFICATE_REQUEST;
3684*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3685*37da2899SCharles.Forsyth		i += 3;
3686*37da2899SCharles.Forsyth		a[i++] = byte ntypes;
3687*37da2899SCharles.Forsyth		a[i:] = m.cert_types;
3688*37da2899SCharles.Forsyth		i += ntypes;
3689*37da2899SCharles.Forsyth		a[i:] = int_encode(nauths, 2);
3690*37da2899SCharles.Forsyth		i += 2;
3691*37da2899SCharles.Forsyth		dl = m.dn_list;
3692*37da2899SCharles.Forsyth		while(dl != nil) {
3693*37da2899SCharles.Forsyth			a[i:] = int_encode(len hd dl, 2);
3694*37da2899SCharles.Forsyth			i += 2;
3695*37da2899SCharles.Forsyth			a[i:] = hd dl;
3696*37da2899SCharles.Forsyth			i += len hd dl;
3697*37da2899SCharles.Forsyth			dl = tl dl;
3698*37da2899SCharles.Forsyth		}
3699*37da2899SCharles.Forsyth		if(i != n+4)
3700*37da2899SCharles.Forsyth			e = "certificate request: wrong message length";
3701*37da2899SCharles.Forsyth
3702*37da2899SCharles.Forsyth        ServerHelloDone =>
3703*37da2899SCharles.Forsyth		n = 0;
3704*37da2899SCharles.Forsyth		a = array[n+4] of byte;
3705*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_SERVER_HELLO_DONE;
3706*37da2899SCharles.Forsyth		a[i:] = int_encode(0, 3); # message has 0 length
3707*37da2899SCharles.Forsyth		i += 3;
3708*37da2899SCharles.Forsyth		if(i != n+4)
3709*37da2899SCharles.Forsyth			e = "server hello done: wrong message length";
3710*37da2899SCharles.Forsyth
3711*37da2899SCharles.Forsyth        CertificateVerify =>
3712*37da2899SCharles.Forsyth		n = 2 + len m.signature;
3713*37da2899SCharles.Forsyth		a = array [n+4] of byte;
3714*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_CERTIFICATE_VERIFY;
3715*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3716*37da2899SCharles.Forsyth		i += 3;
3717*37da2899SCharles.Forsyth		a[i:] = int_encode(n-2, 2);
3718*37da2899SCharles.Forsyth		i += 2;
3719*37da2899SCharles.Forsyth		a[i:] = m.signature;
3720*37da2899SCharles.Forsyth		i += n-2;
3721*37da2899SCharles.Forsyth		if(i != n+4)
3722*37da2899SCharles.Forsyth			e = "certificate verify: wrong message length";
3723*37da2899SCharles.Forsyth
3724*37da2899SCharles.Forsyth        ClientKeyExchange =>
3725*37da2899SCharles.Forsyth		n = len m.xkey;
3726*37da2899SCharles.Forsyth		a = array [n+4] of byte;
3727*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_CLIENT_KEY_EXCHANGE;
3728*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3729*37da2899SCharles.Forsyth		i += 3;
3730*37da2899SCharles.Forsyth		a[i:] = m.xkey;
3731*37da2899SCharles.Forsyth		i += n;
3732*37da2899SCharles.Forsyth		if(i != n+4)
3733*37da2899SCharles.Forsyth			e = "client key exchange: wrong message length";
3734*37da2899SCharles.Forsyth
3735*37da2899SCharles.Forsyth        Finished =>
3736*37da2899SCharles.Forsyth		n = len m.md5_hash + len m.sha_hash;
3737*37da2899SCharles.Forsyth		a = array [n+4] of byte;
3738*37da2899SCharles.Forsyth		a[i++] = byte SSL_HANDSHAKE_FINISHED;
3739*37da2899SCharles.Forsyth		a[i:] = int_encode(n, 3);
3740*37da2899SCharles.Forsyth		i += 3;
3741*37da2899SCharles.Forsyth		a[i:] = m.md5_hash;
3742*37da2899SCharles.Forsyth		i += len m.md5_hash;
3743*37da2899SCharles.Forsyth		a[i:] = m.sha_hash;
3744*37da2899SCharles.Forsyth		i += len m.sha_hash;
3745*37da2899SCharles.Forsyth		if(i != n+4)
3746*37da2899SCharles.Forsyth			e = "finished: wrong message length";
3747*37da2899SCharles.Forsyth
3748*37da2899SCharles.Forsyth	* =>
3749*37da2899SCharles.Forsyth		e = "unknown message";
3750*37da2899SCharles.Forsyth	}
3751*37da2899SCharles.Forsyth
3752*37da2899SCharles.Forsyth	if(e != nil)
3753*37da2899SCharles.Forsyth		return (nil, "Handshake encode: " + e);
3754*37da2899SCharles.Forsyth
3755*37da2899SCharles.Forsyth	return (a, e);
3756*37da2899SCharles.Forsyth}
3757*37da2899SCharles.Forsyth
3758*37da2899SCharles.ForsythHandshake.tostring(handshake: self ref Handshake): string
3759*37da2899SCharles.Forsyth{
3760*37da2899SCharles.Forsyth	info: string;
3761*37da2899SCharles.Forsyth
3762*37da2899SCharles.Forsyth	pick m := handshake {
3763*37da2899SCharles.Forsyth        HelloRequest =>
3764*37da2899SCharles.Forsyth		info = "\tHelloRequest\n";
3765*37da2899SCharles.Forsyth
3766*37da2899SCharles.Forsyth        ClientHello =>
3767*37da2899SCharles.Forsyth		info = "\tClientHello\n" +
3768*37da2899SCharles.Forsyth			"\tversion = \n\t\t" + bastr(m.version) + "\n" +
3769*37da2899SCharles.Forsyth			"\trandom = \n\t\t" + bastr(m.random) + "\n" +
3770*37da2899SCharles.Forsyth			"\tsession_id = \n\t\t" + bastr(m.session_id) + "\n" +
3771*37da2899SCharles.Forsyth			"\tsuites = \n\t\t" + bastr(m.suites) + "\n" +
3772*37da2899SCharles.Forsyth			"\tcomperssion_methods = \n\t\t" + bastr(m.compressions) +"\n";
3773*37da2899SCharles.Forsyth
3774*37da2899SCharles.Forsyth        ServerHello =>
3775*37da2899SCharles.Forsyth		info = "\tServerHello\n" +
3776*37da2899SCharles.Forsyth			"\tversion = \n\t\t" + bastr(m.version) + "\n" +
3777*37da2899SCharles.Forsyth			"\trandom = \n\t\t" + bastr(m.random) + "\n" +
3778*37da2899SCharles.Forsyth			"\tsession_id = \n\t\t" + bastr(m.session_id) + "\n" +
3779*37da2899SCharles.Forsyth			"\tsuite = \n\t\t" + bastr(m.suite) + "\n" +
3780*37da2899SCharles.Forsyth			"\tcomperssion_method = \n\t\t" + string m.compression +"\n";
3781*37da2899SCharles.Forsyth
3782*37da2899SCharles.Forsyth        Certificate =>
3783*37da2899SCharles.Forsyth		info = "\tCertificate\n" +
3784*37da2899SCharles.Forsyth			"\tcert_list = \n\t\t" + lbastr(m.cert_list) + "\n";
3785*37da2899SCharles.Forsyth
3786*37da2899SCharles.Forsyth        ServerKeyExchange =>
3787*37da2899SCharles.Forsyth		info = "\tServerKeyExchange\n" +
3788*37da2899SCharles.Forsyth			"\txkey = \n\t\t" + bastr(m.xkey) +"\n";
3789*37da2899SCharles.Forsyth
3790*37da2899SCharles.Forsyth        CertificateRequest =>
3791*37da2899SCharles.Forsyth		info = "\tCertificateRequest\n" +
3792*37da2899SCharles.Forsyth			"\tcert_types = \n\t\t" + bastr(m.cert_types) + "\n" +
3793*37da2899SCharles.Forsyth			"\tdn_list = \n\t\t" + lbastr(m.dn_list) + "\n";
3794*37da2899SCharles.Forsyth
3795*37da2899SCharles.Forsyth        ServerHelloDone =>
3796*37da2899SCharles.Forsyth		info = "\tServerDone\n";
3797*37da2899SCharles.Forsyth
3798*37da2899SCharles.Forsyth        CertificateVerify =>
3799*37da2899SCharles.Forsyth		info = "\tCertificateVerify\n" +
3800*37da2899SCharles.Forsyth			"\tsignature = \n\t\t" + bastr(m.signature) + "\n";
3801*37da2899SCharles.Forsyth
3802*37da2899SCharles.Forsyth        ClientKeyExchange =>
3803*37da2899SCharles.Forsyth		info = "\tClientKeyExchange\n" +
3804*37da2899SCharles.Forsyth			"\txkey = \n\t\t" + bastr(m.xkey) +"\n";
3805*37da2899SCharles.Forsyth
3806*37da2899SCharles.Forsyth        Finished =>
3807*37da2899SCharles.Forsyth		info = "\tFinished\n" +
3808*37da2899SCharles.Forsyth			"\tmd5_hash = \n\t\t" + bastr(m.md5_hash) + "\n" +
3809*37da2899SCharles.Forsyth			"\tsha_hash = \n\t\t" + bastr(m.sha_hash) + "\n";
3810*37da2899SCharles.Forsyth	}
3811*37da2899SCharles.Forsyth
3812*37da2899SCharles.Forsyth	return info;
3813*37da2899SCharles.Forsyth}
3814*37da2899SCharles.Forsyth
3815*37da2899SCharles.ForsythAlert.tostring(alert: self ref Alert): string
3816*37da2899SCharles.Forsyth{
3817*37da2899SCharles.Forsyth	info: string;
3818*37da2899SCharles.Forsyth
3819*37da2899SCharles.Forsyth	case alert.level {
3820*37da2899SCharles.Forsyth	SSL_WARNING =>
3821*37da2899SCharles.Forsyth		info += "\t\twarning: ";
3822*37da2899SCharles.Forsyth
3823*37da2899SCharles.Forsyth	SSL_FATAL =>
3824*37da2899SCharles.Forsyth		info += "\t\tfatal: ";
3825*37da2899SCharles.Forsyth
3826*37da2899SCharles.Forsyth	*  =>
3827*37da2899SCharles.Forsyth		info += sys->sprint("unknown alert level[%d]: ", alert.level);
3828*37da2899SCharles.Forsyth	}
3829*37da2899SCharles.Forsyth
3830*37da2899SCharles.Forsyth	case alert.description {
3831*37da2899SCharles.Forsyth	SSL_CLOSE_NOTIFY =>
3832*37da2899SCharles.Forsyth		info += "close notify";
3833*37da2899SCharles.Forsyth
3834*37da2899SCharles.Forsyth	SSL_NO_CERTIFICATE =>
3835*37da2899SCharles.Forsyth		info += "no certificate";
3836*37da2899SCharles.Forsyth
3837*37da2899SCharles.Forsyth	SSL_BAD_CERTIFICATE =>
3838*37da2899SCharles.Forsyth		info += "bad certificate";
3839*37da2899SCharles.Forsyth
3840*37da2899SCharles.Forsyth	SSL_UNSUPPORTED_CERTIFICATE =>
3841*37da2899SCharles.Forsyth		info += "unsupported certificate";
3842*37da2899SCharles.Forsyth
3843*37da2899SCharles.Forsyth	SSL_CERTIFICATE_REVOKED =>
3844*37da2899SCharles.Forsyth		info += "certificate revoked";
3845*37da2899SCharles.Forsyth
3846*37da2899SCharles.Forsyth	SSL_CERTIFICATE_EXPIRED =>
3847*37da2899SCharles.Forsyth		info += "certificate expired";
3848*37da2899SCharles.Forsyth
3849*37da2899SCharles.Forsyth	SSL_CERTIFICATE_UNKNOWN =>
3850*37da2899SCharles.Forsyth		info += "certificate unknown";
3851*37da2899SCharles.Forsyth
3852*37da2899SCharles.Forsyth	SSL_UNEXPECTED_MESSAGE =>
3853*37da2899SCharles.Forsyth		info += "unexpected message";
3854*37da2899SCharles.Forsyth
3855*37da2899SCharles.Forsyth	SSL_BAD_RECORD_MAC =>
3856*37da2899SCharles.Forsyth		info += "bad record mac";
3857*37da2899SCharles.Forsyth
3858*37da2899SCharles.Forsyth	SSL_DECOMPRESSION_FAILURE =>
3859*37da2899SCharles.Forsyth		info += "decompression failure";
3860*37da2899SCharles.Forsyth
3861*37da2899SCharles.Forsyth	SSL_HANDSHAKE_FAILURE =>
3862*37da2899SCharles.Forsyth		info += "handshake failure";
3863*37da2899SCharles.Forsyth
3864*37da2899SCharles.Forsyth	SSL_ILLEGAL_PARAMETER =>
3865*37da2899SCharles.Forsyth		info += "illegal parameter";
3866*37da2899SCharles.Forsyth
3867*37da2899SCharles.Forsyth	* =>
3868*37da2899SCharles.Forsyth		info += sys->sprint("unknown alert description[%d]", alert.description);
3869*37da2899SCharles.Forsyth	}
3870*37da2899SCharles.Forsyth
3871*37da2899SCharles.Forsyth	return info;
3872*37da2899SCharles.Forsyth}
3873*37da2899SCharles.Forsyth
3874*37da2899SCharles.Forsythfind_cipher_suite(s, suites: array of byte) : array of byte
3875*37da2899SCharles.Forsyth{
3876*37da2899SCharles.Forsyth	i, j : int;
3877*37da2899SCharles.Forsyth	a, b : array of byte;
3878*37da2899SCharles.Forsyth
3879*37da2899SCharles.Forsyth	n := len s;
3880*37da2899SCharles.Forsyth	if((n & 1) || n < 2)
3881*37da2899SCharles.Forsyth		return nil;
3882*37da2899SCharles.Forsyth
3883*37da2899SCharles.Forsyth	m := len suites;
3884*37da2899SCharles.Forsyth	if((m & 1) || m < 2)
3885*37da2899SCharles.Forsyth		return nil;
3886*37da2899SCharles.Forsyth
3887*37da2899SCharles.Forsyth	for(i = 0; i < n; ) {
3888*37da2899SCharles.Forsyth		a = s[i:i+2];
3889*37da2899SCharles.Forsyth		i += 2;
3890*37da2899SCharles.Forsyth		for(j = 0; j < m; ) {
3891*37da2899SCharles.Forsyth			b = suites[j:j+2];
3892*37da2899SCharles.Forsyth			j += 2;
3893*37da2899SCharles.Forsyth			if(a[0] == b[0] && a[1] == b[1])
3894*37da2899SCharles.Forsyth				return b;
3895*37da2899SCharles.Forsyth		}
3896*37da2899SCharles.Forsyth	}
3897*37da2899SCharles.Forsyth
3898*37da2899SCharles.Forsyth	return nil;
3899*37da2899SCharles.Forsyth}
3900*37da2899SCharles.Forsyth
3901*37da2899SCharles.Forsyth#
3902*37da2899SCharles.Forsyth# cipher suites and specs
3903*37da2899SCharles.Forsyth#
3904*37da2899SCharles.Forsythsuite_to_spec(cs: array of byte, cipher_suites: array of array of byte)
3905*37da2899SCharles.Forsyth	: (ref CipherSpec, ref KeyExAlg, ref SigAlg, string)
3906*37da2899SCharles.Forsyth{
3907*37da2899SCharles.Forsyth	cip : ref CipherSpec;
3908*37da2899SCharles.Forsyth	kex : ref KeyExAlg;
3909*37da2899SCharles.Forsyth	sig : ref SigAlg;
3910*37da2899SCharles.Forsyth
3911*37da2899SCharles.Forsyth	n := len cipher_suites;
3912*37da2899SCharles.Forsyth	i : int;
3913*37da2899SCharles.Forsyth	found := array [2] of byte;
3914*37da2899SCharles.Forsyth	for(i = 0; i < n; i++) {
3915*37da2899SCharles.Forsyth		found = cipher_suites[i];
3916*37da2899SCharles.Forsyth		if(found[0]==cs[0] && found[1]==cs[1]) break;
3917*37da2899SCharles.Forsyth	}
3918*37da2899SCharles.Forsyth
3919*37da2899SCharles.Forsyth	if(i == n)
3920*37da2899SCharles.Forsyth		return (nil, nil, nil, "fail to find a matched spec");
3921*37da2899SCharles.Forsyth
3922*37da2899SCharles.Forsyth	case i {
3923*37da2899SCharles.Forsyth	NULL_WITH_NULL_NULL =>
3924*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_NULL_CIPHER,
3925*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 0, 0, SSL_NULL_MAC, 0);
3926*37da2899SCharles.Forsyth		kex = ref KeyExAlg.NULL();
3927*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3928*37da2899SCharles.Forsyth
3929*37da2899SCharles.Forsyth	RSA_WITH_NULL_MD5 => # sign only certificate
3930*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_NULL_CIPHER,
3931*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 0, 0, SSL_MD5, Keyring->MD5dlen);
3932*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3933*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3934*37da2899SCharles.Forsyth
3935*37da2899SCharles.Forsyth	RSA_WITH_NULL_SHA =>
3936*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_NULL_CIPHER,
3937*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 0, 0, SSL_SHA, Keyring->SHA1dlen);
3938*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3939*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3940*37da2899SCharles.Forsyth
3941*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_RC4_40_MD5 =>
3942*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_RC4,
3943*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 5, 0, SSL_MD5, Keyring->MD5dlen);
3944*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3945*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3946*37da2899SCharles.Forsyth
3947*37da2899SCharles.Forsyth	RSA_WITH_RC4_128_MD5 =>
3948*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_RC4,
3949*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 16, 0, SSL_MD5, Keyring->MD5dlen);
3950*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3951*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3952*37da2899SCharles.Forsyth
3953*37da2899SCharles.Forsyth	RSA_WITH_RC4_128_SHA =>
3954*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_RC4,
3955*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 16, 0, SSL_SHA, Keyring->SHA1dlen);
3956*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3957*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3958*37da2899SCharles.Forsyth
3959*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_RC2_CBC_40_MD5 =>
3960*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_RC2_CBC,
3961*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 5, 8, SSL_MD5, Keyring->MD5dlen);
3962*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3963*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
3964*37da2899SCharles.Forsyth
3965*37da2899SCharles.Forsyth	RSA_WITH_IDEA_CBC_SHA =>
3966*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_IDEA_CBC,
3967*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 16, 8, SSL_SHA, Keyring->SHA1dlen);
3968*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3969*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3970*37da2899SCharles.Forsyth
3971*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_DES40_CBC_SHA =>
3972*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_DES_CBC,
3973*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 5, 8, SSL_SHA, Keyring->SHA1dlen);
3974*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3975*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
3976*37da2899SCharles.Forsyth
3977*37da2899SCharles.Forsyth	RSA_WITH_DES_CBC_SHA =>
3978*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC,
3979*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 8, 8, SSL_SHA, Keyring->SHA1dlen);
3980*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3981*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3982*37da2899SCharles.Forsyth
3983*37da2899SCharles.Forsyth	RSA_WITH_3DES_EDE_CBC_SHA =>
3984*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_3DES_EDE_CBC,
3985*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 24, 8, SSL_SHA, Keyring->SHA1dlen);
3986*37da2899SCharles.Forsyth		kex = ref KeyExAlg.RSA(nil, nil, nil);
3987*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
3988*37da2899SCharles.Forsyth
3989*37da2899SCharles.Forsyth	DH_DSS_EXPORT_WITH_DES40_CBC_SHA =>
3990*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_DES_CBC,
3991*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 5, 8, SSL_SHA, Keyring->SHA1dlen);
3992*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
3993*37da2899SCharles.Forsyth		sig = ref SigAlg.DSS(nil, nil);
3994*37da2899SCharles.Forsyth
3995*37da2899SCharles.Forsyth	DH_DSS_WITH_DES_CBC_SHA =>
3996*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC,
3997*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 8, 8, SSL_SHA, Keyring->SHA1dlen);
3998*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
3999*37da2899SCharles.Forsyth		sig = ref SigAlg.DSS(nil, nil);
4000*37da2899SCharles.Forsyth
4001*37da2899SCharles.Forsyth	DH_DSS_WITH_3DES_EDE_CBC_SHA =>
4002*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_3DES_EDE_CBC,
4003*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 24, 8, SSL_SHA, Keyring->SHA1dlen);
4004*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4005*37da2899SCharles.Forsyth		sig = ref SigAlg.DSS(nil, nil);
4006*37da2899SCharles.Forsyth
4007*37da2899SCharles.Forsyth	DH_RSA_EXPORT_WITH_DES40_CBC_SHA =>
4008*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_DES_CBC,
4009*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 5, 8, SSL_SHA, Keyring->SHA1dlen);
4010*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4011*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
4012*37da2899SCharles.Forsyth
4013*37da2899SCharles.Forsyth	DH_RSA_WITH_DES_CBC_SHA =>
4014*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC,
4015*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 8, 8, SSL_SHA, Keyring->SHA1dlen);
4016*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4017*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
4018*37da2899SCharles.Forsyth
4019*37da2899SCharles.Forsyth	DH_RSA_WITH_3DES_EDE_CBC_SHA =>
4020*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_3DES_EDE_CBC,
4021*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 24, 8, SSL_SHA, Keyring->SHA1dlen);
4022*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4023*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
4024*37da2899SCharles.Forsyth
4025*37da2899SCharles.Forsyth	DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =>
4026*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC,
4027*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 5, 8, SSL_SHA, Keyring->SHA1dlen);
4028*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4029*37da2899SCharles.Forsyth		sig = ref SigAlg.DSS(nil, nil);
4030*37da2899SCharles.Forsyth
4031*37da2899SCharles.Forsyth	DHE_DSS_WITH_DES_CBC_SHA =>
4032*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC,
4033*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 8, 8, SSL_SHA, Keyring->SHA1dlen);
4034*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4035*37da2899SCharles.Forsyth		sig = ref SigAlg.DSS(nil, nil);
4036*37da2899SCharles.Forsyth
4037*37da2899SCharles.Forsyth	DHE_DSS_WITH_3DES_EDE_CBC_SHA =>
4038*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_3DES_EDE_CBC,
4039*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 24, 8, SSL_SHA, Keyring->SHA1dlen);
4040*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4041*37da2899SCharles.Forsyth		sig = ref SigAlg.DSS(nil, nil);
4042*37da2899SCharles.Forsyth
4043*37da2899SCharles.Forsyth	DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =>
4044*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_DES_CBC,
4045*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 5, 8, SSL_SHA, Keyring->SHA1dlen);
4046*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4047*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
4048*37da2899SCharles.Forsyth
4049*37da2899SCharles.Forsyth	DHE_RSA_WITH_DES_CBC_SHA =>
4050*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC,
4051*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 8, 8, SSL_SHA, Keyring->SHA1dlen);
4052*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4053*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
4054*37da2899SCharles.Forsyth
4055*37da2899SCharles.Forsyth	DHE_RSA_WITH_3DES_EDE_CBC_SHA =>
4056*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_3DES_EDE_CBC,
4057*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 24, 8, SSL_SHA, Keyring->SHA1dlen);
4058*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4059*37da2899SCharles.Forsyth		sig = ref SigAlg.RSA(nil, nil);
4060*37da2899SCharles.Forsyth
4061*37da2899SCharles.Forsyth	DH_anon_EXPORT_WITH_RC4_40_MD5 =>
4062*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_RC4,
4063*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 5, 0, SSL_MD5, Keyring->MD5dlen);
4064*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4065*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
4066*37da2899SCharles.Forsyth
4067*37da2899SCharles.Forsyth	DH_anon_WITH_RC4_128_MD5 =>
4068*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_RC4,
4069*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 16, 0, SSL_MD5, Keyring->MD5dlen);
4070*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4071*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
4072*37da2899SCharles.Forsyth
4073*37da2899SCharles.Forsyth	DH_anon_EXPORT_WITH_DES40_CBC_SHA =>
4074*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_DES_CBC,
4075*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 5, 8, SSL_SHA, Keyring->SHA1dlen);
4076*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4077*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
4078*37da2899SCharles.Forsyth
4079*37da2899SCharles.Forsyth	DH_anon_WITH_DES_CBC_SHA =>
4080*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC,
4081*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 8, 8, SSL_SHA, Keyring->SHA1dlen);
4082*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4083*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
4084*37da2899SCharles.Forsyth
4085*37da2899SCharles.Forsyth	DH_anon_WITH_3DES_EDE_CBC_SHA =>
4086*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_3DES_EDE_CBC,
4087*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 24, 8, SSL_SHA, Keyring->SHA1dlen);
4088*37da2899SCharles.Forsyth		kex = ref KeyExAlg.DH(nil, nil, nil, nil, nil);
4089*37da2899SCharles.Forsyth		sig = ref SigAlg.anon();
4090*37da2899SCharles.Forsyth
4091*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_NULL_SHA =>
4092*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_NULL_CIPHER,
4093*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 0, 0, SSL_SHA, Keyring->SHA1dlen);
4094*37da2899SCharles.Forsyth		kex = ref KeyExAlg.FORTEZZA_KEA();
4095*37da2899SCharles.Forsyth		sig = ref SigAlg.FORTEZZA_KEA();
4096*37da2899SCharles.Forsyth
4097*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA =>
4098*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_FORTEZZA_CBC,
4099*37da2899SCharles.Forsyth			SSL_BLOCK_CIPHER, 0, 0, SSL_SHA, Keyring->SHA1dlen);
4100*37da2899SCharles.Forsyth		kex = ref KeyExAlg.FORTEZZA_KEA();
4101*37da2899SCharles.Forsyth		sig = ref SigAlg.FORTEZZA_KEA();
4102*37da2899SCharles.Forsyth
4103*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_RC4_128_SHA =>
4104*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_RC4,
4105*37da2899SCharles.Forsyth			SSL_STREAM_CIPHER, 16, 0, SSL_SHA, Keyring->SHA1dlen);
4106*37da2899SCharles.Forsyth		kex = ref KeyExAlg.FORTEZZA_KEA();
4107*37da2899SCharles.Forsyth		sig = ref SigAlg.FORTEZZA_KEA();
4108*37da2899SCharles.Forsyth
4109*37da2899SCharles.Forsyth	}
4110*37da2899SCharles.Forsyth
4111*37da2899SCharles.Forsyth	return (cip, kex, sig, nil);
4112*37da2899SCharles.Forsyth}
4113*37da2899SCharles.Forsyth
4114*37da2899SCharles.Forsyth#
4115*37da2899SCharles.Forsyth# use suites as default SSL3_Suites
4116*37da2899SCharles.Forsyth#
4117*37da2899SCharles.Forsythcipher_suite_info(cs: array of byte, suites: array of array of byte) : string
4118*37da2899SCharles.Forsyth{
4119*37da2899SCharles.Forsyth	tag : string;
4120*37da2899SCharles.Forsyth
4121*37da2899SCharles.Forsyth	a := array [2] of byte;
4122*37da2899SCharles.Forsyth	n := len suites;
4123*37da2899SCharles.Forsyth	for(i := 0; i < n; i++) {
4124*37da2899SCharles.Forsyth		a = suites[i];
4125*37da2899SCharles.Forsyth		if(a[0]==cs[0] && a[1]==cs[1]) break;
4126*37da2899SCharles.Forsyth	}
4127*37da2899SCharles.Forsyth
4128*37da2899SCharles.Forsyth	if(i == n)
4129*37da2899SCharles.Forsyth		return "unknown cipher suite [" + string cs + "]";
4130*37da2899SCharles.Forsyth
4131*37da2899SCharles.Forsyth	case i {
4132*37da2899SCharles.Forsyth	NULL_WITH_NULL_NULL =>
4133*37da2899SCharles.Forsyth		tag = "NULL_WITH_NULL_NULL";
4134*37da2899SCharles.Forsyth
4135*37da2899SCharles.Forsyth	RSA_WITH_NULL_MD5 =>
4136*37da2899SCharles.Forsyth		tag = "RSA_WITH_NULL_MD5";
4137*37da2899SCharles.Forsyth
4138*37da2899SCharles.Forsyth	RSA_WITH_NULL_SHA =>
4139*37da2899SCharles.Forsyth		tag = "RSA_WITH_NULL_SHA";
4140*37da2899SCharles.Forsyth
4141*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_RC4_40_MD5 =>
4142*37da2899SCharles.Forsyth		tag = "RSA_EXPORT_WITH_RC4_40_MD5";
4143*37da2899SCharles.Forsyth
4144*37da2899SCharles.Forsyth	RSA_WITH_RC4_128_MD5 =>
4145*37da2899SCharles.Forsyth		tag = "RSA_WITH_RC4_128_MD5";
4146*37da2899SCharles.Forsyth
4147*37da2899SCharles.Forsyth	RSA_WITH_RC4_128_SHA =>
4148*37da2899SCharles.Forsyth		tag = "RSA_WITH_RC4_128_SHA";
4149*37da2899SCharles.Forsyth
4150*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_RC2_CBC_40_MD5 =>
4151*37da2899SCharles.Forsyth		tag = "RSA_EXPORT_WITH_RC2_CBC_40_MD5";
4152*37da2899SCharles.Forsyth
4153*37da2899SCharles.Forsyth	RSA_WITH_IDEA_CBC_SHA =>
4154*37da2899SCharles.Forsyth		tag = "RSA_WITH_IDEA_CBC_SHA";
4155*37da2899SCharles.Forsyth
4156*37da2899SCharles.Forsyth	RSA_EXPORT_WITH_DES40_CBC_SHA =>
4157*37da2899SCharles.Forsyth		tag ="RSA_EXPORT_WITH_DES40_CBC_SHA";
4158*37da2899SCharles.Forsyth
4159*37da2899SCharles.Forsyth	RSA_WITH_DES_CBC_SHA =>
4160*37da2899SCharles.Forsyth		tag = "RSA_WITH_DES_CBC_SHA";
4161*37da2899SCharles.Forsyth
4162*37da2899SCharles.Forsyth	RSA_WITH_3DES_EDE_CBC_SHA =>
4163*37da2899SCharles.Forsyth		tag = "RSA_WITH_3DES_EDE_CBC_SHA";
4164*37da2899SCharles.Forsyth
4165*37da2899SCharles.Forsyth	DH_DSS_EXPORT_WITH_DES40_CBC_SHA =>
4166*37da2899SCharles.Forsyth		tag = "DH_DSS_EXPORT_WITH_DES40_CBC_SHA";
4167*37da2899SCharles.Forsyth
4168*37da2899SCharles.Forsyth	DH_DSS_WITH_DES_CBC_SHA =>
4169*37da2899SCharles.Forsyth		tag = "DH_DSS_WITH_DES_CBC_SHA";
4170*37da2899SCharles.Forsyth
4171*37da2899SCharles.Forsyth	DH_DSS_WITH_3DES_EDE_CBC_SHA =>
4172*37da2899SCharles.Forsyth		tag = "DH_DSS_WITH_3DES_EDE_CBC_SHA";
4173*37da2899SCharles.Forsyth
4174*37da2899SCharles.Forsyth	DH_RSA_EXPORT_WITH_DES40_CBC_SHA =>
4175*37da2899SCharles.Forsyth		tag = "DH_RSA_EXPORT_WITH_DES40_CBC_SHA";
4176*37da2899SCharles.Forsyth
4177*37da2899SCharles.Forsyth	DH_RSA_WITH_DES_CBC_SHA =>
4178*37da2899SCharles.Forsyth		tag = "DH_RSA_WITH_DES_CBC_SHA";
4179*37da2899SCharles.Forsyth
4180*37da2899SCharles.Forsyth	DH_RSA_WITH_3DES_EDE_CBC_SHA =>
4181*37da2899SCharles.Forsyth		tag = "DH_RSA_WITH_3DES_EDE_CBC_SHA";
4182*37da2899SCharles.Forsyth
4183*37da2899SCharles.Forsyth	DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =>
4184*37da2899SCharles.Forsyth		tag = "DHE_DSS_EXPORT_WITH_DES40_CBC_SHA";
4185*37da2899SCharles.Forsyth
4186*37da2899SCharles.Forsyth	DHE_DSS_WITH_DES_CBC_SHA =>
4187*37da2899SCharles.Forsyth		tag = "DHE_DSS_WITH_DES_CBC_SHA";
4188*37da2899SCharles.Forsyth
4189*37da2899SCharles.Forsyth	DHE_DSS_WITH_3DES_EDE_CBC_SHA =>
4190*37da2899SCharles.Forsyth		tag = "DHE_DSS_WITH_3DES_EDE_CBC_SHA";
4191*37da2899SCharles.Forsyth
4192*37da2899SCharles.Forsyth	DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =>
4193*37da2899SCharles.Forsyth		tag = "DHE_RSA_EXPORT_WITH_DES40_CBC_SHA";
4194*37da2899SCharles.Forsyth
4195*37da2899SCharles.Forsyth	DHE_RSA_WITH_DES_CBC_SHA =>
4196*37da2899SCharles.Forsyth		tag = "DHE_RSA_WITH_DES_CBC_SHA";
4197*37da2899SCharles.Forsyth
4198*37da2899SCharles.Forsyth	DHE_RSA_WITH_3DES_EDE_CBC_SHA =>
4199*37da2899SCharles.Forsyth		tag = "DHE_RSA_WITH_3DES_EDE_CBC_SHA";
4200*37da2899SCharles.Forsyth
4201*37da2899SCharles.Forsyth	DH_anon_EXPORT_WITH_RC4_40_MD5 =>
4202*37da2899SCharles.Forsyth		tag = "DH_anon_EXPORT_WITH_RC4_40_MD5";
4203*37da2899SCharles.Forsyth
4204*37da2899SCharles.Forsyth	DH_anon_WITH_RC4_128_MD5 =>
4205*37da2899SCharles.Forsyth		tag = "DH_anon_WITH_RC4_128_MD5";
4206*37da2899SCharles.Forsyth
4207*37da2899SCharles.Forsyth	DH_anon_EXPORT_WITH_DES40_CBC_SHA =>
4208*37da2899SCharles.Forsyth		tag = "DH_anon_EXPORT_WITH_DES40_CBC_SHA";
4209*37da2899SCharles.Forsyth
4210*37da2899SCharles.Forsyth	DH_anon_WITH_DES_CBC_SHA =>
4211*37da2899SCharles.Forsyth		tag = "DH_anon_WITH_DES_CBC_SHA";
4212*37da2899SCharles.Forsyth
4213*37da2899SCharles.Forsyth	DH_anon_WITH_3DES_EDE_CBC_SHA =>
4214*37da2899SCharles.Forsyth		tag = "DH_anon_WITH_3DES_EDE_CBC_SHA";
4215*37da2899SCharles.Forsyth
4216*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_NULL_SHA =>
4217*37da2899SCharles.Forsyth		tag = "FORTEZZA_KEA_WITH_NULL_SHA";
4218*37da2899SCharles.Forsyth
4219*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA =>
4220*37da2899SCharles.Forsyth		tag = "FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA";
4221*37da2899SCharles.Forsyth
4222*37da2899SCharles.Forsyth	FORTEZZA_KEA_WITH_RC4_128_SHA =>
4223*37da2899SCharles.Forsyth		tag = "FORTEZZA_KEA_WITH_RC4_128_SHA";
4224*37da2899SCharles.Forsyth	}
4225*37da2899SCharles.Forsyth
4226*37da2899SCharles.Forsyth	return "cipher suite = [" + tag + "]";
4227*37da2899SCharles.Forsyth}
4228*37da2899SCharles.Forsyth
4229*37da2899SCharles.Forsyth#################################
4230*37da2899SCharles.Forsyth## FOR SSLv2 BACKWARD COMPATIBLE
4231*37da2899SCharles.Forsyth#################################
4232*37da2899SCharles.Forsyth
4233*37da2899SCharles.Forsyth# Protocol Version Codes
4234*37da2899SCharles.ForsythSSL2_CLIENT_VERSION				:= array [] of {byte 0, byte 16r02};
4235*37da2899SCharles.ForsythSSL2_SERVER_VERSION				:= array [] of {byte 0, byte 16r02};
4236*37da2899SCharles.Forsyth
4237*37da2899SCharles.Forsyth# Protocol Message Codes
4238*37da2899SCharles.Forsyth
4239*37da2899SCharles.ForsythSSL2_MT_ERROR,
4240*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_HELLO,
4241*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_MASTER_KEY,
4242*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_FINISHED,
4243*37da2899SCharles.Forsyth	SSL2_MT_SERVER_HELLO,
4244*37da2899SCharles.Forsyth	SSL2_MT_SERVER_VERIFY,
4245*37da2899SCharles.Forsyth	SSL2_MT_SERVER_FINISHED,
4246*37da2899SCharles.Forsyth	SSL2_MT_REQUEST_CERTIFICATE,
4247*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_CERTIFICATE		: con iota;
4248*37da2899SCharles.Forsyth
4249*37da2899SCharles.Forsyth# Error Message Codes
4250*37da2899SCharles.Forsyth
4251*37da2899SCharles.ForsythSSL2_PE_NO_CIPHER				:= array [] of {byte 0, byte 16r01};
4252*37da2899SCharles.ForsythSSL2_PE_NO_CERTIFICATE				:= array [] of {byte 0, byte 16r02};
4253*37da2899SCharles.ForsythSSL2_PE_BAD_CERTIFICATE				:= array [] of {byte 0, byte 16r04};
4254*37da2899SCharles.ForsythSSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE		:= array [] of {byte 0, byte 16r06};
4255*37da2899SCharles.Forsyth
4256*37da2899SCharles.Forsyth# Cipher Kind Values
4257*37da2899SCharles.Forsyth
4258*37da2899SCharles.ForsythSSL2_CK_RC4_128_WITH_MD5,
4259*37da2899SCharles.Forsyth	SSL2_CK_RC4_128_EXPORT40_WITH_MD5,
4260*37da2899SCharles.Forsyth	SSL2_CK_RC2_CBC_128_CBC_WITH_MD5,
4261*37da2899SCharles.Forsyth	SSL2_CK_RC2_CBC_128_CBC_EXPORT40_WITH_MD5,
4262*37da2899SCharles.Forsyth	SSL2_CK_IDEA_128_CBC_WITH_MD5,
4263*37da2899SCharles.Forsyth	SSL2_CK_DES_64_CBC_WITH_MD5,
4264*37da2899SCharles.Forsyth	SSL2_CK_DES_192_EDE3_CBC_WITH_MD5 	: con iota;
4265*37da2899SCharles.Forsyth
4266*37da2899SCharles.ForsythSSL2_Cipher_Kinds := array [] of {
4267*37da2899SCharles.Forsyth	SSL2_CK_RC4_128_WITH_MD5 => 		array [] of {byte 16r01, byte 0, byte 16r80},
4268*37da2899SCharles.Forsyth	SSL2_CK_RC4_128_EXPORT40_WITH_MD5 => 	array [] of {byte 16r02, byte 0, byte 16r80},
4269*37da2899SCharles.Forsyth	SSL2_CK_RC2_CBC_128_CBC_WITH_MD5 => 	array [] of {byte 16r03, byte 0, byte 16r80},
4270*37da2899SCharles.Forsyth	SSL2_CK_RC2_CBC_128_CBC_EXPORT40_WITH_MD5 =>
4271*37da2899SCharles.Forsyth						array [] of {byte 16r04, byte 0, byte 16r80},
4272*37da2899SCharles.Forsyth	SSL2_CK_IDEA_128_CBC_WITH_MD5 => 	array [] of {byte 16r05, byte 0, byte 16r80},
4273*37da2899SCharles.Forsyth	SSL2_CK_DES_64_CBC_WITH_MD5 => 		array [] of {byte 16r06, byte 0, byte 16r40},
4274*37da2899SCharles.Forsyth	SSL2_CK_DES_192_EDE3_CBC_WITH_MD5 => 	array [] of {byte 16r07, byte 0, byte 16rC0},
4275*37da2899SCharles.Forsyth};
4276*37da2899SCharles.Forsyth
4277*37da2899SCharles.Forsyth# Certificate Type Codes
4278*37da2899SCharles.Forsyth
4279*37da2899SCharles.ForsythSSL2_CT_X509_CERTIFICATE			: con 16r01; # encode as one byte
4280*37da2899SCharles.Forsyth
4281*37da2899SCharles.Forsyth# Authentication Type Codes
4282*37da2899SCharles.Forsyth
4283*37da2899SCharles.ForsythSSL2_AT_MD5_WITH_RSA_ENCRYPTION			: con byte 16r01;
4284*37da2899SCharles.Forsyth
4285*37da2899SCharles.Forsyth# Upper/Lower Bounds
4286*37da2899SCharles.Forsyth
4287*37da2899SCharles.ForsythSSL2_MAX_MASTER_KEY_LENGTH_IN_BITS		: con 256;
4288*37da2899SCharles.ForsythSSL2_MAX_SESSION_ID_LENGTH_IN_BYTES		: con 16;
4289*37da2899SCharles.ForsythSSL2_MIN_RSA_MODULUS_LENGTH_IN_BYTES		: con 64;
4290*37da2899SCharles.ForsythSSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER		: con 32767;
4291*37da2899SCharles.ForsythSSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER		: con 16383;
4292*37da2899SCharles.Forsyth
4293*37da2899SCharles.Forsyth# Handshake Internal State
4294*37da2899SCharles.Forsyth
4295*37da2899SCharles.ForsythSSL2_STATE_CLIENT_HELLO,
4296*37da2899SCharles.Forsyth	SSL2_STATE_SERVER_HELLO,
4297*37da2899SCharles.Forsyth	SSL2_STATE_CLIENT_MASTER_KEY,
4298*37da2899SCharles.Forsyth	SSL2_STATE_SERVER_VERIFY,
4299*37da2899SCharles.Forsyth	SSL2_STATE_REQUEST_CERTIFICATE,
4300*37da2899SCharles.Forsyth	SSL2_STATE_CLIENT_CERTIFICATE,
4301*37da2899SCharles.Forsyth	SSL2_STATE_CLIENT_FINISHED,
4302*37da2899SCharles.Forsyth	SSL2_STATE_SERVER_FINISHED,
4303*37da2899SCharles.Forsyth	SSL2_STATE_ERROR			: con iota;
4304*37da2899SCharles.Forsyth
4305*37da2899SCharles.Forsyth# The client's challenge to the server for the server to identify itself is a
4306*37da2899SCharles.Forsyth# (near) arbitary length random. The v3 server will right justify the challenge
4307*37da2899SCharles.Forsyth# data to become the ClientHello.random data (padding with leading zeros, if
4308*37da2899SCharles.Forsyth# necessary). If the length of the challenge is greater than 32 bytes, then only
4309*37da2899SCharles.Forsyth# the last 32 bytes are used. It is legitimate (but not necessary) for a v3
4310*37da2899SCharles.Forsyth# server to reject a v2 ClientHello that has fewer than 16 bytes of challenge
4311*37da2899SCharles.Forsyth# data.
4312*37da2899SCharles.Forsyth
4313*37da2899SCharles.ForsythSSL2_CHALLENGE_LENGTH				: con 16;
4314*37da2899SCharles.Forsyth
4315*37da2899SCharles.ForsythV2Handshake: adt {
4316*37da2899SCharles.Forsyth	pick {
4317*37da2899SCharles.Forsyth	Error =>
4318*37da2899SCharles.Forsyth		code				: array of byte; # [2];
4319*37da2899SCharles.Forsyth	ClientHello =>
4320*37da2899SCharles.Forsyth		version				: array of byte; # [2]
4321*37da2899SCharles.Forsyth		cipher_specs			: array of byte; # [3] x
4322*37da2899SCharles.Forsyth		session_id			: array of byte;
4323*37da2899SCharles.Forsyth		challenge			: array of byte;
4324*37da2899SCharles.Forsyth	ServerHello =>
4325*37da2899SCharles.Forsyth		session_id_hit			: int;
4326*37da2899SCharles.Forsyth		certificate_type		: int;
4327*37da2899SCharles.Forsyth		version				: array of byte; # [2]
4328*37da2899SCharles.Forsyth		certificate			: array of byte; # only user certificate
4329*37da2899SCharles.Forsyth		cipher_specs			: array of byte; # [3] x
4330*37da2899SCharles.Forsyth		connection_id			: array of byte;
4331*37da2899SCharles.Forsyth	ClientMasterKey =>
4332*37da2899SCharles.Forsyth		cipher_kind			: array of byte; # [3]
4333*37da2899SCharles.Forsyth		clear_key			: array of byte;
4334*37da2899SCharles.Forsyth		encrypt_key			: array of byte;
4335*37da2899SCharles.Forsyth		key_arg				: array of byte;
4336*37da2899SCharles.Forsyth	ServerVerify =>
4337*37da2899SCharles.Forsyth		challenge			: array of byte;
4338*37da2899SCharles.Forsyth	RequestCertificate =>
4339*37da2899SCharles.Forsyth		authentication_type		: int;
4340*37da2899SCharles.Forsyth		certificate_challenge		: array of byte;
4341*37da2899SCharles.Forsyth	ClientCertificate =>
4342*37da2899SCharles.Forsyth		certificate_type		: int;
4343*37da2899SCharles.Forsyth		certificate			: array of byte; # only user certificate
4344*37da2899SCharles.Forsyth		response			: array of byte;
4345*37da2899SCharles.Forsyth	ClientFinished =>
4346*37da2899SCharles.Forsyth		connection_id			: array of byte;
4347*37da2899SCharles.Forsyth	ServerFinished =>
4348*37da2899SCharles.Forsyth		session_id			: array of byte;
4349*37da2899SCharles.Forsyth	}
4350*37da2899SCharles.Forsyth
4351*37da2899SCharles.Forsyth	encode: fn(hm: self ref V2Handshake): (array of byte, string);
4352*37da2899SCharles.Forsyth	decode: fn(a: array of byte): (ref V2Handshake, string);
4353*37da2899SCharles.Forsyth	tostring: fn(h: self ref V2Handshake): string;
4354*37da2899SCharles.Forsyth};
4355*37da2899SCharles.Forsyth
4356*37da2899SCharles.Forsyth
4357*37da2899SCharles.ForsythV2Handshake.tostring(handshake: self ref V2Handshake): string
4358*37da2899SCharles.Forsyth{
4359*37da2899SCharles.Forsyth	info := "";
4360*37da2899SCharles.Forsyth
4361*37da2899SCharles.Forsyth	pick m := handshake {
4362*37da2899SCharles.Forsyth        ClientHello =>
4363*37da2899SCharles.Forsyth		info += "\tClientHello\n" +
4364*37da2899SCharles.Forsyth			"\tversion = \n\t\t" + bastr(m.version) + "\n" +
4365*37da2899SCharles.Forsyth			"\tcipher_specs = \n\t\t" + bastr(m.cipher_specs) + "\n" +
4366*37da2899SCharles.Forsyth			"\tsession_id = \n\t\t" + bastr(m.session_id) + "\n" +
4367*37da2899SCharles.Forsyth			"\tchallenge = \n\t\t" + bastr(m.challenge) + "\n";
4368*37da2899SCharles.Forsyth
4369*37da2899SCharles.Forsyth        ServerHello =>
4370*37da2899SCharles.Forsyth		info += "\tServerHello\n" +
4371*37da2899SCharles.Forsyth			"\tsession_id_hit = \n\t\t" + string m.session_id_hit + "\n" +
4372*37da2899SCharles.Forsyth			"\tcertificate_type = \n\t\t" + string m.certificate_type + "\n" +
4373*37da2899SCharles.Forsyth			"\tversion = \n\t\t" + bastr(m.version) + "\n" +
4374*37da2899SCharles.Forsyth			"\tcertificate = \n\t\t" + bastr(m.certificate) + "\n" +
4375*37da2899SCharles.Forsyth			"\tcipher_specs = \n\t\t" + bastr(m.cipher_specs) + "\n" +
4376*37da2899SCharles.Forsyth			"\tconnection_id = \n\t\t" + bastr(m.connection_id) + "\n";
4377*37da2899SCharles.Forsyth
4378*37da2899SCharles.Forsyth	ClientMasterKey =>
4379*37da2899SCharles.Forsyth		info += "\tClientMasterKey\n" +
4380*37da2899SCharles.Forsyth			"\tcipher_kind = \n\t\t" + bastr(m.cipher_kind) + "\n" +
4381*37da2899SCharles.Forsyth			"\tclear_key = \n\t\t" + bastr(m.clear_key) + "\n" +
4382*37da2899SCharles.Forsyth			"\tencrypt_key = \n\t\t" + bastr(m.encrypt_key) + "\n" +
4383*37da2899SCharles.Forsyth			"\tkey_arg = \n\t\t" + bastr(m.key_arg) + "\n";
4384*37da2899SCharles.Forsyth
4385*37da2899SCharles.Forsyth	ServerVerify =>
4386*37da2899SCharles.Forsyth		info += "\tServerVerify\n" +
4387*37da2899SCharles.Forsyth			"\tchallenge = \n\t\t" + bastr(m.challenge) + "\n";
4388*37da2899SCharles.Forsyth
4389*37da2899SCharles.Forsyth	RequestCertificate =>
4390*37da2899SCharles.Forsyth		info += "\tRequestCertificate\n" +
4391*37da2899SCharles.Forsyth			"\tauthentication_type = \n\t\t" + string m.authentication_type + "\n" +
4392*37da2899SCharles.Forsyth			"\tcertificate_challenge = \n\t\t" + bastr(m.certificate_challenge) + "\n";
4393*37da2899SCharles.Forsyth
4394*37da2899SCharles.Forsyth	ClientCertificate =>
4395*37da2899SCharles.Forsyth		info += "ClientCertificate\n" +
4396*37da2899SCharles.Forsyth			"\tcertificate_type = \n\t\t" + string m.certificate_type + "\n" +
4397*37da2899SCharles.Forsyth			"\tcertificate = \n\t\t" + bastr(m.certificate) + "\n" +
4398*37da2899SCharles.Forsyth			"\tresponse = \n\t\t" + bastr(m.response) + "\n";
4399*37da2899SCharles.Forsyth
4400*37da2899SCharles.Forsyth	ClientFinished =>
4401*37da2899SCharles.Forsyth		info += "\tClientFinished\n" +
4402*37da2899SCharles.Forsyth			"\tconnection_id = \n\t\t" + bastr(m.connection_id) + "\n";
4403*37da2899SCharles.Forsyth
4404*37da2899SCharles.Forsyth	ServerFinished =>
4405*37da2899SCharles.Forsyth		info += "\tServerFinished\n" +
4406*37da2899SCharles.Forsyth			"\tsession_id = \n\t\t" + bastr(m.session_id) + "\n";
4407*37da2899SCharles.Forsyth	}
4408*37da2899SCharles.Forsyth
4409*37da2899SCharles.Forsyth	return info;
4410*37da2899SCharles.Forsyth}
4411*37da2899SCharles.Forsyth
4412*37da2899SCharles.Forsyth
4413*37da2899SCharles.Forsyth# v2 handshake protocol - message driven, v2 and v3 sharing the same context stack
4414*37da2899SCharles.Forsyth
4415*37da2899SCharles.Forsythdo_v2handshake(v2hs: ref V2Handshake, ctx: ref Context): string
4416*37da2899SCharles.Forsyth{
4417*37da2899SCharles.Forsyth	e: string = nil;
4418*37da2899SCharles.Forsyth
4419*37da2899SCharles.Forsyth	pick h := v2hs {
4420*37da2899SCharles.Forsyth	Error =>
4421*37da2899SCharles.Forsyth		do_v2error(h, ctx);
4422*37da2899SCharles.Forsyth
4423*37da2899SCharles.Forsyth	ClientHello =>
4424*37da2899SCharles.Forsyth		if((ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_CLIENT_HELLO) {
4425*37da2899SCharles.Forsyth			e = "V2ClientHello";
4426*37da2899SCharles.Forsyth			break;
4427*37da2899SCharles.Forsyth		}
4428*37da2899SCharles.Forsyth		do_v2client_hello(h, ctx);
4429*37da2899SCharles.Forsyth
4430*37da2899SCharles.Forsyth	ServerHello =>
4431*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_SERVER_HELLO) {
4432*37da2899SCharles.Forsyth			e = "V2ServerHello";
4433*37da2899SCharles.Forsyth			break;
4434*37da2899SCharles.Forsyth		}
4435*37da2899SCharles.Forsyth		do_v2server_hello(h, ctx);
4436*37da2899SCharles.Forsyth
4437*37da2899SCharles.Forsyth	ClientMasterKey =>
4438*37da2899SCharles.Forsyth		if((ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_CLIENT_MASTER_KEY) {
4439*37da2899SCharles.Forsyth			e = "V2ClientMasterKey";
4440*37da2899SCharles.Forsyth			break;
4441*37da2899SCharles.Forsyth		}
4442*37da2899SCharles.Forsyth		do_v2client_master_key(h, ctx);
4443*37da2899SCharles.Forsyth
4444*37da2899SCharles.Forsyth	ServerVerify =>
4445*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_SERVER_VERIFY) {
4446*37da2899SCharles.Forsyth			e = "V2ServerVerify";
4447*37da2899SCharles.Forsyth			break;
4448*37da2899SCharles.Forsyth		}
4449*37da2899SCharles.Forsyth		do_v2server_verify(h, ctx);
4450*37da2899SCharles.Forsyth
4451*37da2899SCharles.Forsyth	RequestCertificate =>
4452*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_SERVER_VERIFY) {
4453*37da2899SCharles.Forsyth			e = "V2RequestCertificate";
4454*37da2899SCharles.Forsyth			break;
4455*37da2899SCharles.Forsyth		}
4456*37da2899SCharles.Forsyth		do_v2req_cert(h, ctx);
4457*37da2899SCharles.Forsyth
4458*37da2899SCharles.Forsyth	ClientCertificate =>
4459*37da2899SCharles.Forsyth		if((ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_CLIENT_CERTIFICATE) {
4460*37da2899SCharles.Forsyth			e = "V2ClientCertificate";
4461*37da2899SCharles.Forsyth			break;
4462*37da2899SCharles.Forsyth		}
4463*37da2899SCharles.Forsyth		do_v2client_certificate(h, ctx);
4464*37da2899SCharles.Forsyth
4465*37da2899SCharles.Forsyth	ClientFinished =>
4466*37da2899SCharles.Forsyth		if((ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_CLIENT_FINISHED) {
4467*37da2899SCharles.Forsyth			e = "V2ClientFinished";
4468*37da2899SCharles.Forsyth			break;
4469*37da2899SCharles.Forsyth		}
4470*37da2899SCharles.Forsyth		do_v2client_finished(h, ctx);
4471*37da2899SCharles.Forsyth
4472*37da2899SCharles.Forsyth	ServerFinished =>
4473*37da2899SCharles.Forsyth		if(!(ctx.status & CLIENT_SIDE) || ctx.state != SSL2_STATE_SERVER_FINISHED) {
4474*37da2899SCharles.Forsyth			e = "V2ServerFinished";
4475*37da2899SCharles.Forsyth			break;
4476*37da2899SCharles.Forsyth		}
4477*37da2899SCharles.Forsyth		do_v2server_finished(h, ctx);
4478*37da2899SCharles.Forsyth	}
4479*37da2899SCharles.Forsyth
4480*37da2899SCharles.Forsyth	return e;
4481*37da2899SCharles.Forsyth}
4482*37da2899SCharles.Forsyth
4483*37da2899SCharles.Forsythdo_v2error(v2hs: ref V2Handshake.Error, ctx: ref Context)
4484*37da2899SCharles.Forsyth{
4485*37da2899SCharles.Forsyth	if(SSL_DEBUG)
4486*37da2899SCharles.Forsyth		log("do_v2error: " + string v2hs.code);
4487*37da2899SCharles.Forsyth	ctx.state = STATE_EXIT;
4488*37da2899SCharles.Forsyth}
4489*37da2899SCharles.Forsyth
4490*37da2899SCharles.Forsyth# [server side]
4491*37da2899SCharles.Forsythdo_v2client_hello(v2hs: ref V2Handshake.ClientHello, ctx: ref Context)
4492*37da2899SCharles.Forsyth{
4493*37da2899SCharles.Forsyth	if(v2hs.version[0] != SSL2_CLIENT_VERSION[0] || v2hs.version[1] != SSL2_CLIENT_VERSION[1]) {
4494*37da2899SCharles.Forsyth		# promote this message to v3 handshake protocol
4495*37da2899SCharles.Forsyth		ctx.state = STATE_CLIENT_HELLO;
4496*37da2899SCharles.Forsyth		return;
4497*37da2899SCharles.Forsyth	}
4498*37da2899SCharles.Forsyth
4499*37da2899SCharles.Forsyth	# trying to resume
4500*37da2899SCharles.Forsyth	s: ref Session;
4501*37da2899SCharles.Forsyth	if((v2hs.session_id != nil) && (ctx.status & SESSION_RESUMABLE))
4502*37da2899SCharles.Forsyth		s = sslsession->get_session_byid(v2hs.session_id);
4503*37da2899SCharles.Forsyth	if(s != nil) { # found a hit
4504*37da2899SCharles.Forsyth		# prepare and send v2 handshake hello message
4505*37da2899SCharles.Forsyth		v2handshake_enque(
4506*37da2899SCharles.Forsyth			ref V2Handshake.ServerHello(
4507*37da2899SCharles.Forsyth				1, # hit found
4508*37da2899SCharles.Forsyth				0, # no certificate required
4509*37da2899SCharles.Forsyth				SSL2_SERVER_VERSION,
4510*37da2899SCharles.Forsyth				nil, # no authetication required
4511*37da2899SCharles.Forsyth				s.suite, # use hit session cipher kind
4512*37da2899SCharles.Forsyth				ctx.server_random # connection_id
4513*37da2899SCharles.Forsyth			),
4514*37da2899SCharles.Forsyth			ctx
4515*37da2899SCharles.Forsyth		);
4516*37da2899SCharles.Forsyth		# TODO: should in supported cipher_kinds
4517*37da2899SCharles.Forsyth		err: string;
4518*37da2899SCharles.Forsyth		(ctx.sel_ciph, ctx.sel_keyx, ctx.sel_sign, err)
4519*37da2899SCharles.Forsyth			= v2suite_to_spec(ctx.session.suite, SSL2_Cipher_Kinds);
4520*37da2899SCharles.Forsyth		if(err != "") {
4521*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4522*37da2899SCharles.Forsyth				log("do_v2client_hello: " + err);
4523*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4524*37da2899SCharles.Forsyth			return;
4525*37da2899SCharles.Forsyth		}
4526*37da2899SCharles.Forsyth		ctx.state = SSL2_STATE_SERVER_FINISHED;
4527*37da2899SCharles.Forsyth	}
4528*37da2899SCharles.Forsyth	else {
4529*37da2899SCharles.Forsyth		# find matching cipher kinds
4530*37da2899SCharles.Forsyth		n := len v2hs.cipher_specs;
4531*37da2899SCharles.Forsyth		matchs := array [n] of byte;
4532*37da2899SCharles.Forsyth		j, k: int = 0;
4533*37da2899SCharles.Forsyth		while(j < n) {
4534*37da2899SCharles.Forsyth			# ignore those not in SSL2_Cipher_Kinds
4535*37da2899SCharles.Forsyth			matchs[k:] = v2hs.cipher_specs[j:j+3];
4536*37da2899SCharles.Forsyth			for(i := 0; i < len SSL2_Cipher_Kinds; i++) {
4537*37da2899SCharles.Forsyth				ck := SSL2_Cipher_Kinds[i];
4538*37da2899SCharles.Forsyth				if(matchs[k] == ck[0] && matchs[k+1] == ck[1] && matchs[k+2] == ck[2])
4539*37da2899SCharles.Forsyth					k +=3;
4540*37da2899SCharles.Forsyth			}
4541*37da2899SCharles.Forsyth			j += 3;
4542*37da2899SCharles.Forsyth		}
4543*37da2899SCharles.Forsyth		if(k == 0) {
4544*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4545*37da2899SCharles.Forsyth				log("do_v2client_hello: No matching cipher kind");
4546*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4547*37da2899SCharles.Forsyth		}
4548*37da2899SCharles.Forsyth		else {
4549*37da2899SCharles.Forsyth			matchs = matchs[0:k];
4550*37da2899SCharles.Forsyth
4551*37da2899SCharles.Forsyth			# Note:
4552*37da2899SCharles.Forsyth			#	v2 challenge -> v3 client_random
4553*37da2899SCharles.Forsyth			#	v2 connection_id -> v3 server_random
4554*37da2899SCharles.Forsyth
4555*37da2899SCharles.Forsyth			chlen := len v2hs.challenge;
4556*37da2899SCharles.Forsyth			if(chlen > 32)
4557*37da2899SCharles.Forsyth				chlen = 32;
4558*37da2899SCharles.Forsyth			ctx.client_random = array [chlen] of byte;
4559*37da2899SCharles.Forsyth			if(chlen > 32)
4560*37da2899SCharles.Forsyth				ctx.client_random[0:] = v2hs.challenge[chlen-32:];
4561*37da2899SCharles.Forsyth			else
4562*37da2899SCharles.Forsyth				ctx.client_random[0:] = v2hs.challenge;
4563*37da2899SCharles.Forsyth			ctx.server_random = random->randombuf(Random->NotQuiteRandom, 16);
4564*37da2899SCharles.Forsyth			s.session_id = random->randombuf (
4565*37da2899SCharles.Forsyth					Random->NotQuiteRandom,
4566*37da2899SCharles.Forsyth					SSL2_MAX_SESSION_ID_LENGTH_IN_BYTES
4567*37da2899SCharles.Forsyth				);
4568*37da2899SCharles.Forsyth			s.suite = matchs;
4569*37da2899SCharles.Forsyth			ctx.session = s;
4570*37da2899SCharles.Forsyth			v2handshake_enque(
4571*37da2899SCharles.Forsyth				ref V2Handshake.ServerHello(
4572*37da2899SCharles.Forsyth					0, # no hit - not resumable
4573*37da2899SCharles.Forsyth					SSL2_CT_X509_CERTIFICATE,
4574*37da2899SCharles.Forsyth					SSL2_SERVER_VERSION,
4575*37da2899SCharles.Forsyth					hd ctx.local_info.certs, # the first is user certificate
4576*37da2899SCharles.Forsyth					ctx.session.suite, # matched cipher kinds
4577*37da2899SCharles.Forsyth					ctx.server_random # connection_id
4578*37da2899SCharles.Forsyth				),
4579*37da2899SCharles.Forsyth				ctx
4580*37da2899SCharles.Forsyth			);
4581*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_CLIENT_MASTER_KEY;
4582*37da2899SCharles.Forsyth		}
4583*37da2899SCharles.Forsyth	}
4584*37da2899SCharles.Forsyth}
4585*37da2899SCharles.Forsyth
4586*37da2899SCharles.Forsyth# [client side]
4587*37da2899SCharles.Forsyth
4588*37da2899SCharles.Forsythdo_v2server_hello(v2hs: ref V2Handshake.ServerHello, ctx: ref Context)
4589*37da2899SCharles.Forsyth{
4590*37da2899SCharles.Forsyth	# must be v2 server hello otherwise it will be v3 server hello
4591*37da2899SCharles.Forsyth	# determined by auto record layer version detection
4592*37da2899SCharles.Forsyth	if(v2hs.version[0] != SSL2_SERVER_VERSION[0]
4593*37da2899SCharles.Forsyth		|| v2hs.version[1] != SSL2_SERVER_VERSION[1]) {
4594*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4595*37da2899SCharles.Forsyth			log("do_v2server_hello: not a v2 version");
4596*37da2899SCharles.Forsyth		ctx.state = SSL2_STATE_ERROR;
4597*37da2899SCharles.Forsyth		return;
4598*37da2899SCharles.Forsyth	}
4599*37da2899SCharles.Forsyth
4600*37da2899SCharles.Forsyth	ctx.session.version = SSL2_SERVER_VERSION;
4601*37da2899SCharles.Forsyth	ctx.server_random = v2hs.connection_id;
4602*37da2899SCharles.Forsyth
4603*37da2899SCharles.Forsyth	# check if a resumable session is found
4604*37da2899SCharles.Forsyth	if(v2hs.session_id_hit != 0) { # resume ok
4605*37da2899SCharles.Forsyth		err: string;
4606*37da2899SCharles.Forsyth		# TODO: should in supported cipher_kinds
4607*37da2899SCharles.Forsyth		(ctx.sel_ciph, nil, nil, err) = v2suite_to_spec(ctx.session.suite, SSL2_Cipher_Kinds);
4608*37da2899SCharles.Forsyth		if(err !=  "") {
4609*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4610*37da2899SCharles.Forsyth				log("do_v2server_hello: " + err);
4611*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4612*37da2899SCharles.Forsyth			return;
4613*37da2899SCharles.Forsyth		}
4614*37da2899SCharles.Forsyth	}
4615*37da2899SCharles.Forsyth	else { 	# not resumable session
4616*37da2899SCharles.Forsyth
4617*37da2899SCharles.Forsyth		# use the first matched cipher kind; install cipher spec
4618*37da2899SCharles.Forsyth		if(len v2hs.cipher_specs < 3) {
4619*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4620*37da2899SCharles.Forsyth				log("do_v2server_hello: too few bytes");
4621*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4622*37da2899SCharles.Forsyth			return;
4623*37da2899SCharles.Forsyth		}
4624*37da2899SCharles.Forsyth		ctx.session.suite = array [3] of byte;
4625*37da2899SCharles.Forsyth		ctx.session.suite[0:] = v2hs.cipher_specs[0:3];
4626*37da2899SCharles.Forsyth		err: string;
4627*37da2899SCharles.Forsyth		(ctx.sel_ciph, nil, nil, err) = v2suite_to_spec(ctx.session.suite, SSL2_Cipher_Kinds);
4628*37da2899SCharles.Forsyth		if(err != "") {
4629*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4630*37da2899SCharles.Forsyth				log("do_v2server_hello: " + err);
4631*37da2899SCharles.Forsyth			return;
4632*37da2899SCharles.Forsyth		}
4633*37da2899SCharles.Forsyth
4634*37da2899SCharles.Forsyth		# decode x509 certificates, authenticate server and extract
4635*37da2899SCharles.Forsyth		# public key from server certificate
4636*37da2899SCharles.Forsyth		if(v2hs.certificate_type != int SSL2_CT_X509_CERTIFICATE) {
4637*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4638*37da2899SCharles.Forsyth				log("do_v2server_hello: not x509 certificate");
4639*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4640*37da2899SCharles.Forsyth			return;
4641*37da2899SCharles.Forsyth		}
4642*37da2899SCharles.Forsyth		ctx.session.peer_certs = v2hs.certificate :: nil;
4643*37da2899SCharles.Forsyth		# TODO: decode v2hs.certificate as list of certificate
4644*37da2899SCharles.Forsyth		# 	verify the list of certificate
4645*37da2899SCharles.Forsyth		(e, signed) := x509->Signed.decode(v2hs.certificate);
4646*37da2899SCharles.Forsyth		if(e != "") {
4647*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4648*37da2899SCharles.Forsyth				log("do_v2server_hello: " + e);
4649*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4650*37da2899SCharles.Forsyth			return;
4651*37da2899SCharles.Forsyth		}
4652*37da2899SCharles.Forsyth		certificate: ref Certificate;
4653*37da2899SCharles.Forsyth		(e, certificate) = x509->Certificate.decode(signed.tobe_signed);
4654*37da2899SCharles.Forsyth		if(e != "") {
4655*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4656*37da2899SCharles.Forsyth				log("do_v2server_hello: " + e);
4657*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4658*37da2899SCharles.Forsyth			return;
4659*37da2899SCharles.Forsyth		}
4660*37da2899SCharles.Forsyth		id: int;
4661*37da2899SCharles.Forsyth		peer_pk: ref X509->PublicKey;
4662*37da2899SCharles.Forsyth		(e, id, peer_pk) = certificate.subject_pkinfo.getPublicKey();
4663*37da2899SCharles.Forsyth		if(e != nil) {
4664*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR; # protocol error
4665*37da2899SCharles.Forsyth			return;
4666*37da2899SCharles.Forsyth		}
4667*37da2899SCharles.Forsyth		pk: ref RSAKey;
4668*37da2899SCharles.Forsyth		pick key := peer_pk {
4669*37da2899SCharles.Forsyth		RSA =>
4670*37da2899SCharles.Forsyth			pk = key.pk;
4671*37da2899SCharles.Forsyth		* =>
4672*37da2899SCharles.Forsyth		}
4673*37da2899SCharles.Forsyth		# prepare and send client master key message
4674*37da2899SCharles.Forsyth		# TODO: change CipherSpec adt for more key info
4675*37da2899SCharles.Forsyth		# Temporary solution
4676*37da2899SCharles.Forsyth		# mkey (master key), ckey (clear key), skey(secret key)
4677*37da2899SCharles.Forsyth		mkey, ckey, skey, keyarg: array of byte;
4678*37da2899SCharles.Forsyth		(mkeylen, ckeylen, keyarglen) := v2suite_more(ctx.sel_ciph);
4679*37da2899SCharles.Forsyth		mkey = random->randombuf(Random->NotQuiteRandom, mkeylen);
4680*37da2899SCharles.Forsyth		if(ckeylen != 0)
4681*37da2899SCharles.Forsyth			ckey = mkey[0:ckeylen];
4682*37da2899SCharles.Forsyth		if(mkeylen > ckeylen)
4683*37da2899SCharles.Forsyth			skey = mkey[ckeylen:];
4684*37da2899SCharles.Forsyth		if(keyarglen > 0)
4685*37da2899SCharles.Forsyth			keyarg = random->randombuf(Random->NotQuiteRandom, keyarglen);
4686*37da2899SCharles.Forsyth		ekey: array of byte;
4687*37da2899SCharles.Forsyth		(e, ekey) = pkcs->rsa_encrypt(skey, pk, 2);
4688*37da2899SCharles.Forsyth		if(e != nil) {
4689*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4690*37da2899SCharles.Forsyth				log("do_v2server_hello: " + e);
4691*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4692*37da2899SCharles.Forsyth			return;
4693*37da2899SCharles.Forsyth		}
4694*37da2899SCharles.Forsyth		ctx.session.master_secret = mkey;
4695*37da2899SCharles.Forsyth		v2handshake_enque(
4696*37da2899SCharles.Forsyth			ref V2Handshake.ClientMasterKey(ctx.session.suite, ckey, ekey, keyarg),
4697*37da2899SCharles.Forsyth			ctx
4698*37da2899SCharles.Forsyth		);
4699*37da2899SCharles.Forsyth	}
4700*37da2899SCharles.Forsyth
4701*37da2899SCharles.Forsyth	# clean up out_queue before switch cipher
4702*37da2899SCharles.Forsyth	record_write_queue(ctx);
4703*37da2899SCharles.Forsyth	ctx.out_queue.data = nil;
4704*37da2899SCharles.Forsyth
4705*37da2899SCharles.Forsyth	# install keys onto ctx that will be pushed on ssl record when ready
4706*37da2899SCharles.Forsyth	(ctx.cw_mac, ctx.sw_mac, ctx.cw_key, ctx.sw_key, ctx.cw_IV, ctx.sw_IV)
4707*37da2899SCharles.Forsyth		= v2calc_keys(ctx.sel_ciph, ctx.session.master_secret,
4708*37da2899SCharles.Forsyth		ctx.client_random, ctx.server_random);
4709*37da2899SCharles.Forsyth	e := set_queues(ctx);
4710*37da2899SCharles.Forsyth	if(e != "") {
4711*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4712*37da2899SCharles.Forsyth			log("do_v2server_finished: " + e);
4713*37da2899SCharles.Forsyth		ctx.state = SSL2_STATE_ERROR;
4714*37da2899SCharles.Forsyth		return;
4715*37da2899SCharles.Forsyth	}
4716*37da2899SCharles.Forsyth	ctx.status |= IN_READY;
4717*37da2899SCharles.Forsyth	ctx.status |= OUT_READY;
4718*37da2899SCharles.Forsyth
4719*37da2899SCharles.Forsyth	# prepare and send client finished message
4720*37da2899SCharles.Forsyth	v2handshake_enque(
4721*37da2899SCharles.Forsyth		ref V2Handshake.ClientFinished(ctx.server_random), # as connection_id
4722*37da2899SCharles.Forsyth		ctx
4723*37da2899SCharles.Forsyth	);
4724*37da2899SCharles.Forsyth
4725*37da2899SCharles.Forsyth	ctx.state = SSL2_STATE_SERVER_VERIFY;
4726*37da2899SCharles.Forsyth}
4727*37da2899SCharles.Forsyth
4728*37da2899SCharles.Forsyth# [server side]
4729*37da2899SCharles.Forsyth
4730*37da2899SCharles.Forsythdo_v2client_master_key(v2hs: ref V2Handshake.ClientMasterKey, ctx: ref Context)
4731*37da2899SCharles.Forsyth{
4732*37da2899SCharles.Forsyth	#if(cmk.cipher == -1 || cipher_info[cmk.cipher].cryptalg == -1) {
4733*37da2899SCharles.Forsyth	#	# return ("protocol error: bad cipher in masterkey", nullc);
4734*37da2899SCharles.Forsyth	#	ctx.state = SSL2_STATE_ERROR; # protocol error
4735*37da2899SCharles.Forsyth	#	return;
4736*37da2899SCharles.Forsyth	#}
4737*37da2899SCharles.Forsyth
4738*37da2899SCharles.Forsyth	ctx.session.suite = v2hs.cipher_kind;
4739*37da2899SCharles.Forsyth
4740*37da2899SCharles.Forsyth	# TODO:
4741*37da2899SCharles.Forsyth	#	someplace shall be able to install the key
4742*37da2899SCharles.Forsyth	# need further encapsulate encrypt and decrypt functions from KeyExAlg adt
4743*37da2899SCharles.Forsyth	master_key_length: int;
4744*37da2899SCharles.Forsyth	secret_key: array of byte;
4745*37da2899SCharles.Forsyth	pick alg := ctx.sel_keyx {
4746*37da2899SCharles.Forsyth	RSA =>
4747*37da2899SCharles.Forsyth		e: string;
4748*37da2899SCharles.Forsyth		(e, secret_key) = pkcs->rsa_decrypt(v2hs.encrypt_key, alg.sk, 0);
4749*37da2899SCharles.Forsyth		if(e != "") {
4750*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4751*37da2899SCharles.Forsyth				log("do_v2client_master_key: " + e);
4752*37da2899SCharles.Forsyth			ctx.state = SSL2_STATE_ERROR;
4753*37da2899SCharles.Forsyth			return;
4754*37da2899SCharles.Forsyth		}
4755*37da2899SCharles.Forsyth		master_key_length = len v2hs.clear_key + len secret_key;
4756*37da2899SCharles.Forsyth	* =>
4757*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4758*37da2899SCharles.Forsyth			log("do_v2client_master_key: unknown public key algorithm");
4759*37da2899SCharles.Forsyth		ctx.state = SSL2_STATE_ERROR;
4760*37da2899SCharles.Forsyth		return;
4761*37da2899SCharles.Forsyth	}
4762*37da2899SCharles.Forsyth	#TODO: do the following lines after modifying the CipherSpec adt
4763*37da2899SCharles.Forsyth	#if(master_key_length != ci.keylen) {
4764*37da2899SCharles.Forsyth	#	ctx.state = SSL2_STATE_ERROR; # protocol error
4765*37da2899SCharles.Forsyth	#	return;
4766*37da2899SCharles.Forsyth	#}
4767*37da2899SCharles.Forsyth
4768*37da2899SCharles.Forsyth	ctx.session.master_secret = array [master_key_length] of byte;
4769*37da2899SCharles.Forsyth	ctx.session.master_secret[0:] = v2hs.clear_key;
4770*37da2899SCharles.Forsyth	ctx.session.master_secret[len v2hs.clear_key:] = secret_key;
4771*37da2899SCharles.Forsyth
4772*37da2899SCharles.Forsyth	# install keys onto ctx that will be pushed on ssl record when ready
4773*37da2899SCharles.Forsyth	(ctx.cw_mac, ctx.sw_mac, ctx.cw_key, ctx.sw_key, ctx.cw_IV, ctx.sw_IV)
4774*37da2899SCharles.Forsyth		= v2calc_keys(ctx.sel_ciph, ctx.session.master_secret,
4775*37da2899SCharles.Forsyth		ctx.client_random, ctx.server_random);
4776*37da2899SCharles.Forsyth	v2handshake_enque(
4777*37da2899SCharles.Forsyth		ref V2Handshake.ServerVerify(ctx.client_random[16:]),
4778*37da2899SCharles.Forsyth		ctx
4779*37da2899SCharles.Forsyth	);
4780*37da2899SCharles.Forsyth	v2handshake_enque(
4781*37da2899SCharles.Forsyth		ref V2Handshake.ServerFinished(ctx.session.session_id),
4782*37da2899SCharles.Forsyth		ctx
4783*37da2899SCharles.Forsyth	);
4784*37da2899SCharles.Forsyth	ctx.state = SSL2_STATE_CLIENT_FINISHED;
4785*37da2899SCharles.Forsyth}
4786*37da2899SCharles.Forsyth
4787*37da2899SCharles.Forsyth# used by client side
4788*37da2899SCharles.Forsythdo_v2server_verify(v2hs: ref V2Handshake.ServerVerify, ctx: ref Context)
4789*37da2899SCharles.Forsyth{
4790*37da2899SCharles.Forsyth	# TODO:
4791*37da2899SCharles.Forsyth	#	the challenge length may not be 16 bytes
4792*37da2899SCharles.Forsyth	if(bytes_cmp(v2hs.challenge, ctx.client_random[32-SSL2_CHALLENGE_LENGTH:]) < 0) {
4793*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4794*37da2899SCharles.Forsyth			log("do_v2server_verify: challenge mismatch");
4795*37da2899SCharles.Forsyth		ctx.state = SSL2_STATE_ERROR;
4796*37da2899SCharles.Forsyth		return;
4797*37da2899SCharles.Forsyth	}
4798*37da2899SCharles.Forsyth
4799*37da2899SCharles.Forsyth	ctx.state = SSL2_STATE_SERVER_FINISHED;
4800*37da2899SCharles.Forsyth}
4801*37da2899SCharles.Forsyth
4802*37da2899SCharles.Forsyth# [client side]
4803*37da2899SCharles.Forsyth
4804*37da2899SCharles.Forsythdo_v2req_cert(v2hs: ref V2Handshake.RequestCertificate, ctx: ref Context)
4805*37da2899SCharles.Forsyth{
4806*37da2899SCharles.Forsyth	# not supported until v3
4807*37da2899SCharles.Forsyth	if(SSL_DEBUG)
4808*37da2899SCharles.Forsyth		log("do_v2req_cert: authenticate client not supported");
4809*37da2899SCharles.Forsyth	v2hs = nil;
4810*37da2899SCharles.Forsyth	ctx.state = SSL2_STATE_ERROR;
4811*37da2899SCharles.Forsyth}
4812*37da2899SCharles.Forsyth
4813*37da2899SCharles.Forsyth# [server side]
4814*37da2899SCharles.Forsyth
4815*37da2899SCharles.Forsythdo_v2client_certificate(v2hs: ref V2Handshake.ClientCertificate, ctx: ref Context)
4816*37da2899SCharles.Forsyth{
4817*37da2899SCharles.Forsyth	# not supported until v3
4818*37da2899SCharles.Forsyth	if(SSL_DEBUG)
4819*37da2899SCharles.Forsyth		log("do_v2client_certificate: authenticate client not supported");
4820*37da2899SCharles.Forsyth	v2handshake_enque (
4821*37da2899SCharles.Forsyth		ref V2Handshake.Error(SSL2_PE_NO_CERTIFICATE),
4822*37da2899SCharles.Forsyth		ctx
4823*37da2899SCharles.Forsyth	);
4824*37da2899SCharles.Forsyth	v2hs = nil;
4825*37da2899SCharles.Forsyth	ctx.state = SSL2_STATE_ERROR;
4826*37da2899SCharles.Forsyth}
4827*37da2899SCharles.Forsyth
4828*37da2899SCharles.Forsyth# [server side]
4829*37da2899SCharles.Forsyth
4830*37da2899SCharles.Forsythdo_v2client_finished(v2hs: ref V2Handshake.ClientFinished, ctx: ref Context)
4831*37da2899SCharles.Forsyth{
4832*37da2899SCharles.Forsyth	if(bytes_cmp(ctx.server_random, v2hs.connection_id) < 0) {
4833*37da2899SCharles.Forsyth		ctx.session.session_id = nil;
4834*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4835*37da2899SCharles.Forsyth			log("do_v2client_finished: connection id mismatch");
4836*37da2899SCharles.Forsyth		ctx.state = SSL2_STATE_ERROR;
4837*37da2899SCharles.Forsyth	}
4838*37da2899SCharles.Forsyth	# TODO:
4839*37da2899SCharles.Forsyth	#	the challenge length may not be 16 bytes
4840*37da2899SCharles.Forsyth	v2handshake_enque(
4841*37da2899SCharles.Forsyth		ref V2Handshake.ServerVerify(ctx.client_random[32-SSL2_CHALLENGE_LENGTH:]),
4842*37da2899SCharles.Forsyth		ctx
4843*37da2899SCharles.Forsyth	);
4844*37da2899SCharles.Forsyth	if(ctx.session.session_id == nil)
4845*37da2899SCharles.Forsyth		ctx.session.session_id = random->randombuf(Random->NotQuiteRandom, 16);
4846*37da2899SCharles.Forsyth	v2handshake_enque(
4847*37da2899SCharles.Forsyth		ref V2Handshake.ServerFinished(ctx.session.session_id),
4848*37da2899SCharles.Forsyth		ctx
4849*37da2899SCharles.Forsyth	);
4850*37da2899SCharles.Forsyth	e := set_queues(ctx);
4851*37da2899SCharles.Forsyth	if(e != "") {
4852*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4853*37da2899SCharles.Forsyth			log("do_v2client_finished: " + e);
4854*37da2899SCharles.Forsyth		ctx.state = SSL2_STATE_ERROR;
4855*37da2899SCharles.Forsyth		return;
4856*37da2899SCharles.Forsyth	}
4857*37da2899SCharles.Forsyth	ctx.status |= IN_READY;
4858*37da2899SCharles.Forsyth	ctx.status |= OUT_READY;
4859*37da2899SCharles.Forsyth	sslsession->add_session(ctx.session);
4860*37da2899SCharles.Forsyth
4861*37da2899SCharles.Forsyth	ctx.state = STATE_EXIT;
4862*37da2899SCharles.Forsyth}
4863*37da2899SCharles.Forsyth
4864*37da2899SCharles.Forsyth# [client side]
4865*37da2899SCharles.Forsyth
4866*37da2899SCharles.Forsythdo_v2server_finished(v2hs: ref V2Handshake.ServerFinished, ctx: ref Context)
4867*37da2899SCharles.Forsyth{
4868*37da2899SCharles.Forsyth	if(ctx.session.session_id == nil)
4869*37da2899SCharles.Forsyth		ctx.session.session_id = array [16] of byte;
4870*37da2899SCharles.Forsyth	ctx.session.session_id[0:] = v2hs.session_id[0:];
4871*37da2899SCharles.Forsyth
4872*37da2899SCharles.Forsyth	sslsession->add_session(ctx.session);
4873*37da2899SCharles.Forsyth
4874*37da2899SCharles.Forsyth	ctx.state = STATE_EXIT;
4875*37da2899SCharles.Forsyth}
4876*37da2899SCharles.Forsyth
4877*37da2899SCharles.Forsyth
4878*37da2899SCharles.Forsyth# Note:
4879*37da2899SCharles.Forsyth#	the key partitioning for v2 is different from v3
4880*37da2899SCharles.Forsyth
4881*37da2899SCharles.Forsythv2calc_keys(ciph: ref CipherSpec, ms, cr, sr: array of byte)
4882*37da2899SCharles.Forsyth	: (array of byte, array of byte, array of byte, array of byte, array of byte, array of byte)
4883*37da2899SCharles.Forsyth{
4884*37da2899SCharles.Forsyth	cw_mac, sw_mac, cw_key, sw_key,	cw_IV, sw_IV: array of byte;
4885*37da2899SCharles.Forsyth
4886*37da2899SCharles.Forsyth	# TODO: check the size of key block if IV exists
4887*37da2899SCharles.Forsyth	(mkeylen, ckeylen, keyarglen) := v2suite_more(ciph);
4888*37da2899SCharles.Forsyth	kblen := 2*mkeylen;
4889*37da2899SCharles.Forsyth	if(kblen%Keyring->MD5dlen != 0) {
4890*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4891*37da2899SCharles.Forsyth			log("v2calc_keys: key block length is not multiple of MD5 hash length");
4892*37da2899SCharles.Forsyth	}
4893*37da2899SCharles.Forsyth	else {
4894*37da2899SCharles.Forsyth		key_block := array [kblen] of byte;
4895*37da2899SCharles.Forsyth
4896*37da2899SCharles.Forsyth		challenge := cr[32-SSL2_CHALLENGE_LENGTH:32]; # TODO: if challenge length != 16 ?
4897*37da2899SCharles.Forsyth		connection_id := sr[0:16]; # TODO: if connection_id length != 16 ?
4898*37da2899SCharles.Forsyth		var := array [1] of byte;
4899*37da2899SCharles.Forsyth		var[0] = byte 16r30;
4900*37da2899SCharles.Forsyth		i := 0;
4901*37da2899SCharles.Forsyth		while(i < kblen) {
4902*37da2899SCharles.Forsyth			(hash, nil) := md5_hash(ms::var::challenge::connection_id::nil, nil);
4903*37da2899SCharles.Forsyth			key_block[i:] = hash;
4904*37da2899SCharles.Forsyth			i += Keyring->MD5dlen;
4905*37da2899SCharles.Forsyth			++var[0];
4906*37da2899SCharles.Forsyth		}
4907*37da2899SCharles.Forsyth
4908*37da2899SCharles.Forsyth		if(SSL_DEBUG)
4909*37da2899SCharles.Forsyth			log("ssl3: calc_keys:"
4910*37da2899SCharles.Forsyth			+ "\n\tmaster key = \n\t\t" + bastr(ms)
4911*37da2899SCharles.Forsyth			+ "\n\tchallenge = \n\t\t" + bastr(challenge)
4912*37da2899SCharles.Forsyth			+ "\n\tconnection id = \n\t\t" + bastr(connection_id)
4913*37da2899SCharles.Forsyth			+ "\n\tkey block = \n\t\t" + bastr(key_block) + "\n");
4914*37da2899SCharles.Forsyth
4915*37da2899SCharles.Forsyth		i = 0;
4916*37da2899SCharles.Forsyth		# server write key == client read key
4917*37da2899SCharles.Forsyth		# server write mac == server write key
4918*37da2899SCharles.Forsyth		sw_key = array [mkeylen] of byte;
4919*37da2899SCharles.Forsyth		sw_key[0:] = key_block[i:mkeylen];
4920*37da2899SCharles.Forsyth		sw_mac = array [mkeylen] of byte;
4921*37da2899SCharles.Forsyth		sw_mac[0:] = key_block[i:mkeylen];
4922*37da2899SCharles.Forsyth		# client write key == server read key
4923*37da2899SCharles.Forsyth		# client write mac == client write key
4924*37da2899SCharles.Forsyth		i += mkeylen;
4925*37da2899SCharles.Forsyth		cw_key = array [mkeylen] of byte;
4926*37da2899SCharles.Forsyth		cw_key[0:] = key_block[i:i+mkeylen];
4927*37da2899SCharles.Forsyth		cw_mac = array [mkeylen] of byte;
4928*37da2899SCharles.Forsyth		cw_mac[0:] = key_block[i:i+mkeylen];
4929*37da2899SCharles.Forsyth		# client IV == server IV
4930*37da2899SCharles.Forsyth		# Note:
4931*37da2899SCharles.Forsyth		#	IV is a part of writing or reading key for ssl device
4932*37da2899SCharles.Forsyth		#	this is composed again in setctl
4933*37da2899SCharles.Forsyth		cw_IV = array [keyarglen] of byte;
4934*37da2899SCharles.Forsyth		cw_IV[0:] = ms[mkeylen:mkeylen+keyarglen];
4935*37da2899SCharles.Forsyth		sw_IV = array [keyarglen] of byte;
4936*37da2899SCharles.Forsyth		sw_IV[0:] = ms[mkeylen:mkeylen+keyarglen];
4937*37da2899SCharles.Forsyth	}
4938*37da2899SCharles.Forsyth
4939*37da2899SCharles.Forsyth	if(SSL_DEBUG)
4940*37da2899SCharles.Forsyth		log("ssl3: calc_keys:"
4941*37da2899SCharles.Forsyth		+ "\n\tclient_write_mac = \n\t\t" + bastr(cw_mac)
4942*37da2899SCharles.Forsyth		+ "\n\tserver_write_mac = \n\t\t" + bastr(sw_mac)
4943*37da2899SCharles.Forsyth		+ "\n\tclient_write_key = \n\t\t" + bastr(cw_key)
4944*37da2899SCharles.Forsyth		+ "\n\tserver_write_key = \n\t\t" + bastr(sw_key)
4945*37da2899SCharles.Forsyth 		+ "\n\tclient_write_IV  = \n\t\t" + bastr(cw_IV)
4946*37da2899SCharles.Forsyth		+ "\n\tserver_write_IV = \n\t\t" + bastr(sw_IV) + "\n");
4947*37da2899SCharles.Forsyth
4948*37da2899SCharles.Forsyth	return (cw_mac, sw_mac, cw_key, sw_key, cw_IV, sw_IV);
4949*37da2899SCharles.Forsyth}
4950*37da2899SCharles.Forsyth
4951*37da2899SCharles.Forsythv3tov2specs(suites: array of byte): array of byte
4952*37da2899SCharles.Forsyth{
4953*37da2899SCharles.Forsyth	# v3 suite codes are 2 bytes each, v2 codes are 3 bytes
4954*37da2899SCharles.Forsyth	n := len suites / 2;
4955*37da2899SCharles.Forsyth	kinds := array [n*3*2] of byte;
4956*37da2899SCharles.Forsyth	k := 0;
4957*37da2899SCharles.Forsyth	for(i := 0; i < n;) {
4958*37da2899SCharles.Forsyth		a := suites[i:i+2];
4959*37da2899SCharles.Forsyth		i += 2;
4960*37da2899SCharles.Forsyth		m := len SSL3_Suites;
4961*37da2899SCharles.Forsyth		for(j := 0; j < m; j++) {
4962*37da2899SCharles.Forsyth			b := SSL3_Suites[j];
4963*37da2899SCharles.Forsyth			if(a[0]==b[0] && a[1]==b[1])
4964*37da2899SCharles.Forsyth				break;
4965*37da2899SCharles.Forsyth		}
4966*37da2899SCharles.Forsyth		if (j == m) {
4967*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4968*37da2899SCharles.Forsyth				log("ssl3: unknown v3 suite");
4969*37da2899SCharles.Forsyth			continue;
4970*37da2899SCharles.Forsyth		}
4971*37da2899SCharles.Forsyth		case j {
4972*37da2899SCharles.Forsyth		RSA_EXPORT_WITH_RC4_40_MD5 =>
4973*37da2899SCharles.Forsyth			kinds[k:] = SSL2_Cipher_Kinds[SSL2_CK_RC4_128_EXPORT40_WITH_MD5];
4974*37da2899SCharles.Forsyth			k += 3;
4975*37da2899SCharles.Forsyth		RSA_WITH_RC4_128_MD5 =>
4976*37da2899SCharles.Forsyth			kinds[k:] = SSL2_Cipher_Kinds[SSL2_CK_RC4_128_WITH_MD5];
4977*37da2899SCharles.Forsyth			k += 3;
4978*37da2899SCharles.Forsyth		RSA_WITH_IDEA_CBC_SHA =>
4979*37da2899SCharles.Forsyth			kinds[k:] = SSL2_Cipher_Kinds[SSL2_CK_IDEA_128_CBC_WITH_MD5];
4980*37da2899SCharles.Forsyth			k += 3;
4981*37da2899SCharles.Forsyth		RSA_WITH_DES_CBC_SHA =>
4982*37da2899SCharles.Forsyth			;
4983*37da2899SCharles.Forsyth		* =>
4984*37da2899SCharles.Forsyth			if(SSL_DEBUG)
4985*37da2899SCharles.Forsyth				log("ssl3: unable to convert v3 suite to v2 kind");
4986*37da2899SCharles.Forsyth		}
4987*37da2899SCharles.Forsyth		# append v3 code in v2-safe manner
4988*37da2899SCharles.Forsyth		# (suite[0] == 0) => will be ignored by v2 server, picked up by v3 server
4989*37da2899SCharles.Forsyth		kinds[k] = byte 16r00;
4990*37da2899SCharles.Forsyth		kinds[k+1:] = SSL3_Suites[j];
4991*37da2899SCharles.Forsyth		k += 3;
4992*37da2899SCharles.Forsyth	}
4993*37da2899SCharles.Forsyth	return kinds[0:k];
4994*37da2899SCharles.Forsyth}
4995*37da2899SCharles.Forsyth
4996*37da2899SCharles.Forsythv2suite_to_spec(cs: array of byte, cipher_kinds: array of array of byte)
4997*37da2899SCharles.Forsyth	: (ref CipherSpec, ref KeyExAlg, ref SigAlg, string)
4998*37da2899SCharles.Forsyth{
4999*37da2899SCharles.Forsyth	cip : ref CipherSpec;
5000*37da2899SCharles.Forsyth	kex : ref KeyExAlg;
5001*37da2899SCharles.Forsyth	sig : ref SigAlg;
5002*37da2899SCharles.Forsyth
5003*37da2899SCharles.Forsyth	n := len cipher_kinds;
5004*37da2899SCharles.Forsyth	for(i := 0; i < n; i++) {
5005*37da2899SCharles.Forsyth		found := cipher_kinds[i];
5006*37da2899SCharles.Forsyth		if(found[0]==cs[0] && found[1]==cs[1] && found[2]==cs[2]) break;
5007*37da2899SCharles.Forsyth	}
5008*37da2899SCharles.Forsyth
5009*37da2899SCharles.Forsyth	if(i == n)
5010*37da2899SCharles.Forsyth		return (nil, nil, nil, "fail to find a matched spec");
5011*37da2899SCharles.Forsyth
5012*37da2899SCharles.Forsyth	case i {
5013*37da2899SCharles.Forsyth	SSL2_CK_RC4_128_WITH_MD5 =>
5014*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_RC4, SSL_STREAM_CIPHER,
5015*37da2899SCharles.Forsyth				16, 0, SSL_MD5, Keyring->MD4dlen);
5016*37da2899SCharles.Forsyth
5017*37da2899SCharles.Forsyth	SSL2_CK_RC4_128_EXPORT40_WITH_MD5 =>
5018*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_RC4, SSL_STREAM_CIPHER,
5019*37da2899SCharles.Forsyth				5, 0, SSL_MD5, Keyring->MD4dlen);
5020*37da2899SCharles.Forsyth
5021*37da2899SCharles.Forsyth	SSL2_CK_RC2_CBC_128_CBC_WITH_MD5 =>
5022*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_RC2_CBC, SSL_BLOCK_CIPHER,
5023*37da2899SCharles.Forsyth				16, 8, SSL_MD5, Keyring->MD4dlen);
5024*37da2899SCharles.Forsyth
5025*37da2899SCharles.Forsyth	SSL2_CK_RC2_CBC_128_CBC_EXPORT40_WITH_MD5 =>
5026*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_TRUE, SSL_RC2_CBC, SSL_BLOCK_CIPHER,
5027*37da2899SCharles.Forsyth				5, 8, SSL_MD5, Keyring->MD4dlen);
5028*37da2899SCharles.Forsyth
5029*37da2899SCharles.Forsyth	SSL2_CK_IDEA_128_CBC_WITH_MD5 =>
5030*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_IDEA_CBC, SSL_BLOCK_CIPHER,
5031*37da2899SCharles.Forsyth				16, 8, SSL_MD5, Keyring->MD4dlen);
5032*37da2899SCharles.Forsyth
5033*37da2899SCharles.Forsyth	SSL2_CK_DES_64_CBC_WITH_MD5 =>
5034*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_DES_CBC, SSL_BLOCK_CIPHER,
5035*37da2899SCharles.Forsyth				8, 8, SSL_MD5, Keyring->MD4dlen);
5036*37da2899SCharles.Forsyth
5037*37da2899SCharles.Forsyth	SSL2_CK_DES_192_EDE3_CBC_WITH_MD5 =>
5038*37da2899SCharles.Forsyth		cip = ref CipherSpec(SSL_EXPORT_FALSE, SSL_3DES_EDE_CBC, SSL_BLOCK_CIPHER,
5039*37da2899SCharles.Forsyth				24, 8, SSL_MD5, Keyring->MD4dlen);
5040*37da2899SCharles.Forsyth	}
5041*37da2899SCharles.Forsyth
5042*37da2899SCharles.Forsyth	kex = ref KeyExAlg.RSA(nil, nil, nil);
5043*37da2899SCharles.Forsyth	sig = ref SigAlg.RSA(nil, nil);
5044*37da2899SCharles.Forsyth
5045*37da2899SCharles.Forsyth	return (cip, kex, sig, nil);
5046*37da2899SCharles.Forsyth}
5047*37da2899SCharles.Forsyth
5048*37da2899SCharles.Forsythv2suite_more(ciph: ref CipherSpec): (int, int, int)
5049*37da2899SCharles.Forsyth{
5050*37da2899SCharles.Forsyth	mkeylen, ckeylen, keyarglen: int;
5051*37da2899SCharles.Forsyth
5052*37da2899SCharles.Forsyth	case ciph.bulk_cipher_algorithm {
5053*37da2899SCharles.Forsyth	SSL_RC4 =>
5054*37da2899SCharles.Forsyth		mkeylen = 16;
5055*37da2899SCharles.Forsyth		if(ciph.key_material == 5)
5056*37da2899SCharles.Forsyth			ckeylen = 16 - 5;
5057*37da2899SCharles.Forsyth		else
5058*37da2899SCharles.Forsyth			ckeylen = 0;
5059*37da2899SCharles.Forsyth		keyarglen = 0;
5060*37da2899SCharles.Forsyth
5061*37da2899SCharles.Forsyth	SSL_RC2_CBC =>
5062*37da2899SCharles.Forsyth		mkeylen = 16;
5063*37da2899SCharles.Forsyth		if(ciph.key_material == 5)
5064*37da2899SCharles.Forsyth			ckeylen = 16 - 5;
5065*37da2899SCharles.Forsyth		else
5066*37da2899SCharles.Forsyth			ckeylen = 0;
5067*37da2899SCharles.Forsyth		keyarglen = 8;
5068*37da2899SCharles.Forsyth
5069*37da2899SCharles.Forsyth	SSL_IDEA_CBC =>
5070*37da2899SCharles.Forsyth		mkeylen = 16;
5071*37da2899SCharles.Forsyth		ckeylen = 0;
5072*37da2899SCharles.Forsyth		keyarglen = 8;
5073*37da2899SCharles.Forsyth
5074*37da2899SCharles.Forsyth	SSL_DES_CBC =>
5075*37da2899SCharles.Forsyth		mkeylen = 8;
5076*37da2899SCharles.Forsyth		if(ciph.key_material == 5)
5077*37da2899SCharles.Forsyth			ckeylen = 8 - 5;
5078*37da2899SCharles.Forsyth		else
5079*37da2899SCharles.Forsyth			ckeylen = 0;
5080*37da2899SCharles.Forsyth		keyarglen = 8;
5081*37da2899SCharles.Forsyth
5082*37da2899SCharles.Forsyth	SSL_3DES_EDE_CBC =>
5083*37da2899SCharles.Forsyth		mkeylen = 24;
5084*37da2899SCharles.Forsyth		ckeylen = 0;
5085*37da2899SCharles.Forsyth		keyarglen = 8;
5086*37da2899SCharles.Forsyth	}
5087*37da2899SCharles.Forsyth
5088*37da2899SCharles.Forsyth	return (mkeylen, ckeylen, keyarglen);
5089*37da2899SCharles.Forsyth}
5090*37da2899SCharles.Forsyth
5091*37da2899SCharles.Forsythv2handshake_enque(h: ref V2Handshake, ctx: ref Context)
5092*37da2899SCharles.Forsyth{
5093*37da2899SCharles.Forsyth	p := ref Protocol.pV2Handshake(h);
5094*37da2899SCharles.Forsyth
5095*37da2899SCharles.Forsyth	protocol_write(p, ctx);
5096*37da2899SCharles.Forsyth}
5097*37da2899SCharles.Forsyth
5098*37da2899SCharles.ForsythV2Handshake.encode(hm: self ref V2Handshake): (array of byte, string)
5099*37da2899SCharles.Forsyth{
5100*37da2899SCharles.Forsyth	a : array of byte;
5101*37da2899SCharles.Forsyth	n : int;
5102*37da2899SCharles.Forsyth	e : string;
5103*37da2899SCharles.Forsyth
5104*37da2899SCharles.Forsyth	i := 0;
5105*37da2899SCharles.Forsyth	pick m := hm {
5106*37da2899SCharles.Forsyth	Error =>
5107*37da2899SCharles.Forsyth		n = 3;
5108*37da2899SCharles.Forsyth		a = array[n] of byte;
5109*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_ERROR;
5110*37da2899SCharles.Forsyth		a[i:] = m.code;
5111*37da2899SCharles.Forsyth
5112*37da2899SCharles.Forsyth	ClientHello =>
5113*37da2899SCharles.Forsyth		specslen := len m.cipher_specs;
5114*37da2899SCharles.Forsyth		sidlen := len m.session_id;
5115*37da2899SCharles.Forsyth		challen := len m.challenge;
5116*37da2899SCharles.Forsyth		n = 9+specslen + sidlen + challen;
5117*37da2899SCharles.Forsyth		a = array[n] of byte;
5118*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_CLIENT_HELLO;
5119*37da2899SCharles.Forsyth		a[i:] = m.version;
5120*37da2899SCharles.Forsyth		i += 2;
5121*37da2899SCharles.Forsyth		a[i:] = int_encode(specslen, 2);
5122*37da2899SCharles.Forsyth		i += 2;
5123*37da2899SCharles.Forsyth		a[i:] = int_encode(sidlen, 2);
5124*37da2899SCharles.Forsyth		i += 2;
5125*37da2899SCharles.Forsyth		a[i:] = int_encode(challen, 2);
5126*37da2899SCharles.Forsyth		i += 2;
5127*37da2899SCharles.Forsyth		a[i:] = m.cipher_specs;
5128*37da2899SCharles.Forsyth		i += specslen;
5129*37da2899SCharles.Forsyth		if(sidlen != 0) {
5130*37da2899SCharles.Forsyth			a[i:] = m.session_id;
5131*37da2899SCharles.Forsyth			i += sidlen;
5132*37da2899SCharles.Forsyth		}
5133*37da2899SCharles.Forsyth		if(challen != 0) {
5134*37da2899SCharles.Forsyth			a[i:] = m.challenge;
5135*37da2899SCharles.Forsyth			i += challen;
5136*37da2899SCharles.Forsyth		}
5137*37da2899SCharles.Forsyth
5138*37da2899SCharles.Forsyth	ServerHello =>
5139*37da2899SCharles.Forsyth		# use only the user certificate
5140*37da2899SCharles.Forsyth		certlen := len m.certificate;
5141*37da2899SCharles.Forsyth#		specslen := 3*len m.cipher_specs;
5142*37da2899SCharles.Forsyth		specslen := len m.cipher_specs;
5143*37da2899SCharles.Forsyth		cidlen := len m.connection_id;
5144*37da2899SCharles.Forsyth		n = 11 + certlen + specslen + cidlen;
5145*37da2899SCharles.Forsyth		a = array[n] of byte;
5146*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_SERVER_HELLO;
5147*37da2899SCharles.Forsyth		a[i++] = byte m.session_id_hit;
5148*37da2899SCharles.Forsyth		a[i++] = byte m.certificate_type;
5149*37da2899SCharles.Forsyth		a[i:] = m.version;
5150*37da2899SCharles.Forsyth		i += 2;
5151*37da2899SCharles.Forsyth		a[i:] = int_encode(certlen, 2);
5152*37da2899SCharles.Forsyth		i += 2;
5153*37da2899SCharles.Forsyth		a[i:] = int_encode(specslen, 2);
5154*37da2899SCharles.Forsyth		i += 2;
5155*37da2899SCharles.Forsyth		a[i:] = int_encode(cidlen, 2);
5156*37da2899SCharles.Forsyth		i += 2;
5157*37da2899SCharles.Forsyth		a[i:] = m.certificate;
5158*37da2899SCharles.Forsyth		i += certlen;
5159*37da2899SCharles.Forsyth		a[i:] = m.cipher_specs;
5160*37da2899SCharles.Forsyth		i += specslen;
5161*37da2899SCharles.Forsyth		a[i:] = m.connection_id;
5162*37da2899SCharles.Forsyth		i += cidlen;
5163*37da2899SCharles.Forsyth
5164*37da2899SCharles.Forsyth	ClientMasterKey =>
5165*37da2899SCharles.Forsyth		ckeylen := len m.clear_key;
5166*37da2899SCharles.Forsyth		ekeylen := len m.encrypt_key;
5167*37da2899SCharles.Forsyth		karglen := len m.key_arg;
5168*37da2899SCharles.Forsyth		n = 10 + ckeylen + ekeylen + karglen;
5169*37da2899SCharles.Forsyth		a = array[n] of byte;
5170*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_CLIENT_MASTER_KEY;
5171*37da2899SCharles.Forsyth		a[i:] = m.cipher_kind;
5172*37da2899SCharles.Forsyth		i += 3;
5173*37da2899SCharles.Forsyth		a[i:] = int_encode(ckeylen, 2);
5174*37da2899SCharles.Forsyth		i += 2;
5175*37da2899SCharles.Forsyth		a[i:] = int_encode(ekeylen, 2);
5176*37da2899SCharles.Forsyth		i += 2;
5177*37da2899SCharles.Forsyth		a[i:] = int_encode(karglen, 2);
5178*37da2899SCharles.Forsyth		i += 2;
5179*37da2899SCharles.Forsyth		a[i:] = m.clear_key;
5180*37da2899SCharles.Forsyth		i += ckeylen;
5181*37da2899SCharles.Forsyth		a[i:] = m.encrypt_key;
5182*37da2899SCharles.Forsyth		i += ekeylen;
5183*37da2899SCharles.Forsyth		a[i:] = m.key_arg;
5184*37da2899SCharles.Forsyth		i += karglen;
5185*37da2899SCharles.Forsyth
5186*37da2899SCharles.Forsyth	ServerVerify =>
5187*37da2899SCharles.Forsyth		challen := len m.challenge;
5188*37da2899SCharles.Forsyth		n = 1 + challen;
5189*37da2899SCharles.Forsyth		a = array[n] of byte;
5190*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_SERVER_VERIFY;
5191*37da2899SCharles.Forsyth		a[i:] = m.challenge;
5192*37da2899SCharles.Forsyth
5193*37da2899SCharles.Forsyth	RequestCertificate =>
5194*37da2899SCharles.Forsyth		cclen := len m.certificate_challenge;
5195*37da2899SCharles.Forsyth		n = 2 + cclen;
5196*37da2899SCharles.Forsyth		a = array[n] of byte;
5197*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_REQUEST_CERTIFICATE;
5198*37da2899SCharles.Forsyth		a[i++] = byte m.authentication_type;
5199*37da2899SCharles.Forsyth		a[i:] = m.certificate_challenge;
5200*37da2899SCharles.Forsyth		i += cclen;
5201*37da2899SCharles.Forsyth
5202*37da2899SCharles.Forsyth	ClientCertificate =>
5203*37da2899SCharles.Forsyth		# use only the user certificate
5204*37da2899SCharles.Forsyth		certlen := len m.certificate;
5205*37da2899SCharles.Forsyth		resplen := len m.response;
5206*37da2899SCharles.Forsyth		n = 6 + certlen + resplen;
5207*37da2899SCharles.Forsyth		a = array[n] of byte;
5208*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_CLIENT_CERTIFICATE;
5209*37da2899SCharles.Forsyth		a[i++] = byte m.certificate_type;
5210*37da2899SCharles.Forsyth		a[i:] = int_encode(certlen, 2);
5211*37da2899SCharles.Forsyth		i += 2;
5212*37da2899SCharles.Forsyth		a[i:] = int_encode(resplen, 2);
5213*37da2899SCharles.Forsyth		i += 2;
5214*37da2899SCharles.Forsyth		a[i:] = m.certificate;
5215*37da2899SCharles.Forsyth		i += certlen;
5216*37da2899SCharles.Forsyth		a[i:] = m.response;
5217*37da2899SCharles.Forsyth		i += resplen;
5218*37da2899SCharles.Forsyth
5219*37da2899SCharles.Forsyth	ClientFinished =>
5220*37da2899SCharles.Forsyth		cidlen := len m.connection_id;
5221*37da2899SCharles.Forsyth		n = 1 + cidlen;
5222*37da2899SCharles.Forsyth		a = array[n] of byte;
5223*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_CLIENT_FINISHED;
5224*37da2899SCharles.Forsyth		a[i:] = m.connection_id;
5225*37da2899SCharles.Forsyth		i += cidlen;
5226*37da2899SCharles.Forsyth
5227*37da2899SCharles.Forsyth	ServerFinished =>
5228*37da2899SCharles.Forsyth		sidlen := len m.session_id;
5229*37da2899SCharles.Forsyth		n = 1 + sidlen;
5230*37da2899SCharles.Forsyth		a = array[n] of byte;
5231*37da2899SCharles.Forsyth		a[i++] = byte SSL2_MT_SERVER_FINISHED;
5232*37da2899SCharles.Forsyth		a[i:] = m.session_id;
5233*37da2899SCharles.Forsyth		i += sidlen;
5234*37da2899SCharles.Forsyth	}
5235*37da2899SCharles.Forsyth
5236*37da2899SCharles.Forsyth	return (a, e);
5237*37da2899SCharles.Forsyth}
5238*37da2899SCharles.Forsyth
5239*37da2899SCharles.ForsythV2Handshake.decode(a: array of byte): (ref V2Handshake, string)
5240*37da2899SCharles.Forsyth{
5241*37da2899SCharles.Forsyth	m : ref V2Handshake;
5242*37da2899SCharles.Forsyth	e : string;
5243*37da2899SCharles.Forsyth
5244*37da2899SCharles.Forsyth	n := len a;
5245*37da2899SCharles.Forsyth	i := 1;
5246*37da2899SCharles.Forsyth	case int a[0] {
5247*37da2899SCharles.Forsyth	SSL2_MT_ERROR =>
5248*37da2899SCharles.Forsyth		if(n != 3)
5249*37da2899SCharles.Forsyth			break;
5250*37da2899SCharles.Forsyth		code := a[i:i+2];
5251*37da2899SCharles.Forsyth		i += 2;
5252*37da2899SCharles.Forsyth		m = ref V2Handshake.Error(code);
5253*37da2899SCharles.Forsyth
5254*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_HELLO =>
5255*37da2899SCharles.Forsyth		if(n < 9) {
5256*37da2899SCharles.Forsyth			e = "client hello: message too short";
5257*37da2899SCharles.Forsyth			break;
5258*37da2899SCharles.Forsyth		}
5259*37da2899SCharles.Forsyth		ver := a[i:i+2];
5260*37da2899SCharles.Forsyth		i += 2;
5261*37da2899SCharles.Forsyth		specslen := int_decode(a[i:i+2]);
5262*37da2899SCharles.Forsyth		i += 2;
5263*37da2899SCharles.Forsyth		sidlen := int_decode(a[i:i+2]);
5264*37da2899SCharles.Forsyth		i += 2;
5265*37da2899SCharles.Forsyth		challen := int_decode(a[i:i+2]);
5266*37da2899SCharles.Forsyth		i += 2;
5267*37da2899SCharles.Forsyth		if(n != 9+specslen+sidlen+challen) {
5268*37da2899SCharles.Forsyth			e = "client hello: length mismatch";
5269*37da2899SCharles.Forsyth			break;
5270*37da2899SCharles.Forsyth		}
5271*37da2899SCharles.Forsyth		if(specslen%3 != 0) {
5272*37da2899SCharles.Forsyth			e = "client hello: must multiple of 3 bytes";
5273*37da2899SCharles.Forsyth			break;
5274*37da2899SCharles.Forsyth		}
5275*37da2899SCharles.Forsyth		specs: array of byte;
5276*37da2899SCharles.Forsyth		if(specslen != 0) {
5277*37da2899SCharles.Forsyth			specs = a[i:i+specslen];
5278*37da2899SCharles.Forsyth			i += specslen;
5279*37da2899SCharles.Forsyth		}
5280*37da2899SCharles.Forsyth		sid: array of byte;
5281*37da2899SCharles.Forsyth		if(sidlen != 0) {
5282*37da2899SCharles.Forsyth			sid = a[i:i+sidlen];
5283*37da2899SCharles.Forsyth			i += sidlen;
5284*37da2899SCharles.Forsyth		}
5285*37da2899SCharles.Forsyth		chal: array of byte;
5286*37da2899SCharles.Forsyth		if(challen != 0) {
5287*37da2899SCharles.Forsyth			chal = a[i:i+challen];
5288*37da2899SCharles.Forsyth			i += challen;
5289*37da2899SCharles.Forsyth		}
5290*37da2899SCharles.Forsyth		m = ref V2Handshake.ClientHello(ver, specs, sid, chal);
5291*37da2899SCharles.Forsyth
5292*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_MASTER_KEY =>
5293*37da2899SCharles.Forsyth		if(n < 10) {
5294*37da2899SCharles.Forsyth			e = "client master key: message too short";
5295*37da2899SCharles.Forsyth			break;
5296*37da2899SCharles.Forsyth		}
5297*37da2899SCharles.Forsyth		kind := a[i:i+3];
5298*37da2899SCharles.Forsyth		i += 3;
5299*37da2899SCharles.Forsyth		ckeylen := int_decode(a[i:i+2]);
5300*37da2899SCharles.Forsyth		i += 2;
5301*37da2899SCharles.Forsyth		ekeylen := int_decode(a[i:i+2]);
5302*37da2899SCharles.Forsyth		i += 2;
5303*37da2899SCharles.Forsyth		karglen := int_decode(a[i:i+2]);
5304*37da2899SCharles.Forsyth		i += 2;
5305*37da2899SCharles.Forsyth		if(n != 10 + ckeylen + ekeylen + karglen) {
5306*37da2899SCharles.Forsyth			e = "client master key: length mismatch";
5307*37da2899SCharles.Forsyth			break;
5308*37da2899SCharles.Forsyth		}
5309*37da2899SCharles.Forsyth		ckey := a[i:i+ckeylen];
5310*37da2899SCharles.Forsyth		i += ckeylen;
5311*37da2899SCharles.Forsyth		ekey := a[i:i+ekeylen];
5312*37da2899SCharles.Forsyth		i += ekeylen;
5313*37da2899SCharles.Forsyth		karg := a[i:i+karglen];
5314*37da2899SCharles.Forsyth		i += karglen;
5315*37da2899SCharles.Forsyth		m = ref V2Handshake.ClientMasterKey(kind, ckey, ekey, karg);
5316*37da2899SCharles.Forsyth
5317*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_FINISHED =>
5318*37da2899SCharles.Forsyth		cid := a[i:n];
5319*37da2899SCharles.Forsyth		i = n;
5320*37da2899SCharles.Forsyth		m = ref V2Handshake.ClientFinished(cid);
5321*37da2899SCharles.Forsyth
5322*37da2899SCharles.Forsyth	SSL2_MT_SERVER_HELLO =>
5323*37da2899SCharles.Forsyth		if(n < 11) {
5324*37da2899SCharles.Forsyth			e = "server hello: messsage too short";
5325*37da2899SCharles.Forsyth			break;
5326*37da2899SCharles.Forsyth		}
5327*37da2899SCharles.Forsyth		sidhit := int a[i++];
5328*37da2899SCharles.Forsyth		certtype := int a[i++];
5329*37da2899SCharles.Forsyth		ver := a[i:i+2];
5330*37da2899SCharles.Forsyth		i += 2;
5331*37da2899SCharles.Forsyth		certlen := int_decode(a[i:i+2]);
5332*37da2899SCharles.Forsyth		i += 2;
5333*37da2899SCharles.Forsyth		specslen := int_decode(a[i:i+2]);
5334*37da2899SCharles.Forsyth		i += 2;
5335*37da2899SCharles.Forsyth		cidlen := int_decode(a[i:i+2]);
5336*37da2899SCharles.Forsyth		i += 2;
5337*37da2899SCharles.Forsyth		if(n != 11+certlen+specslen+cidlen) {
5338*37da2899SCharles.Forsyth			e = "server hello: length mismatch";
5339*37da2899SCharles.Forsyth			break;
5340*37da2899SCharles.Forsyth		}
5341*37da2899SCharles.Forsyth		cert := a[i:i+certlen];
5342*37da2899SCharles.Forsyth		i += certlen;
5343*37da2899SCharles.Forsyth		if(specslen%3 != 0) {
5344*37da2899SCharles.Forsyth			e = "server hello: must be multiple of 3 bytes";
5345*37da2899SCharles.Forsyth			break;
5346*37da2899SCharles.Forsyth		}
5347*37da2899SCharles.Forsyth		specs := a[i:i+specslen];
5348*37da2899SCharles.Forsyth		i += specslen;
5349*37da2899SCharles.Forsyth		if(cidlen < 16 || cidlen > 32) {
5350*37da2899SCharles.Forsyth			e = "server hello: connection id length out of range";
5351*37da2899SCharles.Forsyth			break;
5352*37da2899SCharles.Forsyth		}
5353*37da2899SCharles.Forsyth		cid := a[i:i+cidlen];
5354*37da2899SCharles.Forsyth		i += cidlen;
5355*37da2899SCharles.Forsyth		m = ref V2Handshake.ServerHello(sidhit, certtype, ver, cert, specs, cid);
5356*37da2899SCharles.Forsyth
5357*37da2899SCharles.Forsyth	SSL2_MT_SERVER_VERIFY =>
5358*37da2899SCharles.Forsyth		chal := a[i:n];
5359*37da2899SCharles.Forsyth		i = n;
5360*37da2899SCharles.Forsyth		m = ref V2Handshake.ServerVerify(chal);
5361*37da2899SCharles.Forsyth
5362*37da2899SCharles.Forsyth	SSL2_MT_SERVER_FINISHED =>
5363*37da2899SCharles.Forsyth		sid := a[i:n];
5364*37da2899SCharles.Forsyth		m = ref V2Handshake.ServerFinished(sid);
5365*37da2899SCharles.Forsyth
5366*37da2899SCharles.Forsyth	SSL2_MT_REQUEST_CERTIFICATE =>
5367*37da2899SCharles.Forsyth		if(n < 2) {
5368*37da2899SCharles.Forsyth			e = "request certificate: message too short";
5369*37da2899SCharles.Forsyth			break;
5370*37da2899SCharles.Forsyth		}
5371*37da2899SCharles.Forsyth		authtype := int a[i++];
5372*37da2899SCharles.Forsyth		certchal := a[i:n];
5373*37da2899SCharles.Forsyth		i = n;
5374*37da2899SCharles.Forsyth		m = ref V2Handshake.RequestCertificate(authtype, certchal);
5375*37da2899SCharles.Forsyth
5376*37da2899SCharles.Forsyth	SSL2_MT_CLIENT_CERTIFICATE =>
5377*37da2899SCharles.Forsyth		if(n < 6) {
5378*37da2899SCharles.Forsyth			e = "client certificate: message too short";
5379*37da2899SCharles.Forsyth			break;
5380*37da2899SCharles.Forsyth		}
5381*37da2899SCharles.Forsyth		certtype := int a[i++];
5382*37da2899SCharles.Forsyth		certlen := int_decode(a[i:i+2]);
5383*37da2899SCharles.Forsyth		i += 2;
5384*37da2899SCharles.Forsyth		resplen := int_decode(a[i:i+2]);
5385*37da2899SCharles.Forsyth		i += 2;
5386*37da2899SCharles.Forsyth		if(n != 6+certlen+resplen) {
5387*37da2899SCharles.Forsyth			e = "client certificate: length mismatch";
5388*37da2899SCharles.Forsyth			break;
5389*37da2899SCharles.Forsyth		}
5390*37da2899SCharles.Forsyth		cert := a[i:i+certlen];
5391*37da2899SCharles.Forsyth		i += certlen;
5392*37da2899SCharles.Forsyth		resp := a[i:i+resplen];
5393*37da2899SCharles.Forsyth		m = ref V2Handshake.ClientCertificate(certtype, cert, resp);
5394*37da2899SCharles.Forsyth
5395*37da2899SCharles.Forsyth	* =>
5396*37da2899SCharles.Forsyth		e = "unknown message [" + string a[0] + "]";
5397*37da2899SCharles.Forsyth	}
5398*37da2899SCharles.Forsyth
5399*37da2899SCharles.Forsyth	return (m, e);
5400*37da2899SCharles.Forsyth}
5401*37da2899SCharles.Forsyth
5402*37da2899SCharles.Forsyth# utilities
5403*37da2899SCharles.Forsyth
5404*37da2899SCharles.Forsythmd5_hash(input: list of array of byte, md5_ds: ref DigestState): (array of byte, ref DigestState)
5405*37da2899SCharles.Forsyth{
5406*37da2899SCharles.Forsyth	hash_value := array [Keyring->MD5dlen] of byte;
5407*37da2899SCharles.Forsyth	ds : ref DigestState;
5408*37da2899SCharles.Forsyth
5409*37da2899SCharles.Forsyth	if(md5_ds != nil)
5410*37da2899SCharles.Forsyth		ds = md5_ds.copy();
5411*37da2899SCharles.Forsyth
5412*37da2899SCharles.Forsyth	lab := input;
5413*37da2899SCharles.Forsyth	for(i := 0; i < len input - 1; i++) {
5414*37da2899SCharles.Forsyth		ds = keyring->md5(hd lab, len hd lab, nil, ds);
5415*37da2899SCharles.Forsyth		lab = tl lab;
5416*37da2899SCharles.Forsyth	}
5417*37da2899SCharles.Forsyth	ds = keyring->md5(hd lab, len hd lab, hash_value, ds);
5418*37da2899SCharles.Forsyth
5419*37da2899SCharles.Forsyth	return (hash_value, ds);
5420*37da2899SCharles.Forsyth}
5421*37da2899SCharles.Forsyth
5422*37da2899SCharles.Forsythsha_hash(input: list of array of byte, sha_ds: ref DigestState): (array of byte, ref DigestState)
5423*37da2899SCharles.Forsyth{
5424*37da2899SCharles.Forsyth	hash_value := array [Keyring->SHA1dlen] of byte;
5425*37da2899SCharles.Forsyth	ds : ref DigestState;
5426*37da2899SCharles.Forsyth
5427*37da2899SCharles.Forsyth	if(sha_ds != nil)
5428*37da2899SCharles.Forsyth		ds = sha_ds.copy();
5429*37da2899SCharles.Forsyth
5430*37da2899SCharles.Forsyth	lab := input;
5431*37da2899SCharles.Forsyth	for(i := 0; i < len input - 1; i++) {
5432*37da2899SCharles.Forsyth		ds = keyring->sha1(hd lab, len hd lab, nil, ds);
5433*37da2899SCharles.Forsyth		lab = tl lab;
5434*37da2899SCharles.Forsyth	}
5435*37da2899SCharles.Forsyth	ds = keyring->sha1(hd lab, len hd lab, hash_value, ds);
5436*37da2899SCharles.Forsyth
5437*37da2899SCharles.Forsyth	return (hash_value, ds);
5438*37da2899SCharles.Forsyth}
5439*37da2899SCharles.Forsyth
5440*37da2899SCharles.Forsythmd5_sha_hash(input: list of array of byte, md5_ds, sha_ds: ref DigestState)
5441*37da2899SCharles.Forsyth	: (array of byte, ref DigestState, ref DigestState)
5442*37da2899SCharles.Forsyth{
5443*37da2899SCharles.Forsyth	buf := array [Keyring->MD5dlen+Keyring->SHA1dlen] of byte;
5444*37da2899SCharles.Forsyth
5445*37da2899SCharles.Forsyth	(buf[0:], md5_ds) = md5_hash(input, md5_ds);
5446*37da2899SCharles.Forsyth	(buf[Keyring->MD5dlen:], sha_ds) = sha_hash(input, sha_ds);
5447*37da2899SCharles.Forsyth
5448*37da2899SCharles.Forsyth	return (buf, md5_ds, sha_ds);
5449*37da2899SCharles.Forsyth}
5450*37da2899SCharles.Forsyth
5451*37da2899SCharles.Forsythint_decode(buf: array of byte): int
5452*37da2899SCharles.Forsyth{
5453*37da2899SCharles.Forsyth	val := 0;
5454*37da2899SCharles.Forsyth	for(i := 0; i < len buf; i++)
5455*37da2899SCharles.Forsyth		val = (val << 8) | (int buf[i]);
5456*37da2899SCharles.Forsyth
5457*37da2899SCharles.Forsyth	return val;
5458*37da2899SCharles.Forsyth}
5459*37da2899SCharles.Forsyth
5460*37da2899SCharles.Forsythint_encode(value, length: int): array of byte
5461*37da2899SCharles.Forsyth{
5462*37da2899SCharles.Forsyth	buf := array [length] of byte;
5463*37da2899SCharles.Forsyth
5464*37da2899SCharles.Forsyth	while(length--)	{
5465*37da2899SCharles.Forsyth		buf[length] = byte value;
5466*37da2899SCharles.Forsyth		value >>= 8;
5467*37da2899SCharles.Forsyth	}
5468*37da2899SCharles.Forsyth
5469*37da2899SCharles.Forsyth	return buf;
5470*37da2899SCharles.Forsyth}
5471*37da2899SCharles.Forsyth
5472*37da2899SCharles.Forsyth
5473*37da2899SCharles.Forsythbastr(a: array of byte) : string
5474*37da2899SCharles.Forsyth{
5475*37da2899SCharles.Forsyth	ans : string = "";
5476*37da2899SCharles.Forsyth
5477*37da2899SCharles.Forsyth	for(i := 0; i < len a; i++) {
5478*37da2899SCharles.Forsyth		if(i < len a - 1 && i != 0 && i%10 == 0)
5479*37da2899SCharles.Forsyth			ans += "\n\t\t";
5480*37da2899SCharles.Forsyth		if(i == len a -1)
5481*37da2899SCharles.Forsyth			ans += sys->sprint("%2x", int a[i]);
5482*37da2899SCharles.Forsyth		else
5483*37da2899SCharles.Forsyth			ans += sys->sprint("%2x ", int a[i]);
5484*37da2899SCharles.Forsyth	}
5485*37da2899SCharles.Forsyth
5486*37da2899SCharles.Forsyth	return ans;
5487*37da2899SCharles.Forsyth}
5488*37da2899SCharles.Forsyth
5489*37da2899SCharles.Forsythbbastr(a: array of array of byte) : string
5490*37da2899SCharles.Forsyth{
5491*37da2899SCharles.Forsyth	info := "";
5492*37da2899SCharles.Forsyth
5493*37da2899SCharles.Forsyth	for(i := 0; i < len a; i++)
5494*37da2899SCharles.Forsyth		info += bastr(a[i]);
5495*37da2899SCharles.Forsyth
5496*37da2899SCharles.Forsyth	return info;
5497*37da2899SCharles.Forsyth}
5498*37da2899SCharles.Forsyth
5499*37da2899SCharles.Forsythlbastr(a: list of array of byte) : string
5500*37da2899SCharles.Forsyth{
5501*37da2899SCharles.Forsyth	info := "";
5502*37da2899SCharles.Forsyth
5503*37da2899SCharles.Forsyth	l := a;
5504*37da2899SCharles.Forsyth	while(l != nil) {
5505*37da2899SCharles.Forsyth		info += bastr(hd l) + "\n\t\t";
5506*37da2899SCharles.Forsyth		l = tl l;
5507*37da2899SCharles.Forsyth	}
5508*37da2899SCharles.Forsyth
5509*37da2899SCharles.Forsyth	return info;
5510*37da2899SCharles.Forsyth}
5511*37da2899SCharles.Forsyth
5512*37da2899SCharles.Forsyth# need to fix (string a == string b)
5513*37da2899SCharles.Forsythbytes_cmp(a, b: array of byte): int
5514*37da2899SCharles.Forsyth{
5515*37da2899SCharles.Forsyth	if(len a != len b)
5516*37da2899SCharles.Forsyth		return -1;
5517*37da2899SCharles.Forsyth
5518*37da2899SCharles.Forsyth	n := len a;
5519*37da2899SCharles.Forsyth	for(i := 0; i < n; i++) {
5520*37da2899SCharles.Forsyth		if(a[i] != b[i])
5521*37da2899SCharles.Forsyth			return -1;
5522*37da2899SCharles.Forsyth	}
5523*37da2899SCharles.Forsyth
5524*37da2899SCharles.Forsyth	return 0;
5525*37da2899SCharles.Forsyth}
5526*37da2899SCharles.Forsyth
5527*37da2899SCharles.Forsythputn(a: array of byte, i, value, n: int): int
5528*37da2899SCharles.Forsyth{
5529*37da2899SCharles.Forsyth	j := n;
5530*37da2899SCharles.Forsyth	while(j--) {
5531*37da2899SCharles.Forsyth		a[i+j] = byte value;
5532*37da2899SCharles.Forsyth		value >>= 8;
5533*37da2899SCharles.Forsyth	}
5534*37da2899SCharles.Forsyth	return i+n;
5535*37da2899SCharles.Forsyth}
5536*37da2899SCharles.Forsyth
5537*37da2899SCharles.ForsythINVALID_SUITE : con "invalid suite list";
5538*37da2899SCharles.ForsythILLEGAL_SUITE : con "illegal suite list";
5539*37da2899SCharles.Forsyth
5540*37da2899SCharles.Forsythcksuites(suites : array of byte) : string
5541*37da2899SCharles.Forsyth{
5542*37da2899SCharles.Forsyth	m := len suites;
5543*37da2899SCharles.Forsyth	if (m == 0 || (m&1))
5544*37da2899SCharles.Forsyth		return INVALID_SUITE;
5545*37da2899SCharles.Forsyth	n := len SSL3_Suites;
5546*37da2899SCharles.Forsyth	ssl3s := array [2] of byte;
5547*37da2899SCharles.Forsyth	for (j := 0; j < m; j += 2) {
5548*37da2899SCharles.Forsyth		for( i := 0; i < n; i++) {
5549*37da2899SCharles.Forsyth			ssl3s = SSL3_Suites[i];
5550*37da2899SCharles.Forsyth			if(suites[j] == ssl3s[0] && suites[j+1] == ssl3s[1])
5551*37da2899SCharles.Forsyth				break;
5552*37da2899SCharles.Forsyth		}
5553*37da2899SCharles.Forsyth		if (i == n)
5554*37da2899SCharles.Forsyth			return ILLEGAL_SUITE;
5555*37da2899SCharles.Forsyth	}
5556*37da2899SCharles.Forsyth	return nil;
5557*37da2899SCharles.Forsyth}
5558