X-Git-Url: https://www.bearssl.org/gitweb//home/git/?p=BearSSL;a=blobdiff_plain;f=src%2Fssl%2Fssl_hs_client.t0;h=23b39e719856f9784e896e05c693377ff83b6700;hp=37c554cd4dde2f2623cbdb330220ac969460692e;hb=dda1f8a0c46e15b4a235163470ff700b2f13dcc5;hpb=e61ad42191511226309bad2cbde8cd9e8cc743cb diff --git a/src/ssl/ssl_hs_client.t0 b/src/ssl/ssl_hs_client.t0 index 37c554c..23b39e7 100644 --- a/src/ssl/ssl_hs_client.t0 +++ b/src/ssl/ssl_hs_client.t0 @@ -31,7 +31,7 @@ preamble { * specific name. It must be noted that since the engine context is the * first field of the br_ssl_client_context structure ('eng'), then * pointers values of both types are interchangeable, modulo an - * appropriate cast. This also means that "adresses" computed as offsets + * appropriate cast. This also means that "addresses" computed as offsets * within the structure work for both kinds of context. */ #define CTX ((br_ssl_client_context *)ENG) @@ -115,32 +115,12 @@ make_pms_rsa(br_ssl_client_context *ctx, int prf_id) /* * OID for hash functions in RSA signatures. */ -static const unsigned char HASH_OID_SHA1[] = { - 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A -}; - -static const unsigned char HASH_OID_SHA224[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 -}; - -static const unsigned char HASH_OID_SHA256[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 -}; - -static const unsigned char HASH_OID_SHA384[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 -}; - -static const unsigned char HASH_OID_SHA512[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 -}; - static const unsigned char *HASH_OID[] = { - HASH_OID_SHA1, - HASH_OID_SHA224, - HASH_OID_SHA256, - HASH_OID_SHA384, - HASH_OID_SHA512 + BR_HASH_OID_SHA1, + BR_HASH_OID_SHA224, + BR_HASH_OID_SHA256, + BR_HASH_OID_SHA384, + BR_HASH_OID_SHA512 }; /* @@ -230,8 +210,8 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) { int curve; unsigned char key[66], point[133]; - const unsigned char *generator, *order, *point_src; - size_t glen, olen, point_len; + const unsigned char *order, *point_src; + size_t glen, olen, point_len, xoff, xlen; unsigned char mask; if (ecdhe) { @@ -271,7 +251,7 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) * Compute the common ECDH point, whose X coordinate is the * pre-master secret. */ - generator = ctx->eng.iec->generator(curve, &glen); + ctx->eng.iec->generator(curve, &glen); if (glen != point_len) { return -BR_ERR_INVALID_ALGORITHM; } @@ -284,12 +264,10 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) /* * The pre-master secret is the X coordinate. */ - br_ssl_engine_compute_master(&ctx->eng, prf_id, point + 1, glen >> 1); + xoff = ctx->eng.iec->xoff(curve, &xlen); + br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen); - memcpy(point, generator, glen); - if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) { - return -BR_ERR_INVALID_ALGORITHM; - } + ctx->eng.iec->mulgen(point, key, olen, curve); memcpy(ctx->eng.pad, point, glen); return (int)glen; } @@ -320,12 +298,12 @@ make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id) } memcpy(point, pk->key.ec.q, point_len); if (!(*ctx->client_auth_vtable)->do_keyx( - ctx->client_auth_vtable, point, point_len)) + ctx->client_auth_vtable, point, &point_len)) { return -1; } br_ssl_engine_compute_master(&ctx->eng, - prf_id, point + 1, point_len >> 1); + prf_id, point, point_len); return 0; } @@ -393,10 +371,9 @@ addr-ctx: hash_id \ Length of Signatures extension. : ext-signatures-length ( -- len ) - supported-hash-functions { x } drop - 0 - supports-rsa-sign? if x + then - supports-ecdsa? if x + then + supported-hash-functions { num } drop 0 + supports-rsa-sign? if num + then + supports-ecdsa? if num + then dup if 1 << 6 + then ; \ Write supported hash functions ( sign -- ) @@ -429,6 +406,21 @@ addr-ctx: hash_id : ext-point-format-length ( -- len ) supported-curves if 6 else 0 then ; +\ Length of ALPN extension. +cc: ext-ALPN-length ( -- len ) { + size_t u, len; + + if (ENG->protocol_names_num == 0) { + T0_PUSH(0); + T0_RET(); + } + len = 6; + for (u = 0; u < ENG->protocol_names_num; u ++) { + len += 1 + strlen(ENG->protocol_names[u]); + } + T0_PUSH(len); +} + \ Write handshake message: ClientHello : write-ClientHello ( -- ) { ; total-ext-length } @@ -438,6 +430,7 @@ addr-ctx: hash_id ext-reneg-length ext-sni-length + ext-frag-length + ext-signatures-length + ext-supported-curves-length + ext-point-format-length + + ext-ALPN-length + >total-ext-length \ ClientHello type @@ -522,13 +515,16 @@ addr-ctx: hash_id supports-rsa-sign? if 1 write-hashes then then \ TODO: add an API to specify preference order for curves. - \ Right now we use increasing id order, which makes P-256 - \ the preferred curve. + \ Right now we send Curve25519 first, then other curves in + \ increasing ID values (hence P-256 in second). ext-supported-curves-length dup if 0x000A write16 \ extension type (10) 4 - dup write16 \ extension length 2- write16 \ list length supported-curves 0 + dup 0x20000000 and if + 0xDFFFFFFF and 29 write16 + then begin dup 32 < while dup2 >> 1 and if dup write16 then 1+ @@ -542,6 +538,21 @@ addr-ctx: hash_id 0x0002 write16 \ extension length 0x0100 write16 \ value: 1 format: uncompressed then + ext-ALPN-length dup if + 0x0010 write16 \ extension type (16) + 4 - dup write16 \ extension length + 2- write16 \ list length + addr-protocol_names_num get16 0 + begin + dup2 > while + dup copy-protocol-name + dup write8 addr-pad swap write-blob + 1+ + repeat + 2drop + else + drop + then ext-padding-amount 0< ifnot 0x0015 write16 \ extension value (21) ext-padding-amount @@ -595,6 +606,24 @@ addr-ctx: hash_id then then ; +\ Read the ALPN extension from the server. It must contain a single name, +\ and that name must match one of our names. +: read-ALPN-from-server ( lim -- lim ) + \ Extension contents length. + read16 open-elt + \ Length of list of names. + read16 open-elt + \ There should be a single name. + read8 addr-pad swap dup { len } read-blob + close-elt + close-elt + len test-protocol-name dup 0< if + 3 flag? if ERR_UNEXPECTED fail then + drop + else + 1+ addr-selected_protocol set16 + then ; + \ Save a value in a 16-bit field, or check it in case of session resumption. : check-resume ( val addr resume -- ) if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ; @@ -657,16 +686,12 @@ cc: DEBUG-BLOB ( addr len -- ) { \ Cipher suite. We check that it is part of the list of cipher \ suites that we advertised. - \ read16 { suite ; found } - \ 0 >found - \ addr-suites_buf dup addr-suites_num get8 1 << + - \ begin dup2 < while - \ 2 - dup get16 - \ suite = found or >found - \ repeat - \ 2drop found ifnot ERR_BAD_CIPHER_SUITE fail then read16 dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then + \ Also check that the cipher suite is compatible with the + \ announced version: suites that don't use HMAC/SHA-1 are + \ for TLS-1.2 only, not older versions. + dup use-tls12? version 0x0303 < and if ERR_BAD_CIPHER_SUITE fail then addr-cipher_suite resume check-resume \ Compression method. Should be 0 (no compression). @@ -688,6 +713,7 @@ cc: DEBUG-BLOB ( addr len -- ) { ext-signatures-length { ok-signatures } ext-supported-curves-length { ok-curves } ext-point-format-length { ok-points } + ext-ALPN-length { ok-ALPN } begin dup while read16 case @@ -753,6 +779,15 @@ cc: DEBUG-BLOB ( addr len -- ) { read-ignore-16 endof + \ ALPN. + 0x0010 of + ok-ALPN ifnot + ERR_EXTRA_EXTENSION fail + then + 0 >ok-ALPN + read-ALPN-from-server + endof + ERR_EXTRA_EXTENSION fail endcase repeat @@ -766,6 +801,13 @@ cc: DEBUG-BLOB ( addr len -- ) { 1 addr-reneg set8 then close-elt + else + \ No extension received at all, so the server does not + \ support secure renegotiation. This is a hard failure + \ if the server was previously known to support it (i.e. + \ this is a renegotiation). + ext-reneg-length 5 > if ERR_BAD_SECRENEG fail then + 1 addr-reneg set8 then close-elt resume @@ -927,7 +969,7 @@ cc: get-client-chain ( auth_types -- ) { \ Parse CertificateRequest. Header has already been read. : read-contents-CertificateRequest ( lim -- ) - \ Read supported client authentification types. We keep only + \ Read supported client authentication types. We keep only \ RSA, ECDSA, and ECDH. 0 { auth_types } read8 open-elt @@ -967,7 +1009,7 @@ cc: get-client-chain ( auth_types -- ) { \ - There is an explicit list of supported sign+hash. \ - The ECDH flags must be adjusted for RSA/ECDSA \ support. - read-list-sign-algos dup addr-hashes set16 + read-list-sign-algos dup addr-hashes set32 \ Trim down the list depending on what hash functions \ we support (since the hashing itself is done by the SSL @@ -1102,6 +1144,7 @@ cc: do-client-sign ( -- sig_len ) { : do-handshake ( -- ) 0 addr-application_data set8 22 addr-record_type_out set8 + 0 addr-selected_protocol set16 multihash-init write-ClientHello @@ -1217,6 +1260,12 @@ cc: do-client-sign ( -- sig_len ) { wait-co drop repeat 100 send-warning + \ We rejected the renegotiation, + \ but the connection is not dead. + \ We must set back things into + \ working "application data" state. + 1 addr-application_data set8 + 23 addr-record_type_out set8 else do-handshake then