Added API to save and restore session parameters (for controllable session resumption...
[BearSSL] / src / ssl / ssl_hs_client.t0
1 \ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
2 \
3 \ Permission is hereby granted, free of charge, to any person obtaining
4 \ a copy of this software and associated documentation files (the
5 \ "Software"), to deal in the Software without restriction, including
6 \ without limitation the rights to use, copy, modify, merge, publish,
7 \ distribute, sublicense, and/or sell copies of the Software, and to
8 \ permit persons to whom the Software is furnished to do so, subject to
9 \ the following conditions:
10 \
11 \ The above copyright notice and this permission notice shall be
12 \ included in all copies or substantial portions of the Software.
13 \
14 \ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 \ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 \ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 \ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 \ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 \ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 \ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 \ SOFTWARE.
22
23 \ ----------------------------------------------------------------------
24 \ Handshake processing code, for the client.
25 \ The common T0 code (ssl_hs_common.t0) shall be read first.
26
27 preamble {
28
29 /*
30 * This macro evaluates to a pointer to the client context, under that
31 * specific name. It must be noted that since the engine context is the
32 * first field of the br_ssl_client_context structure ('eng'), then
33 * pointers values of both types are interchangeable, modulo an
34 * appropriate cast. This also means that "adresses" computed as offsets
35 * within the structure work for both kinds of context.
36 */
37 #define CTX ((br_ssl_client_context *)ENG)
38
39 /*
40 * Generate the pre-master secret for RSA key exchange, and encrypt it
41 * with the server's public key. Returned value is either the encrypted
42 * data length (in bytes), or -x on error, with 'x' being an error code.
43 *
44 * This code assumes that the public key has been already verified (it
45 * was properly obtained by the X.509 engine, and it has the right type,
46 * i.e. it is of type RSA and suitable for encryption).
47 */
48 static int
49 make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
50 {
51 const br_x509_class **xc;
52 const br_x509_pkey *pk;
53 const unsigned char *n;
54 unsigned char *pms;
55 size_t nlen, u;
56
57 xc = ctx->eng.x509ctx;
58 pk = (*xc)->get_pkey(xc);
59
60 /*
61 * Compute actual RSA key length, in case there are leading zeros.
62 */
63 n = pk->key.rsa.n;
64 nlen = pk->key.rsa.nlen;
65 while (nlen > 0 && *n == 0) {
66 n ++;
67 nlen --;
68 }
69
70 /*
71 * We need at least 59 bytes (48 bytes for pre-master secret, and
72 * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
73 * minimal engine normally blocks RSA keys shorter than 128 bytes,
74 * so this is mostly for public keys provided explicitly by the
75 * caller.
76 */
77 if (nlen < 59) {
78 return -BR_ERR_X509_WEAK_PUBLIC_KEY;
79 }
80 if (nlen > sizeof ctx->eng.pad) {
81 return -BR_ERR_LIMIT_EXCEEDED;
82 }
83
84 /*
85 * Make PMS.
86 */
87 pms = ctx->eng.pad + nlen - 48;
88 br_enc16be(pms, ctx->eng.version_max);
89 br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
90 br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
91
92 /*
93 * Apply PKCS#1 type 2 padding.
94 */
95 ctx->eng.pad[0] = 0x00;
96 ctx->eng.pad[1] = 0x02;
97 ctx->eng.pad[nlen - 49] = 0x00;
98 br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
99 for (u = 2; u < nlen - 49; u ++) {
100 while (ctx->eng.pad[u] == 0) {
101 br_hmac_drbg_generate(&ctx->eng.rng,
102 &ctx->eng.pad[u], 1);
103 }
104 }
105
106 /*
107 * Compute RSA encryption.
108 */
109 if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
110 return -BR_ERR_LIMIT_EXCEEDED;
111 }
112 return (int)nlen;
113 }
114
115 /*
116 * OID for hash functions in RSA signatures.
117 */
118 static const unsigned char HASH_OID_SHA1[] = {
119 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
120 };
121
122 static const unsigned char HASH_OID_SHA224[] = {
123 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
124 };
125
126 static const unsigned char HASH_OID_SHA256[] = {
127 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
128 };
129
130 static const unsigned char HASH_OID_SHA384[] = {
131 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
132 };
133
134 static const unsigned char HASH_OID_SHA512[] = {
135 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
136 };
137
138 static const unsigned char *HASH_OID[] = {
139 HASH_OID_SHA1,
140 HASH_OID_SHA224,
141 HASH_OID_SHA256,
142 HASH_OID_SHA384,
143 HASH_OID_SHA512
144 };
145
146 /*
147 * Check the RSA signature on the ServerKeyExchange message.
148 * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
149 * use_rsa non-zero for RSA signature, zero for ECDSA
150 * sig_len signature length (in bytes); signature value is in the pad
151 * Returned value is 0 on success, or an error code.
152 */
153 static int
154 verify_SKE_sig(br_ssl_client_context *ctx,
155 int hash, int use_rsa, size_t sig_len)
156 {
157 const br_x509_class **xc;
158 const br_x509_pkey *pk;
159 br_multihash_context mhc;
160 unsigned char hv[64], head[4];
161 size_t hv_len;
162
163 xc = ctx->eng.x509ctx;
164 pk = (*xc)->get_pkey(xc);
165 br_multihash_zero(&mhc);
166 br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
167 br_multihash_init(&mhc);
168 br_multihash_update(&mhc,
169 ctx->eng.client_random, sizeof ctx->eng.client_random);
170 br_multihash_update(&mhc,
171 ctx->eng.server_random, sizeof ctx->eng.server_random);
172 head[0] = 3;
173 head[1] = 0;
174 head[2] = ctx->eng.ecdhe_curve;
175 head[3] = ctx->eng.ecdhe_point_len;
176 br_multihash_update(&mhc, head, sizeof head);
177 br_multihash_update(&mhc,
178 ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
179 if (hash) {
180 hv_len = br_multihash_out(&mhc, hash, hv);
181 if (hv_len == 0) {
182 return BR_ERR_INVALID_ALGORITHM;
183 }
184 } else {
185 if (!br_multihash_out(&mhc, br_md5_ID, hv)
186 || !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
187 {
188 return BR_ERR_INVALID_ALGORITHM;
189 }
190 hv_len = 36;
191 }
192 if (use_rsa) {
193 unsigned char tmp[64];
194 const unsigned char *hash_oid;
195
196 if (hash) {
197 hash_oid = HASH_OID[hash - 2];
198 } else {
199 hash_oid = NULL;
200 }
201 if (!ctx->irsavrfy(ctx->eng.pad, sig_len,
202 hash_oid, hv_len, &pk->key.rsa, tmp)
203 || memcmp(tmp, hv, hv_len) != 0)
204 {
205 return BR_ERR_BAD_SIGNATURE;
206 }
207 } else {
208 if (!ctx->iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
209 ctx->eng.pad, sig_len))
210 {
211 return BR_ERR_BAD_SIGNATURE;
212 }
213 }
214 return 0;
215 }
216
217 /*
218 * Perform client-size ECDH (or ECDHE). The point that should be sent to
219 * the server is written in the pad; returned value is either the point
220 * length (in bytes), or -x on error, with 'x' being an error code.
221 *
222 * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
223 * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
224 * (for static ECDH).
225 */
226 static int
227 make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
228 {
229 int curve;
230 unsigned char key[66], point[133];
231 const unsigned char *generator, *order, *point_src;
232 size_t glen, olen, point_len;
233 unsigned char mask;
234
235 if (ecdhe) {
236 curve = ctx->eng.ecdhe_curve;
237 point_src = ctx->eng.ecdhe_point;
238 point_len = ctx->eng.ecdhe_point_len;
239 } else {
240 const br_x509_class **xc;
241 const br_x509_pkey *pk;
242
243 xc = ctx->eng.x509ctx;
244 pk = (*xc)->get_pkey(xc);
245 curve = pk->key.ec.curve;
246 point_src = pk->key.ec.q;
247 point_len = pk->key.ec.qlen;
248 }
249 if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
250 return -BR_ERR_INVALID_ALGORITHM;
251 }
252
253 /*
254 * We need to generate our key, as a non-zero random value which
255 * is lower than the curve order, in a "large enough" range. We
256 * force top bit to 0 and bottom bit to 1, which guarantees that
257 * the value is in the proper range.
258 */
259 order = ctx->eng.iec->order(curve, &olen);
260 mask = 0xFF;
261 while (mask >= order[0]) {
262 mask >>= 1;
263 }
264 br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
265 key[0] &= mask;
266 key[olen - 1] |= 0x01;
267
268 /*
269 * Compute the common ECDH point, whose X coordinate is the
270 * pre-master secret.
271 */
272 generator = ctx->eng.iec->generator(curve, &glen);
273 if (glen != point_len) {
274 return -BR_ERR_INVALID_ALGORITHM;
275 }
276
277 memcpy(point, point_src, glen);
278 if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
279 return -BR_ERR_INVALID_ALGORITHM;
280 }
281
282 /*
283 * The pre-master secret is the X coordinate.
284 */
285 br_ssl_engine_compute_master(&ctx->eng, prf_id, point + 1, glen >> 1);
286
287 memcpy(point, generator, glen);
288 if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
289 return -BR_ERR_INVALID_ALGORITHM;
290 }
291 memcpy(ctx->eng.pad, point, glen);
292 return (int)glen;
293 }
294
295 }
296
297 \ =======================================================================
298
299 : addr-ctx:
300 next-word { field }
301 "addr-" field + 0 1 define-word
302 0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX
303 postpone literal postpone ; ;
304
305 addr-ctx: min_clienthello_len
306
307 \ Length of the Secure Renegotiation extension. This is 5 for the
308 \ first handshake, 17 for a renegotiation (if the server supports the
309 \ extension), or 0 if we know that the server does not support the
310 \ extension.
311 : ext-reneg-length ( -- n )
312 addr-reneg get8 dup if 1 - 17 * else drop 5 then ;
313
314 \ Length of SNI extension.
315 : ext-sni-length ( -- len )
316 addr-server_name strlen dup if 9 + then ;
317
318 \ Length of Maximum Fragment Length extension.
319 : ext-frag-length ( -- len )
320 addr-log_max_frag_len get8 14 = if 0 else 5 then ;
321
322 \ Test support for RSA signatures.
323 cc: supports-rsa-sign? ( -- bool ) {
324 T0_PUSHi(-(CTX->irsavrfy != 0));
325 }
326
327 \ Test support for ECDSA signatures.
328 cc: supports-ecdsa? ( -- bool ) {
329 T0_PUSHi(-(CTX->iecdsa != 0));
330 }
331
332 \ Length of Signatures extension.
333 : ext-signatures-length ( -- len )
334 supported-hash-functions { x } drop
335 0
336 supports-rsa-sign? if x + then
337 supports-ecdsa? if x + then
338 dup if 1 << 6 + then ;
339
340 \ Write supported hash functions ( sign -- )
341 : write-hashes
342 { sign }
343 supported-hash-functions drop
344 \ We advertise hash functions in the following preference order:
345 \ SHA-256 SHA-224 SHA-384 SHA-512 SHA-1
346 \ Rationale:
347 \ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures
348 \ -- SHA-1 is less than ideally collision-resistant
349 dup 0x10 and if 4 write8 sign write8 then
350 dup 0x08 and if 3 write8 sign write8 then
351 dup 0x20 and if 5 write8 sign write8 then
352 dup 0x40 and if 6 write8 sign write8 then
353 0x04 and if 2 write8 sign write8 then ;
354
355 \ Length of Supported Curves extension.
356 : ext-supported-curves-length ( -- len )
357 supported-curves dup if
358 0 { x }
359 begin dup while
360 dup 1 and x + >x
361 1 >>
362 repeat
363 drop x 1 << 6 +
364 then ;
365
366 \ Length of Supported Point Formats extension.
367 : ext-point-format-length ( -- len )
368 supported-curves if 6 else 0 then ;
369
370 \ Write handshake message: ClientHello
371 : write-ClientHello ( -- )
372 { ; total-ext-length }
373
374 \ Compute length for extensions (without the general two-byte header).
375 \ This does not take padding extension into account.
376 ext-reneg-length ext-sni-length + ext-frag-length +
377 ext-signatures-length +
378 ext-supported-curves-length + ext-point-format-length +
379 >total-ext-length
380
381 \ ClientHello type
382 1 write8
383
384 \ Compute and write length
385 39 addr-session_id_len get8 + addr-suites_num get8 1 << +
386 total-ext-length if 2+ total-ext-length + then
387 \ Compute padding (if requested).
388 addr-min_clienthello_len get16 over - dup 0> if
389 \ We well add a Pad ClientHello extension, which has its
390 \ own header (4 bytes) and might be the only extension
391 \ (2 extra bytes for the extension list header).
392 total-ext-length ifnot swap 2+ swap 2- then
393 \ Account for the extension header.
394 4 - dup 0< if drop 0 then
395 \ Adjust total extension length.
396 dup 4 + total-ext-length + >total-ext-length
397 \ Adjust ClientHello length.
398 swap 4 + over + swap
399 else
400 drop
401 -1
402 then
403 { ext-padding-amount }
404 write24
405
406 \ Protocol version
407 addr-version_max get16 write16
408
409 \ Client random
410 addr-client_random 4 bzero
411 addr-client_random 4 + 28 mkrand
412 addr-client_random 32 write-blob
413
414 \ Session ID
415 addr-session_id addr-session_id_len get8 write-blob-head8
416
417 \ Supported cipher suites. We also check here that we indeed
418 \ support all these suites.
419 addr-suites_num get8 dup 1 << write16
420 addr-suites_buf swap
421 begin
422 dup while 1-
423 over get16
424 dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then
425 write16
426 swap 2+ swap
427 repeat
428 2drop
429
430 \ Compression methods (only "null" compression)
431 1 write8 0 write8
432
433 \ Extensions
434 total-ext-length if
435 total-ext-length write16
436 ext-reneg-length if
437 0xFF01 write16 \ extension type (0xFF01)
438 addr-saved_finished
439 ext-reneg-length 4 - dup write16 \ extension length
440 1- write-blob-head8 \ verify data
441 then
442 ext-sni-length if
443 0x0000 write16 \ extension type (0)
444 addr-server_name
445 ext-sni-length 4 - dup write16 \ extension length
446 2 - dup write16 \ ServerNameList length
447 0 write8 \ name type: host_name
448 3 - write-blob-head16 \ the name itself
449 then
450 ext-frag-length if
451 0x0001 write16 \ extension type (1)
452 0x0001 write16 \ extension length
453 addr-log_max_frag_len get8 8 - write8
454 then
455 ext-signatures-length if
456 0x000D write16 \ extension type (13)
457 ext-signatures-length 4 - dup write16 \ extension length
458 2 - write16 \ list length
459 supports-ecdsa? if 3 write-hashes then
460 supports-rsa-sign? if 1 write-hashes then
461 then
462 \ TODO: add an API to specify preference order for curves.
463 \ Right now we use increasing id order, which makes P-256
464 \ the preferred curve.
465 ext-supported-curves-length dup if
466 0x000A write16 \ extension type (10)
467 4 - dup write16 \ extension length
468 2- write16 \ list length
469 supported-curves 0
470 begin dup 32 < while
471 dup2 >> 1 and if dup write16 then
472 1+
473 repeat
474 2drop
475 else
476 drop
477 then
478 ext-point-format-length if
479 0x000B write16 \ extension type (11)
480 0x0002 write16 \ extension length
481 0x0100 write16 \ value: 1 format: uncompressed
482 then
483 ext-padding-amount 0< ifnot
484 0x0015 write16 \ extension value (21)
485 ext-padding-amount
486 dup write16 \ extension length
487 begin dup while
488 1- 0 write8 repeat \ value (only zeros)
489 drop
490 then
491 then
492 ;
493
494 \ =======================================================================
495
496 \ Parse server SNI extension. If present, then it should be empty.
497 : read-server-sni ( lim -- lim )
498 read16 if ERR_BAD_SNI fail then ;
499
500 \ Parse server Max Fragment Length extension. If present, then it should
501 \ advertise the same length as the client. Note that whether the server
502 \ sends it or not changes nothing for us: we won't send any record larger
503 \ than the advertised value anyway, and we will accept incoming records
504 \ up to our input buffer length.
505 : read-server-frag ( lim -- lim )
506 read16 1 = ifnot ERR_BAD_FRAGLEN fail then
507 read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ;
508
509 \ Parse server Secure Renegotiation extension. This is called only if
510 \ the client sent that extension, so we only have two cases to
511 \ distinguish: first handshake, and renegotiation; in the latter case,
512 \ we know that the server supports the extension, otherwise the client
513 \ would not have sent it.
514 : read-server-reneg ( lim -- lim )
515 read16
516 addr-reneg get8 ifnot
517 \ "reneg" is 0, so this is a first handshake. The server's
518 \ extension MUST be empty. We also learn that the server
519 \ supports the extension.
520 1 = ifnot ERR_BAD_SECRENEG fail then
521 read8 0 = ifnot ERR_BAD_SECRENEG fail then
522 2 addr-reneg set8
523 else
524 \ "reneg" is non-zero, and we sent an extension, so it must
525 \ be 2 and this is a renegotiation. We must verify that
526 \ the extension contents have length exactly 24 bytes and
527 \ match the saved client and server "Finished".
528 25 = ifnot ERR_BAD_SECRENEG fail then
529 read8 24 = ifnot ERR_BAD_SECRENEG fail then
530 addr-pad 24 read-blob
531 addr-saved_finished addr-pad 24 memcmp ifnot
532 ERR_BAD_SECRENEG fail
533 then
534 then ;
535
536 \ Save a value in a 16-bit field, or check it in case of session resumption.
537 : check-resume ( val addr resume -- )
538 if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
539
540 cc: DEBUG-BLOB ( addr len -- ) {
541 extern int printf(const char *fmt, ...);
542
543 size_t len = T0_POP();
544 unsigned char *buf = (unsigned char *)CTX + T0_POP();
545 size_t u;
546
547 printf("BLOB:");
548 for (u = 0; u < len; u ++) {
549 if (u % 16 == 0) {
550 printf("\n ");
551 }
552 printf(" %02x", buf[u]);
553 }
554 printf("\n");
555 }
556
557 \ Parse incoming ServerHello. Returned value is true (-1) on session
558 \ resumption.
559 : read-ServerHello ( -- bool )
560 \ Get header, and check message type.
561 read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then
562
563 \ Get protocol version.
564 read16 { version }
565 version addr-version_min get16 < version addr-version_max get16 > or if
566 ERR_UNSUPPORTED_VERSION fail
567 then
568
569 \ Enforce chosen version for subsequent records in both directions.
570 version addr-version_in get16 <> if ERR_BAD_VERSION fail then
571 version addr-version_out set16
572
573 \ Server random.
574 addr-server_random 32 read-blob
575
576 \ The "session resumption" flag.
577 0 { resume }
578
579 \ Session ID.
580 read8 { idlen }
581 idlen 32 > if ERR_OVERSIZED_ID fail then
582 addr-pad idlen read-blob
583 idlen addr-session_id_len get8 = idlen 0 > and if
584 addr-session_id addr-pad idlen memcmp if
585 \ Server session ID is non-empty and matches what
586 \ we sent, so this is a session resumption.
587 -1 >resume
588 then
589 then
590 addr-session_id addr-pad idlen memcpy
591 idlen addr-session_id_len set8
592
593 \ Record version.
594 version addr-version resume check-resume
595
596 \ Cipher suite. We check that it is part of the list of cipher
597 \ suites that we advertised.
598 \ read16 { suite ; found }
599 \ 0 >found
600 \ addr-suites_buf dup addr-suites_num get8 1 << +
601 \ begin dup2 < while
602 \ 2 - dup get16
603 \ suite = found or >found
604 \ repeat
605 \ 2drop found ifnot ERR_BAD_CIPHER_SUITE fail then
606 read16
607 dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then
608 addr-cipher_suite resume check-resume
609
610 \ Compression method. Should be 0 (no compression).
611 read8 if ERR_BAD_COMPRESSION fail then
612
613 \ Parse extensions (if any). If there is no extension, then the
614 \ read limit (on the TOS) should be 0 at that point.
615 dup if
616 \ Length of extension list.
617 \ message size.
618 read16 open-elt
619
620 \ Enumerate extensions. For each of them, check that we
621 \ sent an extension of that type, and did not see it
622 \ yet; and then process it.
623 ext-sni-length { ok-sni }
624 ext-reneg-length { ok-reneg }
625 ext-frag-length { ok-frag }
626 ext-signatures-length { ok-signatures }
627 ext-supported-curves-length { ok-curves }
628 ext-point-format-length { ok-points }
629 begin dup while
630 read16
631 case
632 \ Server Name Indication. The server may
633 \ send such an extension if it uses the SNI
634 \ from the client, but that "response
635 \ extension" is supposed to be empty.
636 0x0000 of
637 ok-sni ifnot
638 ERR_EXTRA_EXTENSION fail
639 then
640 0 >ok-sni
641 read-server-sni
642 endof
643
644 \ Max Frag Length. The contents shall be
645 \ a single byte whose value matches the one
646 \ sent by the client.
647 0x0001 of
648 ok-frag ifnot
649 ERR_EXTRA_EXTENSION fail
650 then
651 0 >ok-frag
652 read-server-frag
653 endof
654
655 \ Secure Renegotiation.
656 0xFF01 of
657 ok-reneg ifnot
658 ERR_EXTRA_EXTENSION fail
659 then
660 0 >ok-reneg
661 read-server-reneg
662 endof
663
664 \ Signature Algorithms.
665 \ Normally, the server should never send this
666 \ extension (so says RFC 5246 #7.4.1.4.1),
667 \ but some existing servers do.
668 0x000D of
669 ok-signatures ifnot
670 ERR_EXTRA_EXTENSION fail
671 then
672 0 >ok-signatures
673 read-ignore-16
674 endof
675
676 \ Supported Curves.
677 0x000A of
678 ok-curves ifnot
679 ERR_EXTRA_EXTENSION fail
680 then
681 0 >ok-curves
682 read-ignore-16
683 endof
684
685 \ Supported Point Formats.
686 0x000B of
687 ok-points ifnot
688 ERR_EXTRA_EXTENSION fail
689 then
690 0 >ok-points
691 read-ignore-16
692 endof
693
694 ERR_EXTRA_EXTENSION fail
695 endcase
696 repeat
697
698 \ If we sent a secure renegotiation extension but did not
699 \ receive a response, then the server does not support
700 \ secure renegotiation. This is a hard failure if this
701 \ is a renegotiation.
702 ok-reneg if
703 ok-reneg 5 > if ERR_BAD_SECRENEG fail then
704 1 addr-reneg set8
705 then
706 close-elt
707 then
708 close-elt
709 resume
710 ;
711
712 cc: x509-start-chain ( expected-key-type -- ) {
713 const br_x509_class *xc;
714
715 xc = *(ENG->x509ctx);
716 xc->start_chain(ENG->x509ctx, T0_POP(), ENG->server_name);
717 }
718
719 cc: x509-start-cert ( length -- ) {
720 const br_x509_class *xc;
721
722 xc = *(ENG->x509ctx);
723 xc->start_cert(ENG->x509ctx, T0_POP());
724 }
725
726 cc: x509-append ( length -- ) {
727 const br_x509_class *xc;
728 size_t len;
729
730 xc = *(ENG->x509ctx);
731 len = T0_POP();
732 xc->append(ENG->x509ctx, ENG->pad, len);
733 }
734
735 cc: x509-end-cert ( -- ) {
736 const br_x509_class *xc;
737
738 xc = *(ENG->x509ctx);
739 xc->end_cert(ENG->x509ctx);
740 }
741
742 cc: x509-end-chain ( -- err ) {
743 const br_x509_class *xc;
744
745 xc = *(ENG->x509ctx);
746 T0_PUSH(xc->end_chain(ENG->x509ctx));
747 }
748
749 \ Parse Certificate
750 : read-Certificate ( -- )
751 \ Get header, and check message type.
752 read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then
753
754 \ Start processing the chain through the X.509 engine.
755 addr-cipher_suite get16 expected-key-type
756 x509-start-chain
757
758 \ Total chain length is a 24-bit integer.
759 read24 open-elt
760 begin
761 dup while
762 read24 open-elt
763 dup x509-start-cert
764
765 \ We read the certificate by chunks through the pad, so
766 \ as to use the existing reading function (read-blob)
767 \ that also ensures proper hashing.
768 begin
769 dup while
770 dup 256 > if 256 else dup then { len }
771 addr-pad len read-blob
772 len x509-append
773 repeat
774 close-elt
775 x509-end-cert
776 repeat
777
778 \ We must close the chain AND the handshake message.
779 close-elt
780 close-elt
781
782 \ Chain processing is finished; get the error code.
783 x509-end-chain
784 dup if fail then drop
785 ;
786
787 \ Verify signature on ECDHE point sent by the server.
788 \ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1)
789 \ 'use-rsa' is 0 for ECDSA, -1 for for RSA
790 \ 'sig-len' is the signature length (in bytes)
791 \ The signature itself is in the pad.
792 cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) {
793 size_t sig_len = T0_POP();
794 int use_rsa = T0_POPi();
795 int hash = T0_POPi();
796
797 T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
798 }
799
800 \ Parse ServerKeyExchange
801 : read-ServerKeyExchange ( -- )
802 \ Get header, and check message type.
803 read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then
804
805 \ We expect a named curve, and we must support it.
806 read8 3 = ifnot ERR_INVALID_ALGORITHM fail then
807 read16 dup addr-ecdhe_curve set8
808 dup 32 >= if ERR_INVALID_ALGORITHM fail then
809 supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then
810
811 \ Read the server point.
812 read8
813 dup 133 > if ERR_INVALID_ALGORITHM fail then
814 dup addr-ecdhe_point_len set8
815 addr-ecdhe_point swap read-blob
816
817 \ If using TLS-1.2+, then the hash function and signature algorithm
818 \ are explicitly provided; the signature algorithm must match what
819 \ the cipher suite specifies. With TLS-1.0 and 1.1, the signature
820 \ algorithm is inferred from the cipher suite, and the hash is
821 \ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA).
822 addr-version get16 0x0303 >= { tls1.2+ }
823 addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa }
824 2 { hash }
825 tls1.2+ if
826 \ Read hash function; accept only the SHA-* identifiers
827 \ (from SHA-1 to SHA-512, no MD5 here).
828 read8
829 dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then
830 >hash
831 read8
832 \ Get expected signature algorithm and compare with what
833 \ the server just sent. Expected value is 1 for RSA, 3
834 \ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA,
835 \ 0 for ECDSA.
836 use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then
837 else
838 \ For MD5+SHA-1, we set 'hash' to 0.
839 use-rsa if 0 >hash then
840 then
841
842 \ Read signature into the pad.
843 read16 dup { sig-len }
844
845 dup 512 > if ERR_LIMIT_EXCEEDED fail then
846 addr-pad swap read-blob
847
848 \ Verify signature.
849 hash use-rsa sig-len verify-SKE-sig
850 dup if fail then drop
851
852 close-elt ;
853
854 \ Parse CertificateRequest. Header has already been read.
855 : read-contents-CertificateRequest ( lim -- )
856 \ TODO: implement client certificates. Right now, we simply
857 \ drop the complete message.
858 begin dup while read8 drop repeat drop ;
859
860 \ Write an empty Certificate message.
861 : write-empty-Certificate ( -- )
862 11 write8 3 write24 0 write24 ;
863
864 cc: do-rsa-encrypt ( prf_id -- nlen ) {
865 int x;
866
867 x = make_pms_rsa(CTX, T0_POP());
868 if (x < 0) {
869 br_ssl_engine_fail(ENG, -x);
870 T0_CO();
871 } else {
872 T0_PUSH(x);
873 }
874 }
875
876 cc: do-ecdh ( echde prf_id -- ulen ) {
877 unsigned prf_id = T0_POP();
878 unsigned ecdhe = T0_POP();
879 int x;
880
881 x = make_pms_ecdh(CTX, ecdhe, prf_id);
882 if (x < 0) {
883 br_ssl_engine_fail(ENG, -x);
884 T0_CO();
885 } else {
886 T0_PUSH(x);
887 }
888 }
889
890 \ Write ClientKeyExchange
891 : write-ClientKeyExchange ( -- )
892 16 write8
893 addr-cipher_suite get16
894 dup use-rsa-keyx? if
895 prf-id do-rsa-encrypt
896 dup 2+ write24
897 dup write16
898 addr-pad swap write-blob
899 else
900 dup use-ecdhe? swap prf-id do-ecdh
901 dup 1+ write24
902 dup write8
903 addr-pad swap write-blob
904 then ;
905
906 \ =======================================================================
907
908 \ Perform a handshake.
909 : do-handshake ( -- )
910 0 addr-application_data set8
911 22 addr-record_type_out set8
912 multihash-init
913
914 write-ClientHello
915 flush-record
916 read-ServerHello
917
918 if
919 \ Session resumption.
920 -1 read-CCS-Finished
921 -1 write-CCS-Finished
922
923 else
924
925 \ Not a session resumption.
926
927 read-Certificate
928
929 \ Depending on cipher suite, we may now expect a
930 \ ServerKeyExchange.
931 addr-cipher_suite get16 expected-key-type
932 CX 0 63 { BR_KEYTYPE_SIGN } and if
933 read-ServerKeyExchange
934 then
935
936 \ Get next header.
937 read-handshake-header
938
939 \ If this is a CertificateRequest, parse it, then read
940 \ next header.
941 dup 13 = if
942 drop read-contents-CertificateRequest
943 read-handshake-header
944 -1
945 else
946 0
947 then
948 { seen-CR }
949
950 \ At that point, we should have a ServerHelloDone,
951 \ whose length must be 0.
952 14 = ifnot ERR_UNEXPECTED fail then
953 if ERR_BAD_HELLO_DONE fail then
954
955 \ There should not be more bytes in the record at that point.
956 more-incoming-bytes? if ERR_UNEXPECTED fail then
957
958 seen-CR if
959 \ TODO: client certificate support.
960 write-empty-Certificate
961 then
962 write-ClientKeyExchange
963
964 \ TODO: CertificateVerify
965
966 -1 write-CCS-Finished
967 -1 read-CCS-Finished
968 then
969
970 \ Now we should be invoked only in case of renegotiation.
971 1 addr-application_data set8
972 23 addr-record_type_out set8 ;
973
974 \ Read a HelloRequest message.
975 : read-HelloRequest ( -- )
976 \ A HelloRequest has length 0 and type 0.
977 read-handshake-header-core
978 if ERR_UNEXPECTED fail then
979 if ERR_BAD_HANDSHAKE fail then ;
980
981 \ Entry point.
982 : main ( -- ! )
983 \ Perform initial handshake.
984 do-handshake
985
986 begin
987 \ Wait for further invocation. At that point, we should
988 \ get either an explicit call for renegotiation, or
989 \ an incoming HelloRequest handshake message.
990 wait-co
991 dup 0x07 and case
992 0x00 of
993 0x10 and if
994 do-handshake
995 then
996 endof
997 0x01 of
998 drop
999 0 addr-application_data set8
1000 read-HelloRequest
1001 \ Reject renegotiations if the peer does not
1002 \ support secure renegotiation, or if the
1003 \ "no renegotiation" flag is set.
1004 addr-reneg get8 1 = 1 flag? or if
1005 flush-record
1006 begin can-output? not while
1007 wait-co drop
1008 repeat
1009 100 send-warning
1010 else
1011 do-handshake
1012 then
1013 endof
1014 ERR_UNEXPECTED fail
1015 endcase
1016 again
1017 ;