Added ALPN support (client and server).
This commit is contained in:
parent
8bb8d74d4a
commit
05ac106834
9 changed files with 1172 additions and 727 deletions
|
|
@ -945,6 +945,27 @@ typedef struct {
|
||||||
const unsigned char *cert_cur;
|
const unsigned char *cert_cur;
|
||||||
size_t cert_len;
|
size_t cert_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of supported protocol names (ALPN extension). If unset,
|
||||||
|
* (number of names is 0), then:
|
||||||
|
* - the client sends no ALPN extension;
|
||||||
|
* - the server ignores any incoming ALPN extension.
|
||||||
|
*
|
||||||
|
* Otherwise:
|
||||||
|
* - the client sends an ALPN extension with all the names;
|
||||||
|
* - the server selects the first protocol in its list that
|
||||||
|
* the client also supports, or fails (fatal alert 120)
|
||||||
|
* if the client sends an ALPN extension and there is no
|
||||||
|
* match.
|
||||||
|
*
|
||||||
|
* The 'selected_protocol' field contains 1+n if the matching
|
||||||
|
* name has index n in the list (the value is 0 if no match was
|
||||||
|
* performed, e.g. the peer did not send an ALPN extension).
|
||||||
|
*/
|
||||||
|
const char **protocol_names;
|
||||||
|
uint16_t protocol_names_num;
|
||||||
|
uint16_t selected_protocol;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pointers to implementations; left to NULL for unsupported
|
* Pointers to implementations; left to NULL for unsupported
|
||||||
* functions. For the raw hash functions, implementations are
|
* functions. For the raw hash functions, implementations are
|
||||||
|
|
@ -1064,6 +1085,32 @@ br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags)
|
||||||
*/
|
*/
|
||||||
#define BR_OPT_TOLERATE_NO_CLIENT_AUTH ((uint32_t)1 << 2)
|
#define BR_OPT_TOLERATE_NO_CLIENT_AUTH ((uint32_t)1 << 2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Behavioural flag: fail on application protocol mismatch.
|
||||||
|
*
|
||||||
|
* The ALPN extension ([RFC 7301](https://tools.ietf.org/html/rfc7301))
|
||||||
|
* allows the client to send a list of application protocol names, and
|
||||||
|
* the server to select one. A mismatch is one of the following occurrences:
|
||||||
|
*
|
||||||
|
* - On the client: the client sends a list of names, the server
|
||||||
|
* responds with a protocol name which is _not_ part of the list of
|
||||||
|
* names sent by the client.
|
||||||
|
*
|
||||||
|
* - On the server: the client sends a list of names, and the server
|
||||||
|
* is also configured with a list of names, but there is no common
|
||||||
|
* protocol name between the two lists.
|
||||||
|
*
|
||||||
|
* Normal behaviour in case of mismatch is to report no matching name
|
||||||
|
* (`br_ssl_engine_get_selected_protocol()` returns `NULL`) and carry on.
|
||||||
|
* If the flag is set, then a mismatch implies a protocol failure (if
|
||||||
|
* the mismatch is detected by the server, it will send a fatal alert).
|
||||||
|
*
|
||||||
|
* Note: even with this flag, `br_ssl_engine_get_selected_protocol()`
|
||||||
|
* may still return `NULL` if the client or the server does not send an
|
||||||
|
* ALPN extension at all.
|
||||||
|
*/
|
||||||
|
#define BR_OPT_FAIL_ON_ALPN_MISMATCH ((uint32_t)1 << 3)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set the minimum and maximum supported protocol versions.
|
* \brief Set the minimum and maximum supported protocol versions.
|
||||||
*
|
*
|
||||||
|
|
@ -1119,6 +1166,65 @@ br_ssl_engine_set_x509(br_ssl_engine_context *cc, const br_x509_class **x509ctx)
|
||||||
cc->x509ctx = x509ctx;
|
cc->x509ctx = x509ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the supported protocol names.
|
||||||
|
*
|
||||||
|
* Protocol names are part of the ALPN extension ([RFC
|
||||||
|
* 7301](https://tools.ietf.org/html/rfc7301)). Each protocol name is a
|
||||||
|
* character string, containing no more than 255 characters (256 with the
|
||||||
|
* terminating zero). When names are set, then:
|
||||||
|
*
|
||||||
|
* - The client will send an ALPN extension, containing the names. If
|
||||||
|
* the server responds with an ALPN extension, the client will verify
|
||||||
|
* that the response contains one of its name, and report that name
|
||||||
|
* through `br_ssl_engine_get_selected_protocol()`.
|
||||||
|
*
|
||||||
|
* - The server will parse incoming ALPN extension (from clients), and
|
||||||
|
* try to find a common protocol; if none is found, the connection
|
||||||
|
* is aborted with a fatal alert. On match, a response ALPN extension
|
||||||
|
* is sent, and name is reported through
|
||||||
|
* `br_ssl_engine_get_selected_protocol()`.
|
||||||
|
*
|
||||||
|
* The provided array is linked in, and must remain valid while the
|
||||||
|
* connection is live.
|
||||||
|
*
|
||||||
|
* Names MUST NOT be empty. Names MUST NOT be longer than 255 characters
|
||||||
|
* (excluding the terminating 0).
|
||||||
|
*
|
||||||
|
* \param ctx SSL engine context.
|
||||||
|
* \param names list of protocol names (zero-terminated).
|
||||||
|
* \param num number of protocol names (MUST be 1 or more).
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
br_ssl_engine_set_protocol_names(br_ssl_engine_context *ctx,
|
||||||
|
const char **names, size_t num)
|
||||||
|
{
|
||||||
|
ctx->protocol_names = names;
|
||||||
|
ctx->protocol_names_num = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the selected protocol.
|
||||||
|
*
|
||||||
|
* If this context was initialised with a non-empty list of protocol
|
||||||
|
* names, and both client and server sent ALPN extensions during the
|
||||||
|
* handshake, and a common name was found, then that name is returned.
|
||||||
|
* Otherwise, `NULL` is returned.
|
||||||
|
*
|
||||||
|
* The returned pointer is one of the pointers provided to the context
|
||||||
|
* with `br_ssl_engine_set_protocol_names()`.
|
||||||
|
*
|
||||||
|
* \return the selected protocol, or `NULL`.
|
||||||
|
*/
|
||||||
|
static inline const char *
|
||||||
|
br_ssl_engine_get_selected_protocol(br_ssl_engine_context *ctx)
|
||||||
|
{
|
||||||
|
unsigned k;
|
||||||
|
|
||||||
|
k = ctx->selected_protocol;
|
||||||
|
return (k == 0 || k == 0xFFFF) ? NULL : ctx->protocol_names[k - 1];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set a hash function implementation (by ID).
|
* \brief Set a hash function implementation (by ID).
|
||||||
*
|
*
|
||||||
|
|
@ -3727,5 +3833,6 @@ int br_sslio_close(br_sslio_context *cc);
|
||||||
#define BR_ALERT_USER_CANCELED 90
|
#define BR_ALERT_USER_CANCELED 90
|
||||||
#define BR_ALERT_NO_RENEGOTIATION 100
|
#define BR_ALERT_NO_RENEGOTIATION 100
|
||||||
#define BR_ALERT_UNSUPPORTED_EXTENSION 110
|
#define BR_ALERT_UNSUPPORTED_EXTENSION 110
|
||||||
|
#define BR_ALERT_NO_APPLICATION_PROTOCOL 120
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -429,6 +429,21 @@ addr-ctx: hash_id
|
||||||
: ext-point-format-length ( -- len )
|
: ext-point-format-length ( -- len )
|
||||||
supported-curves if 6 else 0 then ;
|
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 handshake message: ClientHello
|
||||||
: write-ClientHello ( -- )
|
: write-ClientHello ( -- )
|
||||||
{ ; total-ext-length }
|
{ ; total-ext-length }
|
||||||
|
|
@ -438,6 +453,7 @@ addr-ctx: hash_id
|
||||||
ext-reneg-length ext-sni-length + ext-frag-length +
|
ext-reneg-length ext-sni-length + ext-frag-length +
|
||||||
ext-signatures-length +
|
ext-signatures-length +
|
||||||
ext-supported-curves-length + ext-point-format-length +
|
ext-supported-curves-length + ext-point-format-length +
|
||||||
|
ext-ALPN-length +
|
||||||
>total-ext-length
|
>total-ext-length
|
||||||
|
|
||||||
\ ClientHello type
|
\ ClientHello type
|
||||||
|
|
@ -542,6 +558,21 @@ addr-ctx: hash_id
|
||||||
0x0002 write16 \ extension length
|
0x0002 write16 \ extension length
|
||||||
0x0100 write16 \ value: 1 format: uncompressed
|
0x0100 write16 \ value: 1 format: uncompressed
|
||||||
then
|
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
|
ext-padding-amount 0< ifnot
|
||||||
0x0015 write16 \ extension value (21)
|
0x0015 write16 \ extension value (21)
|
||||||
ext-padding-amount
|
ext-padding-amount
|
||||||
|
|
@ -595,6 +626,24 @@ addr-ctx: hash_id
|
||||||
then
|
then
|
||||||
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.
|
\ Save a value in a 16-bit field, or check it in case of session resumption.
|
||||||
: check-resume ( val addr resume -- )
|
: check-resume ( val addr resume -- )
|
||||||
if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
|
if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
|
||||||
|
|
@ -688,6 +737,7 @@ cc: DEBUG-BLOB ( addr len -- ) {
|
||||||
ext-signatures-length { ok-signatures }
|
ext-signatures-length { ok-signatures }
|
||||||
ext-supported-curves-length { ok-curves }
|
ext-supported-curves-length { ok-curves }
|
||||||
ext-point-format-length { ok-points }
|
ext-point-format-length { ok-points }
|
||||||
|
ext-ALPN-length { ok-ALPN }
|
||||||
begin dup while
|
begin dup while
|
||||||
read16
|
read16
|
||||||
case
|
case
|
||||||
|
|
@ -753,6 +803,15 @@ cc: DEBUG-BLOB ( addr len -- ) {
|
||||||
read-ignore-16
|
read-ignore-16
|
||||||
endof
|
endof
|
||||||
|
|
||||||
|
\ ALPN.
|
||||||
|
0x0010 of
|
||||||
|
ok-ALPN ifnot
|
||||||
|
ERR_EXTRA_EXTENSION fail
|
||||||
|
then
|
||||||
|
0 >ok-ALPN
|
||||||
|
read-ALPN-from-server
|
||||||
|
endof
|
||||||
|
|
||||||
ERR_EXTRA_EXTENSION fail
|
ERR_EXTRA_EXTENSION fail
|
||||||
endcase
|
endcase
|
||||||
repeat
|
repeat
|
||||||
|
|
@ -1102,6 +1161,7 @@ cc: do-client-sign ( -- sig_len ) {
|
||||||
: do-handshake ( -- )
|
: do-handshake ( -- )
|
||||||
0 addr-application_data set8
|
0 addr-application_data set8
|
||||||
22 addr-record_type_out set8
|
22 addr-record_type_out set8
|
||||||
|
0 addr-selected_protocol set16
|
||||||
multihash-init
|
multihash-init
|
||||||
|
|
||||||
write-ClientHello
|
write-ClientHello
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,8 @@ addr-eng: pad
|
||||||
addr-eng: action
|
addr-eng: action
|
||||||
addr-eng: alert
|
addr-eng: alert
|
||||||
addr-eng: close_received
|
addr-eng: close_received
|
||||||
|
addr-eng: protocol_names_num
|
||||||
|
addr-eng: selected_protocol
|
||||||
|
|
||||||
\ Similar to 'addr-eng:', for fields in the 'session' substructure.
|
\ Similar to 'addr-eng:', for fields in the 'session' substructure.
|
||||||
: addr-session-field:
|
: addr-session-field:
|
||||||
|
|
@ -1235,3 +1237,33 @@ cc: get-key-type-usages ( -- key-type-usages ) {
|
||||||
|
|
||||||
\ Return key type and usages.
|
\ Return key type and usages.
|
||||||
get-key-type-usages ;
|
get-key-type-usages ;
|
||||||
|
|
||||||
|
\ =======================================================================
|
||||||
|
|
||||||
|
\ Copy a specific protocol name from the list to the pad. The byte
|
||||||
|
\ length is returned.
|
||||||
|
cc: copy-protocol-name ( idx -- len ) {
|
||||||
|
size_t idx = T0_POP();
|
||||||
|
size_t len = strlen(ENG->protocol_names[idx]);
|
||||||
|
memcpy(ENG->pad, ENG->protocol_names[idx], len);
|
||||||
|
T0_PUSH(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
\ Compare name in pad with the configured list of protocol names.
|
||||||
|
\ If a match is found, then the index is returned; otherwise, -1
|
||||||
|
\ is returned.
|
||||||
|
cc: test-protocol-name ( len -- n ) {
|
||||||
|
size_t len = T0_POP();
|
||||||
|
size_t u;
|
||||||
|
|
||||||
|
for (u = 0; u < ENG->protocol_names_num; u ++) {
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
name = ENG->protocol_names[u];
|
||||||
|
if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
|
||||||
|
T0_PUSH(u);
|
||||||
|
T0_RET();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
T0_PUSHi(-1);
|
||||||
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -528,6 +528,41 @@ cc: set-max-frag-len ( len -- ) {
|
||||||
close-elt
|
close-elt
|
||||||
close-elt ;
|
close-elt ;
|
||||||
|
|
||||||
|
\ Read the ALPN extension from client.
|
||||||
|
: read-ALPN-from-client ( lim -- lim )
|
||||||
|
\ If we do not have configured names, then we just ignore the
|
||||||
|
\ extension.
|
||||||
|
addr-protocol_names_num get16 ifnot read-ignore-16 ret then
|
||||||
|
|
||||||
|
\ Open extension value.
|
||||||
|
read16 open-elt
|
||||||
|
|
||||||
|
\ Open list of protocol names.
|
||||||
|
read16 open-elt
|
||||||
|
|
||||||
|
\ Get all names and test for their support. We keep the one with
|
||||||
|
\ the lowest index (because we apply server's preferences, as
|
||||||
|
\ recommended by RFC 7301, section 3.2. We set the 'found' variable
|
||||||
|
\ to -2 and use an unsigned comparison, making -2 a huge value.
|
||||||
|
-2 { found }
|
||||||
|
begin dup while
|
||||||
|
read8 dup { len } addr-pad swap read-blob
|
||||||
|
len test-protocol-name dup found u< if
|
||||||
|
>found
|
||||||
|
else
|
||||||
|
drop
|
||||||
|
then
|
||||||
|
repeat
|
||||||
|
|
||||||
|
\ End of extension.
|
||||||
|
close-elt
|
||||||
|
close-elt
|
||||||
|
|
||||||
|
\ Write back found name index (or not). If no match was found,
|
||||||
|
\ then we write -1 (0xFFFF) in the index value, not 0, so that
|
||||||
|
\ the caller knows that we tried to match, and failed.
|
||||||
|
found 1+ addr-selected_protocol set16 ;
|
||||||
|
|
||||||
\ Call policy handler to get cipher suite, hash function identifier and
|
\ Call policy handler to get cipher suite, hash function identifier and
|
||||||
\ certificate chain. Returned value is 0 (false) on failure.
|
\ certificate chain. Returned value is 0 (false) on failure.
|
||||||
cc: call-policy-handler ( -- bool ) {
|
cc: call-policy-handler ( -- bool ) {
|
||||||
|
|
@ -709,6 +744,11 @@ cc: save-session ( -- ) {
|
||||||
\ read-ignore-16
|
\ read-ignore-16
|
||||||
\ endof
|
\ endof
|
||||||
|
|
||||||
|
\ ALPN
|
||||||
|
0x0010 of
|
||||||
|
read-ALPN-from-client
|
||||||
|
endof
|
||||||
|
|
||||||
\ Other extensions are ignored.
|
\ Other extensions are ignored.
|
||||||
drop read-ignore-16 0
|
drop read-ignore-16 0
|
||||||
endcase
|
endcase
|
||||||
|
|
@ -832,6 +872,12 @@ cc: save-session ( -- ) {
|
||||||
then
|
then
|
||||||
addr-client_suites_num set8
|
addr-client_suites_num set8
|
||||||
|
|
||||||
|
\ Check ALPN.
|
||||||
|
addr-selected_protocol get16 0xFFFF = if
|
||||||
|
3 flag? if 120 fail-alert then
|
||||||
|
0 addr-selected_protocol set16
|
||||||
|
then
|
||||||
|
|
||||||
\ Call policy handler to obtain the cipher suite and other
|
\ Call policy handler to obtain the cipher suite and other
|
||||||
\ parameters.
|
\ parameters.
|
||||||
call-policy-handler ifnot 40 fail-alert then
|
call-policy-handler ifnot 40 fail-alert then
|
||||||
|
|
@ -842,20 +888,28 @@ cc: save-session ( -- ) {
|
||||||
\ Write ServerHello.
|
\ Write ServerHello.
|
||||||
: write-ServerHello ( initial -- )
|
: write-ServerHello ( initial -- )
|
||||||
{ initial }
|
{ initial }
|
||||||
\ Compute ServerHello length. Right now we only send the
|
\ Compute ServerHello length.
|
||||||
\ "secure renegotiation" extension.
|
|
||||||
2 write8 70
|
2 write8 70
|
||||||
|
|
||||||
|
\ Compute length of Secure Renegotiation extension.
|
||||||
addr-reneg get8 2 = if
|
addr-reneg get8 2 = if
|
||||||
initial if 5 else 29 then
|
initial if 5 else 29 then
|
||||||
else
|
else
|
||||||
0
|
0
|
||||||
then
|
then
|
||||||
{ ext-reneg-len }
|
{ ext-reneg-len }
|
||||||
|
|
||||||
|
\ Compute length of Max Fragment Length extension.
|
||||||
addr-peer_log_max_frag_len get8 if 5 else 0 then
|
addr-peer_log_max_frag_len get8 if 5 else 0 then
|
||||||
{ ext-max-frag-len }
|
{ ext-max-frag-len }
|
||||||
|
|
||||||
ext-reneg-len ext-max-frag-len + dup if 2 + then +
|
\ Compute length of ALPN extension. This also copy the
|
||||||
|
\ selected protocol name into the pad.
|
||||||
|
addr-selected_protocol get16 dup if 1- copy-protocol-name 7 + then
|
||||||
|
{ ext-ALPN-len }
|
||||||
|
|
||||||
|
\ Adjust ServerHello length to account for the extensions.
|
||||||
|
ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if 2 + then +
|
||||||
write24
|
write24
|
||||||
|
|
||||||
\ Protocol version
|
\ Protocol version
|
||||||
|
|
@ -880,7 +934,7 @@ cc: save-session ( -- ) {
|
||||||
0 write8
|
0 write8
|
||||||
|
|
||||||
\ Extensions
|
\ Extensions
|
||||||
ext-reneg-len ext-max-frag-len + dup if
|
ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if
|
||||||
write16
|
write16
|
||||||
ext-reneg-len dup if
|
ext-reneg-len dup if
|
||||||
0xFF01 write16
|
0xFF01 write16
|
||||||
|
|
@ -893,6 +947,16 @@ cc: save-session ( -- ) {
|
||||||
0x0001 write16
|
0x0001 write16
|
||||||
1 write16 addr-peer_log_max_frag_len get8 8 - write8
|
1 write16 addr-peer_log_max_frag_len get8 8 - write8
|
||||||
then
|
then
|
||||||
|
ext-ALPN-len dup if
|
||||||
|
\ Note: the selected protocol name was previously
|
||||||
|
\ copied into the pad.
|
||||||
|
0x0010 write16
|
||||||
|
4 - dup write16
|
||||||
|
2- dup write16
|
||||||
|
1- addr-pad swap write-blob-head8
|
||||||
|
else
|
||||||
|
drop
|
||||||
|
then
|
||||||
else
|
else
|
||||||
drop
|
drop
|
||||||
then ;
|
then ;
|
||||||
|
|
@ -1289,6 +1353,7 @@ cc: verify-CV-sig ( sig-len -- err ) {
|
||||||
: do-handshake ( initial -- )
|
: do-handshake ( initial -- )
|
||||||
0 addr-application_data set8
|
0 addr-application_data set8
|
||||||
22 addr-record_type_out set8
|
22 addr-record_type_out set8
|
||||||
|
0 addr-selected_protocol set16
|
||||||
multihash-init
|
multihash-init
|
||||||
read-ClientHello
|
read-ClientHello
|
||||||
more-incoming-bytes? if ERR_UNEXPECTED fail then
|
more-incoming-bytes? if ERR_UNEXPECTED fail then
|
||||||
|
|
|
||||||
|
|
@ -419,6 +419,12 @@ static const br_ssl_client_certificate_class ccert_vtable = {
|
||||||
cc_do_sign
|
cc_do_sign
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_alpn(void *alpn)
|
||||||
|
{
|
||||||
|
xfree(*(char **)alpn);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage_client(void)
|
usage_client(void)
|
||||||
{
|
{
|
||||||
|
|
@ -462,6 +468,10 @@ usage_client(void)
|
||||||
" -fallback send the TLS_FALLBACK_SCSV (i.e. claim a downgrade)\n");
|
" -fallback send the TLS_FALLBACK_SCSV (i.e. claim a downgrade)\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" -noreneg prohibit renegotiations\n");
|
" -noreneg prohibit renegotiations\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" -alpn name add protocol name to list of protocols (ALPN extension)\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" -strictalpn fail on ALPN mismatch\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see brssl.h */
|
/* see brssl.h */
|
||||||
|
|
@ -478,6 +488,7 @@ do_client(int argc, char *argv[])
|
||||||
const char *sni;
|
const char *sni;
|
||||||
anchor_list anchors = VEC_INIT;
|
anchor_list anchors = VEC_INIT;
|
||||||
unsigned vmin, vmax;
|
unsigned vmin, vmax;
|
||||||
|
VECTOR(const char *) alpn_names = VEC_INIT;
|
||||||
cipher_suite *suites;
|
cipher_suite *suites;
|
||||||
size_t num_suites;
|
size_t num_suites;
|
||||||
uint16_t *suite_ids;
|
uint16_t *suite_ids;
|
||||||
|
|
@ -744,6 +755,16 @@ do_client(int argc, char *argv[])
|
||||||
fallback = 1;
|
fallback = 1;
|
||||||
} else if (eqstr(arg, "-noreneg")) {
|
} else if (eqstr(arg, "-noreneg")) {
|
||||||
flags |= BR_OPT_NO_RENEGOTIATION;
|
flags |= BR_OPT_NO_RENEGOTIATION;
|
||||||
|
} else if (eqstr(arg, "-alpn")) {
|
||||||
|
if (++ i >= argc) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: no argument for '-alpn'\n");
|
||||||
|
usage_client();
|
||||||
|
goto client_exit_error;
|
||||||
|
}
|
||||||
|
VEC_ADD(alpn_names, xstrdup(argv[i]));
|
||||||
|
} else if (eqstr(arg, "-strictalpn")) {
|
||||||
|
flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
|
fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
|
||||||
usage_client();
|
usage_client();
|
||||||
|
|
@ -1002,6 +1023,10 @@ do_client(int argc, char *argv[])
|
||||||
br_ssl_client_set_min_clienthello_len(&cc, minhello_len);
|
br_ssl_client_set_min_clienthello_len(&cc, minhello_len);
|
||||||
}
|
}
|
||||||
br_ssl_engine_set_all_flags(&cc.eng, flags);
|
br_ssl_engine_set_all_flags(&cc.eng, flags);
|
||||||
|
if (VEC_LEN(alpn_names) != 0) {
|
||||||
|
br_ssl_engine_set_protocol_names(&cc.eng,
|
||||||
|
&VEC_ELT(alpn_names, 0), VEC_LEN(alpn_names));
|
||||||
|
}
|
||||||
|
|
||||||
if (chain != NULL) {
|
if (chain != NULL) {
|
||||||
zc.vtable = &ccert_vtable;
|
zc.vtable = &ccert_vtable;
|
||||||
|
|
@ -1057,6 +1082,7 @@ client_exit:
|
||||||
xfree(suites);
|
xfree(suites);
|
||||||
xfree(suite_ids);
|
xfree(suite_ids);
|
||||||
VEC_CLEAREXT(anchors, &free_ta_contents);
|
VEC_CLEAREXT(anchors, &free_ta_contents);
|
||||||
|
VEC_CLEAREXT(alpn_names, &free_alpn);
|
||||||
free_certificates(chain, chain_len);
|
free_certificates(chain, chain_len);
|
||||||
free_private_key(sk);
|
free_private_key(sk);
|
||||||
xfree(iobuf);
|
xfree(iobuf);
|
||||||
|
|
|
||||||
|
|
@ -229,6 +229,12 @@ usage_server(void)
|
||||||
" -hf names add support for some hash functions (comma-separated)\n");
|
" -hf names add support for some hash functions (comma-separated)\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" -serverpref enforce server's preferences for cipher suites\n");
|
" -serverpref enforce server's preferences for cipher suites\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" -noreneg prohibit renegotiations\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" -alpn name add protocol name to list of protocols (ALPN extension)\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
" -strictalpn fail on ALPN mismatch\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -512,6 +518,12 @@ static const br_ssl_server_policy_class policy_vtable = {
|
||||||
sp_do_sign
|
sp_do_sign
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
free_alpn(void *alpn)
|
||||||
|
{
|
||||||
|
xfree(*(char **)alpn);
|
||||||
|
}
|
||||||
|
|
||||||
/* see brssl.h */
|
/* see brssl.h */
|
||||||
int
|
int
|
||||||
do_server(int argc, char *argv[])
|
do_server(int argc, char *argv[])
|
||||||
|
|
@ -532,6 +544,7 @@ do_server(int argc, char *argv[])
|
||||||
int cert_signer_algo;
|
int cert_signer_algo;
|
||||||
private_key *sk;
|
private_key *sk;
|
||||||
anchor_list anchors = VEC_INIT;
|
anchor_list anchors = VEC_INIT;
|
||||||
|
VECTOR(const char *) alpn_names = VEC_INIT;
|
||||||
br_x509_minimal_context xc;
|
br_x509_minimal_context xc;
|
||||||
const br_hash_class *dnhash;
|
const br_hash_class *dnhash;
|
||||||
size_t u;
|
size_t u;
|
||||||
|
|
@ -781,6 +794,16 @@ do_server(int argc, char *argv[])
|
||||||
flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES;
|
flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES;
|
||||||
} else if (eqstr(arg, "-noreneg")) {
|
} else if (eqstr(arg, "-noreneg")) {
|
||||||
flags |= BR_OPT_NO_RENEGOTIATION;
|
flags |= BR_OPT_NO_RENEGOTIATION;
|
||||||
|
} else if (eqstr(arg, "-alpn")) {
|
||||||
|
if (++ i >= argc) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: no argument for '-alpn'\n");
|
||||||
|
usage_server();
|
||||||
|
goto server_exit_error;
|
||||||
|
}
|
||||||
|
VEC_ADD(alpn_names, xstrdup(argv[i]));
|
||||||
|
} else if (eqstr(arg, "-strictalpn")) {
|
||||||
|
flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
|
fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
|
||||||
usage_server();
|
usage_server();
|
||||||
|
|
@ -999,6 +1022,11 @@ do_server(int argc, char *argv[])
|
||||||
br_ssl_session_cache_lru_init(&lru, cache, cache_len);
|
br_ssl_session_cache_lru_init(&lru, cache, cache_len);
|
||||||
br_ssl_server_set_cache(&cc, &lru.vtable);
|
br_ssl_server_set_cache(&cc, &lru.vtable);
|
||||||
|
|
||||||
|
if (VEC_LEN(alpn_names) != 0) {
|
||||||
|
br_ssl_engine_set_protocol_names(&cc.eng,
|
||||||
|
&VEC_ELT(alpn_names, 0), VEC_LEN(alpn_names));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the policy handler (that chooses the actual cipher suite,
|
* Set the policy handler (that chooses the actual cipher suite,
|
||||||
* selects the certificate chain, and runs the private key
|
* selects the certificate chain, and runs the private key
|
||||||
|
|
@ -1091,6 +1119,7 @@ server_exit:
|
||||||
free_certificates(chain, chain_len);
|
free_certificates(chain, chain_len);
|
||||||
free_private_key(sk);
|
free_private_key(sk);
|
||||||
VEC_CLEAREXT(anchors, &free_ta_contents);
|
VEC_CLEAREXT(anchors, &free_ta_contents);
|
||||||
|
VEC_CLEAREXT(alpn_names, &free_alpn);
|
||||||
xfree(iobuf);
|
xfree(iobuf);
|
||||||
xfree(cache);
|
xfree(cache);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,7 @@ run_ssl_engine(br_ssl_engine_context *cc, int fd, unsigned flags)
|
||||||
recvapp = ((st & BR_SSL_RECVAPP) != 0);
|
recvapp = ((st & BR_SSL_RECVAPP) != 0);
|
||||||
if (verbose && sendapp && !hsdetails) {
|
if (verbose && sendapp && !hsdetails) {
|
||||||
char csn[80];
|
char csn[80];
|
||||||
|
const char *pname;
|
||||||
|
|
||||||
fprintf(stderr, "Handshake completed\n");
|
fprintf(stderr, "Handshake completed\n");
|
||||||
fprintf(stderr, " version: ");
|
fprintf(stderr, " version: ");
|
||||||
|
|
@ -240,6 +241,12 @@ run_ssl_engine(br_ssl_engine_context *cc, int fd, unsigned flags)
|
||||||
fprintf(stderr, " cipher suite: %s\n", csn);
|
fprintf(stderr, " cipher suite: %s\n", csn);
|
||||||
fprintf(stderr, " secure renegotiation: %s\n",
|
fprintf(stderr, " secure renegotiation: %s\n",
|
||||||
cc->reneg == 1 ? "no" : "yes");
|
cc->reneg == 1 ? "no" : "yes");
|
||||||
|
pname = br_ssl_engine_get_selected_protocol(cc);
|
||||||
|
if (pname != NULL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
" protocol name (ALPN): %s\n",
|
||||||
|
pname);
|
||||||
|
}
|
||||||
hsdetails = 1;
|
hsdetails = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue