diff --git a/CHANGES.md b/CHANGES.md index 3799c28c97..212532bce2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,6 +24,15 @@ OpenSSL 3.1 ### Changes between 3.0 and 3.1 [xx XXX xxxx] + * Add new SSL APIs to aid in efficiently implementing TLS/SSL fingerprinting. The + SSL_CTRL_GET_IANA_GROUPS control code, exposed as the SSL_get0_iana_groups() + function-like macro, retrieves the list of supported groups sent by the peer, + and the function SSL_client_hello_get_extension_order() populates a caller-supplied + array with the list of extension types present in the ClientHello, in order of + appearance. + + *Phus Lu* + * Fixed PEM_write_bio_PKCS8PrivateKey() and PEM_write_bio_PKCS8PrivateKey_nid() to make it possible to use empty passphrase strings. diff --git a/doc/man3/SSL_CTX_set1_curves.pod b/doc/man3/SSL_CTX_set1_curves.pod index cbd8f71346..d24db8f812 100644 --- a/doc/man3/SSL_CTX_set1_curves.pod +++ b/doc/man3/SSL_CTX_set1_curves.pod @@ -3,9 +3,10 @@ =head1 NAME SSL_CTX_set1_groups, SSL_CTX_set1_groups_list, SSL_set1_groups, -SSL_set1_groups_list, SSL_get1_groups, SSL_get_shared_group, -SSL_get_negotiated_group, SSL_CTX_set1_curves, SSL_CTX_set1_curves_list, -SSL_set1_curves, SSL_set1_curves_list, SSL_get1_curves, SSL_get_shared_curve +SSL_set1_groups_list, SSL_get1_groups, SSL_get0_iana_groups, +SSL_get_shared_group, SSL_get_negotiated_group, SSL_CTX_set1_curves, +SSL_CTX_set1_curves_list, SSL_set1_curves, SSL_set1_curves_list, +SSL_get1_curves, SSL_get_shared_curve - EC supported curve functions =head1 SYNOPSIS @@ -19,6 +20,7 @@ SSL_set1_curves, SSL_set1_curves_list, SSL_get1_curves, SSL_get_shared_curve int SSL_set1_groups_list(SSL *ssl, char *list); int SSL_get1_groups(SSL *ssl, int *groups); + int SSL_get0_iana_groups(SSL *ssl, uint16_t **out); int SSL_get_shared_group(SSL *s, int n); int SSL_get_negotiated_group(SSL *s); @@ -68,6 +70,13 @@ order. It can return zero if the client did not send a supported groups extension. If a supported group NID is unknown then the value is set to the bitwise OR of TLSEXT_nid_unknown (0x1000000) and the id of the group. +SSL_get0_iana_groups() retrieves the list of groups sent by the +client in the supported_groups extension. The B<*out> array of bytes +is populated with the host-byte-order representation of the uint16_t group +identifiers, as assigned by IANA. The group list is returned in the same order +that was received in the ClientHello. The return value is the number of groups, +not the number of bytes written. + SSL_get_shared_group() returns the NID of the shared group B for a server-side SSL B. If B is -1 then the total number of shared groups is returned, which may be zero. Other than for diagnostic purposes, @@ -108,6 +117,8 @@ SSL_set1_groups_list(), return 1 for success and 0 for failure. SSL_get1_groups() returns the number of groups, which may be zero. +SSL_get0_iana_groups() returns the number of (uint16_t) groups, which may be zero. + SSL_get_shared_group() returns the NID of shared group B or NID_undef if there is no shared group B; or the total number of shared groups if B is -1. diff --git a/doc/man3/SSL_CTX_set_client_hello_cb.pod b/doc/man3/SSL_CTX_set_client_hello_cb.pod index f324647abc..dc882a12e6 100644 --- a/doc/man3/SSL_CTX_set_client_hello_cb.pod +++ b/doc/man3/SSL_CTX_set_client_hello_cb.pod @@ -2,7 +2,7 @@ =head1 NAME -SSL_CTX_set_client_hello_cb, SSL_client_hello_cb_fn, SSL_client_hello_isv2, SSL_client_hello_get0_legacy_version, SSL_client_hello_get0_random, SSL_client_hello_get0_session_id, SSL_client_hello_get0_ciphers, SSL_client_hello_get0_compression_methods, SSL_client_hello_get1_extensions_present, SSL_client_hello_get0_ext - callback functions for early server-side ClientHello processing +SSL_CTX_set_client_hello_cb, SSL_client_hello_cb_fn, SSL_client_hello_isv2, SSL_client_hello_get0_legacy_version, SSL_client_hello_get0_random, SSL_client_hello_get0_session_id, SSL_client_hello_get0_ciphers, SSL_client_hello_get0_compression_methods, SSL_client_hello_get1_extensions_present, SSL_client_hello_get_extension_order, SSL_client_hello_get0_ext - callback functions for early server-side ClientHello processing =head1 SYNOPSIS @@ -18,6 +18,8 @@ SSL_CTX_set_client_hello_cb, SSL_client_hello_cb_fn, SSL_client_hello_isv2, SSL_ const unsigned char **out); int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen); + int SSL_client_hello_get_extension_order(SSL *s, uint16_t *exts, + size_t *num_exts); int SSL_client_hello_get0_ext(SSL *s, unsigned int type, const unsigned char **out, size_t *outlen); @@ -68,6 +70,20 @@ in the ClientHello. B<*outlen> contains the number of elements in the array. In situations when the ClientHello has no extensions, the function will return success with B<*out> set to NULL and B<*outlen> set to 0. +SSL_client_hello_get_extension_order() is similar to +SSL_client_hello_get1_extensions_present(), without internal memory allocation. +When called with B set to NULL, returns the number of extensions +(e.g., to allocate storage for a subsequent call). Otherwise, B<*exts> is populated +with the ExtensionType values in the order that the corresponding extensions +appeared in the ClientHello. B<*num_exts> is an input/output parameter, used +as input to supply the size of storage allocated by the caller, and as output to +indicate how many ExtensionType values were written. If the input B<*num_exts> +is smaller then the number of extensions in question, that is treated as an error. +A subsequent call with B set to NULL can retrieve the size of storage needed. +A ClientHello that contained no extensions is treated as success, with B<*num_exts> +set to 0. + + =head1 NOTES The ClientHello callback provides a vast window of possibilities for application @@ -107,6 +123,8 @@ SSL_client_hello_get0_ext() returns 1 if the extension of type 'type' is present SSL_client_hello_get1_extensions_present() returns 1 on success and 0 on failure. +SSL_client_hello_get_extension_order() returns 1 on success and 0 on failure. + =head1 SEE ALSO L, L, @@ -119,6 +137,8 @@ SSL_client_hello_get0_random(), SSL_client_hello_get0_session_id(), SSL_client_hello_get0_ciphers(), SSL_client_hello_get0_compression_methods(), SSL_client_hello_get0_ext(), and SSL_client_hello_get1_extensions_present() were added in OpenSSL 1.1.1. +SSL_client_hello_get_extension_order() +was added in OpenSSL 3.1.0. =head1 COPYRIGHT diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index 9c00eb3d13..47f277969c 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -1308,6 +1308,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) # define SSL_CTRL_GET_SIGNATURE_NID 132 # define SSL_CTRL_GET_TMP_KEY 133 # define SSL_CTRL_GET_NEGOTIATED_GROUP 134 +# define SSL_CTRL_GET_IANA_GROUPS 135 # define SSL_CERT_SET_FIRST 1 # define SSL_CERT_SET_NEXT 2 # define SSL_CERT_SET_SERVER 3 @@ -1401,6 +1402,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)(st)) # define SSL_get1_groups(s, glist) \ SSL_ctrl(s,SSL_CTRL_GET_GROUPS,0,(int*)(glist)) +# define SSL_get0_iana_groups(s, plst) \ + SSL_ctrl(s,SSL_CTRL_GET_IANA_GROUPS,0,(uint16_t **)(plst)) # define SSL_CTX_set1_groups(ctx, glist, glistlen) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_GROUPS,glistlen,(int *)(glist)) # define SSL_CTX_set1_groups_list(ctx, s) \ @@ -1848,6 +1851,8 @@ size_t SSL_client_hello_get0_ciphers(SSL *s, const unsigned char **out); size_t SSL_client_hello_get0_compression_methods(SSL *s, const unsigned char **out); int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen); +int SSL_client_hello_get_extension_order(SSL *s, uint16_t *exts, + size_t *num_exts); int SSL_client_hello_get0_ext(SSL *s, unsigned int type, const unsigned char **out, size_t *outlen); diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 120b5cedeb..3b3cc8a32a 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3729,6 +3729,14 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) return (int)s->ext.peer_ecpointformats_len; } + case SSL_CTRL_GET_IANA_GROUPS: + { + if (parg != NULL) { + *(uint16_t **)parg = (uint16_t *)s->ext.peer_supportedgroups; + } + return (int)s->ext.peer_supportedgroups_len; + } + default: break; } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 655eac0b7c..cb7a52ab7e 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5424,6 +5424,40 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) return 0; } +int SSL_client_hello_get_extension_order(SSL *s, uint16_t *exts, size_t *num_exts) +{ + RAW_EXTENSION *ext; + size_t num = 0, i; + + if (s->clienthello == NULL || num_exts == NULL) + return 0; + for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) { + ext = s->clienthello->pre_proc_exts + i; + if (ext->present) + num++; + } + if (num == 0) { + *num_exts = 0; + return 1; + } + if (exts == NULL) { + *num_exts = num; + return 1; + } + if (*num_exts < num) + return 0; + for (i = 0; i < s->clienthello->pre_proc_exts_len; i++) { + ext = s->clienthello->pre_proc_exts + i; + if (ext->present) { + if (ext->received_order >= num) + return 0; + exts[ext->received_order] = ext->type; + } + } + *num_exts = num; + return 1; +} + int SSL_client_hello_get0_ext(SSL *s, unsigned int type, const unsigned char **out, size_t *outlen) { diff --git a/util/libssl.num b/util/libssl.num index f055c967bf..c7afa8fdb0 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -520,3 +520,4 @@ SSL_load_client_CA_file_ex 520 3_0_0 EXIST::FUNCTION: SSL_set0_tmp_dh_pkey 521 3_0_0 EXIST::FUNCTION: SSL_CTX_set0_tmp_dh_pkey 522 3_0_0 EXIST::FUNCTION: SSL_group_to_name 523 3_0_0 EXIST::FUNCTION: +SSL_client_hello_get_extension_order ? 3_1_0 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index da5f937c3f..ae675b78f4 100644 --- a/util/other.syms +++ b/util/other.syms @@ -532,6 +532,7 @@ SSL_clear_chain_certs define SSL_clear_mode define SSL_disable_ct define SSL_get0_chain_certs define +SSL_get0_iana_groups define SSL_get0_session define SSL_get1_curves define SSL_get1_groups define