Fixed efficiency pre-test on RSA prime generation (no security issue, but RSA key...
[BearSSL] / src / ssl / ssl_hs_server.t0
index a7475af..9f6e934 100644 (file)
@@ -31,7 +31,7 @@ preamble {
  * specific name. It must be noted that since the engine context is the
  * first field of the br_ssl_server_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_server_context *)ENG)
@@ -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
 
@@ -859,7 +864,7 @@ cc: save-session ( -- ) {
        \ suites are filtered out. In particular:
        \ -- ECDHE suites are removed if there is no common hash function
        \    (for the relevant signature algorithm) or no common curve.
-       \ -- TLS-1.2-only suites are removed if the negociated version is
+       \ -- TLS-1.2-only suites are removed if the negotiated version is
        \    TLS-1.1 or lower.
        addr-client_suites dup >css-off
        begin dup css-max < while
@@ -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