xref: /freebsd/contrib/bearssl/src/ssl/ssl_hs_client.t0 (revision 2aaf9152a852aba9eb2036b95f4948ee77988826)
1*0957b409SSimon J. Gerraty\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
2*0957b409SSimon J. Gerraty\
3*0957b409SSimon J. Gerraty\ Permission is hereby granted, free of charge, to any person obtaining
4*0957b409SSimon J. Gerraty\ a copy of this software and associated documentation files (the
5*0957b409SSimon J. Gerraty\ "Software"), to deal in the Software without restriction, including
6*0957b409SSimon J. Gerraty\ without limitation the rights to use, copy, modify, merge, publish,
7*0957b409SSimon J. Gerraty\ distribute, sublicense, and/or sell copies of the Software, and to
8*0957b409SSimon J. Gerraty\ permit persons to whom the Software is furnished to do so, subject to
9*0957b409SSimon J. Gerraty\ the following conditions:
10*0957b409SSimon J. Gerraty\
11*0957b409SSimon J. Gerraty\ The above copyright notice and this permission notice shall be
12*0957b409SSimon J. Gerraty\ included in all copies or substantial portions of the Software.
13*0957b409SSimon J. Gerraty\
14*0957b409SSimon J. Gerraty\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15*0957b409SSimon J. Gerraty\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16*0957b409SSimon J. Gerraty\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17*0957b409SSimon J. Gerraty\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18*0957b409SSimon J. Gerraty\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19*0957b409SSimon J. Gerraty\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20*0957b409SSimon J. Gerraty\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*0957b409SSimon J. Gerraty\ SOFTWARE.
22*0957b409SSimon J. Gerraty
23*0957b409SSimon J. Gerraty\ ----------------------------------------------------------------------
24*0957b409SSimon J. Gerraty\ Handshake processing code, for the client.
25*0957b409SSimon J. Gerraty\ The common T0 code (ssl_hs_common.t0) shall be read first.
26*0957b409SSimon J. Gerraty
27*0957b409SSimon J. Gerratypreamble {
28*0957b409SSimon J. Gerraty
29*0957b409SSimon J. Gerraty/*
30*0957b409SSimon J. Gerraty * This macro evaluates to a pointer to the client context, under that
31*0957b409SSimon J. Gerraty * specific name. It must be noted that since the engine context is the
32*0957b409SSimon J. Gerraty * first field of the br_ssl_client_context structure ('eng'), then
33*0957b409SSimon J. Gerraty * pointers values of both types are interchangeable, modulo an
34*0957b409SSimon J. Gerraty * appropriate cast. This also means that "addresses" computed as offsets
35*0957b409SSimon J. Gerraty * within the structure work for both kinds of context.
36*0957b409SSimon J. Gerraty */
37*0957b409SSimon J. Gerraty#define CTX  ((br_ssl_client_context *)ENG)
38*0957b409SSimon J. Gerraty
39*0957b409SSimon J. Gerraty/*
40*0957b409SSimon J. Gerraty * Generate the pre-master secret for RSA key exchange, and encrypt it
41*0957b409SSimon J. Gerraty * with the server's public key. Returned value is either the encrypted
42*0957b409SSimon J. Gerraty * data length (in bytes), or -x on error, with 'x' being an error code.
43*0957b409SSimon J. Gerraty *
44*0957b409SSimon J. Gerraty * This code assumes that the public key has been already verified (it
45*0957b409SSimon J. Gerraty * was properly obtained by the X.509 engine, and it has the right type,
46*0957b409SSimon J. Gerraty * i.e. it is of type RSA and suitable for encryption).
47*0957b409SSimon J. Gerraty */
48*0957b409SSimon J. Gerratystatic int
49*0957b409SSimon J. Gerratymake_pms_rsa(br_ssl_client_context *ctx, int prf_id)
50*0957b409SSimon J. Gerraty{
51*0957b409SSimon J. Gerraty	const br_x509_class **xc;
52*0957b409SSimon J. Gerraty	const br_x509_pkey *pk;
53*0957b409SSimon J. Gerraty	const unsigned char *n;
54*0957b409SSimon J. Gerraty	unsigned char *pms;
55*0957b409SSimon J. Gerraty	size_t nlen, u;
56*0957b409SSimon J. Gerraty
57*0957b409SSimon J. Gerraty	xc = ctx->eng.x509ctx;
58*0957b409SSimon J. Gerraty	pk = (*xc)->get_pkey(xc, NULL);
59*0957b409SSimon J. Gerraty
60*0957b409SSimon J. Gerraty	/*
61*0957b409SSimon J. Gerraty	 * Compute actual RSA key length, in case there are leading zeros.
62*0957b409SSimon J. Gerraty	 */
63*0957b409SSimon J. Gerraty	n = pk->key.rsa.n;
64*0957b409SSimon J. Gerraty	nlen = pk->key.rsa.nlen;
65*0957b409SSimon J. Gerraty	while (nlen > 0 && *n == 0) {
66*0957b409SSimon J. Gerraty		n ++;
67*0957b409SSimon J. Gerraty		nlen --;
68*0957b409SSimon J. Gerraty	}
69*0957b409SSimon J. Gerraty
70*0957b409SSimon J. Gerraty	/*
71*0957b409SSimon J. Gerraty	 * We need at least 59 bytes (48 bytes for pre-master secret, and
72*0957b409SSimon J. Gerraty	 * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
73*0957b409SSimon J. Gerraty	 * minimal engine normally blocks RSA keys shorter than 128 bytes,
74*0957b409SSimon J. Gerraty	 * so this is mostly for public keys provided explicitly by the
75*0957b409SSimon J. Gerraty	 * caller.
76*0957b409SSimon J. Gerraty	 */
77*0957b409SSimon J. Gerraty	if (nlen < 59) {
78*0957b409SSimon J. Gerraty		return -BR_ERR_X509_WEAK_PUBLIC_KEY;
79*0957b409SSimon J. Gerraty	}
80*0957b409SSimon J. Gerraty	if (nlen > sizeof ctx->eng.pad) {
81*0957b409SSimon J. Gerraty		return -BR_ERR_LIMIT_EXCEEDED;
82*0957b409SSimon J. Gerraty	}
83*0957b409SSimon J. Gerraty
84*0957b409SSimon J. Gerraty	/*
85*0957b409SSimon J. Gerraty	 * Make PMS.
86*0957b409SSimon J. Gerraty	 */
87*0957b409SSimon J. Gerraty	pms = ctx->eng.pad + nlen - 48;
88*0957b409SSimon J. Gerraty	br_enc16be(pms, ctx->eng.version_max);
89*0957b409SSimon J. Gerraty	br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
90*0957b409SSimon J. Gerraty	br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
91*0957b409SSimon J. Gerraty
92*0957b409SSimon J. Gerraty	/*
93*0957b409SSimon J. Gerraty	 * Apply PKCS#1 type 2 padding.
94*0957b409SSimon J. Gerraty	 */
95*0957b409SSimon J. Gerraty	ctx->eng.pad[0] = 0x00;
96*0957b409SSimon J. Gerraty	ctx->eng.pad[1] = 0x02;
97*0957b409SSimon J. Gerraty	ctx->eng.pad[nlen - 49] = 0x00;
98*0957b409SSimon J. Gerraty	br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
99*0957b409SSimon J. Gerraty	for (u = 2; u < nlen - 49; u ++) {
100*0957b409SSimon J. Gerraty		while (ctx->eng.pad[u] == 0) {
101*0957b409SSimon J. Gerraty			br_hmac_drbg_generate(&ctx->eng.rng,
102*0957b409SSimon J. Gerraty				&ctx->eng.pad[u], 1);
103*0957b409SSimon J. Gerraty		}
104*0957b409SSimon J. Gerraty	}
105*0957b409SSimon J. Gerraty
106*0957b409SSimon J. Gerraty	/*
107*0957b409SSimon J. Gerraty	 * Compute RSA encryption.
108*0957b409SSimon J. Gerraty	 */
109*0957b409SSimon J. Gerraty	if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
110*0957b409SSimon J. Gerraty		return -BR_ERR_LIMIT_EXCEEDED;
111*0957b409SSimon J. Gerraty	}
112*0957b409SSimon J. Gerraty	return (int)nlen;
113*0957b409SSimon J. Gerraty}
114*0957b409SSimon J. Gerraty
115*0957b409SSimon J. Gerraty/*
116*0957b409SSimon J. Gerraty * OID for hash functions in RSA signatures.
117*0957b409SSimon J. Gerraty */
118*0957b409SSimon J. Gerratystatic const unsigned char *HASH_OID[] = {
119*0957b409SSimon J. Gerraty	BR_HASH_OID_SHA1,
120*0957b409SSimon J. Gerraty	BR_HASH_OID_SHA224,
121*0957b409SSimon J. Gerraty	BR_HASH_OID_SHA256,
122*0957b409SSimon J. Gerraty	BR_HASH_OID_SHA384,
123*0957b409SSimon J. Gerraty	BR_HASH_OID_SHA512
124*0957b409SSimon J. Gerraty};
125*0957b409SSimon J. Gerraty
126*0957b409SSimon J. Gerraty/*
127*0957b409SSimon J. Gerraty * Check the RSA signature on the ServerKeyExchange message.
128*0957b409SSimon J. Gerraty *
129*0957b409SSimon J. Gerraty *   hash      hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
130*0957b409SSimon J. Gerraty *   use_rsa   non-zero for RSA signature, zero for ECDSA
131*0957b409SSimon J. Gerraty *   sig_len   signature length (in bytes); signature value is in the pad
132*0957b409SSimon J. Gerraty *
133*0957b409SSimon J. Gerraty * Returned value is 0 on success, or an error code.
134*0957b409SSimon J. Gerraty */
135*0957b409SSimon J. Gerratystatic int
136*0957b409SSimon J. Gerratyverify_SKE_sig(br_ssl_client_context *ctx,
137*0957b409SSimon J. Gerraty	int hash, int use_rsa, size_t sig_len)
138*0957b409SSimon J. Gerraty{
139*0957b409SSimon J. Gerraty	const br_x509_class **xc;
140*0957b409SSimon J. Gerraty	const br_x509_pkey *pk;
141*0957b409SSimon J. Gerraty	br_multihash_context mhc;
142*0957b409SSimon J. Gerraty	unsigned char hv[64], head[4];
143*0957b409SSimon J. Gerraty	size_t hv_len;
144*0957b409SSimon J. Gerraty
145*0957b409SSimon J. Gerraty	xc = ctx->eng.x509ctx;
146*0957b409SSimon J. Gerraty	pk = (*xc)->get_pkey(xc, NULL);
147*0957b409SSimon J. Gerraty	br_multihash_zero(&mhc);
148*0957b409SSimon J. Gerraty	br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
149*0957b409SSimon J. Gerraty	br_multihash_init(&mhc);
150*0957b409SSimon J. Gerraty	br_multihash_update(&mhc,
151*0957b409SSimon J. Gerraty		ctx->eng.client_random, sizeof ctx->eng.client_random);
152*0957b409SSimon J. Gerraty	br_multihash_update(&mhc,
153*0957b409SSimon J. Gerraty		ctx->eng.server_random, sizeof ctx->eng.server_random);
154*0957b409SSimon J. Gerraty	head[0] = 3;
155*0957b409SSimon J. Gerraty	head[1] = 0;
156*0957b409SSimon J. Gerraty	head[2] = ctx->eng.ecdhe_curve;
157*0957b409SSimon J. Gerraty	head[3] = ctx->eng.ecdhe_point_len;
158*0957b409SSimon J. Gerraty	br_multihash_update(&mhc, head, sizeof head);
159*0957b409SSimon J. Gerraty	br_multihash_update(&mhc,
160*0957b409SSimon J. Gerraty		ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
161*0957b409SSimon J. Gerraty	if (hash) {
162*0957b409SSimon J. Gerraty		hv_len = br_multihash_out(&mhc, hash, hv);
163*0957b409SSimon J. Gerraty		if (hv_len == 0) {
164*0957b409SSimon J. Gerraty			return BR_ERR_INVALID_ALGORITHM;
165*0957b409SSimon J. Gerraty		}
166*0957b409SSimon J. Gerraty	} else {
167*0957b409SSimon J. Gerraty		if (!br_multihash_out(&mhc, br_md5_ID, hv)
168*0957b409SSimon J. Gerraty			|| !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
169*0957b409SSimon J. Gerraty		{
170*0957b409SSimon J. Gerraty			return BR_ERR_INVALID_ALGORITHM;
171*0957b409SSimon J. Gerraty		}
172*0957b409SSimon J. Gerraty		hv_len = 36;
173*0957b409SSimon J. Gerraty	}
174*0957b409SSimon J. Gerraty	if (use_rsa) {
175*0957b409SSimon J. Gerraty		unsigned char tmp[64];
176*0957b409SSimon J. Gerraty		const unsigned char *hash_oid;
177*0957b409SSimon J. Gerraty
178*0957b409SSimon J. Gerraty		if (hash) {
179*0957b409SSimon J. Gerraty			hash_oid = HASH_OID[hash - 2];
180*0957b409SSimon J. Gerraty		} else {
181*0957b409SSimon J. Gerraty			hash_oid = NULL;
182*0957b409SSimon J. Gerraty		}
183*0957b409SSimon J. Gerraty		if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len,
184*0957b409SSimon J. Gerraty			hash_oid, hv_len, &pk->key.rsa, tmp)
185*0957b409SSimon J. Gerraty			|| memcmp(tmp, hv, hv_len) != 0)
186*0957b409SSimon J. Gerraty		{
187*0957b409SSimon J. Gerraty			return BR_ERR_BAD_SIGNATURE;
188*0957b409SSimon J. Gerraty		}
189*0957b409SSimon J. Gerraty	} else {
190*0957b409SSimon J. Gerraty		if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
191*0957b409SSimon J. Gerraty			ctx->eng.pad, sig_len))
192*0957b409SSimon J. Gerraty		{
193*0957b409SSimon J. Gerraty			return BR_ERR_BAD_SIGNATURE;
194*0957b409SSimon J. Gerraty		}
195*0957b409SSimon J. Gerraty	}
196*0957b409SSimon J. Gerraty	return 0;
197*0957b409SSimon J. Gerraty}
198*0957b409SSimon J. Gerraty
199*0957b409SSimon J. Gerraty/*
200*0957b409SSimon J. Gerraty * Perform client-side ECDH (or ECDHE). The point that should be sent to
201*0957b409SSimon J. Gerraty * the server is written in the pad; returned value is either the point
202*0957b409SSimon J. Gerraty * length (in bytes), or -x on error, with 'x' being an error code.
203*0957b409SSimon J. Gerraty *
204*0957b409SSimon J. Gerraty * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
205*0957b409SSimon J. Gerraty * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
206*0957b409SSimon J. Gerraty * (for static ECDH).
207*0957b409SSimon J. Gerraty */
208*0957b409SSimon J. Gerratystatic int
209*0957b409SSimon J. Gerratymake_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
210*0957b409SSimon J. Gerraty{
211*0957b409SSimon J. Gerraty	int curve;
212*0957b409SSimon J. Gerraty	unsigned char key[66], point[133];
213*0957b409SSimon J. Gerraty	const unsigned char *order, *point_src;
214*0957b409SSimon J. Gerraty	size_t glen, olen, point_len, xoff, xlen;
215*0957b409SSimon J. Gerraty	unsigned char mask;
216*0957b409SSimon J. Gerraty
217*0957b409SSimon J. Gerraty	if (ecdhe) {
218*0957b409SSimon J. Gerraty		curve = ctx->eng.ecdhe_curve;
219*0957b409SSimon J. Gerraty		point_src = ctx->eng.ecdhe_point;
220*0957b409SSimon J. Gerraty		point_len = ctx->eng.ecdhe_point_len;
221*0957b409SSimon J. Gerraty	} else {
222*0957b409SSimon J. Gerraty		const br_x509_class **xc;
223*0957b409SSimon J. Gerraty		const br_x509_pkey *pk;
224*0957b409SSimon J. Gerraty
225*0957b409SSimon J. Gerraty		xc = ctx->eng.x509ctx;
226*0957b409SSimon J. Gerraty		pk = (*xc)->get_pkey(xc, NULL);
227*0957b409SSimon J. Gerraty		curve = pk->key.ec.curve;
228*0957b409SSimon J. Gerraty		point_src = pk->key.ec.q;
229*0957b409SSimon J. Gerraty		point_len = pk->key.ec.qlen;
230*0957b409SSimon J. Gerraty	}
231*0957b409SSimon J. Gerraty	if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
232*0957b409SSimon J. Gerraty		return -BR_ERR_INVALID_ALGORITHM;
233*0957b409SSimon J. Gerraty	}
234*0957b409SSimon J. Gerraty
235*0957b409SSimon J. Gerraty	/*
236*0957b409SSimon J. Gerraty	 * We need to generate our key, as a non-zero random value which
237*0957b409SSimon J. Gerraty	 * is lower than the curve order, in a "large enough" range. We
238*0957b409SSimon J. Gerraty	 * force top bit to 0 and bottom bit to 1, which guarantees that
239*0957b409SSimon J. Gerraty	 * the value is in the proper range.
240*0957b409SSimon J. Gerraty	 */
241*0957b409SSimon J. Gerraty	order = ctx->eng.iec->order(curve, &olen);
242*0957b409SSimon J. Gerraty	mask = 0xFF;
243*0957b409SSimon J. Gerraty	while (mask >= order[0]) {
244*0957b409SSimon J. Gerraty		mask >>= 1;
245*0957b409SSimon J. Gerraty	}
246*0957b409SSimon J. Gerraty	br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
247*0957b409SSimon J. Gerraty	key[0] &= mask;
248*0957b409SSimon J. Gerraty	key[olen - 1] |= 0x01;
249*0957b409SSimon J. Gerraty
250*0957b409SSimon J. Gerraty	/*
251*0957b409SSimon J. Gerraty	 * Compute the common ECDH point, whose X coordinate is the
252*0957b409SSimon J. Gerraty	 * pre-master secret.
253*0957b409SSimon J. Gerraty	 */
254*0957b409SSimon J. Gerraty	ctx->eng.iec->generator(curve, &glen);
255*0957b409SSimon J. Gerraty	if (glen != point_len) {
256*0957b409SSimon J. Gerraty		return -BR_ERR_INVALID_ALGORITHM;
257*0957b409SSimon J. Gerraty	}
258*0957b409SSimon J. Gerraty
259*0957b409SSimon J. Gerraty	memcpy(point, point_src, glen);
260*0957b409SSimon J. Gerraty	if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
261*0957b409SSimon J. Gerraty		return -BR_ERR_INVALID_ALGORITHM;
262*0957b409SSimon J. Gerraty	}
263*0957b409SSimon J. Gerraty
264*0957b409SSimon J. Gerraty	/*
265*0957b409SSimon J. Gerraty	 * The pre-master secret is the X coordinate.
266*0957b409SSimon J. Gerraty	 */
267*0957b409SSimon J. Gerraty	xoff = ctx->eng.iec->xoff(curve, &xlen);
268*0957b409SSimon J. Gerraty	br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen);
269*0957b409SSimon J. Gerraty
270*0957b409SSimon J. Gerraty	ctx->eng.iec->mulgen(point, key, olen, curve);
271*0957b409SSimon J. Gerraty	memcpy(ctx->eng.pad, point, glen);
272*0957b409SSimon J. Gerraty	return (int)glen;
273*0957b409SSimon J. Gerraty}
274*0957b409SSimon J. Gerraty
275*0957b409SSimon J. Gerraty/*
276*0957b409SSimon J. Gerraty * Perform full static ECDH. This occurs only in the context of client
277*0957b409SSimon J. Gerraty * authentication with certificates: the server uses an EC public key,
278*0957b409SSimon J. Gerraty * the cipher suite is of type ECDH (not ECDHE), the server requested a
279*0957b409SSimon J. Gerraty * client certificate and accepts static ECDH, the client has a
280*0957b409SSimon J. Gerraty * certificate with an EC public key in the same curve, and accepts
281*0957b409SSimon J. Gerraty * static ECDH as well.
282*0957b409SSimon J. Gerraty *
283*0957b409SSimon J. Gerraty * Returned value is 0 on success, -1 on error.
284*0957b409SSimon J. Gerraty */
285*0957b409SSimon J. Gerratystatic int
286*0957b409SSimon J. Gerratymake_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id)
287*0957b409SSimon J. Gerraty{
288*0957b409SSimon J. Gerraty	unsigned char point[133];
289*0957b409SSimon J. Gerraty	size_t point_len;
290*0957b409SSimon J. Gerraty	const br_x509_class **xc;
291*0957b409SSimon J. Gerraty	const br_x509_pkey *pk;
292*0957b409SSimon J. Gerraty
293*0957b409SSimon J. Gerraty	xc = ctx->eng.x509ctx;
294*0957b409SSimon J. Gerraty	pk = (*xc)->get_pkey(xc, NULL);
295*0957b409SSimon J. Gerraty	point_len = pk->key.ec.qlen;
296*0957b409SSimon J. Gerraty	if (point_len > sizeof point) {
297*0957b409SSimon J. Gerraty		return -1;
298*0957b409SSimon J. Gerraty	}
299*0957b409SSimon J. Gerraty	memcpy(point, pk->key.ec.q, point_len);
300*0957b409SSimon J. Gerraty	if (!(*ctx->client_auth_vtable)->do_keyx(
301*0957b409SSimon J. Gerraty		ctx->client_auth_vtable, point, &point_len))
302*0957b409SSimon J. Gerraty	{
303*0957b409SSimon J. Gerraty		return -1;
304*0957b409SSimon J. Gerraty	}
305*0957b409SSimon J. Gerraty	br_ssl_engine_compute_master(&ctx->eng,
306*0957b409SSimon J. Gerraty		prf_id, point, point_len);
307*0957b409SSimon J. Gerraty	return 0;
308*0957b409SSimon J. Gerraty}
309*0957b409SSimon J. Gerraty
310*0957b409SSimon J. Gerraty/*
311*0957b409SSimon J. Gerraty * Compute the client-side signature. This is invoked only when a
312*0957b409SSimon J. Gerraty * signature-based client authentication was selected. The computed
313*0957b409SSimon J. Gerraty * signature is in the pad; its length (in bytes) is returned. On
314*0957b409SSimon J. Gerraty * error, 0 is returned.
315*0957b409SSimon J. Gerraty */
316*0957b409SSimon J. Gerratystatic size_t
317*0957b409SSimon J. Gerratymake_client_sign(br_ssl_client_context *ctx)
318*0957b409SSimon J. Gerraty{
319*0957b409SSimon J. Gerraty	size_t hv_len;
320*0957b409SSimon J. Gerraty
321*0957b409SSimon J. Gerraty	/*
322*0957b409SSimon J. Gerraty	 * Compute hash of handshake messages so far. This "cannot" fail
323*0957b409SSimon J. Gerraty	 * because the list of supported hash functions provided to the
324*0957b409SSimon J. Gerraty	 * client certificate handler was trimmed to include only the
325*0957b409SSimon J. Gerraty	 * hash functions that the multi-hasher supports.
326*0957b409SSimon J. Gerraty	 */
327*0957b409SSimon J. Gerraty	if (ctx->hash_id) {
328*0957b409SSimon J. Gerraty		hv_len = br_multihash_out(&ctx->eng.mhash,
329*0957b409SSimon J. Gerraty			ctx->hash_id, ctx->eng.pad);
330*0957b409SSimon J. Gerraty	} else {
331*0957b409SSimon J. Gerraty		br_multihash_out(&ctx->eng.mhash,
332*0957b409SSimon J. Gerraty			br_md5_ID, ctx->eng.pad);
333*0957b409SSimon J. Gerraty		br_multihash_out(&ctx->eng.mhash,
334*0957b409SSimon J. Gerraty			br_sha1_ID, ctx->eng.pad + 16);
335*0957b409SSimon J. Gerraty		hv_len = 36;
336*0957b409SSimon J. Gerraty	}
337*0957b409SSimon J. Gerraty	return (*ctx->client_auth_vtable)->do_sign(
338*0957b409SSimon J. Gerraty		ctx->client_auth_vtable, ctx->hash_id, hv_len,
339*0957b409SSimon J. Gerraty		ctx->eng.pad, sizeof ctx->eng.pad);
340*0957b409SSimon J. Gerraty}
341*0957b409SSimon J. Gerraty
342*0957b409SSimon J. Gerraty}
343*0957b409SSimon J. Gerraty
344*0957b409SSimon J. Gerraty\ =======================================================================
345*0957b409SSimon J. Gerraty
346*0957b409SSimon J. Gerraty: addr-ctx:
347*0957b409SSimon J. Gerraty	next-word { field }
348*0957b409SSimon J. Gerraty	"addr-" field + 0 1 define-word
349*0957b409SSimon J. Gerraty	0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX
350*0957b409SSimon J. Gerraty	postpone literal postpone ; ;
351*0957b409SSimon J. Gerraty
352*0957b409SSimon J. Gerratyaddr-ctx: min_clienthello_len
353*0957b409SSimon J. Gerratyaddr-ctx: hashes
354*0957b409SSimon J. Gerratyaddr-ctx: auth_type
355*0957b409SSimon J. Gerratyaddr-ctx: hash_id
356*0957b409SSimon J. Gerraty
357*0957b409SSimon J. Gerraty\ Length of the Secure Renegotiation extension. This is 5 for the
358*0957b409SSimon J. Gerraty\ first handshake, 17 for a renegotiation (if the server supports the
359*0957b409SSimon J. Gerraty\ extension), or 0 if we know that the server does not support the
360*0957b409SSimon J. Gerraty\ extension.
361*0957b409SSimon J. Gerraty: ext-reneg-length ( -- n )
362*0957b409SSimon J. Gerraty	addr-reneg get8 dup if 1 - 17 * else drop 5 then ;
363*0957b409SSimon J. Gerraty
364*0957b409SSimon J. Gerraty\ Length of SNI extension.
365*0957b409SSimon J. Gerraty: ext-sni-length ( -- len )
366*0957b409SSimon J. Gerraty	addr-server_name strlen dup if 9 + then ;
367*0957b409SSimon J. Gerraty
368*0957b409SSimon J. Gerraty\ Length of Maximum Fragment Length extension.
369*0957b409SSimon J. Gerraty: ext-frag-length ( -- len )
370*0957b409SSimon J. Gerraty	addr-log_max_frag_len get8 14 = if 0 else 5 then ;
371*0957b409SSimon J. Gerraty
372*0957b409SSimon J. Gerraty\ Length of Signatures extension.
373*0957b409SSimon J. Gerraty: ext-signatures-length ( -- len )
374*0957b409SSimon J. Gerraty	supported-hash-functions { num } drop 0
375*0957b409SSimon J. Gerraty	supports-rsa-sign? if num + then
376*0957b409SSimon J. Gerraty	supports-ecdsa? if num + then
377*0957b409SSimon J. Gerraty	dup if 1 << 6 + then ;
378*0957b409SSimon J. Gerraty
379*0957b409SSimon J. Gerraty\ Write supported hash functions ( sign -- )
380*0957b409SSimon J. Gerraty: write-hashes
381*0957b409SSimon J. Gerraty	{ sign }
382*0957b409SSimon J. Gerraty	supported-hash-functions drop
383*0957b409SSimon J. Gerraty	\ We advertise hash functions in the following preference order:
384*0957b409SSimon J. Gerraty	\   SHA-256 SHA-224 SHA-384 SHA-512 SHA-1
385*0957b409SSimon J. Gerraty	\ Rationale:
386*0957b409SSimon J. Gerraty	\ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures
387*0957b409SSimon J. Gerraty	\ -- SHA-1 is less than ideally collision-resistant
388*0957b409SSimon J. Gerraty	dup 0x10 and if 4 write8 sign write8 then
389*0957b409SSimon J. Gerraty	dup 0x08 and if 3 write8 sign write8 then
390*0957b409SSimon J. Gerraty	dup 0x20 and if 5 write8 sign write8 then
391*0957b409SSimon J. Gerraty	dup 0x40 and if 6 write8 sign write8 then
392*0957b409SSimon J. Gerraty	0x04 and if 2 write8 sign write8 then ;
393*0957b409SSimon J. Gerraty
394*0957b409SSimon J. Gerraty\ Length of Supported Curves extension.
395*0957b409SSimon J. Gerraty: ext-supported-curves-length ( -- len )
396*0957b409SSimon J. Gerraty	supported-curves dup if
397*0957b409SSimon J. Gerraty		0 { x }
398*0957b409SSimon J. Gerraty		begin dup while
399*0957b409SSimon J. Gerraty			dup 1 and x + >x
400*0957b409SSimon J. Gerraty			1 >>
401*0957b409SSimon J. Gerraty		repeat
402*0957b409SSimon J. Gerraty		drop x 1 << 6 +
403*0957b409SSimon J. Gerraty	then ;
404*0957b409SSimon J. Gerraty
405*0957b409SSimon J. Gerraty\ Length of Supported Point Formats extension.
406*0957b409SSimon J. Gerraty: ext-point-format-length ( -- len )
407*0957b409SSimon J. Gerraty	supported-curves if 6 else 0 then ;
408*0957b409SSimon J. Gerraty
409*0957b409SSimon J. Gerraty\ Length of ALPN extension.
410*0957b409SSimon J. Gerratycc: ext-ALPN-length ( -- len ) {
411*0957b409SSimon J. Gerraty	size_t u, len;
412*0957b409SSimon J. Gerraty
413*0957b409SSimon J. Gerraty	if (ENG->protocol_names_num == 0) {
414*0957b409SSimon J. Gerraty		T0_PUSH(0);
415*0957b409SSimon J. Gerraty		T0_RET();
416*0957b409SSimon J. Gerraty	}
417*0957b409SSimon J. Gerraty	len = 6;
418*0957b409SSimon J. Gerraty	for (u = 0; u < ENG->protocol_names_num; u ++) {
419*0957b409SSimon J. Gerraty		len += 1 + strlen(ENG->protocol_names[u]);
420*0957b409SSimon J. Gerraty	}
421*0957b409SSimon J. Gerraty	T0_PUSH(len);
422*0957b409SSimon J. Gerraty}
423*0957b409SSimon J. Gerraty
424*0957b409SSimon J. Gerraty\ Write handshake message: ClientHello
425*0957b409SSimon J. Gerraty: write-ClientHello ( -- )
426*0957b409SSimon J. Gerraty	{ ; total-ext-length }
427*0957b409SSimon J. Gerraty
428*0957b409SSimon J. Gerraty	\ Compute length for extensions (without the general two-byte header).
429*0957b409SSimon J. Gerraty	\ This does not take padding extension into account.
430*0957b409SSimon J. Gerraty	ext-reneg-length ext-sni-length + ext-frag-length +
431*0957b409SSimon J. Gerraty	ext-signatures-length +
432*0957b409SSimon J. Gerraty	ext-supported-curves-length + ext-point-format-length +
433*0957b409SSimon J. Gerraty	ext-ALPN-length +
434*0957b409SSimon J. Gerraty	>total-ext-length
435*0957b409SSimon J. Gerraty
436*0957b409SSimon J. Gerraty	\ ClientHello type
437*0957b409SSimon J. Gerraty	1 write8
438*0957b409SSimon J. Gerraty
439*0957b409SSimon J. Gerraty	\ Compute and write length
440*0957b409SSimon J. Gerraty	39 addr-session_id_len get8 + addr-suites_num get8 1 << +
441*0957b409SSimon J. Gerraty	total-ext-length if 2+ total-ext-length + then
442*0957b409SSimon J. Gerraty	\ Compute padding (if requested).
443*0957b409SSimon J. Gerraty	addr-min_clienthello_len get16 over - dup 0> if
444*0957b409SSimon J. Gerraty		\ We well add a Pad ClientHello extension, which has its
445*0957b409SSimon J. Gerraty		\ own header (4 bytes) and might be the only extension
446*0957b409SSimon J. Gerraty		\ (2 extra bytes for the extension list header).
447*0957b409SSimon J. Gerraty		total-ext-length ifnot swap 2+ swap 2- then
448*0957b409SSimon J. Gerraty		\ Account for the extension header.
449*0957b409SSimon J. Gerraty		4 - dup 0< if drop 0 then
450*0957b409SSimon J. Gerraty		\ Adjust total extension length.
451*0957b409SSimon J. Gerraty		dup 4 + total-ext-length + >total-ext-length
452*0957b409SSimon J. Gerraty		\ Adjust ClientHello length.
453*0957b409SSimon J. Gerraty		swap 4 + over + swap
454*0957b409SSimon J. Gerraty	else
455*0957b409SSimon J. Gerraty		drop
456*0957b409SSimon J. Gerraty		-1
457*0957b409SSimon J. Gerraty	then
458*0957b409SSimon J. Gerraty	{ ext-padding-amount }
459*0957b409SSimon J. Gerraty	write24
460*0957b409SSimon J. Gerraty
461*0957b409SSimon J. Gerraty	\ Protocol version
462*0957b409SSimon J. Gerraty	addr-version_max get16 write16
463*0957b409SSimon J. Gerraty
464*0957b409SSimon J. Gerraty	\ Client random
465*0957b409SSimon J. Gerraty	addr-client_random 4 bzero
466*0957b409SSimon J. Gerraty	addr-client_random 4 + 28 mkrand
467*0957b409SSimon J. Gerraty	addr-client_random 32 write-blob
468*0957b409SSimon J. Gerraty
469*0957b409SSimon J. Gerraty	\ Session ID
470*0957b409SSimon J. Gerraty	addr-session_id addr-session_id_len get8 write-blob-head8
471*0957b409SSimon J. Gerraty
472*0957b409SSimon J. Gerraty	\ Supported cipher suites. We also check here that we indeed
473*0957b409SSimon J. Gerraty	\ support all these suites.
474*0957b409SSimon J. Gerraty	addr-suites_num get8 dup 1 << write16
475*0957b409SSimon J. Gerraty	addr-suites_buf swap
476*0957b409SSimon J. Gerraty	begin
477*0957b409SSimon J. Gerraty		dup while 1-
478*0957b409SSimon J. Gerraty		over get16
479*0957b409SSimon J. Gerraty		dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then
480*0957b409SSimon J. Gerraty		write16
481*0957b409SSimon J. Gerraty		swap 2+ swap
482*0957b409SSimon J. Gerraty	repeat
483*0957b409SSimon J. Gerraty	2drop
484*0957b409SSimon J. Gerraty
485*0957b409SSimon J. Gerraty	\ Compression methods (only "null" compression)
486*0957b409SSimon J. Gerraty	1 write8 0 write8
487*0957b409SSimon J. Gerraty
488*0957b409SSimon J. Gerraty	\ Extensions
489*0957b409SSimon J. Gerraty	total-ext-length if
490*0957b409SSimon J. Gerraty		total-ext-length write16
491*0957b409SSimon J. Gerraty		ext-reneg-length if
492*0957b409SSimon J. Gerraty			0xFF01 write16          \ extension type (0xFF01)
493*0957b409SSimon J. Gerraty			addr-saved_finished
494*0957b409SSimon J. Gerraty			ext-reneg-length 4 - dup write16 \ extension length
495*0957b409SSimon J. Gerraty			1- write-blob-head8              \ verify data
496*0957b409SSimon J. Gerraty		then
497*0957b409SSimon J. Gerraty		ext-sni-length if
498*0957b409SSimon J. Gerraty			0x0000 write16          \ extension type (0)
499*0957b409SSimon J. Gerraty			addr-server_name
500*0957b409SSimon J. Gerraty			ext-sni-length 4 - dup write16 \ extension length
501*0957b409SSimon J. Gerraty			2 - dup write16                \ ServerNameList length
502*0957b409SSimon J. Gerraty			0 write8                       \ name type: host_name
503*0957b409SSimon J. Gerraty			3 - write-blob-head16          \ the name itself
504*0957b409SSimon J. Gerraty		then
505*0957b409SSimon J. Gerraty		ext-frag-length if
506*0957b409SSimon J. Gerraty			0x0001 write16          \ extension type (1)
507*0957b409SSimon J. Gerraty			0x0001 write16          \ extension length
508*0957b409SSimon J. Gerraty			addr-log_max_frag_len get8 8 - write8
509*0957b409SSimon J. Gerraty		then
510*0957b409SSimon J. Gerraty		ext-signatures-length if
511*0957b409SSimon J. Gerraty			0x000D write16          \ extension type (13)
512*0957b409SSimon J. Gerraty			ext-signatures-length 4 - dup write16 \ extension length
513*0957b409SSimon J. Gerraty			2 - write16             \ list length
514*0957b409SSimon J. Gerraty			supports-ecdsa? if 3 write-hashes then
515*0957b409SSimon J. Gerraty			supports-rsa-sign? if 1 write-hashes then
516*0957b409SSimon J. Gerraty		then
517*0957b409SSimon J. Gerraty		\ TODO: add an API to specify preference order for curves.
518*0957b409SSimon J. Gerraty		\ Right now we send Curve25519 first, then other curves in
519*0957b409SSimon J. Gerraty		\ increasing ID values (hence P-256 in second).
520*0957b409SSimon J. Gerraty		ext-supported-curves-length dup if
521*0957b409SSimon J. Gerraty			0x000A write16          \ extension type (10)
522*0957b409SSimon J. Gerraty			4 - dup write16         \ extension length
523*0957b409SSimon J. Gerraty			2- write16              \ list length
524*0957b409SSimon J. Gerraty			supported-curves 0
525*0957b409SSimon J. Gerraty			dup 0x20000000 and if
526*0957b409SSimon J. Gerraty				0xDFFFFFFF and 29 write16
527*0957b409SSimon J. Gerraty			then
528*0957b409SSimon J. Gerraty			begin dup 32 < while
529*0957b409SSimon J. Gerraty				dup2 >> 1 and if dup write16 then
530*0957b409SSimon J. Gerraty				1+
531*0957b409SSimon J. Gerraty			repeat
532*0957b409SSimon J. Gerraty			2drop
533*0957b409SSimon J. Gerraty		else
534*0957b409SSimon J. Gerraty			drop
535*0957b409SSimon J. Gerraty		then
536*0957b409SSimon J. Gerraty		ext-point-format-length if
537*0957b409SSimon J. Gerraty			0x000B write16          \ extension type (11)
538*0957b409SSimon J. Gerraty			0x0002 write16          \ extension length
539*0957b409SSimon J. Gerraty			0x0100 write16          \ value: 1 format: uncompressed
540*0957b409SSimon J. Gerraty		then
541*0957b409SSimon J. Gerraty		ext-ALPN-length dup if
542*0957b409SSimon J. Gerraty			0x0010 write16          \ extension type (16)
543*0957b409SSimon J. Gerraty			4 - dup write16         \ extension length
544*0957b409SSimon J. Gerraty			2- write16              \ list length
545*0957b409SSimon J. Gerraty			addr-protocol_names_num get16 0
546*0957b409SSimon J. Gerraty			begin
547*0957b409SSimon J. Gerraty				dup2 > while
548*0957b409SSimon J. Gerraty				dup copy-protocol-name
549*0957b409SSimon J. Gerraty				dup write8 addr-pad swap write-blob
550*0957b409SSimon J. Gerraty				1+
551*0957b409SSimon J. Gerraty			repeat
552*0957b409SSimon J. Gerraty			2drop
553*0957b409SSimon J. Gerraty		else
554*0957b409SSimon J. Gerraty			drop
555*0957b409SSimon J. Gerraty		then
556*0957b409SSimon J. Gerraty		ext-padding-amount 0< ifnot
557*0957b409SSimon J. Gerraty			0x0015 write16          \ extension value (21)
558*0957b409SSimon J. Gerraty			ext-padding-amount
559*0957b409SSimon J. Gerraty			dup write16             \ extension length
560*0957b409SSimon J. Gerraty			begin dup while
561*0957b409SSimon J. Gerraty			1- 0 write8 repeat      \ value (only zeros)
562*0957b409SSimon J. Gerraty			drop
563*0957b409SSimon J. Gerraty		then
564*0957b409SSimon J. Gerraty	then
565*0957b409SSimon J. Gerraty	;
566*0957b409SSimon J. Gerraty
567*0957b409SSimon J. Gerraty\ =======================================================================
568*0957b409SSimon J. Gerraty
569*0957b409SSimon J. Gerraty\ Parse server SNI extension. If present, then it should be empty.
570*0957b409SSimon J. Gerraty: read-server-sni ( lim -- lim )
571*0957b409SSimon J. Gerraty	read16 if ERR_BAD_SNI fail then ;
572*0957b409SSimon J. Gerraty
573*0957b409SSimon J. Gerraty\ Parse server Max Fragment Length extension. If present, then it should
574*0957b409SSimon J. Gerraty\ advertise the same length as the client. Note that whether the server
575*0957b409SSimon J. Gerraty\ sends it or not changes nothing for us: we won't send any record larger
576*0957b409SSimon J. Gerraty\ than the advertised value anyway, and we will accept incoming records
577*0957b409SSimon J. Gerraty\ up to our input buffer length.
578*0957b409SSimon J. Gerraty: read-server-frag ( lim -- lim )
579*0957b409SSimon J. Gerraty	read16 1 = ifnot ERR_BAD_FRAGLEN fail then
580*0957b409SSimon J. Gerraty	read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ;
581*0957b409SSimon J. Gerraty
582*0957b409SSimon J. Gerraty\ Parse server Secure Renegotiation extension. This is called only if
583*0957b409SSimon J. Gerraty\ the client sent that extension, so we only have two cases to
584*0957b409SSimon J. Gerraty\ distinguish: first handshake, and renegotiation; in the latter case,
585*0957b409SSimon J. Gerraty\ we know that the server supports the extension, otherwise the client
586*0957b409SSimon J. Gerraty\ would not have sent it.
587*0957b409SSimon J. Gerraty: read-server-reneg ( lim -- lim )
588*0957b409SSimon J. Gerraty	read16
589*0957b409SSimon J. Gerraty	addr-reneg get8 ifnot
590*0957b409SSimon J. Gerraty		\ "reneg" is 0, so this is a first handshake. The server's
591*0957b409SSimon J. Gerraty		\ extension MUST be empty. We also learn that the server
592*0957b409SSimon J. Gerraty		\ supports the extension.
593*0957b409SSimon J. Gerraty		1 = ifnot ERR_BAD_SECRENEG fail then
594*0957b409SSimon J. Gerraty		read8 0 = ifnot ERR_BAD_SECRENEG fail then
595*0957b409SSimon J. Gerraty		2 addr-reneg set8
596*0957b409SSimon J. Gerraty	else
597*0957b409SSimon J. Gerraty		\ "reneg" is non-zero, and we sent an extension, so it must
598*0957b409SSimon J. Gerraty		\ be 2 and this is a renegotiation. We must verify that
599*0957b409SSimon J. Gerraty		\ the extension contents have length exactly 24 bytes and
600*0957b409SSimon J. Gerraty		\ match the saved client and server "Finished".
601*0957b409SSimon J. Gerraty		25 = ifnot ERR_BAD_SECRENEG fail then
602*0957b409SSimon J. Gerraty		read8 24 = ifnot ERR_BAD_SECRENEG fail then
603*0957b409SSimon J. Gerraty		addr-pad 24 read-blob
604*0957b409SSimon J. Gerraty		addr-saved_finished addr-pad 24 memcmp ifnot
605*0957b409SSimon J. Gerraty			ERR_BAD_SECRENEG fail
606*0957b409SSimon J. Gerraty		then
607*0957b409SSimon J. Gerraty	then ;
608*0957b409SSimon J. Gerraty
609*0957b409SSimon J. Gerraty\ Read the ALPN extension from the server. It must contain a single name,
610*0957b409SSimon J. Gerraty\ and that name must match one of our names.
611*0957b409SSimon J. Gerraty: read-ALPN-from-server ( lim -- lim )
612*0957b409SSimon J. Gerraty	\ Extension contents length.
613*0957b409SSimon J. Gerraty	read16 open-elt
614*0957b409SSimon J. Gerraty	\ Length of list of names.
615*0957b409SSimon J. Gerraty	read16 open-elt
616*0957b409SSimon J. Gerraty	\ There should be a single name.
617*0957b409SSimon J. Gerraty	read8 addr-pad swap dup { len } read-blob
618*0957b409SSimon J. Gerraty	close-elt
619*0957b409SSimon J. Gerraty	close-elt
620*0957b409SSimon J. Gerraty	len test-protocol-name dup 0< if
621*0957b409SSimon J. Gerraty		3 flag? if ERR_UNEXPECTED fail then
622*0957b409SSimon J. Gerraty		drop
623*0957b409SSimon J. Gerraty	else
624*0957b409SSimon J. Gerraty		1+ addr-selected_protocol set16
625*0957b409SSimon J. Gerraty	then ;
626*0957b409SSimon J. Gerraty
627*0957b409SSimon J. Gerraty\ Save a value in a 16-bit field, or check it in case of session resumption.
628*0957b409SSimon J. Gerraty: check-resume ( val addr resume -- )
629*0957b409SSimon J. Gerraty	if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
630*0957b409SSimon J. Gerraty
631*0957b409SSimon J. Gerratycc: DEBUG-BLOB ( addr len -- ) {
632*0957b409SSimon J. Gerraty	extern int printf(const char *fmt, ...);
633*0957b409SSimon J. Gerraty
634*0957b409SSimon J. Gerraty	size_t len = T0_POP();
635*0957b409SSimon J. Gerraty	unsigned char *buf = (unsigned char *)CTX + T0_POP();
636*0957b409SSimon J. Gerraty	size_t u;
637*0957b409SSimon J. Gerraty
638*0957b409SSimon J. Gerraty	printf("BLOB:");
639*0957b409SSimon J. Gerraty	for (u = 0; u < len; u ++) {
640*0957b409SSimon J. Gerraty		if (u % 16 == 0) {
641*0957b409SSimon J. Gerraty			printf("\n    ");
642*0957b409SSimon J. Gerraty		}
643*0957b409SSimon J. Gerraty		printf(" %02x", buf[u]);
644*0957b409SSimon J. Gerraty	}
645*0957b409SSimon J. Gerraty	printf("\n");
646*0957b409SSimon J. Gerraty}
647*0957b409SSimon J. Gerraty
648*0957b409SSimon J. Gerraty\ Parse incoming ServerHello. Returned value is true (-1) on session
649*0957b409SSimon J. Gerraty\ resumption.
650*0957b409SSimon J. Gerraty: read-ServerHello ( -- bool )
651*0957b409SSimon J. Gerraty	\ Get header, and check message type.
652*0957b409SSimon J. Gerraty	read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then
653*0957b409SSimon J. Gerraty
654*0957b409SSimon J. Gerraty	\ Get protocol version.
655*0957b409SSimon J. Gerraty	read16 { version }
656*0957b409SSimon J. Gerraty	version addr-version_min get16 < version addr-version_max get16 > or if
657*0957b409SSimon J. Gerraty		ERR_UNSUPPORTED_VERSION fail
658*0957b409SSimon J. Gerraty	then
659*0957b409SSimon J. Gerraty
660*0957b409SSimon J. Gerraty	\ Enforce chosen version for subsequent records in both directions.
661*0957b409SSimon J. Gerraty	version addr-version_in get16 <> if ERR_BAD_VERSION fail then
662*0957b409SSimon J. Gerraty	version addr-version_out set16
663*0957b409SSimon J. Gerraty
664*0957b409SSimon J. Gerraty	\ Server random.
665*0957b409SSimon J. Gerraty	addr-server_random 32 read-blob
666*0957b409SSimon J. Gerraty
667*0957b409SSimon J. Gerraty	\ The "session resumption" flag.
668*0957b409SSimon J. Gerraty	0 { resume }
669*0957b409SSimon J. Gerraty
670*0957b409SSimon J. Gerraty	\ Session ID.
671*0957b409SSimon J. Gerraty	read8 { idlen }
672*0957b409SSimon J. Gerraty	idlen 32 > if ERR_OVERSIZED_ID fail then
673*0957b409SSimon J. Gerraty	addr-pad idlen read-blob
674*0957b409SSimon J. Gerraty	idlen addr-session_id_len get8 = idlen 0 > and if
675*0957b409SSimon J. Gerraty		addr-session_id addr-pad idlen memcmp if
676*0957b409SSimon J. Gerraty			\ Server session ID is non-empty and matches what
677*0957b409SSimon J. Gerraty			\ we sent, so this is a session resumption.
678*0957b409SSimon J. Gerraty			-1 >resume
679*0957b409SSimon J. Gerraty		then
680*0957b409SSimon J. Gerraty	then
681*0957b409SSimon J. Gerraty	addr-session_id addr-pad idlen memcpy
682*0957b409SSimon J. Gerraty	idlen addr-session_id_len set8
683*0957b409SSimon J. Gerraty
684*0957b409SSimon J. Gerraty	\ Record version.
685*0957b409SSimon J. Gerraty	version addr-version resume check-resume
686*0957b409SSimon J. Gerraty
687*0957b409SSimon J. Gerraty	\ Cipher suite. We check that it is part of the list of cipher
688*0957b409SSimon J. Gerraty	\ suites that we advertised.
689*0957b409SSimon J. Gerraty	read16
690*0957b409SSimon J. Gerraty	dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then
691*0957b409SSimon J. Gerraty	\ Also check that the cipher suite is compatible with the
692*0957b409SSimon J. Gerraty	\ announced version: suites that don't use HMAC/SHA-1 are
693*0957b409SSimon J. Gerraty	\ for TLS-1.2 only, not older versions.
694*0957b409SSimon J. Gerraty	dup use-tls12? version 0x0303 < and if ERR_BAD_CIPHER_SUITE fail then
695*0957b409SSimon J. Gerraty	addr-cipher_suite resume check-resume
696*0957b409SSimon J. Gerraty
697*0957b409SSimon J. Gerraty	\ Compression method. Should be 0 (no compression).
698*0957b409SSimon J. Gerraty	read8 if ERR_BAD_COMPRESSION fail then
699*0957b409SSimon J. Gerraty
700*0957b409SSimon J. Gerraty	\ Parse extensions (if any). If there is no extension, then the
701*0957b409SSimon J. Gerraty	\ read limit (on the TOS) should be 0 at that point.
702*0957b409SSimon J. Gerraty	dup if
703*0957b409SSimon J. Gerraty		\ Length of extension list.
704*0957b409SSimon J. Gerraty		\ message size.
705*0957b409SSimon J. Gerraty		read16 open-elt
706*0957b409SSimon J. Gerraty
707*0957b409SSimon J. Gerraty		\ Enumerate extensions. For each of them, check that we
708*0957b409SSimon J. Gerraty		\ sent an extension of that type, and did not see it
709*0957b409SSimon J. Gerraty		\ yet; and then process it.
710*0957b409SSimon J. Gerraty		ext-sni-length { ok-sni }
711*0957b409SSimon J. Gerraty		ext-reneg-length { ok-reneg }
712*0957b409SSimon J. Gerraty		ext-frag-length { ok-frag }
713*0957b409SSimon J. Gerraty		ext-signatures-length { ok-signatures }
714*0957b409SSimon J. Gerraty		ext-supported-curves-length { ok-curves }
715*0957b409SSimon J. Gerraty		ext-point-format-length { ok-points }
716*0957b409SSimon J. Gerraty		ext-ALPN-length { ok-ALPN }
717*0957b409SSimon J. Gerraty		begin dup while
718*0957b409SSimon J. Gerraty			read16
719*0957b409SSimon J. Gerraty			case
720*0957b409SSimon J. Gerraty				\ Server Name Indication. The server may
721*0957b409SSimon J. Gerraty				\ send such an extension if it uses the SNI
722*0957b409SSimon J. Gerraty				\ from the client, but that "response
723*0957b409SSimon J. Gerraty				\ extension" is supposed to be empty.
724*0957b409SSimon J. Gerraty				0x0000 of
725*0957b409SSimon J. Gerraty					ok-sni ifnot
726*0957b409SSimon J. Gerraty						ERR_EXTRA_EXTENSION fail
727*0957b409SSimon J. Gerraty					then
728*0957b409SSimon J. Gerraty					0 >ok-sni
729*0957b409SSimon J. Gerraty					read-server-sni
730*0957b409SSimon J. Gerraty				endof
731*0957b409SSimon J. Gerraty
732*0957b409SSimon J. Gerraty				\ Max Frag Length. The contents shall be
733*0957b409SSimon J. Gerraty				\ a single byte whose value matches the one
734*0957b409SSimon J. Gerraty				\ sent by the client.
735*0957b409SSimon J. Gerraty				0x0001 of
736*0957b409SSimon J. Gerraty					ok-frag ifnot
737*0957b409SSimon J. Gerraty						ERR_EXTRA_EXTENSION fail
738*0957b409SSimon J. Gerraty					then
739*0957b409SSimon J. Gerraty					0 >ok-frag
740*0957b409SSimon J. Gerraty					read-server-frag
741*0957b409SSimon J. Gerraty				endof
742*0957b409SSimon J. Gerraty
743*0957b409SSimon J. Gerraty				\ Secure Renegotiation.
744*0957b409SSimon J. Gerraty				0xFF01 of
745*0957b409SSimon J. Gerraty					ok-reneg ifnot
746*0957b409SSimon J. Gerraty						ERR_EXTRA_EXTENSION fail
747*0957b409SSimon J. Gerraty					then
748*0957b409SSimon J. Gerraty					0 >ok-reneg
749*0957b409SSimon J. Gerraty					read-server-reneg
750*0957b409SSimon J. Gerraty				endof
751*0957b409SSimon J. Gerraty
752*0957b409SSimon J. Gerraty				\ Signature Algorithms.
753*0957b409SSimon J. Gerraty				\ Normally, the server should never send this
754*0957b409SSimon J. Gerraty				\ extension (so says RFC 5246 #7.4.1.4.1),
755*0957b409SSimon J. Gerraty				\ but some existing servers do.
756*0957b409SSimon J. Gerraty				0x000D of
757*0957b409SSimon J. Gerraty					ok-signatures ifnot
758*0957b409SSimon J. Gerraty						ERR_EXTRA_EXTENSION fail
759*0957b409SSimon J. Gerraty					then
760*0957b409SSimon J. Gerraty					0 >ok-signatures
761*0957b409SSimon J. Gerraty					read-ignore-16
762*0957b409SSimon J. Gerraty				endof
763*0957b409SSimon J. Gerraty
764*0957b409SSimon J. Gerraty				\ Supported Curves.
765*0957b409SSimon J. Gerraty				0x000A of
766*0957b409SSimon J. Gerraty					ok-curves ifnot
767*0957b409SSimon J. Gerraty						ERR_EXTRA_EXTENSION fail
768*0957b409SSimon J. Gerraty					then
769*0957b409SSimon J. Gerraty					0 >ok-curves
770*0957b409SSimon J. Gerraty					read-ignore-16
771*0957b409SSimon J. Gerraty				endof
772*0957b409SSimon J. Gerraty
773*0957b409SSimon J. Gerraty				\ Supported Point Formats.
774*0957b409SSimon J. Gerraty				0x000B of
775*0957b409SSimon J. Gerraty					ok-points ifnot
776*0957b409SSimon J. Gerraty						ERR_EXTRA_EXTENSION fail
777*0957b409SSimon J. Gerraty					then
778*0957b409SSimon J. Gerraty					0 >ok-points
779*0957b409SSimon J. Gerraty					read-ignore-16
780*0957b409SSimon J. Gerraty				endof
781*0957b409SSimon J. Gerraty
782*0957b409SSimon J. Gerraty				\ ALPN.
783*0957b409SSimon J. Gerraty				0x0010 of
784*0957b409SSimon J. Gerraty					ok-ALPN ifnot
785*0957b409SSimon J. Gerraty						ERR_EXTRA_EXTENSION fail
786*0957b409SSimon J. Gerraty					then
787*0957b409SSimon J. Gerraty					0 >ok-ALPN
788*0957b409SSimon J. Gerraty					read-ALPN-from-server
789*0957b409SSimon J. Gerraty				endof
790*0957b409SSimon J. Gerraty
791*0957b409SSimon J. Gerraty				ERR_EXTRA_EXTENSION fail
792*0957b409SSimon J. Gerraty			endcase
793*0957b409SSimon J. Gerraty		repeat
794*0957b409SSimon J. Gerraty
795*0957b409SSimon J. Gerraty		\ If we sent a secure renegotiation extension but did not
796*0957b409SSimon J. Gerraty		\ receive a response, then the server does not support
797*0957b409SSimon J. Gerraty		\ secure renegotiation. This is a hard failure if this
798*0957b409SSimon J. Gerraty		\ is a renegotiation.
799*0957b409SSimon J. Gerraty		ok-reneg if
800*0957b409SSimon J. Gerraty			ok-reneg 5 > if ERR_BAD_SECRENEG fail then
801*0957b409SSimon J. Gerraty			1 addr-reneg set8
802*0957b409SSimon J. Gerraty		then
803*0957b409SSimon J. Gerraty		close-elt
804*0957b409SSimon J. Gerraty	else
805*0957b409SSimon J. Gerraty		\ No extension received at all, so the server does not
806*0957b409SSimon J. Gerraty		\ support secure renegotiation. This is a hard failure
807*0957b409SSimon J. Gerraty		\ if the server was previously known to support it (i.e.
808*0957b409SSimon J. Gerraty		\ this is a renegotiation).
809*0957b409SSimon J. Gerraty		ext-reneg-length 5 > if ERR_BAD_SECRENEG fail then
810*0957b409SSimon J. Gerraty		1 addr-reneg set8
811*0957b409SSimon J. Gerraty	then
812*0957b409SSimon J. Gerraty	close-elt
813*0957b409SSimon J. Gerraty	resume
814*0957b409SSimon J. Gerraty	;
815*0957b409SSimon J. Gerraty
816*0957b409SSimon J. Gerratycc: set-server-curve ( -- ) {
817*0957b409SSimon J. Gerraty	const br_x509_class *xc;
818*0957b409SSimon J. Gerraty	const br_x509_pkey *pk;
819*0957b409SSimon J. Gerraty
820*0957b409SSimon J. Gerraty	xc = *(ENG->x509ctx);
821*0957b409SSimon J. Gerraty	pk = xc->get_pkey(ENG->x509ctx, NULL);
822*0957b409SSimon J. Gerraty	CTX->server_curve =
823*0957b409SSimon J. Gerraty		(pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0;
824*0957b409SSimon J. Gerraty}
825*0957b409SSimon J. Gerraty
826*0957b409SSimon J. Gerraty\ Read Certificate message from server.
827*0957b409SSimon J. Gerraty: read-Certificate-from-server ( -- )
828*0957b409SSimon J. Gerraty	addr-cipher_suite get16 expected-key-type
829*0957b409SSimon J. Gerraty	-1 read-Certificate
830*0957b409SSimon J. Gerraty	dup 0< if neg fail then
831*0957b409SSimon J. Gerraty	dup ifnot ERR_UNEXPECTED fail then
832*0957b409SSimon J. Gerraty	over and <> if ERR_WRONG_KEY_USAGE fail then
833*0957b409SSimon J. Gerraty
834*0957b409SSimon J. Gerraty	\ Set server curve (used for static ECDH).
835*0957b409SSimon J. Gerraty	set-server-curve ;
836*0957b409SSimon J. Gerraty
837*0957b409SSimon J. Gerraty\ Verify signature on ECDHE point sent by the server.
838*0957b409SSimon J. Gerraty\   'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1)
839*0957b409SSimon J. Gerraty\   'use-rsa' is 0 for ECDSA, -1 for for RSA
840*0957b409SSimon J. Gerraty\   'sig-len' is the signature length (in bytes)
841*0957b409SSimon J. Gerraty\ The signature itself is in the pad.
842*0957b409SSimon J. Gerratycc: verify-SKE-sig ( hash use-rsa sig-len -- err ) {
843*0957b409SSimon J. Gerraty	size_t sig_len = T0_POP();
844*0957b409SSimon J. Gerraty	int use_rsa = T0_POPi();
845*0957b409SSimon J. Gerraty	int hash = T0_POPi();
846*0957b409SSimon J. Gerraty
847*0957b409SSimon J. Gerraty	T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
848*0957b409SSimon J. Gerraty}
849*0957b409SSimon J. Gerraty
850*0957b409SSimon J. Gerraty\ Parse ServerKeyExchange
851*0957b409SSimon J. Gerraty: read-ServerKeyExchange ( -- )
852*0957b409SSimon J. Gerraty	\ Get header, and check message type.
853*0957b409SSimon J. Gerraty	read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then
854*0957b409SSimon J. Gerraty
855*0957b409SSimon J. Gerraty	\ We expect a named curve, and we must support it.
856*0957b409SSimon J. Gerraty	read8 3 = ifnot ERR_INVALID_ALGORITHM fail then
857*0957b409SSimon J. Gerraty	read16 dup addr-ecdhe_curve set8
858*0957b409SSimon J. Gerraty	dup 32 >= if ERR_INVALID_ALGORITHM fail then
859*0957b409SSimon J. Gerraty	supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then
860*0957b409SSimon J. Gerraty
861*0957b409SSimon J. Gerraty	\ Read the server point.
862*0957b409SSimon J. Gerraty	read8
863*0957b409SSimon J. Gerraty	dup 133 > if ERR_INVALID_ALGORITHM fail then
864*0957b409SSimon J. Gerraty	dup addr-ecdhe_point_len set8
865*0957b409SSimon J. Gerraty	addr-ecdhe_point swap read-blob
866*0957b409SSimon J. Gerraty
867*0957b409SSimon J. Gerraty	\ If using TLS-1.2+, then the hash function and signature algorithm
868*0957b409SSimon J. Gerraty	\ are explicitly provided; the signature algorithm must match what
869*0957b409SSimon J. Gerraty	\ the cipher suite specifies. With TLS-1.0 and 1.1, the signature
870*0957b409SSimon J. Gerraty	\ algorithm is inferred from the cipher suite, and the hash is
871*0957b409SSimon J. Gerraty	\ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA).
872*0957b409SSimon J. Gerraty	addr-version get16 0x0303 >= { tls1.2+ }
873*0957b409SSimon J. Gerraty	addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa }
874*0957b409SSimon J. Gerraty	2 { hash }
875*0957b409SSimon J. Gerraty	tls1.2+ if
876*0957b409SSimon J. Gerraty		\ Read hash function; accept only the SHA-* identifiers
877*0957b409SSimon J. Gerraty		\ (from SHA-1 to SHA-512, no MD5 here).
878*0957b409SSimon J. Gerraty		read8
879*0957b409SSimon J. Gerraty		dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then
880*0957b409SSimon J. Gerraty		>hash
881*0957b409SSimon J. Gerraty		read8
882*0957b409SSimon J. Gerraty		\ Get expected signature algorithm and compare with what
883*0957b409SSimon J. Gerraty		\ the server just sent. Expected value is 1 for RSA, 3
884*0957b409SSimon J. Gerraty		\ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA,
885*0957b409SSimon J. Gerraty		\ 0 for ECDSA.
886*0957b409SSimon J. Gerraty		use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then
887*0957b409SSimon J. Gerraty	else
888*0957b409SSimon J. Gerraty		\ For MD5+SHA-1, we set 'hash' to 0.
889*0957b409SSimon J. Gerraty		use-rsa if 0 >hash then
890*0957b409SSimon J. Gerraty	then
891*0957b409SSimon J. Gerraty
892*0957b409SSimon J. Gerraty	\ Read signature into the pad.
893*0957b409SSimon J. Gerraty	read16 dup { sig-len }
894*0957b409SSimon J. Gerraty
895*0957b409SSimon J. Gerraty	dup 512 > if ERR_LIMIT_EXCEEDED fail then
896*0957b409SSimon J. Gerraty	addr-pad swap read-blob
897*0957b409SSimon J. Gerraty
898*0957b409SSimon J. Gerraty	\ Verify signature.
899*0957b409SSimon J. Gerraty	hash use-rsa sig-len verify-SKE-sig
900*0957b409SSimon J. Gerraty	dup if fail then drop
901*0957b409SSimon J. Gerraty
902*0957b409SSimon J. Gerraty	close-elt ;
903*0957b409SSimon J. Gerraty
904*0957b409SSimon J. Gerraty\ Client certificate: start processing of anchor names.
905*0957b409SSimon J. Gerratycc: anchor-dn-start-name-list ( -- ) {
906*0957b409SSimon J. Gerraty	if (CTX->client_auth_vtable != NULL) {
907*0957b409SSimon J. Gerraty		(*CTX->client_auth_vtable)->start_name_list(
908*0957b409SSimon J. Gerraty			CTX->client_auth_vtable);
909*0957b409SSimon J. Gerraty	}
910*0957b409SSimon J. Gerraty}
911*0957b409SSimon J. Gerraty
912*0957b409SSimon J. Gerraty\ Client certificate: start a new anchor DN (length is 16-bit).
913*0957b409SSimon J. Gerratycc: anchor-dn-start-name ( length -- ) {
914*0957b409SSimon J. Gerraty	size_t len;
915*0957b409SSimon J. Gerraty
916*0957b409SSimon J. Gerraty	len = T0_POP();
917*0957b409SSimon J. Gerraty	if (CTX->client_auth_vtable != NULL) {
918*0957b409SSimon J. Gerraty		(*CTX->client_auth_vtable)->start_name(
919*0957b409SSimon J. Gerraty			CTX->client_auth_vtable, len);
920*0957b409SSimon J. Gerraty	}
921*0957b409SSimon J. Gerraty}
922*0957b409SSimon J. Gerraty
923*0957b409SSimon J. Gerraty\ Client certificate: push some data for current anchor DN.
924*0957b409SSimon J. Gerratycc: anchor-dn-append-name ( length -- ) {
925*0957b409SSimon J. Gerraty	size_t len;
926*0957b409SSimon J. Gerraty
927*0957b409SSimon J. Gerraty	len = T0_POP();
928*0957b409SSimon J. Gerraty	if (CTX->client_auth_vtable != NULL) {
929*0957b409SSimon J. Gerraty		(*CTX->client_auth_vtable)->append_name(
930*0957b409SSimon J. Gerraty			CTX->client_auth_vtable, ENG->pad, len);
931*0957b409SSimon J. Gerraty	}
932*0957b409SSimon J. Gerraty}
933*0957b409SSimon J. Gerraty
934*0957b409SSimon J. Gerraty\ Client certificate: end current anchor DN.
935*0957b409SSimon J. Gerratycc: anchor-dn-end-name ( -- ) {
936*0957b409SSimon J. Gerraty	if (CTX->client_auth_vtable != NULL) {
937*0957b409SSimon J. Gerraty		(*CTX->client_auth_vtable)->end_name(
938*0957b409SSimon J. Gerraty			CTX->client_auth_vtable);
939*0957b409SSimon J. Gerraty	}
940*0957b409SSimon J. Gerraty}
941*0957b409SSimon J. Gerraty
942*0957b409SSimon J. Gerraty\ Client certificate: end list of anchor DN.
943*0957b409SSimon J. Gerratycc: anchor-dn-end-name-list ( -- ) {
944*0957b409SSimon J. Gerraty	if (CTX->client_auth_vtable != NULL) {
945*0957b409SSimon J. Gerraty		(*CTX->client_auth_vtable)->end_name_list(
946*0957b409SSimon J. Gerraty			CTX->client_auth_vtable);
947*0957b409SSimon J. Gerraty	}
948*0957b409SSimon J. Gerraty}
949*0957b409SSimon J. Gerraty
950*0957b409SSimon J. Gerraty\ Client certificate: obtain the client certificate chain.
951*0957b409SSimon J. Gerratycc: get-client-chain ( auth_types -- ) {
952*0957b409SSimon J. Gerraty	uint32_t auth_types;
953*0957b409SSimon J. Gerraty
954*0957b409SSimon J. Gerraty	auth_types = T0_POP();
955*0957b409SSimon J. Gerraty	if (CTX->client_auth_vtable != NULL) {
956*0957b409SSimon J. Gerraty		br_ssl_client_certificate ux;
957*0957b409SSimon J. Gerraty
958*0957b409SSimon J. Gerraty		(*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable,
959*0957b409SSimon J. Gerraty			CTX, auth_types, &ux);
960*0957b409SSimon J. Gerraty		CTX->auth_type = (unsigned char)ux.auth_type;
961*0957b409SSimon J. Gerraty		CTX->hash_id = (unsigned char)ux.hash_id;
962*0957b409SSimon J. Gerraty		ENG->chain = ux.chain;
963*0957b409SSimon J. Gerraty		ENG->chain_len = ux.chain_len;
964*0957b409SSimon J. Gerraty	} else {
965*0957b409SSimon J. Gerraty		CTX->hash_id = 0;
966*0957b409SSimon J. Gerraty		ENG->chain_len = 0;
967*0957b409SSimon J. Gerraty	}
968*0957b409SSimon J. Gerraty}
969*0957b409SSimon J. Gerraty
970*0957b409SSimon J. Gerraty\ Parse CertificateRequest. Header has already been read.
971*0957b409SSimon J. Gerraty: read-contents-CertificateRequest ( lim -- )
972*0957b409SSimon J. Gerraty	\ Read supported client authentication types. We keep only
973*0957b409SSimon J. Gerraty	\ RSA, ECDSA, and ECDH.
974*0957b409SSimon J. Gerraty	0 { auth_types }
975*0957b409SSimon J. Gerraty	read8 open-elt
976*0957b409SSimon J. Gerraty	begin dup while
977*0957b409SSimon J. Gerraty		read8 case
978*0957b409SSimon J. Gerraty			1  of 0x0000FF endof
979*0957b409SSimon J. Gerraty			64 of 0x00FF00 endof
980*0957b409SSimon J. Gerraty			65 of 0x010000 endof
981*0957b409SSimon J. Gerraty			66 of 0x020000 endof
982*0957b409SSimon J. Gerraty			0 swap
983*0957b409SSimon J. Gerraty		endcase
984*0957b409SSimon J. Gerraty		auth_types or >auth_types
985*0957b409SSimon J. Gerraty	repeat
986*0957b409SSimon J. Gerraty	close-elt
987*0957b409SSimon J. Gerraty
988*0957b409SSimon J. Gerraty	\ Full static ECDH is allowed only if the cipher suite is ECDH
989*0957b409SSimon J. Gerraty	\ (not ECDHE). It would be theoretically feasible to use static
990*0957b409SSimon J. Gerraty	\ ECDH on the client side with an ephemeral key pair from the
991*0957b409SSimon J. Gerraty	\ server, but RFC 4492 (section 3) forbids it because ECDHE suites
992*0957b409SSimon J. Gerraty	\ are supposed to provide forward secrecy, and static ECDH would
993*0957b409SSimon J. Gerraty	\ negate that property.
994*0957b409SSimon J. Gerraty	addr-cipher_suite get16 use-ecdh? ifnot
995*0957b409SSimon J. Gerraty		auth_types 0xFFFF and >auth_types
996*0957b409SSimon J. Gerraty	then
997*0957b409SSimon J. Gerraty
998*0957b409SSimon J. Gerraty	\ Note: if the cipher suite is ECDH, then the X.509 validation
999*0957b409SSimon J. Gerraty	\ engine was invoked with the BR_KEYTYPE_EC | BR_KEYTYPE_KEYX
1000*0957b409SSimon J. Gerraty	\ combination, so the server's public key has already been
1001*0957b409SSimon J. Gerraty	\ checked to be fit for a key exchange.
1002*0957b409SSimon J. Gerraty
1003*0957b409SSimon J. Gerraty	\ With TLS 1.2:
1004*0957b409SSimon J. Gerraty	\  - rsa_fixed_ecdh and ecdsa_fixed_ecdh are synoymous.
1005*0957b409SSimon J. Gerraty	\  - There is an explicit list of supported sign+hash.
1006*0957b409SSimon J. Gerraty	\ With TLS 1.0,
1007*0957b409SSimon J. Gerraty	addr-version get16 0x0303 >= if
1008*0957b409SSimon J. Gerraty		\ With TLS 1.2:
1009*0957b409SSimon J. Gerraty		\  - There is an explicit list of supported sign+hash.
1010*0957b409SSimon J. Gerraty		\  - The ECDH flags must be adjusted for RSA/ECDSA
1011*0957b409SSimon J. Gerraty		\    support.
1012*0957b409SSimon J. Gerraty		read-list-sign-algos dup addr-hashes set32
1013*0957b409SSimon J. Gerraty
1014*0957b409SSimon J. Gerraty		\ Trim down the list depending on what hash functions
1015*0957b409SSimon J. Gerraty		\ we support (since the hashing itself is done by the SSL
1016*0957b409SSimon J. Gerraty		\ engine, not by the certificate handler).
1017*0957b409SSimon J. Gerraty		supported-hash-functions drop dup 8 << or 0x030000 or and
1018*0957b409SSimon J. Gerraty
1019*0957b409SSimon J. Gerraty		auth_types and
1020*0957b409SSimon J. Gerraty		auth_types 0x030000 and if
1021*0957b409SSimon J. Gerraty			dup 0x0000FF and if 0x010000 or then
1022*0957b409SSimon J. Gerraty			dup 0x00FF00 and if 0x020000 or then
1023*0957b409SSimon J. Gerraty		then
1024*0957b409SSimon J. Gerraty		>auth_types
1025*0957b409SSimon J. Gerraty	else
1026*0957b409SSimon J. Gerraty		\ TLS 1.0 or 1.1. The hash function is fixed for signatures
1027*0957b409SSimon J. Gerraty		\ (MD5+SHA-1 for RSA, SHA-1 for ECDSA).
1028*0957b409SSimon J. Gerraty		auth_types 0x030401 and >auth_types
1029*0957b409SSimon J. Gerraty	then
1030*0957b409SSimon J. Gerraty
1031*0957b409SSimon J. Gerraty	\ Parse list of anchor DN.
1032*0957b409SSimon J. Gerraty	anchor-dn-start-name-list
1033*0957b409SSimon J. Gerraty	read16 open-elt
1034*0957b409SSimon J. Gerraty	begin dup while
1035*0957b409SSimon J. Gerraty		read16 open-elt
1036*0957b409SSimon J. Gerraty		dup anchor-dn-start-name
1037*0957b409SSimon J. Gerraty
1038*0957b409SSimon J. Gerraty		\ We read the DN by chunks through the pad, so
1039*0957b409SSimon J. Gerraty		\ as to use the existing reading function (read-blob)
1040*0957b409SSimon J. Gerraty		\ that also ensures proper hashing.
1041*0957b409SSimon J. Gerraty		begin
1042*0957b409SSimon J. Gerraty			dup while
1043*0957b409SSimon J. Gerraty			dup 256 > if 256 else dup then { len }
1044*0957b409SSimon J. Gerraty			addr-pad len read-blob
1045*0957b409SSimon J. Gerraty			len anchor-dn-append-name
1046*0957b409SSimon J. Gerraty		repeat
1047*0957b409SSimon J. Gerraty		close-elt
1048*0957b409SSimon J. Gerraty		anchor-dn-end-name
1049*0957b409SSimon J. Gerraty	repeat
1050*0957b409SSimon J. Gerraty	close-elt
1051*0957b409SSimon J. Gerraty	anchor-dn-end-name-list
1052*0957b409SSimon J. Gerraty
1053*0957b409SSimon J. Gerraty	\ We should have reached the message end.
1054*0957b409SSimon J. Gerraty	close-elt
1055*0957b409SSimon J. Gerraty
1056*0957b409SSimon J. Gerraty	\ Obtain the client chain.
1057*0957b409SSimon J. Gerraty	auth_types get-client-chain
1058*0957b409SSimon J. Gerraty	;
1059*0957b409SSimon J. Gerraty
1060*0957b409SSimon J. Gerraty\ (obsolete)
1061*0957b409SSimon J. Gerraty\ Write an empty Certificate message.
1062*0957b409SSimon J. Gerraty\ : write-empty-Certificate ( -- )
1063*0957b409SSimon J. Gerraty\ 	11 write8 3 write24 0 write24 ;
1064*0957b409SSimon J. Gerraty
1065*0957b409SSimon J. Gerratycc: do-rsa-encrypt ( prf_id -- nlen ) {
1066*0957b409SSimon J. Gerraty	int x;
1067*0957b409SSimon J. Gerraty
1068*0957b409SSimon J. Gerraty	x = make_pms_rsa(CTX, T0_POP());
1069*0957b409SSimon J. Gerraty	if (x < 0) {
1070*0957b409SSimon J. Gerraty		br_ssl_engine_fail(ENG, -x);
1071*0957b409SSimon J. Gerraty		T0_CO();
1072*0957b409SSimon J. Gerraty	} else {
1073*0957b409SSimon J. Gerraty		T0_PUSH(x);
1074*0957b409SSimon J. Gerraty	}
1075*0957b409SSimon J. Gerraty}
1076*0957b409SSimon J. Gerraty
1077*0957b409SSimon J. Gerratycc: do-ecdh ( echde prf_id -- ulen ) {
1078*0957b409SSimon J. Gerraty	unsigned prf_id = T0_POP();
1079*0957b409SSimon J. Gerraty	unsigned ecdhe = T0_POP();
1080*0957b409SSimon J. Gerraty	int x;
1081*0957b409SSimon J. Gerraty
1082*0957b409SSimon J. Gerraty	x = make_pms_ecdh(CTX, ecdhe, prf_id);
1083*0957b409SSimon J. Gerraty	if (x < 0) {
1084*0957b409SSimon J. Gerraty		br_ssl_engine_fail(ENG, -x);
1085*0957b409SSimon J. Gerraty		T0_CO();
1086*0957b409SSimon J. Gerraty	} else {
1087*0957b409SSimon J. Gerraty		T0_PUSH(x);
1088*0957b409SSimon J. Gerraty	}
1089*0957b409SSimon J. Gerraty}
1090*0957b409SSimon J. Gerraty
1091*0957b409SSimon J. Gerratycc: do-static-ecdh ( prf-id -- ) {
1092*0957b409SSimon J. Gerraty	unsigned prf_id = T0_POP();
1093*0957b409SSimon J. Gerraty
1094*0957b409SSimon J. Gerraty	if (make_pms_static_ecdh(CTX, prf_id) < 0) {
1095*0957b409SSimon J. Gerraty		br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
1096*0957b409SSimon J. Gerraty		T0_CO();
1097*0957b409SSimon J. Gerraty	}
1098*0957b409SSimon J. Gerraty}
1099*0957b409SSimon J. Gerraty
1100*0957b409SSimon J. Gerratycc: do-client-sign ( -- sig_len ) {
1101*0957b409SSimon J. Gerraty	size_t sig_len;
1102*0957b409SSimon J. Gerraty
1103*0957b409SSimon J. Gerraty	sig_len = make_client_sign(CTX);
1104*0957b409SSimon J. Gerraty	if (sig_len == 0) {
1105*0957b409SSimon J. Gerraty		br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
1106*0957b409SSimon J. Gerraty		T0_CO();
1107*0957b409SSimon J. Gerraty	}
1108*0957b409SSimon J. Gerraty	T0_PUSH(sig_len);
1109*0957b409SSimon J. Gerraty}
1110*0957b409SSimon J. Gerraty
1111*0957b409SSimon J. Gerraty\ Write ClientKeyExchange.
1112*0957b409SSimon J. Gerraty: write-ClientKeyExchange ( -- )
1113*0957b409SSimon J. Gerraty	16 write8
1114*0957b409SSimon J. Gerraty	addr-cipher_suite get16
1115*0957b409SSimon J. Gerraty	dup use-rsa-keyx? if
1116*0957b409SSimon J. Gerraty		prf-id do-rsa-encrypt
1117*0957b409SSimon J. Gerraty		dup 2+ write24
1118*0957b409SSimon J. Gerraty		dup write16
1119*0957b409SSimon J. Gerraty		addr-pad swap write-blob
1120*0957b409SSimon J. Gerraty	else
1121*0957b409SSimon J. Gerraty		dup use-ecdhe? swap prf-id do-ecdh
1122*0957b409SSimon J. Gerraty		dup 1+ write24
1123*0957b409SSimon J. Gerraty		dup write8
1124*0957b409SSimon J. Gerraty		addr-pad swap write-blob
1125*0957b409SSimon J. Gerraty	then ;
1126*0957b409SSimon J. Gerraty
1127*0957b409SSimon J. Gerraty\ Write CertificateVerify. This is invoked only if a client certificate
1128*0957b409SSimon J. Gerraty\ was requested and sent, and the authentication is not full static ECDH.
1129*0957b409SSimon J. Gerraty: write-CertificateVerify ( -- )
1130*0957b409SSimon J. Gerraty	do-client-sign
1131*0957b409SSimon J. Gerraty	15 write8 dup
1132*0957b409SSimon J. Gerraty	addr-version get16 0x0303 >= if
1133*0957b409SSimon J. Gerraty		4 + write24
1134*0957b409SSimon J. Gerraty		addr-hash_id get8 write8
1135*0957b409SSimon J. Gerraty		addr-auth_type get8 write8
1136*0957b409SSimon J. Gerraty	else
1137*0957b409SSimon J. Gerraty		2+ write24
1138*0957b409SSimon J. Gerraty	then
1139*0957b409SSimon J. Gerraty	dup write16 addr-pad swap write-blob ;
1140*0957b409SSimon J. Gerraty
1141*0957b409SSimon J. Gerraty\ =======================================================================
1142*0957b409SSimon J. Gerraty
1143*0957b409SSimon J. Gerraty\ Perform a handshake.
1144*0957b409SSimon J. Gerraty: do-handshake ( -- )
1145*0957b409SSimon J. Gerraty	0 addr-application_data set8
1146*0957b409SSimon J. Gerraty	22 addr-record_type_out set8
1147*0957b409SSimon J. Gerraty	0 addr-selected_protocol set16
1148*0957b409SSimon J. Gerraty	multihash-init
1149*0957b409SSimon J. Gerraty
1150*0957b409SSimon J. Gerraty	write-ClientHello
1151*0957b409SSimon J. Gerraty	flush-record
1152*0957b409SSimon J. Gerraty	read-ServerHello
1153*0957b409SSimon J. Gerraty
1154*0957b409SSimon J. Gerraty	if
1155*0957b409SSimon J. Gerraty		\ Session resumption.
1156*0957b409SSimon J. Gerraty		-1 read-CCS-Finished
1157*0957b409SSimon J. Gerraty		-1 write-CCS-Finished
1158*0957b409SSimon J. Gerraty
1159*0957b409SSimon J. Gerraty	else
1160*0957b409SSimon J. Gerraty
1161*0957b409SSimon J. Gerraty		\ Not a session resumption.
1162*0957b409SSimon J. Gerraty
1163*0957b409SSimon J. Gerraty		\ Read certificate; then check key type and usages against
1164*0957b409SSimon J. Gerraty		\ cipher suite.
1165*0957b409SSimon J. Gerraty		read-Certificate-from-server
1166*0957b409SSimon J. Gerraty
1167*0957b409SSimon J. Gerraty		\ Depending on cipher suite, we may now expect a
1168*0957b409SSimon J. Gerraty		\ ServerKeyExchange.
1169*0957b409SSimon J. Gerraty		addr-cipher_suite get16 expected-key-type
1170*0957b409SSimon J. Gerraty		CX 0 63 { BR_KEYTYPE_SIGN } and if
1171*0957b409SSimon J. Gerraty			read-ServerKeyExchange
1172*0957b409SSimon J. Gerraty		then
1173*0957b409SSimon J. Gerraty
1174*0957b409SSimon J. Gerraty		\ Get next header.
1175*0957b409SSimon J. Gerraty		read-handshake-header
1176*0957b409SSimon J. Gerraty
1177*0957b409SSimon J. Gerraty		\ If this is a CertificateRequest, parse it, then read
1178*0957b409SSimon J. Gerraty		\ next header.
1179*0957b409SSimon J. Gerraty		dup 13 = if
1180*0957b409SSimon J. Gerraty			drop read-contents-CertificateRequest
1181*0957b409SSimon J. Gerraty			read-handshake-header
1182*0957b409SSimon J. Gerraty			-1
1183*0957b409SSimon J. Gerraty		else
1184*0957b409SSimon J. Gerraty			0
1185*0957b409SSimon J. Gerraty		then
1186*0957b409SSimon J. Gerraty		{ seen-CR }
1187*0957b409SSimon J. Gerraty
1188*0957b409SSimon J. Gerraty		\ At that point, we should have a ServerHelloDone,
1189*0957b409SSimon J. Gerraty		\ whose length must be 0.
1190*0957b409SSimon J. Gerraty		14 = ifnot ERR_UNEXPECTED fail then
1191*0957b409SSimon J. Gerraty		if ERR_BAD_HELLO_DONE fail then
1192*0957b409SSimon J. Gerraty
1193*0957b409SSimon J. Gerraty		\ There should not be more bytes in the record at that point.
1194*0957b409SSimon J. Gerraty		more-incoming-bytes? if ERR_UNEXPECTED fail then
1195*0957b409SSimon J. Gerraty
1196*0957b409SSimon J. Gerraty		seen-CR if
1197*0957b409SSimon J. Gerraty			\ If the server requested a client certificate, then
1198*0957b409SSimon J. Gerraty			\ we must write a Certificate message (it may be
1199*0957b409SSimon J. Gerraty			\ empty).
1200*0957b409SSimon J. Gerraty			write-Certificate
1201*0957b409SSimon J. Gerraty
1202*0957b409SSimon J. Gerraty			\ If using static ECDH, then the ClientKeyExchange
1203*0957b409SSimon J. Gerraty			\ is empty, and there is no CertificateVerify.
1204*0957b409SSimon J. Gerraty			\ Otherwise, there is a ClientKeyExchange; there
1205*0957b409SSimon J. Gerraty			\ will then be a CertificateVerify if a client chain
1206*0957b409SSimon J. Gerraty			\ was indeed sent.
1207*0957b409SSimon J. Gerraty			addr-hash_id get8 0xFF = if
1208*0957b409SSimon J. Gerraty				drop
1209*0957b409SSimon J. Gerraty				16 write8 0 write24
1210*0957b409SSimon J. Gerraty				addr-cipher_suite get16 prf-id do-static-ecdh
1211*0957b409SSimon J. Gerraty			else
1212*0957b409SSimon J. Gerraty				write-ClientKeyExchange
1213*0957b409SSimon J. Gerraty				if write-CertificateVerify then
1214*0957b409SSimon J. Gerraty			then
1215*0957b409SSimon J. Gerraty		else
1216*0957b409SSimon J. Gerraty			write-ClientKeyExchange
1217*0957b409SSimon J. Gerraty		then
1218*0957b409SSimon J. Gerraty
1219*0957b409SSimon J. Gerraty		-1 write-CCS-Finished
1220*0957b409SSimon J. Gerraty		-1 read-CCS-Finished
1221*0957b409SSimon J. Gerraty	then
1222*0957b409SSimon J. Gerraty
1223*0957b409SSimon J. Gerraty	\ Now we should be invoked only in case of renegotiation.
1224*0957b409SSimon J. Gerraty	1 addr-application_data set8
1225*0957b409SSimon J. Gerraty	23 addr-record_type_out set8 ;
1226*0957b409SSimon J. Gerraty
1227*0957b409SSimon J. Gerraty\ Read a HelloRequest message.
1228*0957b409SSimon J. Gerraty: read-HelloRequest ( -- )
1229*0957b409SSimon J. Gerraty	\ A HelloRequest has length 0 and type 0.
1230*0957b409SSimon J. Gerraty	read-handshake-header-core
1231*0957b409SSimon J. Gerraty	if ERR_UNEXPECTED fail then
1232*0957b409SSimon J. Gerraty	if ERR_BAD_HANDSHAKE fail then ;
1233*0957b409SSimon J. Gerraty
1234*0957b409SSimon J. Gerraty\ Entry point.
1235*0957b409SSimon J. Gerraty: main ( -- ! )
1236*0957b409SSimon J. Gerraty	\ Perform initial handshake.
1237*0957b409SSimon J. Gerraty	do-handshake
1238*0957b409SSimon J. Gerraty
1239*0957b409SSimon J. Gerraty	begin
1240*0957b409SSimon J. Gerraty		\ Wait for further invocation. At that point, we should
1241*0957b409SSimon J. Gerraty		\ get either an explicit call for renegotiation, or
1242*0957b409SSimon J. Gerraty		\ an incoming HelloRequest handshake message.
1243*0957b409SSimon J. Gerraty		wait-co
1244*0957b409SSimon J. Gerraty		dup 0x07 and case
1245*0957b409SSimon J. Gerraty			0x00 of
1246*0957b409SSimon J. Gerraty				0x10 and if
1247*0957b409SSimon J. Gerraty					do-handshake
1248*0957b409SSimon J. Gerraty				then
1249*0957b409SSimon J. Gerraty			endof
1250*0957b409SSimon J. Gerraty			0x01 of
1251*0957b409SSimon J. Gerraty				drop
1252*0957b409SSimon J. Gerraty				0 addr-application_data set8
1253*0957b409SSimon J. Gerraty				read-HelloRequest
1254*0957b409SSimon J. Gerraty				\ Reject renegotiations if the peer does not
1255*0957b409SSimon J. Gerraty				\ support secure renegotiation, or if the
1256*0957b409SSimon J. Gerraty				\ "no renegotiation" flag is set.
1257*0957b409SSimon J. Gerraty				addr-reneg get8 1 = 1 flag? or if
1258*0957b409SSimon J. Gerraty					flush-record
1259*0957b409SSimon J. Gerraty					begin can-output? not while
1260*0957b409SSimon J. Gerraty						wait-co drop
1261*0957b409SSimon J. Gerraty					repeat
1262*0957b409SSimon J. Gerraty					100 send-warning
1263*0957b409SSimon J. Gerraty					\ We rejected the renegotiation,
1264*0957b409SSimon J. Gerraty					\ but the connection is not dead.
1265*0957b409SSimon J. Gerraty					\ We must set back things into
1266*0957b409SSimon J. Gerraty					\ working "application data" state.
1267*0957b409SSimon J. Gerraty					1 addr-application_data set8
1268*0957b409SSimon J. Gerraty					23 addr-record_type_out set8
1269*0957b409SSimon J. Gerraty				else
1270*0957b409SSimon J. Gerraty					do-handshake
1271*0957b409SSimon J. Gerraty				then
1272*0957b409SSimon J. Gerraty			endof
1273*0957b409SSimon J. Gerraty			ERR_UNEXPECTED fail
1274*0957b409SSimon J. Gerraty		endcase
1275*0957b409SSimon J. Gerraty	again
1276*0957b409SSimon J. Gerraty	;
1277