The branch master has been updated via 5b70206cb316024c6dc30ce54f585ce5cf001a56 (commit) via 8b17fbaf46ae8a1319be5975ad8da3e0f4932e77 (commit) via a011b5861b545b40df3c6f111df4fbde74cd7c82 (commit) via c1a74f59ac799087c511d641cb086722817b805b (commit) via ecff43e0ca48b25ddb001b6b63f3b7f8431f6962 (commit) via c8e3a4c61346915a30b0c3594a7710753b8d1126 (commit) via 32fea070dc679f656a9e3d152aa570f6b658bc8e (commit) from 47690cd4ceb3a1cfdf097d575cb0d3cf9c6dac13 (commit)
- Log ----------------------------------------------------------------- commit 5b70206cb316024c6dc30ce54f585ce5cf001a56 Author: Nicola Tuveri <nic....@gmail.com> Date: Mon Sep 28 08:37:13 2020 +0300 [test][tls-provider] Implement KEM algorithm Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018) commit 8b17fbaf46ae8a1319be5975ad8da3e0f4932e77 Author: Nicola Tuveri <nic....@gmail.com> Date: Mon Sep 28 04:32:03 2020 +0300 [ssl] Support ssl_encapsulate on server side Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018) commit a011b5861b545b40df3c6f111df4fbde74cd7c82 Author: Nicola Tuveri <nic....@gmail.com> Date: Mon Sep 28 03:45:30 2020 +0300 [ssl] Support ssl_decapsulate on client side Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018) commit c1a74f59ac799087c511d641cb086722817b805b Author: Nicola Tuveri <nic....@gmail.com> Date: Mon Sep 28 02:16:29 2020 +0300 Define OSSL_CAPABILITY_TLS_GROUP_IS_KEM Note that with this commit the optional parameter is introduced, but libssl still ignores it. Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018) commit ecff43e0ca48b25ddb001b6b63f3b7f8431f6962 Author: Nicola Tuveri <nic....@gmail.com> Date: Mon Sep 28 01:58:24 2020 +0300 [test][tls-provider] Add 2nd pluggable tls group for KEM Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018) commit c8e3a4c61346915a30b0c3594a7710753b8d1126 Author: Nicola Tuveri <nic....@gmail.com> Date: Mon Sep 28 01:26:41 2020 +0300 [test][sslapitest] Add test for pluggable KEM group Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018) commit 32fea070dc679f656a9e3d152aa570f6b658bc8e Author: Nicola Tuveri <nic....@gmail.com> Date: Mon Sep 28 01:05:27 2020 +0300 [test][tls-provider] Group xor_group properties in a struct Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018) ----------------------------------------------------------------------- Summary of changes: crypto/err/openssl.txt | 2 + doc/man7/provider-base.pod | 41 +++++- include/openssl/core_names.h | 1 + include/openssl/sslerr.h | 2 + ssl/s3_lib.c | 162 ++++++++++++++++++--- ssl/ssl_local.h | 8 ++ ssl/statem/extensions_clnt.c | 55 ++++--- ssl/statem/extensions_srvr.c | 106 ++++++++++---- ssl/t1_lib.c | 8 ++ test/sslapitest.c | 13 +- test/tls-provider.c | 334 ++++++++++++++++++++++++++++++++++++------- 11 files changed, 610 insertions(+), 122 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 1724982709..2aca84f838 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1401,11 +1401,13 @@ SSL_F_SSL_CTX_USE_SERVERINFO_EX:543:SSL_CTX_use_serverinfo_ex SSL_F_SSL_CTX_USE_SERVERINFO_FILE:337:SSL_CTX_use_serverinfo_file SSL_F_SSL_DANE_DUP:403:ssl_dane_dup SSL_F_SSL_DANE_ENABLE:395:SSL_dane_enable +SSL_F_SSL_DECAPSULATE:643: SSL_F_SSL_DERIVE:590:ssl_derive SSL_F_SSL_DO_CONFIG:391:ssl_do_config SSL_F_SSL_DO_HANDSHAKE:180:SSL_do_handshake SSL_F_SSL_DUP_CA_LIST:408:SSL_dup_CA_list SSL_F_SSL_ENABLE_CT:402:SSL_enable_ct +SSL_F_SSL_ENCAPSULATE:644: SSL_F_SSL_GENERATE_PKEY_GROUP:559:ssl_generate_pkey_group SSL_F_SSL_GENERATE_SESSION_ID:547:ssl_generate_session_id SSL_F_SSL_GET_NEW_SESSION:181:ssl_get_new_session diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod index efec869e25..b92f117d86 100644 --- a/doc/man7/provider-base.pod +++ b/doc/man7/provider-base.pod @@ -364,15 +364,17 @@ Applications can query the capabilities to discover those services. The "TLS-GROUP" capability can be queried by libssl to discover the list of TLS groups that a provider can support. Each group supported can be used for -key exchange during a TLS handshake. TLS clients can advertise the list of -TLS groups they support in the supported_groups extension, and TLS servers can -select a group from the offered list that they also support. In this way a -provider can add to the list of groups that libssl already supports with -additional ones. +I<key exchange> (KEX) or I<key encapsulation method> (KEM) during a TLS +handshake. +TLS clients can advertise the list of TLS groups they support in the +supported_groups extension, and TLS servers can select a group from the offered +list that they also support. In this way a provider can add to the list of +groups that libssl already supports with additional ones. Each TLS group that a provider supports should be described via the callback passed in through the provider_get_capabilities function. Each group should have -the following details supplied (all are mandatory): +the following details supplied (all are mandatory, except +B<OSSL_CAPABILITY_TLS_GROUP_IS_KEM>): =over 4 @@ -393,7 +395,9 @@ The TLS group id value as given in the IANA TLS Supported Groups registry. =item "tls-group-alg" (B<OSSL_CAPABILITY_TLS_GROUP_ALG>) <utf8 string> The name of a Key Management algorithm that the provider offers and that should -be used with this group. Keys created should be able to support key exchange. +be used with this group. Keys created should be able to support I<key exchange> +or I<key encapsulation method> (KEM), as implied by the optional +B<OSSL_CAPABILITY_TLS_GROUP_IS_KEM> flag. The algorithm must support key and parameter generation as well as the key/parameter generation parameter, B<OSSL_PKEY_PARAM_GROUP_NAME>. The group name given via "tls-group-name-internal" above will be passed via @@ -405,6 +409,29 @@ The number of bits of security offered by keys in this group. The number of bits should be comparable with the ones given in table 2 and 3 of the NIST SP800-57 document. +=item "tls-group-is-kem" (B<OSSL_CAPABILITY_TLS_GROUP_IS_KEM>) <unsigned integer> + +Boolean flag to describe if the group should be used in I<key exchange> (KEX) +mode (0, default) or in I<key encapsulation method> (KEM) mode (1). + +This parameter is optional: if not specified, KEX mode is assumed as the default +mode for the group. + +In KEX mode, in a typical Diffie-Hellman fashion, both sides execute I<keygen> +then I<derive> against the peer public key. To operate in KEX mode, the group +implementation must support the provider functions as described in +L<provider-keyexch(7)>. + +In KEM mode, the client executes I<keygen> and sends its public key, the server +executes I<encapsulate> using the client's public key and sends back the +resulting I<ciphertext>, finally the client executes I<decapsulate> to retrieve +the same I<shared secret> generated by the server's I<encapsulate>. To operate +in KEM mode, the group implementation must support the provider functions as +described in L<provider-kem(7)>. + +Both in KEX and KEM mode, the resulting I<shared secret> is then used according +to the protocol specification. + =item "tls-min-tls" (B<OSSL_CAPABILITY_TLS_GROUP_MIN_TLS>) <integer> =item "tls-max-tls" (B<OSSL_CAPABILITY_TLS_GROUP_MAX_TLS>) <integer> diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index c9f2bfab5e..4a4bd36cbe 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -492,6 +492,7 @@ extern "C" { #define OSSL_CAPABILITY_TLS_GROUP_ID "tls-group-id" #define OSSL_CAPABILITY_TLS_GROUP_ALG "tls-group-alg" #define OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS "tls-group-sec-bits" +#define OSSL_CAPABILITY_TLS_GROUP_IS_KEM "tls-group-is-kem" #define OSSL_CAPABILITY_TLS_GROUP_MIN_TLS "tls-min-tls" #define OSSL_CAPABILITY_TLS_GROUP_MAX_TLS "tls-max-tls" #define OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS "tls-min-dtls" diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index d4ee837a1e..56ece0d175 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -183,11 +183,13 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_CTX_USE_SERVERINFO_FILE 0 # define SSL_F_SSL_DANE_DUP 0 # define SSL_F_SSL_DANE_ENABLE 0 +# define SSL_F_SSL_DECAPSULATE 0 # define SSL_F_SSL_DERIVE 0 # define SSL_F_SSL_DO_CONFIG 0 # define SSL_F_SSL_DO_HANDSHAKE 0 # define SSL_F_SSL_DUP_CA_LIST 0 # define SSL_F_SSL_ENABLE_CT 0 +# define SSL_F_SSL_ENCAPSULATE 0 # define SSL_F_SSL_GENERATE_PKEY_GROUP 0 # define SSL_F_SSL_GENERATE_SESSION_ID 0 # define SSL_F_SSL_GET_NEW_SESSION 0 diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 94c2d8c2ce..1fd424a52e 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -4832,6 +4832,32 @@ EVP_PKEY *ssl_generate_param_group(SSL *s, uint16_t id) return pkey; } +/* Generate secrets from pms */ +int ssl_gensecret(SSL *s, unsigned char *pms, size_t pmslen) +{ + int rv = 0; + + /* SSLfatal() called as appropriate in the below functions */ + if (SSL_IS_TLS13(s)) { + /* + * If we are resuming then we already generated the early secret + * when we created the ClientHello, so don't recreate it. + */ + if (!s->hit) + rv = tls13_generate_secret(s, ssl_handshake_md(s), NULL, NULL, + 0, + (unsigned char *)&s->early_secret); + else + rv = 1; + + rv = rv && tls13_generate_handshake_secret(s, pms, pmslen); + } else { + rv = ssl_generate_master_secret(s, pms, pmslen, 0); + } + + return rv; +} + /* Derive secrets for ECDH/DH */ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int gensecret) { @@ -4876,22 +4902,118 @@ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int gensecret) if (gensecret) { /* SSLfatal() called as appropriate in the below functions */ - if (SSL_IS_TLS13(s)) { - /* - * If we are resuming then we already generated the early secret - * when we created the ClientHello, so don't recreate it. - */ - if (!s->hit) - rv = tls13_generate_secret(s, ssl_handshake_md(s), NULL, NULL, - 0, - (unsigned char *)&s->early_secret); - else - rv = 1; - - rv = rv && tls13_generate_handshake_secret(s, pms, pmslen); - } else { - rv = ssl_generate_master_secret(s, pms, pmslen, 0); - } + rv = ssl_gensecret(s, pms, pmslen); + } else { + /* Save premaster secret */ + s->s3.tmp.pms = pms; + s->s3.tmp.pmslen = pmslen; + pms = NULL; + rv = 1; + } + + err: + OPENSSL_clear_free(pms, pmslen); + EVP_PKEY_CTX_free(pctx); + return rv; +} + +/* Decapsulate secrets for KEM */ +int ssl_decapsulate(SSL *s, EVP_PKEY *privkey, + const unsigned char *ct, size_t ctlen, + int gensecret) +{ + int rv = 0; + unsigned char *pms = NULL; + size_t pmslen = 0; + EVP_PKEY_CTX *pctx; + + if (privkey == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + pctx = EVP_PKEY_CTX_new_from_pkey(s->ctx->libctx, privkey, s->ctx->propq); + + if (EVP_PKEY_decapsulate_init(pctx) <= 0 + || EVP_PKEY_decapsulate(pctx, NULL, &pmslen, ct, ctlen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EVP_PKEY_decapsulate(pctx, pms, &pmslen, ct, ctlen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (gensecret) { + /* SSLfatal() called as appropriate in the below functions */ + rv = ssl_gensecret(s, pms, pmslen); + } else { + /* Save premaster secret */ + s->s3.tmp.pms = pms; + s->s3.tmp.pmslen = pmslen; + pms = NULL; + rv = 1; + } + + err: + OPENSSL_clear_free(pms, pmslen); + EVP_PKEY_CTX_free(pctx); + return rv; +} + +int ssl_encapsulate(SSL *s, EVP_PKEY *pubkey, + unsigned char **ctp, size_t *ctlenp, + int gensecret) +{ + int rv = 0; + unsigned char *pms = NULL, *ct = NULL; + size_t pmslen = 0, ctlen = 0; + EVP_PKEY_CTX *pctx; + + if (pubkey == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + pctx = EVP_PKEY_CTX_new_from_pkey(s->ctx->libctx, pubkey, s->ctx->propq); + + if (EVP_PKEY_encapsulate_init(pctx) <= 0 + || EVP_PKEY_encapsulate(pctx, NULL, &ctlen, NULL, &pmslen) <= 0 + || pmslen == 0 || ctlen == 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + pms = OPENSSL_malloc(pmslen); + ct = OPENSSL_malloc(ctlen); + if (pms == NULL || ct == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EVP_PKEY_encapsulate(pctx, ct, &ctlen, pms, &pmslen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (gensecret) { + /* SSLfatal() called as appropriate in the below functions */ + rv = ssl_gensecret(s, pms, pmslen); } else { /* Save premaster secret */ s->s3.tmp.pms = pms; @@ -4900,8 +5022,16 @@ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int gensecret) rv = 1; } + if (rv > 0) { + /* Pass ownership of ct to caller */ + *ctp = ct; + *ctlenp = ctlen; + ct = NULL; + } + err: OPENSSL_clear_free(pms, pmslen); + OPENSSL_free(ct); EVP_PKEY_CTX_free(pctx); return rv; } diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index fd4eacdc38..66a84cf54e 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -818,6 +818,7 @@ typedef struct tls_group_info_st { int maxtls; /* Maximum TLS version (or 0 for undefined) */ int mindtls; /* Minimum DTLS version, -1 unsupported */ int maxdtls; /* Maximum DTLS version (or 0 for undefined) */ + char is_kem; /* Mode for this Group: 0 is KEX, 1 is KEM */ } TLS_GROUP_INFO; /* flags values */ @@ -2453,8 +2454,15 @@ __owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen, int free_pms); __owur EVP_PKEY *ssl_generate_pkey(SSL *s, EVP_PKEY *pm); +__owur int ssl_gensecret(SSL *s, unsigned char *pms, size_t pmslen); __owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int genmaster); +__owur int ssl_decapsulate(SSL *s, EVP_PKEY *privkey, + const unsigned char *ct, size_t ctlen, + int gensecret); +__owur int ssl_encapsulate(SSL *s, EVP_PKEY *pubkey, + unsigned char **ctp, size_t *ctlenp, + int gensecret); __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh); __owur unsigned int ssl_get_max_send_fragment(const SSL *ssl); __owur unsigned int ssl_get_split_send_fragment(const SSL *ssl); diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 189e2c9e5e..15cd622ed5 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1830,6 +1830,7 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, unsigned int group_id; PACKET encoded_pt; EVP_PKEY *ckey = s->s3.tmp.pkey, *skey = NULL; + const TLS_GROUP_INFO *ginf = NULL; /* Sanity check */ if (ckey == NULL || s->s3.peer_tmp != NULL) { @@ -1893,6 +1894,12 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } + if ((ginf = tls1_group_id_lookup(s->ctx, group_id)) == NULL) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE, + SSL_R_BAD_KEY_SHARE); + return 0; + } + if (!PACKET_as_length_prefixed_2(pkt, &encoded_pt) || PACKET_remaining(&encoded_pt) == 0) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE, @@ -1900,27 +1907,39 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } - skey = EVP_PKEY_new(); - if (skey == NULL || EVP_PKEY_copy_parameters(skey, ckey) <= 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE, - SSL_R_COPY_PARAMETERS_FAILED); - return 0; - } + if (!ginf->is_kem) { + /* Regular KEX */ + skey = EVP_PKEY_new(); + if (skey == NULL || EVP_PKEY_copy_parameters(skey, ckey) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE, + SSL_R_COPY_PARAMETERS_FAILED); + return 0; + } - if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt), - PACKET_remaining(&encoded_pt))) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE, - SSL_R_BAD_ECPOINT); - EVP_PKEY_free(skey); - return 0; - } + if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt), + PACKET_remaining(&encoded_pt))) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE, + SSL_R_BAD_ECPOINT); + EVP_PKEY_free(skey); + return 0; + } - if (ssl_derive(s, ckey, skey, 1) == 0) { - /* SSLfatal() already called */ - EVP_PKEY_free(skey); - return 0; + if (ssl_derive(s, ckey, skey, 1) == 0) { + /* SSLfatal() already called */ + EVP_PKEY_free(skey); + return 0; + } + s->s3.peer_tmp = skey; + } else { + /* KEM Mode */ + const unsigned char *ct = PACKET_data(&encoded_pt); + size_t ctlen = PACKET_remaining(&encoded_pt); + + if (ssl_decapsulate(s, ckey, ct, ctlen, 1) == 0) { + /* SSLfatal() already called */ + return 0; + } } - s->s3.peer_tmp = skey; #endif return 1; diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 9ec48ef56a..eb24d0a19e 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -1696,6 +1696,7 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, unsigned char *encodedPoint; size_t encoded_pt_len = 0; EVP_PKEY *ckey = s->s3.peer_tmp, *skey = NULL; + const TLS_GROUP_INFO *ginf = NULL; if (s->hello_retry_request == SSL_HRR_PENDING) { if (ckey != NULL) { @@ -1733,37 +1734,92 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, return EXT_RETURN_FAIL; } - skey = ssl_generate_pkey(s, ckey); - if (skey == NULL) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, - ERR_R_MALLOC_FAILURE); + if ((ginf = tls1_group_id_lookup(s->ctx, s->s3.group_id)) == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR); return EXT_RETURN_FAIL; } - /* Generate encoding of server key */ - encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint); - if (encoded_pt_len == 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, - ERR_R_EC_LIB); - EVP_PKEY_free(skey); - return EXT_RETURN_FAIL; - } + if (!ginf->is_kem) { + /* Regular KEX */ + skey = ssl_generate_pkey(s, ckey); + if (skey == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, + ERR_R_MALLOC_FAILURE); + return EXT_RETURN_FAIL; + } - if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len) - || !WPACKET_close(pkt)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, - ERR_R_INTERNAL_ERROR); - EVP_PKEY_free(skey); + /* Generate encoding of server key */ + encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint); + if (encoded_pt_len == 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, + ERR_R_EC_LIB); + EVP_PKEY_free(skey); + return EXT_RETURN_FAIL; + } + + if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, + ERR_R_INTERNAL_ERROR); + EVP_PKEY_free(skey); + OPENSSL_free(encodedPoint); + return EXT_RETURN_FAIL; + } OPENSSL_free(encodedPoint); - return EXT_RETURN_FAIL; - } - OPENSSL_free(encodedPoint); - /* This causes the crypto state to be updated based on the derived keys */ - s->s3.tmp.pkey = skey; - if (ssl_derive(s, skey, ckey, 1) == 0) { - /* SSLfatal() already called */ - return EXT_RETURN_FAIL; + /* + * This causes the crypto state to be updated based on the derived keys + */ + s->s3.tmp.pkey = skey; + if (ssl_derive(s, skey, ckey, 1) == 0) { + /* SSLfatal() already called */ + return EXT_RETURN_FAIL; + } + } else { + /* KEM mode */ + unsigned char *ct = NULL; + size_t ctlen = 0; + + /* + * This does not update the crypto state. + * + * The generated pms is stored in `s->s3.tmp.pms` to be later used via + * ssl_gensecret(). + */ + if (ssl_encapsulate(s, ckey, &ct, &ctlen, 0) == 0) { + /* SSLfatal() already called */ + return EXT_RETURN_FAIL; + } + + if (ctlen == 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, + ERR_R_INTERNAL_ERROR); + OPENSSL_free(ct); + return EXT_RETURN_FAIL; + } + + if (!WPACKET_sub_memcpy_u16(pkt, ct, ctlen) + || !WPACKET_close(pkt)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, + SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, + ERR_R_INTERNAL_ERROR); + OPENSSL_free(ct); + return EXT_RETURN_FAIL; + } + OPENSSL_free(ct); + + /* + * This causes the crypto state to be updated based on the generated pms + */ + if (ssl_gensecret(s, s->s3.tmp.pms, s->s3.tmp.pmslen) == 0) { + /* SSLfatal() already called */ + return EXT_RETURN_FAIL; + } } return EXT_RETURN_SENT; #else diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 927154fd98..8005f4ee32 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -249,6 +249,7 @@ static int add_provider_groups(const OSSL_PARAM params[], void *data) TLS_GROUP_INFO *ginf = NULL; EVP_KEYMGMT *keymgmt; unsigned int gid; + unsigned int is_kem = 0; int ret = 0; if (ctx->group_list_max_len == ctx->group_list_len) { @@ -321,6 +322,13 @@ static int add_provider_groups(const OSSL_PARAM params[], void *data) goto err; } + p = OSSL_PARAM_locate_const(params, OSSL_CAPABILITY_TLS_GROUP_IS_KEM); + if (p != NULL && (!OSSL_PARAM_get_uint(p, &is_kem) || is_kem > 1)) { + SSLerr(0, ERR_R_PASSED_INVALID_ARGUMENT); + goto err; + } + ginf->is_kem = 1 & is_kem; + p = OSSL_PARAM_locate_const(params, OSSL_CAPABILITY_TLS_GROUP_MIN_TLS); if (p == NULL || !OSSL_PARAM_get_int(p, &ginf->mintls)) { SSLerr(0, ERR_R_PASSED_INVALID_ARGUMENT); diff --git a/test/sslapitest.c b/test/sslapitest.c index 4331f41549..6dc3be92cb 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -7935,7 +7935,7 @@ static int test_sigalgs_available(int idx) #endif /* OPENSSL_NO_EC */ #ifndef OPENSSL_NO_TLS1_3 -static int test_pluggable_group(void) +static int test_pluggable_group(int idx) { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -7943,6 +7943,7 @@ static int test_pluggable_group(void) OSSL_PROVIDER *tlsprov = OSSL_PROVIDER_load(libctx, "tls-provider"); /* Check that we are not impacted by a provider without any groups */ OSSL_PROVIDER *legacyprov = OSSL_PROVIDER_load(libctx, "legacy"); + const char *group_name = idx == 0 ? "xorgroup" : "xorkemgroup"; if (!TEST_ptr(tlsprov) || !TEST_ptr(legacyprov)) goto end; @@ -7956,8 +7957,8 @@ static int test_pluggable_group(void) NULL, NULL))) goto end; - if (!TEST_true(SSL_set1_groups_list(serverssl, "xorgroup")) - || !TEST_true(SSL_set1_groups_list(clientssl, "xorgroup"))) + if (!TEST_true(SSL_set1_groups_list(serverssl, group_name)) + || !TEST_true(SSL_set1_groups_list(clientssl, group_name))) goto end; if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) @@ -8136,10 +8137,10 @@ int setup_tests(void) goto err; #if !defined(OPENSSL_NO_KTLS) && !defined(OPENSSL_NO_SOCK) -#if !defined(OPENSSL_NO_TLS1_2) || !defined(OPENSSL_NO_TLS1_3) +# if !defined(OPENSSL_NO_TLS1_2) || !defined(OPENSSL_NO_TLS1_3) ADD_ALL_TESTS(test_ktls, 32); ADD_ALL_TESTS(test_ktls_sendfile_anytls, 6); -#endif +# endif #endif ADD_TEST(test_large_message_tls); ADD_TEST(test_large_message_tls_read_ahead); @@ -8247,7 +8248,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_sigalgs_available, 6); #endif #ifndef OPENSSL_NO_TLS1_3 - ADD_TEST(test_pluggable_group); + ADD_ALL_TESTS(test_pluggable_group, 2); #endif #ifndef OPENSSL_NO_TLS1_2 ADD_TEST(test_ssl_dup); diff --git a/test/tls-provider.c b/test/tls-provider.c index 924ede501b..bcbcd710ce 100644 --- a/test/tls-provider.c +++ b/test/tls-provider.c @@ -41,41 +41,134 @@ typedef struct xorkey_st { int haspubkey; } XORKEY; -/* We define a dummy TLS group called "xorgroup" for test purposes */ -static unsigned int group_id = 0; /* IANA reserved for private use */ -static unsigned int secbits = 128; -static unsigned int mintls = TLS1_3_VERSION; -static unsigned int maxtls = 0; -static unsigned int mindtls = -1; -static unsigned int maxdtls = -1; +/* Key Management for the dummy XOR KEX and KEM algorithms */ + +static OSSL_FUNC_keymgmt_new_fn xor_newdata; +static OSSL_FUNC_keymgmt_free_fn xor_freedata; +static OSSL_FUNC_keymgmt_has_fn xor_has; +static OSSL_FUNC_keymgmt_copy_fn xor_copy; +static OSSL_FUNC_keymgmt_gen_init_fn xor_gen_init; +static OSSL_FUNC_keymgmt_gen_set_params_fn xor_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn xor_gen_settable_params; +static OSSL_FUNC_keymgmt_gen_fn xor_gen; +static OSSL_FUNC_keymgmt_gen_cleanup_fn xor_gen_cleanup; +static OSSL_FUNC_keymgmt_get_params_fn xor_get_params; +static OSSL_FUNC_keymgmt_gettable_params_fn xor_gettable_params; +static OSSL_FUNC_keymgmt_set_params_fn xor_set_params; +static OSSL_FUNC_keymgmt_settable_params_fn xor_settable_params; + +/* + * Dummy "XOR" Key Exchange algorithm. We just xor the private and public keys + * together. Don't use this! + */ + +static OSSL_FUNC_keyexch_newctx_fn xor_newctx; +static OSSL_FUNC_keyexch_init_fn xor_init; +static OSSL_FUNC_keyexch_set_peer_fn xor_set_peer; +static OSSL_FUNC_keyexch_derive_fn xor_derive; +static OSSL_FUNC_keyexch_freectx_fn xor_freectx; +static OSSL_FUNC_keyexch_dupctx_fn xor_dupctx; + +/* + * Dummy "XOR" Key Encapsulation Method. We just build a KEM over the xor KEX. + * Don't use this! + */ + +static OSSL_FUNC_kem_newctx_fn xor_newctx; +static OSSL_FUNC_kem_freectx_fn xor_freectx; +static OSSL_FUNC_kem_dupctx_fn xor_dupctx; +static OSSL_FUNC_kem_encapsulate_init_fn xor_init; +static OSSL_FUNC_kem_encapsulate_fn xor_encapsulate; +static OSSL_FUNC_kem_decapsulate_init_fn xor_init; +static OSSL_FUNC_kem_decapsulate_fn xor_decapsulate; + + +/* + * We define 2 dummy TLS groups called "xorgroup" and "xorkemgroup" for test + * purposes + */ +struct tls_group_st { + unsigned int group_id; /* for "tls-group-id", see provider-base(7) */ + unsigned int secbits; + unsigned int mintls; + unsigned int maxtls; + unsigned int mindtls; + unsigned int maxdtls; + unsigned int is_kem; /* boolean */ +}; + +#define XORGROUP_NAME "xorgroup" +#define XORGROUP_NAME_INTERNAL "xorgroup-int" +static struct tls_group_st xor_group = { + 0, /* group_id, set by randomize_tls_group_id() */ + 128, /* secbits */ + TLS1_3_VERSION, /* mintls */ + 0, /* maxtls */ + -1, /* mindtls */ + -1, /* maxdtls */ + 0 /* is_kem */ +}; + +#define XORKEMGROUP_NAME "xorkemgroup" +#define XORKEMGROUP_NAME_INTERNAL "xorkemgroup-int" +static struct tls_group_st xor_kemgroup = { + 0, /* group_id, set by randomize_tls_group_id() */ + 128, /* secbits */ + TLS1_3_VERSION, /* mintls */ + 0, /* maxtls */ + -1, /* mindtls */ + -1, /* maxdtls */ + 1 /* is_kem */ +}; -#define GROUP_NAME "xorgroup" -#define GROUP_NAME_INTERNAL "xorgroup-int" #define ALGORITHM "XOR" static const OSSL_PARAM xor_group_params[] = { OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME, - GROUP_NAME, sizeof(GROUP_NAME)), + XORGROUP_NAME, sizeof(XORGROUP_NAME)), OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL, - GROUP_NAME_INTERNAL, sizeof(GROUP_NAME_INTERNAL)), + XORGROUP_NAME_INTERNAL, + sizeof(XORGROUP_NAME_INTERNAL)), OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_ALG, ALGORITHM, sizeof(ALGORITHM)), - OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_ID, &group_id), - OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS, &secbits), - OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS, &mintls), - OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS, &maxtls), - OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS, &mindtls), - OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS, &maxdtls), + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_ID, &xor_group.group_id), + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS, + &xor_group.secbits), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS, &xor_group.mintls), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS, &xor_group.maxtls), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS, &xor_group.mindtls), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS, &xor_group.maxdtls), + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_IS_KEM, &xor_group.is_kem), OSSL_PARAM_END }; +static const OSSL_PARAM xor_kemgroup_params[] = { + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME, + XORKEMGROUP_NAME, sizeof(XORKEMGROUP_NAME)), + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL, + XORKEMGROUP_NAME_INTERNAL, + sizeof(XORKEMGROUP_NAME_INTERNAL)), + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_ALG, ALGORITHM, + sizeof(ALGORITHM)), + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_ID, &xor_kemgroup.group_id), + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS, + &xor_kemgroup.secbits), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS, &xor_kemgroup.mintls), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS, &xor_kemgroup.maxtls), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS, &xor_kemgroup.mindtls), + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS, &xor_kemgroup.maxdtls), + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_IS_KEM, &xor_kemgroup.is_kem), + OSSL_PARAM_END +}; + + static int tls_prov_get_capabilities(void *provctx, const char *capability, OSSL_CALLBACK *cb, void *arg) { - /* We're only adding one group so we only call the callback once */ if (strcmp(capability, "TLS-GROUP") == 0) - return cb(xor_group_params, arg); + return cb(xor_group_params, arg) + && cb(xor_kemgroup_params, arg); /* We don't support this capability */ return 0; @@ -86,16 +179,10 @@ static int tls_prov_get_capabilities(void *provctx, const char *capability, * together. Don't use this! */ -static OSSL_FUNC_keyexch_newctx_fn xor_newctx; -static OSSL_FUNC_keyexch_init_fn xor_init; -static OSSL_FUNC_keyexch_set_peer_fn xor_set_peer; -static OSSL_FUNC_keyexch_derive_fn xor_derive; -static OSSL_FUNC_keyexch_freectx_fn xor_freectx; -static OSSL_FUNC_keyexch_dupctx_fn xor_dupctx; - typedef struct { XORKEY *key; XORKEY *peerkey; + void *provctx; } PROV_XOR_CTX; static void *xor_newctx(void *provctx) @@ -105,6 +192,8 @@ static void *xor_newctx(void *provctx) if (pxorctx == NULL) return NULL; + pxorctx->provctx = provctx; + return pxorctx; } @@ -188,21 +277,136 @@ static const OSSL_ALGORITHM tls_prov_keyexch[] = { { NULL, NULL, NULL } }; -/* Key Management for the dummy XOR key exchange algorithm */ +/* + * Dummy "XOR" Key Encapsulation Method. We just build a KEM over the xor KEX. + * Don't use this! + */ -static OSSL_FUNC_keymgmt_new_fn xor_newdata; -static OSSL_FUNC_keymgmt_free_fn xor_freedata; -static OSSL_FUNC_keymgmt_has_fn xor_has; -static OSSL_FUNC_keymgmt_copy_fn xor_copy; -static OSSL_FUNC_keymgmt_gen_init_fn xor_gen_init; -static OSSL_FUNC_keymgmt_gen_set_params_fn xor_gen_set_params; -static OSSL_FUNC_keymgmt_gen_settable_params_fn xor_gen_settable_params; -static OSSL_FUNC_keymgmt_gen_fn xor_gen; -static OSSL_FUNC_keymgmt_gen_cleanup_fn xor_gen_cleanup; -static OSSL_FUNC_keymgmt_get_params_fn xor_get_params; -static OSSL_FUNC_keymgmt_gettable_params_fn xor_gettable_params; -static OSSL_FUNC_keymgmt_set_params_fn xor_set_params; -static OSSL_FUNC_keymgmt_settable_params_fn xor_settable_params; +static int xor_encapsulate(void *vpxorctx, + unsigned char *ct, size_t *ctlen, + unsigned char *ss, size_t *sslen) +{ + /* + * We are building this around a KEX: + * + * 1. we generate ephemeral keypair + * 2. we encode our ephemeral pubkey as the outgoing ct + * 3. we derive using our ephemeral privkey in combination with the peer + * pubkey from the ctx; the result is our ss. + */ + int rv = 0; + void *genctx = NULL, *derivectx = NULL; + XORKEY *ourkey = NULL; + PROV_XOR_CTX *pxorctx = vpxorctx; + + if (ct == NULL || ss == NULL) { + /* Just return sizes */ + + if (ctlen == NULL && sslen == NULL) + return 0; + if (ctlen != NULL) + *ctlen = XOR_KEY_SIZE; + if (sslen != NULL) + *sslen = XOR_KEY_SIZE; + return 1; + } + + /* 1. Generate keypair */ + genctx = xor_gen_init(pxorctx->provctx, OSSL_KEYMGMT_SELECT_KEYPAIR); + if (genctx == NULL) + goto end; + ourkey = xor_gen(genctx, NULL, NULL); + if (ourkey == NULL) + goto end; + + /* 2. Encode ephemeral pubkey as ct */ + memcpy(ct, ourkey->pubkey, XOR_KEY_SIZE); + *ctlen = XOR_KEY_SIZE; + + /* 3. Derive ss via KEX */ + derivectx = xor_newctx(pxorctx->provctx); + if (derivectx == NULL + || !xor_init(derivectx, ourkey) + || !xor_set_peer(derivectx, pxorctx->key) + || !xor_derive(derivectx, ss, sslen, XOR_KEY_SIZE)) + goto end; + + rv = 1; + + end: + xor_gen_cleanup(genctx); + xor_freedata(ourkey); + xor_freectx(derivectx); + return rv; +} + +static int xor_decapsulate(void *vpxorctx, + unsigned char *ss, size_t *sslen, + const unsigned char *ct, size_t ctlen) +{ + /* + * We are building this around a KEX: + * + * - ct is our peer's pubkey + * - decapsulate is just derive. + */ + int rv = 0; + void *derivectx = NULL; + XORKEY *peerkey = NULL; + PROV_XOR_CTX *pxorctx = vpxorctx; + + if (ss == NULL) { + /* Just return size */ + if (sslen == NULL) + return 0; + *sslen = XOR_KEY_SIZE; + return 1; + } + + if (ctlen != XOR_KEY_SIZE) + return 0; + peerkey = xor_newdata(pxorctx->provctx); + if (peerkey == NULL) + goto end; + memcpy(peerkey->pubkey, ct, XOR_KEY_SIZE); + + /* Derive ss via KEX */ + derivectx = xor_newctx(pxorctx->provctx); + if (derivectx == NULL + || !xor_init(derivectx, pxorctx->key) + || !xor_set_peer(derivectx, peerkey) + || !xor_derive(derivectx, ss, sslen, XOR_KEY_SIZE)) + goto end; + + rv = 1; + + end: + xor_freedata(peerkey); + xor_freectx(derivectx); + return rv; +} + +static const OSSL_DISPATCH xor_kem_functions[] = { + { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))xor_newctx }, + { OSSL_FUNC_KEM_FREECTX, (void (*)(void))xor_freectx }, + { OSSL_FUNC_KEM_DUPCTX, (void (*)(void))xor_dupctx }, + { OSSL_FUNC_KEM_ENCAPSULATE_INIT, (void (*)(void))xor_init }, + { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))xor_encapsulate }, + { OSSL_FUNC_KEM_DECAPSULATE_INIT, (void (*)(void))xor_init }, + { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))xor_decapsulate }, + { 0, NULL } +}; + +static const OSSL_ALGORITHM tls_prov_kem[] = { + /* + * Obviously this is not FIPS approved, but in order to test in conjuction + * with the FIPS provider we pretend that it is. + */ + { "XOR", "provider=tls-provider,fips=yes", xor_kem_functions }, + { NULL, NULL, NULL } +}; + +/* Key Management for the dummy XOR key exchange algorithm */ static void *xor_newdata(void *provctx) { @@ -269,7 +473,7 @@ static ossl_inline int xor_get_params(void *vkey, OSSL_PARAM params[]) return 0; if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS)) != NULL - && !OSSL_PARAM_set_int(p, secbits)) + && !OSSL_PARAM_set_int(p, xor_group.secbits)) return 0; if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT)) != NULL) { @@ -355,7 +559,8 @@ static int xor_gen_set_params(void *genctx, const OSSL_PARAM params[]) p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); if (p != NULL) { if (p->data_type != OSSL_PARAM_UTF8_STRING - || strcmp(p->data, GROUP_NAME_INTERNAL) != 0) + || (strcmp(p->data, XORGROUP_NAME_INTERNAL) != 0 + && strcmp(p->data, XORKEMGROUP_NAME_INTERNAL) != 0)) return 0; } @@ -435,6 +640,8 @@ static const OSSL_ALGORITHM *tls_prov_query(void *provctx, int operation_id, return tls_prov_keymgmt; case OSSL_OP_KEYEXCH: return tls_prov_keyexch; + case OSSL_OP_KEM: + return tls_prov_kem; } return NULL; } @@ -447,19 +654,19 @@ static const OSSL_DISPATCH tls_prov_dispatch_table[] = { { 0, NULL } }; -int tls_provider_init(const OSSL_CORE_HANDLE *handle, - const OSSL_DISPATCH *in, - const OSSL_DISPATCH **out, - void **provctx) +static +unsigned int randomize_tls_group_id(OPENSSL_CTX *libctx) { - OPENSSL_CTX *libctx = OPENSSL_CTX_new(); - - *provctx = libctx; - /* * Randomise the group_id we're going to use to ensure we don't interoperate * with anything but ourselves. */ + unsigned int group_id; + static unsigned int mem[10] = { 0 }; + static int in_mem = 0; + int i; + + retry: if (!RAND_bytes_ex(libctx, (unsigned char *)&group_id, sizeof(group_id))) return 0; /* @@ -469,6 +676,33 @@ int tls_provider_init(const OSSL_CORE_HANDLE *handle, group_id %= 65279 - 65024; group_id += 65024; + /* Ensure we did not already issue this group_id */ + for (i = 0; i < in_mem; i++) + if (mem[i] == group_id) + goto retry; + + /* Add this group_id to the list of ids issued by this function */ + mem[in_mem++] = group_id; + + return group_id; +} + +int tls_provider_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, + void **provctx) +{ + OPENSSL_CTX *libctx = OPENSSL_CTX_new(); + + *provctx = libctx; + + /* + * Randomise the group_id we're going to use to ensure we don't interoperate + * with anything but ourselves. + */ + xor_group.group_id = randomize_tls_group_id(libctx); + xor_kemgroup.group_id = randomize_tls_group_id(libctx); + *out = tls_prov_dispatch_table; return 1; }