* 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)
/*
* 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
};
/*
{
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) {
* 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;
}
/*
* 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;
}
}
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;
}
\ 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 -- )
: 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 }
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
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+
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
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 ;
\ 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).
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
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
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
\ 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
\ - 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
: do-handshake ( -- )
0 addr-application_data set8
22 addr-record_type_out set8
+ 0 addr-selected_protocol set16
multihash-init
write-ClientHello
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