summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhus Lu <phus.lu@gmail.com>2021-10-25 18:47:00 +0800
committerTomas Mraz <tomas@openssl.org>2022-02-03 13:45:41 +0100
commit13a53fbf13bc6fa09c95ad4bdc6ec70fa15aa16d (patch)
tree34c712b39eae57857d9b3b60abd7d8f59c9cdca5
parent27aca04e13ca8a9bead49de7bc380110ecb7064e (diff)
add SSL_get0_iana_groups() & SSL_client_hello_get_extension_order()
The function/macro allow user get groups/extensions without memory allcations. So we could calculate the ssl fignerprint(ja3) in low cost. Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/16910)
-rw-r--r--CHANGES.md9
-rw-r--r--doc/man3/SSL_CTX_set1_curves.pod17
-rw-r--r--doc/man3/SSL_CTX_set_client_hello_cb.pod22
-rw-r--r--include/openssl/ssl.h.in5
-rw-r--r--ssl/s3_lib.c8
-rw-r--r--ssl/ssl_lib.c34
-rw-r--r--util/libssl.num1
-rw-r--r--util/other.syms1
8 files changed, 93 insertions, 4 deletions
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<n> for a
server-side SSL B<ssl>. If B<n> 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<n> or NID_undef if there
is no shared group B<n>; or the total number of shared groups if B<n>
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<exts> 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<exts> 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<ssl(7)>, L<SSL_CTX_set_tlsext_servername_callback(3)>,
@@ -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