X-Git-Url: https://www.bearssl.org/gitweb//home/git/?p=BearSSL;a=blobdiff_plain;f=src%2Fssl%2Fssl_hs_server.t0;h=58d5c9414ddd30e4b800133162e67bde7fb47006;hp=a7475af0e1a2eb2621354313625546365797de3c;hb=9dc6211237abcc4a4854818f8e5d7b8973bf31e3;hpb=ef318ef83a3a58b0a9e036676b84d11261ed7bb4;ds=sidebyside diff --git a/src/ssl/ssl_hs_server.t0 b/src/ssl/ssl_hs_server.t0 index a7475af..58d5c94 100644 --- a/src/ssl/ssl_hs_server.t0 +++ b/src/ssl/ssl_hs_server.t0 @@ -49,7 +49,7 @@ do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id, /* * Decrypt the PMS. */ - x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, len); + x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len); /* * Set the first two bytes to the maximum supported client @@ -85,21 +85,12 @@ do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id, */ static void ecdh_common(br_ssl_server_context *ctx, int prf_id, - unsigned char *cpoint, size_t cpoint_len, uint32_t ctl) + unsigned char *xcoor, size_t xcoor_len, uint32_t ctl) { unsigned char rpms[80]; - size_t pms_len; - /* - * The point length is supposed to be 1+2*Xlen, where Xlen is - * the length (in bytes) of the X coordinate, i.e. the pre-master - * secret. If the provided point is too large, then it is - * obviously incorrect (i.e. everybody can see that it is - * incorrect), so leaking that fact is not a problem. - */ - pms_len = cpoint_len >> 1; - if (pms_len > sizeof rpms) { - pms_len = sizeof rpms; + if (xcoor_len > sizeof rpms) { + xcoor_len = sizeof rpms; ctl = 0; } @@ -108,19 +99,19 @@ ecdh_common(br_ssl_server_context *ctx, int prf_id, * decryption failed. Note that we use a constant-time conditional * copy. */ - br_hmac_drbg_generate(&ctx->eng.rng, rpms, pms_len); - br_ccopy(ctl ^ 1, cpoint + 1, rpms, pms_len); + br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len); + br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len); /* * Compute master secret. */ - br_ssl_engine_compute_master(&ctx->eng, prf_id, cpoint + 1, pms_len); + br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len); /* * Clear the pre-master secret from RAM: it is normally a buffer * in the context, hence potentially long-lived. */ - memset(cpoint, 0, cpoint_len); + memset(xcoor, 0, xcoor_len); } /* @@ -136,7 +127,7 @@ do_ecdh(br_ssl_server_context *ctx, int prf_id, * Finalise the key exchange. */ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, - cpoint, cpoint_len); + cpoint, &cpoint_len); ecdh_common(ctx, prf_id, cpoint, cpoint_len, x); } @@ -288,16 +279,18 @@ do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id, unsigned char *cpoint, size_t cpoint_len) { int curve; - uint32_t x; + uint32_t ctl; + size_t xoff, xlen; curve = ctx->eng.ecdhe_curve; /* * Finalise the key exchange. */ - x = ctx->eng.iec->mul(cpoint, cpoint_len, + ctl = ctx->eng.iec->mul(cpoint, cpoint_len, ctx->ecdhe_key, ctx->ecdhe_key_len, curve); - ecdh_common(ctx, prf_id, cpoint, cpoint_len, x); + xoff = ctx->eng.iec->xoff(curve, &xlen); + ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl); /* * Clear the ECDHE private key. Forward Secrecy is achieved insofar @@ -618,6 +611,13 @@ cc: save-session ( -- ) { } } +\ Read and drop ClientHello. This is used when a client-triggered +\ renegotiation attempt is rejected. +: skip-ClientHello ( -- ) + read-handshake-header-core + 1 = ifnot ERR_UNEXPECTED fail then + dup skip-blob drop ; + \ Read ClientHello. If the session is resumed, then -1 is returned. : read-ClientHello ( -- resume ) \ Get header, and check message type. @@ -821,6 +821,11 @@ cc: save-session ( -- ) { \ we should mark the client as "supporting secure renegotiation". reneg-scsv if 2 addr-reneg set8 then + \ If, at that point, the 'reneg' value is still 0, then the client + \ did not send the extension or the SCSV, so we have to assume + \ that secure renegotiation is not supported by that client. + addr-reneg get8 ifnot 1 addr-reneg set8 then + \ Check compression. ok-compression ifnot 40 fail-alert then @@ -988,21 +993,33 @@ cc: do-ecdhe-part1 ( curve -- len ) { T0_PUSHi(do_ecdhe_part1(CTX, curve)); } +\ Get index of first bit set to 1 (in low to high order). +: lowest-1 ( bits -- n ) + dup ifnot drop -1 ret then + 0 begin dup2 >> 1 and 0= while 1+ repeat + swap drop ; + \ Write the Server Key Exchange message (if applicable). : write-ServerKeyExchange ( -- ) addr-cipher_suite get16 use-ecdhe? ifnot ret then \ We must select an appropriate curve among the curves that - \ are supported both by us and the peer. Right now we use - \ the one with the smallest ID, which in practice means P-256. + \ are supported both by us and the peer. Right now, we apply + \ a fixed preference order: Curve25519, P-256, P-384, P-521, + \ then the common curve with the lowest ID. \ (TODO: add some option to make that behaviour configurable.) \ \ This loop always terminates because previous processing made \ sure that ECDHE suites are not selectable if there is no common \ curve. - addr-curves get32 0 - begin dup2 >> 1 and 0= while 1+ repeat - { curve-id } drop + addr-curves get32 + dup 0x20000000 and if + drop 29 + else + dup 0x38000000 and dup if swap then + drop lowest-1 + then + { curve-id } \ Compute the signed curve point to send. curve-id do-ecdhe-part1 dup 0< if neg fail then { sig-len } @@ -1463,6 +1480,7 @@ cc: verify-CV-sig ( sig-len -- err ) { \ The best we can do is ask for a \ renegotiation, then wait for it \ to happen. + 0 addr-application_data set8 send-HelloRequest then endof @@ -1472,11 +1490,16 @@ cc: verify-CV-sig ( sig-len -- err ) { \ "no renegotiation" flag is set. drop addr-reneg get8 1 = 1 flag? or if + skip-ClientHello flush-record begin can-output? not while wait-co drop repeat 100 send-warning + \ Put back connection in "application + \ data" state: it's not dead yet. + 1 addr-application_data set8 + 23 addr-record_type_out set8 else 0 do-handshake then