* OpenSSL Software Services, Inc.
* OpenSSL Software Foundation, Inc.
+ * Google LLC
Individuals
-----------
#include <openssl/store.h>
#include <openssl/core_names.h>
#include <openssl/rand.h>
+#include <openssl/safestack.h>
+#include <openssl/ssl.h>
#include <openssl/tls1.h>
#include "apps.h"
#include "app_params.h"
return 1;
}
+#if !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2)
+static void list_tls_groups(int version, int all)
+{
+ SSL_CTX *ctx = NULL;
+ STACK_OF(OPENSSL_CSTRING) *groups;
+ size_t i, num;
+
+ if ((groups = sk_OPENSSL_CSTRING_new_null()) == NULL) {
+ BIO_printf(bio_err, "ERROR: Memory allocation\n");
+ return;
+ }
+ if ((ctx = SSL_CTX_new(TLS_method())) == NULL) {
+ BIO_printf(bio_err, "ERROR: Memory allocation\n");
+ goto err;
+ }
+ if (!SSL_CTX_set_min_proto_version(ctx, version)
+ || !SSL_CTX_set_max_proto_version(ctx, version)) {
+ BIO_printf(bio_err, "ERROR: setting TLS protocol version\n");
+ goto err;
+ }
+ if (!SSL_CTX_get0_implemented_groups(ctx, all, groups)) {
+ BIO_printf(bio_err, "ERROR: getting implemented TLS group list\n");
+ goto err;
+ }
+ num = sk_OPENSSL_CSTRING_num(groups);
+ for (i = 0; i < num; ++i) {
+ BIO_printf(bio_out, "%s%c", sk_OPENSSL_CSTRING_value(groups, i),
+ (i < num - 1) ? ':' : '\n');
+ }
+ err:
+ SSL_CTX_free(ctx);
+ sk_OPENSSL_CSTRING_free(groups);
+ return;
+}
+#endif
+
static void list_tls_signatures(void)
{
int tls_sigalg_listed = 0;
OPT_TLS_SIGNATURE_ALGORITHMS, OPT_ASYM_CIPHER_ALGORITHMS,
OPT_STORE_LOADERS, OPT_PROVIDER_INFO, OPT_OBJECTS,
OPT_SELECT_NAME,
+#if !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2)
+ OPT_ALL_TLS_GROUPS, OPT_TLS_GROUPS,
+# if !defined(OPENSSL_NO_TLS1_2)
+ OPT_TLS1_2,
+# endif
+# if !defined(OPENSSL_NO_TLS1_3)
+ OPT_TLS1_3,
+# endif
+#endif
#ifndef OPENSSL_NO_DEPRECATED_3_0
OPT_ENGINES,
#endif
"List of public key methods"},
{"store-loaders", OPT_STORE_LOADERS, '-',
"List of store loaders"},
+#if !defined(OPENSSL_NO_TLS1_2) || !defined(OPENSSL_NO_TLS1_3)
+ {"tls-groups", OPT_TLS_GROUPS, '-',
+ "List implemented TLS key exchange 'groups'" },
+ {"all-tls-groups", OPT_ALL_TLS_GROUPS, '-',
+ "List implemented TLS key exchange 'groups' and all aliases" },
+# ifndef OPENSSL_NO_TLS1_2
+ {"tls1_2", OPT_TLS1_2, '-',
+ "When listing 'groups', list those compatible with TLS1.2"},
+# endif
+# ifndef OPENSSL_NO_TLS1_3
+ {"tls1_3", OPT_TLS1_3, '-',
+ "When listing 'groups', list those compatible with TLS1.3"},
+# endif
+#endif
{"providers", OPT_PROVIDER_INFO, '-',
"List of provider information"},
#ifndef OPENSSL_NO_DEPRECATED_3_0
HELPLIST_CHOICE o;
int one = 0, done = 0;
int print_newline = 0;
+#if !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2)
+ int all_tls_groups = 0;
+# if !defined(OPENSSL_NO_TLS1_3)
+ unsigned int tls_version = TLS1_3_VERSION;
+# else
+ unsigned int tls_version = TLS1_2_VERSION;
+# endif
+#endif
struct {
unsigned int commands:1;
unsigned int all_algorithms:1;
unsigned int tls_signature_algorithms:1;
unsigned int keyexchange_algorithms:1;
unsigned int kem_algorithms:1;
+ unsigned int tls_groups:1;
unsigned int asym_cipher_algorithms:1;
unsigned int pk_algorithms:1;
unsigned int pk_method:1;
case OPT_KEM_ALGORITHMS:
todo.kem_algorithms = 1;
break;
+#if !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2)
+ case OPT_TLS_GROUPS:
+ todo.tls_groups = 1;
+ break;
+ case OPT_ALL_TLS_GROUPS:
+ all_tls_groups = 1;
+ todo.tls_groups = 1;
+ break;
+# if !defined(OPENSSL_NO_TLS1_2)
+ case OPT_TLS1_2:
+ tls_version = TLS1_2_VERSION;
+ break;
+# endif
+# if !defined(OPENSSL_NO_TLS1_3)
+ case OPT_TLS1_3:
+ tls_version = TLS1_3_VERSION;
+ break;
+# endif
+#endif
case OPT_ASYM_CIPHER_ALGORITHMS:
todo.asym_cipher_algorithms = 1;
break;
MAYBE_ADD_NL(list_keyexchanges());
if (todo.kem_algorithms)
MAYBE_ADD_NL(list_kems());
+#if !defined(OPENSSL_NO_TLS1_3) || !defined(OPENSSL_NO_TLS1_2)
+ if (todo.tls_groups)
+ MAYBE_ADD_NL(list_tls_groups(tls_version, all_tls_groups));
+#endif
if (todo.pk_algorithms)
MAYBE_ADD_NL(list_pkey());
if (todo.pk_method)
PROV_R_NO_INSTANCE_ALLOWED:242:no instance allowed
PROV_R_NO_KEY_SET:114:no key set
PROV_R_NO_PARAMETERS_SET:177:no parameters set
+PROV_R_NULL_LENGTH_POINTER:247:null length pointer
+PROV_R_NULL_OUTPUT_BUFFER:245:null output buffer
PROV_R_ONESHOT_CALL_OUT_OF_ORDER:239:oneshot call out of order
PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE:178:\
operation not supported for this keytype
PROV_R_UNSUPPORTED_KEY_SIZE:153:unsupported key size
PROV_R_UNSUPPORTED_MAC_TYPE:137:unsupported mac type
PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS:152:unsupported number of rounds
+PROV_R_UNSUPPORTED_SELECTION:248:unsupported selection
PROV_R_UPDATE_CALL_OUT_OF_ORDER:240:update call out of order
PROV_R_URI_AUTHORITY_UNSUPPORTED:223:uri authority unsupported
PROV_R_VALUE_ERROR:138:value error
+PROV_R_WRONG_CIPHERTEXT_SIZE:246:wrong ciphertext size
PROV_R_WRONG_FINAL_BLOCK_LENGTH:107:wrong final block length
PROV_R_WRONG_OUTPUT_BUFFER_SIZE:139:wrong output buffer size
PROV_R_XOF_DIGESTS_NOT_ALLOWED:183:xof digests not allowed
* https://www.openssl.org/source/license.html
*/
-/* Copyright (c) 2024, Google Inc. */
-
#include <internal/common.h>
#include <internal/constant_time.h>
#include <internal/sha3.h>
[B<-key-managers>]
[B<-key-exchange-algorithms>]
[B<-kem-algorithms>]
+[B<-tls-groups>]
+[B<-all-tls-groups>]
+[B<-tls1_2>]
+[B<-tls1_3>]
[B<-signature-algorithms>]
[B<-tls-signature-algorithms>]
[B<-asymcipher-algorithms>]
Display a list of key encapsulation algorithms.
+=item B<-tls-groups>
+
+Display a list of the IANA names of all available (implemented) TLS groups.
+By default the listed groups are those compatible with TLS 1.3.
+
+=item B<-all-tls-groups>
+
+Display a list of the names of all available (implemented) TLS groups,
+including any aliases.
+Some groups are known under multiple names, for example, B<secp256r1> is also
+known as B<P-256>.
+By default the listed groups are those compatible with TLS 1.3.
+
+=item B<-tls1_2>
+
+When listing TLS groups, list those compatible with TLS 1.2
+
+=item B<-tls1_3>
+
+When listing TLS groups, output those compatible with TLS 1.3.
+TLS 1.3 is the current default protocol version, but the default version is
+subject to change, so best to specify the version explicitly.
+
=item B<-signature-algorithms>
Display a list of signature algorithms.
Specifies the list of supported curves to be sent by the client. The curve is
ultimately selected by the server.
-The list of all supported groups includes named EC parameters as well as X25519
-and X448 or FFDHE groups, and may also include groups implemented in 3rd-party
-providers. For a list of named EC parameters, use:
-
- $ openssl ecparam -list_curves
+The list of available groups includes various built-in named EC curves, as well
+as X25519 and X448, FFDHE groups, and any additional groups implemented in the
+default or 3rd-party providers.
+The commands below list the available groups for TLS 1.2 and TLS 1.3,
+respectively:
+
+ $ openssl list -tls1_2 -tls-groups
+ $ openssl list -tls1_3 -tls-groups
=item B<-cipher> I<cipherlist>
Specifies the elliptic curve to use. NOTE: this is single curve, not a list.
-The list of all supported groups includes named EC parameters as well as X25519
-and X448 or FFDHE groups, and may also include groups implemented in 3rd-party
-providers. For a list of named EC parameters, use:
-
- $ openssl ecparam -list_curves
+The list of available groups includes various built-in named EC curves, as well
+as X25519 and X448, FFDHE groups, and any additional groups implemented in the
+default or 3rd-party providers.
+The commands below list the available groups for TLS 1.2 and TLS 1.3,
+respectively.
+
+ $ openssl list -tls1_2 -tls-groups
+ $ openssl list -tls1_3 -tls-groups
=item B<-cipher> I<val>
and earlier) and key exchange.
In its simplest form the I<groups> argument is a colon separated list of
-groups. Each group can be either the B<NIST> name (e.g. B<P-256>), some other
-commonly used name where applicable (e.g. B<X25519>, B<ffdhe2048>) or an
-OpenSSL OID name (e.g. B<prime256v1>). Group names are case sensitive. The list
-should be in order of preference with the most preferred group first.
+groups. The preferred names are those listed in the IANA
+L<TLS Supported Groups|https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8>
+registry.
+
+For some groups, OpenSSL supports additional aliases.
+Such an alias could be a B<NIST> name (e.g. B<P-256>), an OpenSSL OID name
+(e.g. B<prime256v1>), or some other commonly used name.
+Group names are case sensitive.
+The list should be in order of preference with the most preferred group first.
+
The first group listed will also be used for the B<key_share> sent by a client
in a TLSv1.3 B<ClientHello>.
+The commands below list the IANA names for TLS 1.2 and TLS 1.3,
+respectively:
+
+ $ openssl list -tls1_2 -tls-groups
+ $ openssl list -tls1_3 -tls-groups
+
+The recommended groups (in order of decreasing performance) for TLS 1.3 are presently:
+
+B<x25519>,
+B<secp256r1>,
+B<x448>,
+and
+B<secp384r1>.
+
+The stronger security margins of the last two, come at a significant
+performance penalty.
+
An enriched alternative syntax, that enables clients to send multiple keyshares
and allows servers to prioritise some groups over others, is described in
L<SSL_CTX_set1_groups_list(3)>.
the enriched syntax is ultimately equivalent to just a simple ordered list of
groups, as with the simple form above.
-The supported groups for B<TLSv1.3> include:
-B<secp256r1>,
-B<secp384r1>,
-B<secp521r1>,
-B<x25519>,
-B<x448>,
-B<brainpoolP256r1tls13>,
-B<brainpoolP384r1tls13>,
-B<brainpoolP512r1tls13>,
-B<ffdhe2048>,
-B<ffdhe3072>,
-B<ffdhe4096>,
-B<ffdhe6144>,
-B<ffdhe8192>
-B<MLKEM512>,
-B<MLKEM768>,
-and
-B<MLKEM1024>.
-
-Additional providers may make available further algorithms via the
-TLS-GROUP capability. See L<provider-base(7)>.
-
=item B<-curves> I<groups>
This is a synonym for the B<-groups> command.
will also be used for the B<key_share> sent by a client in a TLSv1.3
B<ClientHello>.
-The B<value> argument is a colon separated list of groups. The group can be
-either the B<NIST> name (e.g. B<P-256>), some other commonly used name where
-applicable (e.g. B<X25519>, B<ffdhe2048>) or an OpenSSL OID name
-(e.g. B<prime256v1>). Group names are case sensitive. The list should be in
-order of preference with the most preferred group first.
+The B<groups> argument is a colon separated list of groups. The preferred
+names are those listed in the IANA
+L<TLS Supported Groups|https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8>
+registry.
+For some groups, OpenSSL supports additional aliases.
+Such an alias could be a B<NIST> name (e.g. B<P-256>), an OpenSSL OID name
+(e.g. B<prime256v1>), or some other commonly used name.
+Group names are case sensitive.
+The list should be in order of preference with the most preferred group first.
-The supported groups for B<TLSv1.3> include:
-B<secp256r1>,
-B<secp384r1>,
-B<secp521r1>,
-B<x25519>,
-B<x448>,
-B<brainpoolP256r1tls13>,
-B<brainpoolP384r1tls13>,
-B<brainpoolP512r1tls13>,
-B<ffdhe2048>,
-B<ffdhe3072>,
-B<ffdhe4096>,
-B<ffdhe6144>,
-B<ffdhe8192>
-B<MLKEM512>,
-B<MLKEM768>,
-and
-B<MLKEM1024>.
+The commands below list the available groups for TLS 1.2 and TLS 1.3,
+respectively:
+
+ $ openssl list -tls1_2 -tls-groups
+ $ openssl list -tls1_3 -tls-groups
+
+An enriched alternative syntax, that enables clients to send multiple keyshares
+and allows servers to prioritise some groups over others, is described in
+L<SSL_CTX_set1_groups_list(3)>.
+Since TLS 1.2 has neither keyshares nor a hello retry mechanism, with TLS 1.2
+the enriched syntax is ultimately equivalent to just a simple ordered list of
+groups, as with the simple form above.
=item B<Curves>
B<PreferNoDHEKEX> was added in OpenSSL 3.3.
-Support for B<ML-KEM> was added in OpenSSL 3.5.
+OpenSSL 3.5 introduces support for post-quantum (PQ) TLS key exchange via the
+B<MLKEM512>, B<MLKEM768> and B<MLKEM1024> TLS groups.
+These are based on the underlying B<ML-KEM-512>, B<ML-KEM-768> and
+B<ML-KEM-1024> algorithms from FIPS 203.
+
+OpenSSL 3.5 also introduces support for three I<hybrid> ECDH PQ key exchange
+TLS I<groups>: B<X25519MLKEM768>, B<SecP256r1MLKEM768> and
+B<SecP384r1MLKEM1024>.
+They offer CPU performance comparable to the associated ECDH group, though at
+the cost of significantly larger key exchange messages.
+The third group, B<SecP384r1MLKEM1024> is substantially more CPU-intensive,
+largely as a result of the high CPU cost of ECDH for the underlying B<P-384>
+group.
+Also its key exchange messages at close to 1700 bytes are larger than the
+roughly 1200 bytes for the first two groups.
=head1 COPYRIGHT
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
+SSL_get1_curves, SSL_get_shared_curve, SSL_CTX_get0_implemented_groups
- EC supported curve functions
=head1 SYNOPSIS
int SSL_get1_curves(SSL *ssl, int *curves);
int SSL_get_shared_curve(SSL *s, int n);
+ int SSL_CTX_get0_implemented_groups(SSL_CTX *ctx, int all,
+ STACK_OF(OPENSSL_CSTRING) *names);
+
=head1 DESCRIPTION
For all of the functions below that set the supported groups there must be at
string I<list>. In contrast to SSL_CTX_set1_groups(), the names of the
groups, rather than their NIDs, are used.
-The supported groups for B<TLSv1.3> include:
-B<P-256>,
-B<P-384>,
-B<P-521>,
-B<X25519>,
-B<X448>,
-B<ffdhe2048>,
-B<ffdhe3072>,
-B<ffdhe4096>,
-B<ffdhe6144>
-B<ffdhe8192>,
-B<MLKEM512>,
-B<MLKEM768>,
-B<MLKEM1024>,
-B<brainpoolP256r1tls13>,
-B<brainpoolP384r1tls13>, and
-B<brainpoolP512r1tls13>.
-Support for other groups may be added by external providers.
+The commands below list the available groups for TLS 1.2 and TLS 1.3,
+respectively:
+
+ $ openssl list -tls1_2 -tls-groups
+ $ openssl list -tls1_3 -tls-groups
Each group can be either the B<NIST> name (e.g. B<P-256>), some other commonly
used name where applicable (e.g. B<X25519>, B<ffdhe2048>) or an OpenSSL OID name
server. If the NID for the shared group is unknown then the value is set to the
bitwise OR of TLSEXT_nid_unknown (0x1000000) and the id of the group.
+SSL_CTX_get0_implemented_groups() populates a stack with the names of TLS
+groups that are compatible with the TLS version of the B<ctx> argument.
+The returned names are references to internal constants and must not be
+modified or freed. When B<all> is nonzero, the returned list includes not
+only the preferred IANA names of the groups, but also any associated aliases.
+If the SSL_CTX is version-flexible, the groups will be those compatible
+with any configured minimum and maximum protocol versions.
+The B<names> stack should be allocated by the caller and be empty, the
+matching group names are appended to the provided stack.
+The B<-tls-groups> and B<-all-tls-groups> options of the
+L<openssl list|openssl-list(1)> command output these lists for either
+TLS 1.2 or TLS 1.3 (by default).
+
All these functions are implemented as macros.
The curve functions are synonyms for the equivalently named group functions and
=head1 RETURN VALUES
-SSL_CTX_set1_groups(), SSL_CTX_set1_groups_list(), SSL_set1_groups() and
-SSL_set1_groups_list(), return 1 for success and 0 for failure.
+SSL_CTX_set1_groups(), SSL_CTX_set1_groups_list(), SSL_set1_groups(),
+SSL_set1_groups_list(), and SSL_CTX_get0_implemented_groups() return 1 for
+success and 0 for failure.
SSL_get1_groups() returns the number of groups, which may be zero.
Support for B<ML-KEM> was added in OpenSSL 3.5.
+B<SSL_CTX_get0_implemented_groups> was first implemented in OpenSSL 3.5.
+
Earlier versions of this document described the list as a preference order.
However, OpenSSL's behavior as a TLS 1.3 server is to consider I<all>
supported groups as comparable in security.
L<EVP_PKEY_public_check(3)> and L<EVP_PKEY_param_check(3)> now work for
more key types. This includes RSA, DSA, ED25519, X25519, ED448 and X448.
Previously (in 1.1.1) they would return -2. For key types that do not have
-parameters then L<EVP_PKEY_param_check(3)> will always return 1.
+parameters L<EVP_PKEY_param_check(3)> will always return 1.
=head3 Other notable deprecations and changes
* https://www.openssl.org/source/license.html
*/
-/* Copyright (c) 2024, Google Inc. */
-
#ifndef OPENSSL_HEADER_ML_KEM_H
# define OPENSSL_HEADER_ML_KEM_H
# pragma once
# define OSSL_TLS_GROUP_ID_mlkem512 0x0200
# define OSSL_TLS_GROUP_ID_mlkem768 0x0201
# define OSSL_TLS_GROUP_ID_mlkem1024 0x0202
+# define OSSL_TLS_GROUP_ID_SecP256r1MLKEM768 0x11EB
+# define OSSL_TLS_GROUP_ID_X25519MLKEM768 0x11EC
+# define OSSL_TLS_GROUP_ID_SecP384r1MLKEM1024 0x11ED
#endif
/*
* Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
# define PROV_R_NO_INSTANCE_ALLOWED 242
# define PROV_R_NO_KEY_SET 114
# define PROV_R_NO_PARAMETERS_SET 177
+# define PROV_R_NULL_LENGTH_POINTER 247
+# define PROV_R_NULL_OUTPUT_BUFFER 245
# define PROV_R_ONESHOT_CALL_OUT_OF_ORDER 239
# define PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 178
# define PROV_R_OUTPUT_BUFFER_TOO_SMALL 106
# define PROV_R_UNSUPPORTED_KEY_SIZE 153
# define PROV_R_UNSUPPORTED_MAC_TYPE 137
# define PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS 152
+# define PROV_R_UNSUPPORTED_SELECTION 248
# define PROV_R_UPDATE_CALL_OUT_OF_ORDER 240
# define PROV_R_URI_AUTHORITY_UNSUPPORTED 223
# define PROV_R_VALUE_ERROR 138
+# define PROV_R_WRONG_CIPHERTEXT_SIZE 246
# define PROV_R_WRONG_FINAL_BLOCK_LENGTH 107
# define PROV_R_WRONG_OUTPUT_BUFFER_SIZE 139
# define PROV_R_XOF_DIGESTS_NOT_ALLOWED 183
# define SSL_CTRL_SET_RETRY_VERIFY 136
# define SSL_CTRL_GET_VERIFY_CERT_STORE 137
# define SSL_CTRL_GET_CHAIN_CERT_STORE 138
+# define SSL_CTRL_GET0_IMPLEMENTED_GROUPS 139
# define SSL_CERT_SET_FIRST 1
# define SSL_CERT_SET_NEXT 2
# define SSL_CERT_SET_SERVER 3
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_GROUPS,glistlen,(int *)(glist))
# define SSL_CTX_set1_groups_list(ctx, s) \
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_GROUPS_LIST,0,(char *)(s))
+# define SSL_CTX_get0_implemented_groups(ctx, all, out) \
+ SSL_CTX_ctrl(ctx,SSL_CTRL_GET0_IMPLEMENTED_GROUPS, all, \
+ (STACK_OF(OPENSSL_CSTRING) *)(out))
# define SSL_set1_groups(s, glist, glistlen) \
SSL_ctrl(s,SSL_CTRL_SET_GROUPS,glistlen,(char *)(glist))
# define SSL_set1_groups_list(s, str) \
int is_kem; /* Indicates utility as KEM */
} TLS_GROUP_CONSTANTS;
+/*
+ * The indices of entries in this table must be independent of which TLS groups
+ * we do or not support. It just lists basic facts about the groups, and is
+ * used by (numeric slot number) reference in the "param_group_list" below.
+ * Therefore, there must be no #ifdefs in this table, the index of each entry
+ * must be independent of compile-time options.
+ *
+ * For the FFDHE groups, the security bit values are as given by
+ * BN_security_bits(). For the ML-KEM hybrids these are the ML-KEM security
+ * bits.
+ */
static const TLS_GROUP_CONSTANTS group_list[] = {
- { OSSL_TLS_GROUP_ID_sect163k1, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect163r1, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect163r2, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect193r1, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect193r2, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect233k1, 112, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect233r1, 112, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect239k1, 112, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect283k1, 128, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect283r1, 128, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect409k1, 192, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect409r1, 192, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect571k1, 256, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_sect571r1, 256, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp160k1, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp160r1, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp160r2, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp192k1, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp192r1, 80, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp224k1, 112, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp224r1, 112, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp256k1, 128, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_secp256r1, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
- { OSSL_TLS_GROUP_ID_secp384r1, 192, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
- { OSSL_TLS_GROUP_ID_secp521r1, 256, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
- { OSSL_TLS_GROUP_ID_brainpoolP256r1, 128, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_brainpoolP384r1, 192, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_brainpoolP512r1, 256, TLS1_VERSION, TLS1_2_VERSION,
- DTLS1_VERSION, DTLS1_2_VERSION, 0 },
- { OSSL_TLS_GROUP_ID_x25519, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
- { OSSL_TLS_GROUP_ID_x448, 224, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
- { OSSL_TLS_GROUP_ID_brainpoolP256r1_tls13, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
- { OSSL_TLS_GROUP_ID_brainpoolP384r1_tls13, 192, TLS1_3_VERSION, 0, -1, -1, 0 },
- { OSSL_TLS_GROUP_ID_brainpoolP512r1_tls13, 256, TLS1_3_VERSION, 0, -1, -1, 0 },
- /* Security bit values as given by BN_security_bits() */
- { OSSL_TLS_GROUP_ID_ffdhe2048, 112, TLS1_3_VERSION, 0, -1, -1, 0 },
- { OSSL_TLS_GROUP_ID_ffdhe3072, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
- { OSSL_TLS_GROUP_ID_ffdhe4096, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
- { OSSL_TLS_GROUP_ID_ffdhe6144, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
- { OSSL_TLS_GROUP_ID_ffdhe8192, 192, TLS1_3_VERSION, 0, -1, -1, 0 },
-#ifndef OPENSSL_NO_ML_KEM
- { OSSL_TLS_GROUP_ID_mlkem512, ML_KEM_512_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
- { OSSL_TLS_GROUP_ID_mlkem768, ML_KEM_768_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
- { OSSL_TLS_GROUP_ID_mlkem1024, ML_KEM_1024_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
-#endif
+ /* 0 */ { OSSL_TLS_GROUP_ID_sect163k1, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 1 */ { OSSL_TLS_GROUP_ID_sect163r1, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 2 */ { OSSL_TLS_GROUP_ID_sect163r2, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 3 */ { OSSL_TLS_GROUP_ID_sect193r1, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 4 */ { OSSL_TLS_GROUP_ID_sect193r2, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 5 */ { OSSL_TLS_GROUP_ID_sect233k1, 112, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 6 */ { OSSL_TLS_GROUP_ID_sect233r1, 112, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 7 */ { OSSL_TLS_GROUP_ID_sect239k1, 112, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 8 */ { OSSL_TLS_GROUP_ID_sect283k1, 128, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 9 */ { OSSL_TLS_GROUP_ID_sect283r1, 128, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 10 */ { OSSL_TLS_GROUP_ID_sect409k1, 192, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 11 */ { OSSL_TLS_GROUP_ID_sect409r1, 192, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 12 */ { OSSL_TLS_GROUP_ID_sect571k1, 256, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 13 */ { OSSL_TLS_GROUP_ID_sect571r1, 256, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 14 */ { OSSL_TLS_GROUP_ID_secp160k1, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 15 */ { OSSL_TLS_GROUP_ID_secp160r1, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 16 */ { OSSL_TLS_GROUP_ID_secp160r2, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 17 */ { OSSL_TLS_GROUP_ID_secp192k1, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 18 */ { OSSL_TLS_GROUP_ID_secp192r1, 80, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 19 */ { OSSL_TLS_GROUP_ID_secp224k1, 112, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 20 */ { OSSL_TLS_GROUP_ID_secp224r1, 112, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 21 */ { OSSL_TLS_GROUP_ID_secp256k1, 128, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 22 */ { OSSL_TLS_GROUP_ID_secp256r1, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
+ /* 23 */ { OSSL_TLS_GROUP_ID_secp384r1, 192, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
+ /* 24 */ { OSSL_TLS_GROUP_ID_secp521r1, 256, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
+ /* 25 */ { OSSL_TLS_GROUP_ID_brainpoolP256r1, 128, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 26 */ { OSSL_TLS_GROUP_ID_brainpoolP384r1, 192, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 27 */ { OSSL_TLS_GROUP_ID_brainpoolP512r1, 256, TLS1_VERSION, TLS1_2_VERSION, DTLS1_VERSION, DTLS1_2_VERSION, 0 },
+ /* 28 */ { OSSL_TLS_GROUP_ID_x25519, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
+ /* 29 */ { OSSL_TLS_GROUP_ID_x448, 224, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 },
+ /* 30 */ { OSSL_TLS_GROUP_ID_brainpoolP256r1_tls13, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 31 */ { OSSL_TLS_GROUP_ID_brainpoolP384r1_tls13, 192, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 32 */ { OSSL_TLS_GROUP_ID_brainpoolP512r1_tls13, 256, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 33 */ { OSSL_TLS_GROUP_ID_ffdhe2048, 112, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 34 */ { OSSL_TLS_GROUP_ID_ffdhe3072, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 35 */ { OSSL_TLS_GROUP_ID_ffdhe4096, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 36 */ { OSSL_TLS_GROUP_ID_ffdhe6144, 128, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 37 */ { OSSL_TLS_GROUP_ID_ffdhe8192, 192, TLS1_3_VERSION, 0, -1, -1, 0 },
+ /* 38 */ { OSSL_TLS_GROUP_ID_mlkem512, ML_KEM_512_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
+ /* 39 */ { OSSL_TLS_GROUP_ID_mlkem768, ML_KEM_768_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
+ /* 40 */ { OSSL_TLS_GROUP_ID_mlkem1024, ML_KEM_1024_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
+ /* 41 */ { OSSL_TLS_GROUP_ID_X25519MLKEM768, ML_KEM_768_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
+ /* 42 */ { OSSL_TLS_GROUP_ID_SecP256r1MLKEM768, ML_KEM_768_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
+ /* 43 */ { OSSL_TLS_GROUP_ID_SecP384r1MLKEM1024, ML_KEM_1024_SECBITS, TLS1_3_VERSION, 0, -1, -1, 1 },
};
#define TLS_GROUP_ENTRY(tlsname, realname, algorithm, idx) \
OSSL_PARAM_END \
}
+/*-
+ * - The 4th field of each entry is an index into "group_list" above.
+ *
+ * - The 3rd field is the key management algorithm name.
+
+ * - The 2nd field is the GROUP_NAME used with the provider, needed for
+ * providers that implement a family of related algorithms, but required
+ * non-null even when the provider implements just one.
+ *
+ * - The 1st field is the TLS group name used in SSL_CTX_set_group_list(),
+ * aliases repeat everything but the first field.
+ */
static const OSSL_PARAM param_group_list[][11] = {
# ifndef OPENSSL_NO_EC
# ifndef OPENSSL_NO_EC2M
# endif
# if !defined(OPENSSL_NO_ML_KEM) && !defined(FIPS_MODULE)
/* https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 */
- TLS_GROUP_ENTRY("MLKEM512", "MLKEM512", "ML-KEM-512", 38),
- TLS_GROUP_ENTRY("MLKEM768", "MLKEM768", "ML-KEM-768", 39),
- TLS_GROUP_ENTRY("MLKEM1024", "MLKEM1024", "ML-KEM-1024", 40),
+ TLS_GROUP_ENTRY("MLKEM512", "", "ML-KEM-512", 38),
+ TLS_GROUP_ENTRY("MLKEM768", "", "ML-KEM-768", 39),
+ TLS_GROUP_ENTRY("MLKEM1024", "", "ML-KEM-1024", 40),
+# endif
+# if !defined(OPENSSL_NO_ML_KEM) && !defined(OPENSSL_NO_EC)
+# if !defined(OPENSSL_NO_ECX)
+ TLS_GROUP_ENTRY("X25519MLKEM768", "", "X25519MLKEM768", 41),
+# endif
+ TLS_GROUP_ENTRY("SecP256r1MLKEM768", "", "SecP256r1MLKEM768", 42),
+ TLS_GROUP_ENTRY("SecP384r1MLKEM1024", "", "SecP384r1MLKEM1024", 43),
# endif
};
#endif /* !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ML_KEM) */
/*
* Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
/*
* Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
"no instance allowed"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NO_KEY_SET), "no key set"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NO_PARAMETERS_SET), "no parameters set"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NULL_LENGTH_POINTER),
+ "null length pointer"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_NULL_OUTPUT_BUFFER),
+ "null output buffer"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_ONESHOT_CALL_OUT_OF_ORDER),
"oneshot call out of order"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE),
"unsupported mac type"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNSUPPORTED_NUMBER_OF_ROUNDS),
"unsupported number of rounds"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNSUPPORTED_SELECTION),
+ "unsupported selection"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UPDATE_CALL_OUT_OF_ORDER),
"update call out of order"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_URI_AUTHORITY_UNSUPPORTED),
"uri authority unsupported"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_VALUE_ERROR), "value error"},
+ {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_WRONG_CIPHERTEXT_SIZE),
+ "wrong ciphertext size"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_WRONG_FINAL_BLOCK_LENGTH),
"wrong final block length"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_WRONG_OUTPUT_BUFFER_SIZE),
{ PROV_NAMES_ML_KEM_512, "provider=default", ossl_ml_kem_asym_kem_functions },
{ PROV_NAMES_ML_KEM_768, "provider=default", ossl_ml_kem_asym_kem_functions },
{ PROV_NAMES_ML_KEM_1024, "provider=default", ossl_ml_kem_asym_kem_functions },
+# if !defined(OPENSSL_NO_ECX)
+ { "X25519MLKEM768", "provider=default", ossl_mlx_kem_asym_kem_functions },
+ { "X448MLKEM1024", "provider=default", ossl_mlx_kem_asym_kem_functions },
+# endif
+# if !defined(OPENSSL_NO_EC)
+ { "SecP256r1MLKEM768", "provider=default", ossl_mlx_kem_asym_kem_functions },
+ { "SecP384r1MLKEM1024", "provider=default", ossl_mlx_kem_asym_kem_functions },
+# endif
#endif
{ NULL, NULL, NULL }
};
PROV_DESCS_ML_KEM_768 },
{ PROV_NAMES_ML_KEM_1024, "provider=default", ossl_ml_kem_1024_keymgmt_functions,
PROV_DESCS_ML_KEM_1024 },
+# if !defined(OPENSSL_NO_ECX)
+ { PROV_NAMES_X25519MLKEM768, "provider=default", ossl_mlx_x25519_kem_kmgmt_functions,
+ PROV_DESCS_X25519MLKEM768 },
+ { PROV_NAMES_X448MLKEM1024, "provider=default", ossl_mlx_x448_kem_kmgmt_functions,
+ PROV_DESCS_X448MLKEM1024 },
+# endif
+# if !defined(OPENSSL_NO_EC)
+ { PROV_NAMES_SecP256r1MLKEM768, "provider=default", ossl_mlx_p256_kem_kmgmt_functions,
+ PROV_DESCS_SecP256r1MLKEM768 },
+ { PROV_NAMES_SecP384r1MLKEM1024, "provider=default", ossl_mlx_p384_kem_kmgmt_functions,
+ PROV_DESCS_SecP384r1MLKEM1024 },
+# endif
#endif
{ NULL, NULL, NULL }
};
extern const OSSL_DISPATCH ossl_dsa_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_rsa_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_rsapss_keymgmt_functions[];
-#ifndef OPENSSL_NO_ECX
+extern const OSSL_DISPATCH ossl_kdf_keymgmt_functions[];
+extern const OSSL_DISPATCH ossl_mac_legacy_keymgmt_functions[];
+extern const OSSL_DISPATCH ossl_cmac_legacy_keymgmt_functions[];
+#ifndef OPENSSL_NO_EC
+extern const OSSL_DISPATCH ossl_ec_keymgmt_functions[];
+# ifndef OPENSSL_NO_ECX
extern const OSSL_DISPATCH ossl_x25519_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_x448_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_ed25519_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_ed448_keymgmt_functions[];
-#endif
-extern const OSSL_DISPATCH ossl_ec_keymgmt_functions[];
-extern const OSSL_DISPATCH ossl_kdf_keymgmt_functions[];
-extern const OSSL_DISPATCH ossl_mac_legacy_keymgmt_functions[];
-extern const OSSL_DISPATCH ossl_cmac_legacy_keymgmt_functions[];
-#ifndef OPENSSL_NO_SM2
+# endif
+# ifndef OPENSSL_NO_SM2
extern const OSSL_DISPATCH ossl_sm2_keymgmt_functions[];
+# endif
#endif
extern const OSSL_DISPATCH ossl_ml_dsa_44_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_ml_dsa_65_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_ml_kem_512_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_ml_kem_768_keymgmt_functions[];
extern const OSSL_DISPATCH ossl_ml_kem_1024_keymgmt_functions[];
+# ifndef OPENSSL_NO_EC
+# ifndef OPENSSL_NO_ECX
+extern const OSSL_DISPATCH ossl_mlx_x25519_kem_kmgmt_functions[];
+extern const OSSL_DISPATCH ossl_mlx_x448_kem_kmgmt_functions[];
+# endif
+extern const OSSL_DISPATCH ossl_mlx_p256_kem_kmgmt_functions[];
+extern const OSSL_DISPATCH ossl_mlx_p384_kem_kmgmt_functions[];
+# endif
#endif
/* Key Exchange */
extern const OSSL_DISPATCH ossl_dh_keyexch_functions[];
+#ifndef OPENSSL_NO_EC
+extern const OSSL_DISPATCH ossl_ecdh_keyexch_functions[];
+# ifndef OPENSSL_NO_ECX
extern const OSSL_DISPATCH ossl_x25519_keyexch_functions[];
extern const OSSL_DISPATCH ossl_x448_keyexch_functions[];
-extern const OSSL_DISPATCH ossl_ecdh_keyexch_functions[];
+# endif
+#endif
extern const OSSL_DISPATCH ossl_kdf_tls1_prf_keyexch_functions[];
extern const OSSL_DISPATCH ossl_kdf_hkdf_keyexch_functions[];
extern const OSSL_DISPATCH ossl_kdf_scrypt_keyexch_functions[];
/* Asym Key encapsulation */
extern const OSSL_DISPATCH ossl_rsa_asym_kem_functions[];
-extern const OSSL_DISPATCH ossl_ecx_asym_kem_functions[];
+#ifndef OPENSSL_NO_EC
extern const OSSL_DISPATCH ossl_ec_asym_kem_functions[];
+# ifndef OPENSSL_NO_ECX
+extern const OSSL_DISPATCH ossl_ecx_asym_kem_functions[];
+# endif
+#endif
+#ifndef OPENSSL_NO_ML_KEM
extern const OSSL_DISPATCH ossl_ml_kem_asym_kem_functions[];
+# ifndef OPENSSL_NO_EC
+extern const OSSL_DISPATCH ossl_mlx_kem_asym_kem_functions[];
+# endif
+#endif
/* Encoders */
extern const OSSL_DISPATCH ossl_rsa_to_PKCS1_der_encoder_functions[];
--- /dev/null
+#ifndef OSSL_MLX_KEM_H
+# define OSSL_MLX_KEM_H
+# pragma once
+
+#include <openssl/evp.h>
+#include <openssl/ml_kem.h>
+#include <crypto/ml_kem.h>
+#include <crypto/ecx.h>
+
+typedef struct ecdh_vinfo_st {
+ const char *algorithm_name;
+ const char *group_name;
+ size_t pubkey_bytes;
+ size_t prvkey_bytes;
+ size_t shsec_bytes;
+ int ml_kem_slot;
+ int ml_kem_variant;
+} ECDH_VINFO;
+
+typedef struct mlx_key_st {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ const ML_KEM_VINFO *minfo;
+ const ECDH_VINFO *xinfo;
+ EVP_PKEY *mkey;
+ EVP_PKEY *xkey;
+ unsigned int state;
+} MLX_KEY;
+
+#define MLX_HAVE_NOKEYS 0
+#define MLX_HAVE_PUBKEY 1
+#define MLX_HAVE_PRVKEY 2
+
+/* Both key parts have whatever the ML-KEM component has */
+#define mlx_kem_have_pubkey(key) ((key)->state > 0)
+#define mlx_kem_have_prvkey(key) ((key)->state > 1)
+
+#endif
#define PROV_DESCS_ML_KEM_768 "OpenSSL ML-KEM-768 implementation"
#define PROV_NAMES_ML_KEM_1024 "ML-KEM-1024"
#define PROV_DESCS_ML_KEM_1024 "OpenSSL ML-KEM-1024 implementation"
+#define PROV_NAMES_X25519MLKEM768 "X25519MLKEM768"
+#define PROV_DESCS_X25519MLKEM768 "X25519+ML-KEM-768 TLS hybrid implementation"
+#define PROV_NAMES_X448MLKEM1024 "X448MLKEM1024"
+#define PROV_DESCS_X448MLKEM1024 "X448+ML-KEM-1024 TLS hybrid implementation"
+#define PROV_NAMES_SecP256r1MLKEM768 "SecP256r1MLKEM768"
+#define PROV_DESCS_SecP256r1MLKEM768 "P-256+ML-KEM-768 TLS hybrid implementation"
+#define PROV_NAMES_SecP384r1MLKEM1024 "SecP384r1MLKEM1024"
+#define PROV_DESCS_SecP384r1MLKEM1024 "P-384+ML-KEM-1024 TLS hybrid implementation"
$EC_KEM_GOAL=../../libdefault.a
$TEMPLATE_KEM_GOAL=../../libtemplate.a
$ML_KEM_GOAL=../../libdefault.a
+$TLS_ML_KEM_HYBRID_GOAL=../../libdefault.a
SOURCE[$RSA_KEM_GOAL]=rsa_kem.c
ENDIF
ENDIF
-SOURCE[$TEMPLATE_KEM_GOAL]=template_kem.c
IF[{- !$disabled{'ml-kem'} -}]
- SOURCE[$ML_KEM_GOAL] = ml_kem.c
+ IF[{- !$disabled{ec} -}]
+ SOURCE[$TLS_ML_KEM_HYBRID_GOAL]=mlx_kem.c
+ ENDIF
+ SOURCE[$ML_KEM_GOAL] = ml_kem.c
ENDIF
+
+SOURCE[$TEMPLATE_KEM_GOAL]=template_kem.c
goto end;
}
- /* For now tolerate newly-deprecated NULL length pointers. */
if (clen == NULL) {
- clen = &encap_clen;
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_LENGTH_POINTER,
+ "null ciphertext input/output length pointer");
+ goto end;
} else if (*clen < encap_clen) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
"ciphertext buffer too small");
}
if (slen == NULL) {
- slen = &encap_slen;
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_LENGTH_POINTER,
+ "null shared secret input/output length pointer");
+ goto end;
} else if (*slen < encap_slen) {
ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
"shared-secret buffer too small");
return ossl_ml_kem_decap(shsec, decap_slen, ctext, clen, key);
}
-typedef void (*func_ptr_t)(void);
-
const OSSL_DISPATCH ossl_ml_kem_asym_kem_functions[] = {
- { OSSL_FUNC_KEM_NEWCTX, (func_ptr_t) ml_kem_newctx },
- { OSSL_FUNC_KEM_ENCAPSULATE_INIT, (func_ptr_t) ml_kem_encapsulate_init },
- { OSSL_FUNC_KEM_ENCAPSULATE, (func_ptr_t) ml_kem_encapsulate },
- { OSSL_FUNC_KEM_DECAPSULATE_INIT, (func_ptr_t) ml_kem_decapsulate_init },
- { OSSL_FUNC_KEM_DECAPSULATE, (func_ptr_t) ml_kem_decapsulate },
- { OSSL_FUNC_KEM_FREECTX, (func_ptr_t) ml_kem_freectx },
- { OSSL_FUNC_KEM_SET_CTX_PARAMS, (func_ptr_t) ml_kem_set_ctx_params },
- { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, (func_ptr_t) ml_kem_settable_ctx_params },
+ { OSSL_FUNC_KEM_NEWCTX, (OSSL_FUNC) ml_kem_newctx },
+ { OSSL_FUNC_KEM_ENCAPSULATE_INIT, (OSSL_FUNC) ml_kem_encapsulate_init },
+ { OSSL_FUNC_KEM_ENCAPSULATE, (OSSL_FUNC) ml_kem_encapsulate },
+ { OSSL_FUNC_KEM_DECAPSULATE_INIT, (OSSL_FUNC) ml_kem_decapsulate_init },
+ { OSSL_FUNC_KEM_DECAPSULATE, (OSSL_FUNC) ml_kem_decapsulate },
+ { OSSL_FUNC_KEM_FREECTX, (OSSL_FUNC) ml_kem_freectx },
+ { OSSL_FUNC_KEM_SET_CTX_PARAMS, (OSSL_FUNC) ml_kem_set_ctx_params },
+ { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, (OSSL_FUNC) ml_kem_settable_ctx_params },
OSSL_DISPATCH_END
};
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/params.h>
+#include <openssl/proverr.h>
+#include <openssl/rand.h>
+#include "prov/implementations.h"
+#include "prov/mlx_kem.h"
+#include "prov/provider_ctx.h"
+#include "prov/providercommon.h"
+
+static OSSL_FUNC_kem_newctx_fn mlx_kem_newctx;
+static OSSL_FUNC_kem_freectx_fn mlx_kem_freectx;
+static OSSL_FUNC_kem_encapsulate_init_fn mlx_kem_encapsulate_init;
+static OSSL_FUNC_kem_encapsulate_fn mlx_kem_encapsulate;
+static OSSL_FUNC_kem_decapsulate_init_fn mlx_kem_decapsulate_init;
+static OSSL_FUNC_kem_decapsulate_fn mlx_kem_decapsulate;
+static OSSL_FUNC_kem_set_ctx_params_fn mlx_kem_set_ctx_params;
+static OSSL_FUNC_kem_settable_ctx_params_fn mlx_kem_settable_ctx_params;
+
+typedef struct {
+ OSSL_LIB_CTX *libctx;
+ MLX_KEY *key;
+ int op;
+} PROV_MLX_KEM_CTX;
+
+static void *mlx_kem_newctx(void *provctx)
+{
+ PROV_MLX_KEM_CTX *ctx;
+
+ if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL)
+ return NULL;
+
+ ctx->libctx = PROV_LIBCTX_OF(provctx);
+ ctx->key = NULL;
+ ctx->op = 0;
+ return ctx;
+}
+
+static void mlx_kem_freectx(void *vctx)
+{
+ OPENSSL_free(vctx);
+}
+
+static int mlx_kem_init(void *vctx, int op, void *key,
+ ossl_unused const OSSL_PARAM params[])
+{
+ PROV_MLX_KEM_CTX *ctx = vctx;
+
+ if (!ossl_prov_is_running())
+ return 0;
+ ctx->key = key;
+ ctx->op = op;
+ return 1;
+}
+
+static int
+mlx_kem_encapsulate_init(void *vctx, void *vkey, const OSSL_PARAM params[])
+{
+ MLX_KEY *key = vkey;
+
+ if (!mlx_kem_have_pubkey(key)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+ return mlx_kem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, key, params);
+}
+
+static int
+mlx_kem_decapsulate_init(void *vctx, void *vkey, const OSSL_PARAM params[])
+{
+ MLX_KEY *key = vkey;
+
+ if (!mlx_kem_have_prvkey(key)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+ return mlx_kem_init(vctx, EVP_PKEY_OP_DECAPSULATE, key, params);
+}
+
+static const OSSL_PARAM *mlx_kem_settable_ctx_params(ossl_unused void *vctx,
+ ossl_unused void *provctx)
+{
+ static const OSSL_PARAM params[] = { OSSL_PARAM_END };
+
+ return params;
+}
+
+static int
+mlx_kem_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ return 1;
+}
+
+static int mlx_kem_encapsulate(void *vctx, unsigned char *ctext, size_t *clen,
+ unsigned char *shsec, size_t *slen)
+{
+ MLX_KEY *key = ((PROV_MLX_KEM_CTX *) vctx)->key;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *xkey = NULL;
+ size_t encap_clen;
+ size_t encap_slen;
+ uint8_t *cbuf;
+ uint8_t *sbuf;
+ int ml_kem_slot = key->xinfo->ml_kem_slot;
+ int ret = 0;
+
+ if (!mlx_kem_have_pubkey(key)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ goto end;
+ }
+ encap_clen = key->minfo->ctext_bytes + key->xinfo->pubkey_bytes;
+ encap_slen = ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes;
+
+ if (ctext == NULL) {
+ if (clen == NULL && slen == NULL)
+ return 0;
+ if (clen != NULL)
+ *clen = encap_clen;
+ if (slen != NULL)
+ *slen = encap_slen;
+ return 1;
+ }
+ if (shsec == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_OUTPUT_BUFFER,
+ "null shared-secret output buffer");
+ return 0;
+ }
+
+ if (clen == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_LENGTH_POINTER,
+ "null ciphertext input/output length pointer");
+ return 0;
+ } else if (*clen < encap_clen) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
+ "ciphertext buffer too small");
+ return 0;
+ } else {
+ *clen = encap_clen;
+ }
+
+ if (slen == NULL) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_NULL_LENGTH_POINTER,
+ "null shared secret input/output length pointer");
+ return 0;
+ } else if (*slen < encap_slen) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
+ "shared-secret buffer too small");
+ return 0;
+ } else {
+ *slen = encap_slen;
+ }
+
+ /* ML-KEM encapsulation */
+ encap_clen = key->minfo->ctext_bytes;
+ encap_slen = ML_KEM_SHARED_SECRET_BYTES;
+ cbuf = ctext + ml_kem_slot * key->xinfo->pubkey_bytes;
+ sbuf = shsec + ml_kem_slot * key->xinfo->shsec_bytes;
+ ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->mkey, key->propq);
+ if (ctx == NULL
+ || EVP_PKEY_encapsulate_init(ctx, NULL) <= 0
+ || EVP_PKEY_encapsulate(ctx, cbuf, &encap_clen, sbuf, &encap_slen) <= 0)
+ goto end;
+ if (encap_clen != key->minfo->ctext_bytes) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "unexpected %s ciphertext output size: %lu",
+ key->minfo->algorithm_name, (unsigned long) encap_clen);
+ goto end;
+ }
+ if (encap_slen != ML_KEM_SHARED_SECRET_BYTES) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "unexpected %s shared secret output size: %lu",
+ key->minfo->algorithm_name, (unsigned long) encap_slen);
+ goto end;
+ }
+ EVP_PKEY_CTX_free(ctx);
+
+ /*-
+ * ECDHE encapsulation
+ *
+ * Generate own ephemeral private key and add its public key to ctext.
+ *
+ * Note, we could support a settable parameter that sets an extant ECDH
+ * keypair as the keys to use in encap, making it possible to reuse the
+ * same (TLS client) ECDHE keypair for both the classical EC keyshare and a
+ * corresponding ECDHE + ML-KEM keypair. But the TLS layer would then need
+ * know that this is a hybrid, and that it can partly reuse the same keys
+ * as another group for which a keyshare will be sent. Deferred until we
+ * support generating multiple keyshares, there's a workable keyshare
+ * prediction specification, and the optimisation is justified.
+ */
+ cbuf = ctext + (1 - ml_kem_slot) * key->minfo->ctext_bytes;
+ encap_clen = key->xinfo->pubkey_bytes;
+ ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->xkey, key->propq);
+ if (ctx == NULL
+ || EVP_PKEY_keygen_init(ctx) <= 0
+ || EVP_PKEY_keygen(ctx, &xkey) <= 0
+ || EVP_PKEY_get_octet_string_param(xkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ cbuf, encap_clen, &encap_clen) <= 0)
+ goto end;
+ if (encap_clen != key->xinfo->pubkey_bytes) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "unexpected %s public key output size: %lu",
+ key->xinfo->algorithm_name, (unsigned long) encap_clen);
+ goto end;
+ }
+ EVP_PKEY_CTX_free(ctx);
+
+ /* Derive the ECDH shared secret */
+ encap_slen = key->xinfo->shsec_bytes;
+ sbuf = shsec + (1 - ml_kem_slot) * ML_KEM_SHARED_SECRET_BYTES;
+ ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, xkey, key->propq);
+ if (ctx == NULL
+ || EVP_PKEY_derive_init(ctx) <= 0
+ || EVP_PKEY_derive_set_peer(ctx, key->xkey) <= 0
+ || EVP_PKEY_derive(ctx, sbuf, &encap_slen) <= 0)
+ goto end;
+ if (encap_slen != key->xinfo->shsec_bytes) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "unexpected %s shared secret output size: %lu",
+ key->xinfo->algorithm_name, (unsigned long) encap_slen);
+ goto end;
+ }
+
+ ret = 1;
+ end:
+ EVP_PKEY_free(xkey);
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+}
+
+static int mlx_kem_decapsulate(void *vctx, uint8_t *shsec, size_t *slen,
+ const uint8_t *ctext, size_t clen)
+{
+ MLX_KEY *key = ((PROV_MLX_KEM_CTX *) vctx)->key;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *xkey = NULL;
+ const uint8_t *cbuf;
+ uint8_t *sbuf;
+ size_t decap_slen = ML_KEM_SHARED_SECRET_BYTES + key->xinfo->shsec_bytes;
+ size_t decap_clen = key->minfo->ctext_bytes + key->xinfo->pubkey_bytes;
+ int ml_kem_slot = key->xinfo->ml_kem_slot;
+ int ret = 0;
+
+ if (!mlx_kem_have_prvkey(key)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+
+ if (shsec == NULL) {
+ if (slen == NULL)
+ return 0;
+ *slen = decap_slen;
+ return 1;
+ }
+
+ /* For now tolerate newly-deprecated NULL length pointers. */
+ if (slen == NULL) {
+ slen = &decap_slen;
+ } else if (*slen < decap_slen) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
+ "shared-secret buffer too small");
+ return 0;
+ } else {
+ *slen = decap_slen;
+ }
+ if (clen != decap_clen) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_WRONG_CIPHERTEXT_SIZE,
+ "wrong decapsulation input ciphertext size: %lu",
+ (unsigned long) clen);
+ return 0;
+ }
+
+ /* ML-KEM decapsulation */
+ decap_clen = key->minfo->ctext_bytes;
+ decap_slen = ML_KEM_SHARED_SECRET_BYTES;
+ cbuf = ctext + ml_kem_slot * key->xinfo->pubkey_bytes;
+ sbuf = shsec + ml_kem_slot * key->xinfo->shsec_bytes;
+ ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->mkey, key->propq);
+ if (ctx == NULL
+ || EVP_PKEY_decapsulate_init(ctx, NULL) <= 0
+ || EVP_PKEY_decapsulate(ctx, sbuf, &decap_slen, cbuf, decap_clen) <= 0)
+ goto end;
+ if (decap_slen != ML_KEM_SHARED_SECRET_BYTES) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "unexpected %s shared secret output size: %lu",
+ key->minfo->algorithm_name, (unsigned long) decap_slen);
+ goto end;
+ }
+ EVP_PKEY_CTX_free(ctx);
+
+ /* ECDH decapsulation */
+ decap_clen = key->xinfo->pubkey_bytes;
+ decap_slen = key->xinfo->shsec_bytes;
+ cbuf = ctext + (1 - ml_kem_slot) * key->minfo->ctext_bytes;
+ sbuf = shsec + (1 - ml_kem_slot) * ML_KEM_SHARED_SECRET_BYTES;
+ ctx = EVP_PKEY_CTX_new_from_pkey(key->libctx, key->xkey, key->propq);
+ if (ctx == NULL
+ || (xkey = EVP_PKEY_new()) == NULL
+ || EVP_PKEY_copy_parameters(xkey, key->xkey) <= 0
+ || EVP_PKEY_set1_encoded_public_key(xkey, cbuf, decap_clen) <= 0
+ || EVP_PKEY_derive_init(ctx) <= 0
+ || EVP_PKEY_derive_set_peer(ctx, xkey) <= 0
+ || EVP_PKEY_derive(ctx, sbuf, &decap_slen) <= 0)
+ goto end;
+ if (decap_slen != key->xinfo->shsec_bytes) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "unexpected %s shared secret output size: %lu",
+ key->xinfo->algorithm_name, (unsigned long) decap_slen);
+ goto end;
+ }
+
+ ret = 1;
+ end:
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(xkey);
+ return ret;
+}
+
+const OSSL_DISPATCH ossl_mlx_kem_asym_kem_functions[] = {
+ { OSSL_FUNC_KEM_NEWCTX, (OSSL_FUNC) mlx_kem_newctx },
+ { OSSL_FUNC_KEM_ENCAPSULATE_INIT, (OSSL_FUNC) mlx_kem_encapsulate_init },
+ { OSSL_FUNC_KEM_ENCAPSULATE, (OSSL_FUNC) mlx_kem_encapsulate },
+ { OSSL_FUNC_KEM_DECAPSULATE_INIT, (OSSL_FUNC) mlx_kem_decapsulate_init },
+ { OSSL_FUNC_KEM_DECAPSULATE, (OSSL_FUNC) mlx_kem_decapsulate },
+ { OSSL_FUNC_KEM_FREECTX, (OSSL_FUNC) mlx_kem_freectx },
+ { OSSL_FUNC_KEM_SET_CTX_PARAMS, (OSSL_FUNC) mlx_kem_set_ctx_params },
+ { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, (OSSL_FUNC) mlx_kem_settable_ctx_params },
+ OSSL_DISPATCH_END
+};
$TEMPLATE_GOAL=../../libtemplate.a
$ML_DSA_GOAL=../../libdefault.a ../../libfips.a
$ML_KEM_GOAL=../../libdefault.a
+$TLS_ML_KEM_HYBRID_GOAL=../../libdefault.a
IF[{- !$disabled{dh} -}]
SOURCE[$DH_GOAL]=dh_kmgmt.c
ENDIF
ENDIF
+IF[{- !$disabled{'ml-kem'} -}]
+ IF[{- !$disabled{ec} -}]
+ SOURCE[$TLS_ML_KEM_HYBRID_GOAL]=mlx_kmgmt.c
+ ENDIF
+ SOURCE[$ML_KEM_GOAL]=ml_kem_kmgmt.c
+ENDIF
+
SOURCE[$RSA_GOAL]=rsa_kmgmt.c
SOURCE[$KDF_GOAL]=kdf_legacy_kmgmt.c
IF[{- !$disabled{'ml-dsa'} -}]
SOURCE[$ML_DSA_GOAL]=ml_dsa_kmgmt.c
ENDIF
-
-IF[{- !$disabled{'ml-kem'} -}]
- SOURCE[$ML_KEM_GOAL]=ml_kem_kmgmt.c
-ENDIF
static OSSL_FUNC_keymgmt_export_types_fn ml_kem_imexport_types;
static OSSL_FUNC_keymgmt_dup_fn ml_kem_dup;
+static const int minimal_selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
+ | OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+
typedef struct ml_kem_gen_ctx_st {
OSSL_LIB_CTX *libctx;
char *propq;
static void *ml_kem_gen_init(void *provctx, int selection,
const OSSL_PARAM params[], int variant)
{
- static const int minimal =
- OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
- | OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
PROV_ML_KEM_GEN_CTX *gctx = NULL;
/*
* appropriate.
*/
if (!ossl_prov_is_running()
- || (selection & minimal) == 0
+ || (selection & minimal_selection) == 0
|| (gctx = OPENSSL_zalloc(sizeof(*gctx))) == NULL)
return NULL;
return ossl_ml_kem_key_dup(key, selection);
}
-typedef void (*func_ptr_t)(void);
-
#define DECLARE_VARIANT(bits) \
static void *ml_kem_##bits##_new(void *provctx) \
{ \
return ml_kem_gen_init(provctx, selection, params, ML_KEM_##bits##_VARIANT); \
} \
const OSSL_DISPATCH ossl_ml_kem_##bits##_keymgmt_functions[] = { \
- { OSSL_FUNC_KEYMGMT_NEW, (func_ptr_t) ml_kem_##bits##_new }, \
- { OSSL_FUNC_KEYMGMT_FREE, (func_ptr_t) ossl_ml_kem_key_free }, \
- { OSSL_FUNC_KEYMGMT_GET_PARAMS, (func_ptr_t) ml_kem_get_params }, \
- { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (func_ptr_t) ml_kem_gettable_params }, \
- { OSSL_FUNC_KEYMGMT_SET_PARAMS, (func_ptr_t) ml_kem_set_params }, \
- { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (func_ptr_t) ml_kem_settable_params }, \
- { OSSL_FUNC_KEYMGMT_HAS, (func_ptr_t) ml_kem_has }, \
- { OSSL_FUNC_KEYMGMT_MATCH, (func_ptr_t) ml_kem_match }, \
- { OSSL_FUNC_KEYMGMT_GEN_INIT, (func_ptr_t) ml_kem_##bits##_gen_init }, \
- { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (func_ptr_t) ml_kem_gen_set_params }, \
- { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (func_ptr_t) ml_kem_gen_settable_params }, \
- { OSSL_FUNC_KEYMGMT_GEN, (func_ptr_t) ml_kem_gen }, \
- { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (func_ptr_t) ml_kem_gen_cleanup }, \
- { OSSL_FUNC_KEYMGMT_DUP, (func_ptr_t) ml_kem_dup }, \
- { OSSL_FUNC_KEYMGMT_IMPORT, (func_ptr_t) ml_kem_import }, \
- { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (func_ptr_t) ml_kem_imexport_types }, \
- { OSSL_FUNC_KEYMGMT_EXPORT, (func_ptr_t) ml_kem_export }, \
- { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (func_ptr_t) ml_kem_imexport_types }, \
+ { OSSL_FUNC_KEYMGMT_NEW, (OSSL_FUNC) ml_kem_##bits##_new }, \
+ { OSSL_FUNC_KEYMGMT_FREE, (OSSL_FUNC) ossl_ml_kem_key_free }, \
+ { OSSL_FUNC_KEYMGMT_GET_PARAMS, (OSSL_FUNC) ml_kem_get_params }, \
+ { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (OSSL_FUNC) ml_kem_gettable_params }, \
+ { OSSL_FUNC_KEYMGMT_SET_PARAMS, (OSSL_FUNC) ml_kem_set_params }, \
+ { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (OSSL_FUNC) ml_kem_settable_params }, \
+ { OSSL_FUNC_KEYMGMT_HAS, (OSSL_FUNC) ml_kem_has }, \
+ { OSSL_FUNC_KEYMGMT_MATCH, (OSSL_FUNC) ml_kem_match }, \
+ { OSSL_FUNC_KEYMGMT_GEN_INIT, (OSSL_FUNC) ml_kem_##bits##_gen_init }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (OSSL_FUNC) ml_kem_gen_set_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (OSSL_FUNC) ml_kem_gen_settable_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN, (OSSL_FUNC) ml_kem_gen }, \
+ { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (OSSL_FUNC) ml_kem_gen_cleanup }, \
+ { OSSL_FUNC_KEYMGMT_DUP, (OSSL_FUNC) ml_kem_dup }, \
+ { OSSL_FUNC_KEYMGMT_IMPORT, (OSSL_FUNC) ml_kem_import }, \
+ { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (OSSL_FUNC) ml_kem_imexport_types }, \
+ { OSSL_FUNC_KEYMGMT_EXPORT, (OSSL_FUNC) ml_kem_export }, \
+ { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (OSSL_FUNC) ml_kem_imexport_types }, \
OSSL_DISPATCH_END \
}
DECLARE_VARIANT(512);
--- /dev/null
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/err.h>
+#include <openssl/param_build.h>
+#include <openssl/params.h>
+#include <openssl/proverr.h>
+#include <openssl/rand.h>
+#include <openssl/self_test.h>
+#include "internal/nelem.h"
+#include "internal/param_build_set.h"
+#include "prov/implementations.h"
+#include "prov/mlx_kem.h"
+#include "prov/provider_ctx.h"
+#include "prov/providercommon.h"
+#include "prov/securitycheck.h"
+
+static OSSL_FUNC_keymgmt_gen_fn mlx_kem_gen;
+static OSSL_FUNC_keymgmt_gen_cleanup_fn mlx_kem_gen_cleanup;
+static OSSL_FUNC_keymgmt_gen_set_params_fn mlx_kem_gen_set_params;
+static OSSL_FUNC_keymgmt_gen_settable_params_fn mlx_kem_gen_settable_params;
+static OSSL_FUNC_keymgmt_get_params_fn mlx_kem_get_params;
+static OSSL_FUNC_keymgmt_gettable_params_fn mlx_kem_gettable_params;
+static OSSL_FUNC_keymgmt_set_params_fn mlx_kem_set_params;
+static OSSL_FUNC_keymgmt_settable_params_fn mlx_kem_settable_params;
+static OSSL_FUNC_keymgmt_has_fn mlx_kem_has;
+static OSSL_FUNC_keymgmt_match_fn mlx_kem_match;
+static OSSL_FUNC_keymgmt_import_fn mlx_kem_import;
+static OSSL_FUNC_keymgmt_export_fn mlx_kem_export;
+static OSSL_FUNC_keymgmt_import_types_fn mlx_kem_imexport_types;
+static OSSL_FUNC_keymgmt_export_types_fn mlx_kem_imexport_types;
+static OSSL_FUNC_keymgmt_dup_fn mlx_kem_dup;
+
+static const int minimal_selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS
+ | OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+
+/* Must match DECLARE_DISPATCH invocations at the end of the file */
+static const ECDH_VINFO hybrid_vtable[] = {
+ { "EC", "P-256", 65, 32, 32, 1, ML_KEM_768_VARIANT },
+ { "EC", "P-384", 97, 48, 48, 1, ML_KEM_1024_VARIANT },
+#if !defined(OPENSSL_NO_ECX)
+ { "X25519", NULL, 32, 32, 32, 0, ML_KEM_768_VARIANT },
+ { "X448", NULL, 56, 56, 56, 0, ML_KEM_1024_VARIANT },
+#endif
+};
+
+typedef struct mlx_kem_gen_ctx_st {
+ OSSL_LIB_CTX *libctx;
+ char *propq;
+ int selection;
+ unsigned int variant;
+} PROV_ML_KEM_GEN_CTX;
+
+static void mlx_kem_key_free(void *vkey)
+{
+ MLX_KEY *key = vkey;
+
+ if (key == NULL)
+ return;
+ OPENSSL_free(key->propq);
+ EVP_PKEY_free(key->mkey);
+ EVP_PKEY_free(key->xkey);
+ OPENSSL_free(key);
+}
+
+/* Takes ownership of propq */
+static void *
+mlx_kem_key_new(unsigned int v, OSSL_LIB_CTX *libctx, char *propq)
+{
+ MLX_KEY *key = NULL;
+ unsigned int ml_kem_variant;
+
+ if (!ossl_prov_is_running()
+ || v >= OSSL_NELEM(hybrid_vtable)
+ || (key = OPENSSL_malloc(sizeof(*key))) == NULL)
+ goto err;
+
+ ml_kem_variant = hybrid_vtable[v].ml_kem_variant;
+ key->libctx = libctx;
+ key->minfo = ossl_ml_kem_get_vinfo(ml_kem_variant);
+ key->xinfo = &hybrid_vtable[v];
+ key->xkey = key->mkey = NULL;
+ key->state = MLX_HAVE_NOKEYS;
+ key->propq = propq;
+ return key;
+
+ err:
+ OPENSSL_free(propq);
+ return NULL;
+}
+
+
+static int mlx_kem_has(const void *vkey, int selection)
+{
+ const MLX_KEY *key = vkey;
+
+ /* A NULL key MUST fail to have anything */
+ if (!ossl_prov_is_running() || key == NULL)
+ return 0;
+
+ switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) {
+ case 0:
+ return 1;
+ case OSSL_KEYMGMT_SELECT_PUBLIC_KEY:
+ return mlx_kem_have_pubkey(key);
+ default:
+ return mlx_kem_have_prvkey(key);
+ }
+}
+
+static int mlx_kem_match(const void *vkey1, const void *vkey2, int selection)
+{
+ const MLX_KEY *key1 = vkey1;
+ const MLX_KEY *key2 = vkey2;
+ int have_pub1 = mlx_kem_have_pubkey(key1);
+ int have_pub2 = mlx_kem_have_pubkey(key2);
+
+ if (!ossl_prov_is_running())
+ return 0;
+
+ /* Compare domain parameters */
+ if (key1->xinfo != key2->xinfo)
+ return 0;
+
+ if (!(selection & OSSL_KEYMGMT_SELECT_KEYPAIR))
+ return 1;
+
+ if (have_pub1 ^ have_pub2)
+ return 0;
+
+ /* As in other providers, equal when both have no key material. */
+ if (!have_pub1)
+ return 1;
+
+ return EVP_PKEY_eq(key1->mkey, key2->mkey)
+ && EVP_PKEY_eq(key1->xkey, key2->xkey);
+}
+
+typedef struct export_cb_arg_st {
+ const char *algorithm_name;
+ uint8_t *pubenc;
+ uint8_t *prvenc;
+ int pubcount;
+ int prvcount;
+ size_t puboff;
+ size_t prvoff;
+ size_t publen;
+ size_t prvlen;
+} EXPORT_CB_ARG;
+
+/* Copy any exported key material into its storage slot */
+static int export_sub_cb(const OSSL_PARAM *params, void *varg)
+{
+ EXPORT_CB_ARG *sub_arg = varg;
+ const OSSL_PARAM *p = NULL;
+ size_t len;
+
+ /*
+ * The caller will decide whether anything essential is missing, but, if
+ * some key material was returned, it should have the right (parameter)
+ * data type and length.
+ */
+ if (ossl_param_is_empty(params))
+ return 1;
+ if (sub_arg->pubenc != NULL
+ && (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY)) != NULL) {
+ void *pub = sub_arg->pubenc + sub_arg->puboff;
+
+ if (OSSL_PARAM_get_octet_string(p, &pub, sub_arg->publen, &len) != 1)
+ return 0;
+ if (len != sub_arg->publen) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "Unexpected %s public key length %lu != %lu",
+ sub_arg->algorithm_name, (unsigned long) len,
+ sub_arg->publen);
+ return 0;
+ }
+ ++sub_arg->pubcount;
+ }
+ if (sub_arg->prvenc != NULL
+ && (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY)) != NULL) {
+ void *prv = sub_arg->prvenc + sub_arg->prvoff;
+
+ if (OSSL_PARAM_get_octet_string(p, &prv, sub_arg->prvlen, &len) != 1)
+ return 0;
+ if (len != sub_arg->prvlen) {
+ ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,
+ "Unexpected %s private key length %lu != %lu",
+ sub_arg->algorithm_name, (unsigned long) len,
+ (unsigned long) sub_arg->publen);
+ return 0;
+ }
+ ++sub_arg->prvcount;
+ }
+ return 1;
+}
+
+static int
+export_sub(EXPORT_CB_ARG *sub_arg, int selection, MLX_KEY *key)
+{
+ int slot;
+
+ /*
+ * The caller is responsible for initialising only the pubenc and prvenc
+ * pointer fields, the rest are set here or in the callback.
+ */
+ sub_arg->pubcount = 0;
+ sub_arg->prvcount = 0;
+
+ for (slot = 0; slot < 2; ++slot) {
+ int ml_kem_slot = key->xinfo->ml_kem_slot;
+ EVP_PKEY *pkey;
+
+ /* Export the parts of each component into its storage slot */
+ if (slot == ml_kem_slot) {
+ pkey = key->mkey;
+ sub_arg->algorithm_name = key->minfo->algorithm_name;
+ sub_arg->puboff = slot * key->xinfo->pubkey_bytes;
+ sub_arg->prvoff = slot * key->xinfo->prvkey_bytes;
+ sub_arg->publen = key->minfo->pubkey_bytes;
+ sub_arg->prvlen = key->minfo->prvkey_bytes;
+ } else {
+ pkey = key->xkey;
+ sub_arg->algorithm_name = key->xinfo->algorithm_name;
+ sub_arg->puboff = (1 - ml_kem_slot) * key->minfo->pubkey_bytes;
+ sub_arg->prvoff = (1 - ml_kem_slot) * key->minfo->prvkey_bytes;
+ sub_arg->publen = key->xinfo->pubkey_bytes;
+ sub_arg->prvlen = key->xinfo->prvkey_bytes;
+ }
+ if (!EVP_PKEY_export(pkey, selection, export_sub_cb, (void *)sub_arg))
+ return 0;
+ }
+ return 1;
+}
+
+static int mlx_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb,
+ void *cbarg)
+{
+ MLX_KEY *key = vkey;
+ OSSL_PARAM_BLD *tmpl = NULL;
+ OSSL_PARAM *params = NULL;
+ size_t publen;
+ size_t prvlen;
+ int ret = 0;
+ EXPORT_CB_ARG sub_arg;
+
+ if (!ossl_prov_is_running() || key == NULL)
+ return 0;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
+ return 0;
+
+ /* Fail when no key material has yet been provided */
+ if (!mlx_kem_have_pubkey(key)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+ publen = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes;
+ prvlen = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes;
+ memset(&sub_arg, 0, sizeof(sub_arg));
+
+ if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+ sub_arg.pubenc = OPENSSL_malloc(publen);
+ if (sub_arg.pubenc == NULL)
+ goto err;
+ }
+
+ if (mlx_kem_have_prvkey(key)
+ && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+ /*
+ * Allocated on the secure heap if configured, this is detected in
+ * ossl_param_build_set_octet_string(), which will then also use the
+ * secure heap.
+ */
+ sub_arg.prvenc = OPENSSL_secure_zalloc(prvlen);
+ if (sub_arg.prvenc == NULL)
+ goto err;
+ }
+
+ tmpl = OSSL_PARAM_BLD_new();
+ if (tmpl == NULL)
+ goto err;
+
+ /* Extract sub-component key material */
+ if (!export_sub(&sub_arg, selection, key))
+ goto err;
+
+ if (sub_arg.pubenc != NULL && sub_arg.pubcount == 2
+ && !ossl_param_build_set_octet_string(
+ tmpl, NULL, OSSL_PKEY_PARAM_PUB_KEY, sub_arg.pubenc, publen))
+ goto err;
+
+ if (sub_arg.prvenc != NULL && sub_arg.prvcount == 2
+ && !ossl_param_build_set_octet_string(
+ tmpl, NULL, OSSL_PKEY_PARAM_PRIV_KEY, sub_arg.prvenc, prvlen))
+ goto err;
+
+ params = OSSL_PARAM_BLD_to_param(tmpl);
+ if (params == NULL)
+ goto err;
+
+ ret = param_cb(params, cbarg);
+ OSSL_PARAM_free(params);
+
+err:
+ OSSL_PARAM_BLD_free(tmpl);
+ OPENSSL_secure_clear_free(sub_arg.prvenc, prvlen);
+ OPENSSL_free(sub_arg.pubenc);
+ return ret;
+}
+
+static const OSSL_PARAM *mlx_kem_imexport_types(int selection)
+{
+ static const OSSL_PARAM key_types[] = {
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
+ return key_types;
+ return NULL;
+}
+
+static int
+load_slot(OSSL_LIB_CTX *libctx, const char *propq, const char *pname,
+ int selection, MLX_KEY *key, int slot, const uint8_t *in,
+ int mbytes, int xbytes)
+{
+ EVP_PKEY_CTX *ctx;
+ EVP_PKEY **ppkey;
+ OSSL_PARAM parr[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
+ const char *alg;
+ char *group = NULL;
+ size_t off, len;
+ void *val;
+ int ml_kem_slot = key->xinfo->ml_kem_slot;
+ int ret = 0;
+
+ if (slot == ml_kem_slot) {
+ alg = key->minfo->algorithm_name;
+ ppkey = &key->mkey;
+ off = slot * xbytes;
+ len = mbytes;
+ } else {
+ alg = key->xinfo->algorithm_name;
+ group = (char *) key->xinfo->group_name;
+ ppkey = &key->xkey;
+ off = (1 - ml_kem_slot) * mbytes;
+ len = xbytes;
+ }
+ val = (void *)(in + off);
+
+ if ((ctx = EVP_PKEY_CTX_new_from_name(libctx, alg, propq)) == NULL
+ || EVP_PKEY_fromdata_init(ctx) <= 0)
+ goto err;
+ parr[0] = OSSL_PARAM_construct_octet_string(pname, val, len);
+ if (group != NULL)
+ parr[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ group, 0);
+ if (EVP_PKEY_fromdata(ctx, ppkey, selection, parr) > 0)
+ ret = 1;
+
+ err:
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+}
+
+static int
+load_keys(MLX_KEY *key,
+ const uint8_t *pubenc, size_t publen,
+ const uint8_t *prvenc, size_t prvlen)
+{
+ int slot;
+
+ for (slot = 0; slot < 2; ++slot) {
+ if (prvlen) {
+ /* Ignore public keys when private provided */
+ if (!load_slot(key->libctx, key->propq, OSSL_PKEY_PARAM_PRIV_KEY,
+ minimal_selection, key, slot, prvenc,
+ key->minfo->prvkey_bytes, key->xinfo->prvkey_bytes))
+ goto err;
+ } else if (publen) {
+ /* Absent private key data, import public keys */
+ if (!load_slot(key->libctx, key->propq, OSSL_PKEY_PARAM_PUB_KEY,
+ minimal_selection, key, slot, pubenc,
+ key->minfo->pubkey_bytes, key->xinfo->pubkey_bytes))
+ goto err;
+ }
+ }
+ key->state = prvlen ? MLX_HAVE_PRVKEY : MLX_HAVE_PUBKEY;
+ return 1;
+
+ err:
+ EVP_PKEY_free(key->mkey);
+ EVP_PKEY_free(key->xkey);
+ key->xkey = key->mkey = NULL;
+ key->state = MLX_HAVE_NOKEYS;
+ return 0;
+}
+
+static int mlx_kem_key_fromdata(MLX_KEY *key,
+ const OSSL_PARAM params[],
+ int include_private)
+{
+ const OSSL_PARAM *param_prv_key = NULL, *param_pub_key;
+ const void *pubenc = NULL, *prvenc = NULL;
+ size_t pubkey_bytes, prvkey_bytes;
+ size_t publen = 0, prvlen = 0;
+
+ /* Invalid attempt to mutate a key, what is the right error to report? */
+ if (key == NULL || mlx_kem_have_pubkey(key))
+ return 0;
+ pubkey_bytes = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes;
+ prvkey_bytes = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes;
+
+ /* What does the caller want to set? */
+ param_pub_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+ if (param_pub_key != NULL &&
+ OSSL_PARAM_get_octet_string_ptr(param_pub_key, &pubenc, &publen) != 1)
+ return 0;
+ if (include_private)
+ param_prv_key = OSSL_PARAM_locate_const(params,
+ OSSL_PKEY_PARAM_PRIV_KEY);
+ if (param_prv_key != NULL &&
+ OSSL_PARAM_get_octet_string_ptr(param_prv_key, &prvenc, &prvlen) != 1)
+ return 0;
+
+ /* The caller MUST specify at least one of the public or private keys. */
+ if (publen == 0 && prvlen == 0) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+
+ /*
+ * When a pubkey is provided, its length MUST be correct, if a private key
+ * is also provided, the public key will be otherwise ignored. We could
+ * look for a matching encoded block, but unclear this is useful.
+ */
+ if (publen != 0 && publen != pubkey_bytes) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ if (prvlen != 0 && prvlen != prvkey_bytes) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+
+ return load_keys(key, pubenc, publen, prvenc, prvlen);
+}
+
+static int mlx_kem_import(void *vkey, int selection, const OSSL_PARAM params[])
+{
+ MLX_KEY *key = vkey;
+ int include_private;
+
+ if (!ossl_prov_is_running() || key == NULL)
+ return 0;
+
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
+ return 0;
+
+ include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;
+ return mlx_kem_key_fromdata(key, params, include_private);
+}
+
+static const OSSL_PARAM *mlx_kem_gettable_params(void *provctx)
+{
+ static const OSSL_PARAM arr[] = {
+ OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
+ OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
+ OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ return arr;
+}
+
+/*
+ * It is assumed the key is guaranteed non-NULL here, and is from this provider
+ */
+static int mlx_kem_get_params(void *vkey, OSSL_PARAM params[])
+{
+ MLX_KEY *key = vkey;
+ OSSL_PARAM *p, *pub, *prv = NULL;
+ EXPORT_CB_ARG sub_arg;
+ int selection;
+ size_t publen = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes;
+ size_t prvlen = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes;
+
+ /* The reported "bit" count is those of the ML-KEM key */
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS);
+ if (p != NULL)
+ if (!OSSL_PARAM_set_int(p, key->minfo->bits))
+ return 0;
+
+ /* The reported security bits are those of the ML-KEM key */
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS);
+ if (p != NULL)
+ if (!OSSL_PARAM_set_int(p, key->minfo->secbits))
+ return 0;
+
+ /* The ciphertext sizes are additive */
+ p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE);
+ if (p != NULL)
+ if (!OSSL_PARAM_set_int(p, key->minfo->ctext_bytes + key->xinfo->pubkey_bytes))
+ return 0;
+
+ if (!mlx_kem_have_pubkey(key))
+ return 1;
+
+ memset(&sub_arg, 0, sizeof(sub_arg));
+ pub = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
+ if (pub != NULL) {
+ if (pub->data_type != OSSL_PARAM_OCTET_STRING)
+ return 0;
+ pub->return_size = publen;
+ if (pub->data == NULL) {
+ pub = NULL;
+ } else if (pub->data_size < publen) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
+ "public key output buffer too short: %lu < %lu",
+ (unsigned long) pub->data_size,
+ (unsigned long) publen);
+ return 0;
+ } else {
+ sub_arg.pubenc = pub->data;
+ }
+ }
+ if (mlx_kem_have_prvkey(key)) {
+ prv = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY);
+ if (prv != NULL) {
+ if (prv->data_type != OSSL_PARAM_OCTET_STRING)
+ return 0;
+ prv->return_size = prvlen;
+ if (prv->data == NULL) {
+ prv = NULL;
+ } else if (prv->data_size < prvlen) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,
+ "private key output buffer too short: %lu < %lu",
+ (unsigned long) prv->data_size,
+ (unsigned long) prvlen);
+ return 0;
+ } else {
+ sub_arg.prvenc = prv->data;
+ }
+ }
+ }
+ if (pub == NULL && prv == NULL)
+ return 1;
+
+ selection = prv == NULL ? 0 : OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+ selection |= pub == NULL ? 0 : OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+ if (key->xinfo->group_name != NULL)
+ selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;
+
+ /* Extract sub-component key material */
+ if (!export_sub(&sub_arg, selection, key))
+ return 0;
+
+ if ((pub != NULL && sub_arg.pubcount != 2)
+ || (prv != NULL && sub_arg.prvcount != 2))
+ return 0;
+
+ return 1;
+}
+
+static const OSSL_PARAM *mlx_kem_settable_params(void *provctx)
+{
+ static const OSSL_PARAM arr[] = {
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ return arr;
+}
+
+static int mlx_kem_set_params(void *vkey, const OSSL_PARAM params[])
+{
+ MLX_KEY *key = vkey;
+ const OSSL_PARAM *p;
+ const void *pubenc = NULL;
+ size_t publen = 0;
+
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ /* Only one settable parameter is supported */
+ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
+ if (p == NULL)
+ return 1;
+
+ /* Key mutation is reportedly generally not allowed */
+ if (mlx_kem_have_pubkey(key)) {
+ ERR_raise_data(ERR_LIB_PROV,
+ PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE,
+ "keys cannot be mutated");
+ return 0;
+ }
+ /* An unlikely failure mode is the parameter having some unexpected type */
+ if (!OSSL_PARAM_get_octet_string_ptr(p, &pubenc, &publen))
+ return 0;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES);
+ if (p != NULL) {
+ OPENSSL_free(key->propq);
+ key->propq = NULL;
+ if (!OSSL_PARAM_get_utf8_string(p, &key->propq, 0))
+ return 0;
+ }
+
+ if (publen != key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);
+ return 0;
+ }
+
+ return load_keys(key, pubenc, publen, NULL, 0);
+}
+
+static int mlx_kem_gen_set_params(void *vgctx, const OSSL_PARAM params[])
+{
+ PROV_ML_KEM_GEN_CTX *gctx = vgctx;
+ const OSSL_PARAM *p;
+
+ if (gctx == NULL)
+ return 0;
+ if (ossl_param_is_empty(params))
+ return 1;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_UTF8_STRING)
+ return 0;
+ OPENSSL_free(gctx->propq);
+ if ((gctx->propq = OPENSSL_strdup(p->data)) == NULL)
+ return 0;
+ }
+ return 1;
+}
+
+static void *mlx_kem_gen_init(int v, OSSL_LIB_CTX *libctx, int selection,
+ const OSSL_PARAM params[])
+{
+ PROV_ML_KEM_GEN_CTX *gctx = NULL;
+
+ /*
+ * We can only generate private keys, check that the selection is
+ * appropriate.
+ */
+ if (!ossl_prov_is_running()
+ || (selection & minimal_selection) == 0
+ || (gctx = OPENSSL_zalloc(sizeof(*gctx))) == NULL)
+ return NULL;
+
+ gctx->variant = v;
+ gctx->libctx = libctx;
+ gctx->selection = selection;
+ if (mlx_kem_gen_set_params(gctx, params))
+ return gctx;
+
+ mlx_kem_gen_cleanup(gctx);
+ return NULL;
+}
+
+static const OSSL_PARAM *mlx_kem_gen_settable_params(ossl_unused void *vgctx,
+ ossl_unused void *provctx)
+{
+ static OSSL_PARAM settable[] = {
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ return settable;
+}
+
+static void *mlx_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+ PROV_ML_KEM_GEN_CTX *gctx = vgctx;
+ MLX_KEY *key;
+ char *propq = gctx->propq;
+
+ if (gctx == NULL
+ || (gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) ==
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+ return NULL;
+
+ /* Lose ownership of propq */
+ gctx->propq = NULL;
+ if ((key = mlx_kem_key_new(gctx->variant, gctx->libctx, propq)) == NULL)
+ return NULL;
+
+ if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
+ return key;
+
+ /* For now, using the same "propq" for all components */
+ key->mkey = EVP_PKEY_Q_keygen(key->libctx, key->propq,
+ key->minfo->algorithm_name);
+ key->xkey = EVP_PKEY_Q_keygen(key->libctx, key->propq,
+ key->xinfo->algorithm_name,
+ key->xinfo->group_name);
+ if (key->mkey != NULL && key->xkey != NULL) {
+ key->state = MLX_HAVE_PRVKEY;
+ return key;
+ }
+
+ mlx_kem_key_free(key);
+ return NULL;
+}
+
+static void mlx_kem_gen_cleanup(void *vgctx)
+{
+ PROV_ML_KEM_GEN_CTX *gctx = vgctx;
+
+ if (gctx == NULL)
+ return;
+ OPENSSL_free(gctx->propq);
+ OPENSSL_free(gctx);
+}
+
+static void *mlx_kem_dup(const void *vkey, int selection)
+{
+ const MLX_KEY *key = vkey;
+ MLX_KEY *ret;
+
+ if (!ossl_prov_is_running()
+ || (ret = OPENSSL_memdup(key, sizeof(*ret))) == NULL)
+ return NULL;
+
+ switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) {
+ case 0:
+ ret->xkey = ret->mkey = NULL;
+ return ret;
+ case OSSL_KEYMGMT_SELECT_KEYPAIR:
+ ret->mkey = EVP_PKEY_dup(key->mkey);
+ ret->xkey = EVP_PKEY_dup(key->xkey);
+ if (ret->xkey != NULL && ret->mkey != NULL)
+ return ret;
+ break;
+ default:
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_UNSUPPORTED_SELECTION,
+ "duplication of partial key material not supported");
+ break;
+ }
+
+ mlx_kem_key_free(ret);
+ return NULL;
+}
+
+#define DECLARE_DISPATCH(name, variant) \
+ static OSSL_FUNC_keymgmt_new_fn mlx_##name##_kem_new; \
+ static void *mlx_##name##_kem_new(void *provctx) \
+ { \
+ OSSL_LIB_CTX *libctx; \
+ \
+ libctx = provctx == NULL ? NULL : PROV_LIBCTX_OF(provctx); \
+ return mlx_kem_key_new(variant, libctx, NULL); \
+ } \
+ static OSSL_FUNC_keymgmt_gen_init_fn mlx_##name##_kem_gen_init; \
+ static void *mlx_##name##_kem_gen_init(void *provctx, int selection, \
+ const OSSL_PARAM params[]) \
+ { \
+ OSSL_LIB_CTX *libctx; \
+ \
+ libctx = provctx == NULL ? NULL : PROV_LIBCTX_OF(provctx); \
+ return mlx_kem_gen_init(variant, libctx, selection, params); \
+ } \
+ const OSSL_DISPATCH ossl_mlx_##name##_kem_kmgmt_functions[] = { \
+ { OSSL_FUNC_KEYMGMT_NEW, (OSSL_FUNC) mlx_##name##_kem_new }, \
+ { OSSL_FUNC_KEYMGMT_FREE, (OSSL_FUNC) mlx_kem_key_free }, \
+ { OSSL_FUNC_KEYMGMT_GET_PARAMS, (OSSL_FUNC) mlx_kem_get_params }, \
+ { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (OSSL_FUNC) mlx_kem_gettable_params }, \
+ { OSSL_FUNC_KEYMGMT_SET_PARAMS, (OSSL_FUNC) mlx_kem_set_params }, \
+ { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (OSSL_FUNC) mlx_kem_settable_params }, \
+ { OSSL_FUNC_KEYMGMT_HAS, (OSSL_FUNC) mlx_kem_has }, \
+ { OSSL_FUNC_KEYMGMT_MATCH, (OSSL_FUNC) mlx_kem_match }, \
+ { OSSL_FUNC_KEYMGMT_GEN_INIT, (OSSL_FUNC) mlx_##name##_kem_gen_init }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (OSSL_FUNC) mlx_kem_gen_set_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (OSSL_FUNC) mlx_kem_gen_settable_params }, \
+ { OSSL_FUNC_KEYMGMT_GEN, (OSSL_FUNC) mlx_kem_gen }, \
+ { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (OSSL_FUNC) mlx_kem_gen_cleanup }, \
+ { OSSL_FUNC_KEYMGMT_DUP, (OSSL_FUNC) mlx_kem_dup }, \
+ { OSSL_FUNC_KEYMGMT_IMPORT, (OSSL_FUNC) mlx_kem_import }, \
+ { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (OSSL_FUNC) mlx_kem_imexport_types }, \
+ { OSSL_FUNC_KEYMGMT_EXPORT, (OSSL_FUNC) mlx_kem_export }, \
+ { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (OSSL_FUNC) mlx_kem_imexport_types }, \
+ OSSL_DISPATCH_END \
+ }
+/* See |hybrid_vtable| above */
+DECLARE_DISPATCH(p256, 0);
+DECLARE_DISPATCH(p384, 1);
+#if !defined(OPENSSL_NO_ECX)
+DECLARE_DISPATCH(x25519, 2);
+DECLARE_DISPATCH(x448, 3);
+#endif
&ctx->ext.tuples_len,
parg);
+ case SSL_CTRL_GET0_IMPLEMENTED_GROUPS:
+ return tls1_get0_implemented_groups(ctx->min_proto_version,
+ ctx->max_proto_version,
+ ctx->group_list,
+ ctx->group_list_len, larg, parg);
+
case SSL_CTRL_SET_SIGALGS:
return tls1_set_sigalgs(ctx->cert, parg, larg, 0);
__owur uint16_t tls1_nid2group_id(int nid);
__owur int tls1_check_group_id(SSL_CONNECTION *s, uint16_t group_id,
int check_own_curves);
+__owur int tls1_get0_implemented_groups(int min_proto_version,
+ int max_proto_version,
+ TLS_GROUP_INFO *grps,
+ size_t num, long all,
+ STACK_OF(OPENSSL_CSTRING) *out);
__owur uint16_t tls1_shared_group(SSL_CONNECTION *s, int nmatch);
__owur int tls1_set_groups(uint16_t **grpext, size_t *grpextlen,
uint16_t **ksext, size_t *ksextlen,
return 0;
}
+typedef struct {
+ TLS_GROUP_INFO *grp;
+ size_t ix;
+} TLS_GROUP_IX;
+
+DEFINE_STACK_OF(TLS_GROUP_IX)
+
+static void free_wrapper(TLS_GROUP_IX *a)
+{
+ OPENSSL_free(a);
+}
+
+static int tls_group_ix_cmp(const TLS_GROUP_IX *const *a,
+ const TLS_GROUP_IX *const *b)
+{
+ int idcmpab = (*a)->grp->group_id < (*b)->grp->group_id;
+ int idcmpba = (*b)->grp->group_id < (*a)->grp->group_id;
+ int ixcmpab = (*a)->ix < (*b)->ix;
+ int ixcmpba = (*b)->ix < (*a)->ix;
+
+ /* Ascending by group id */
+ if (idcmpab != idcmpba)
+ return (idcmpba - idcmpab);
+ /* Ascending by original appearance index */
+ return ixcmpba - ixcmpab;
+}
+
+int tls1_get0_implemented_groups(int min_proto_version, int max_proto_version,
+ TLS_GROUP_INFO *grps, size_t num, long all,
+ STACK_OF(OPENSSL_CSTRING) *out)
+{
+ STACK_OF(TLS_GROUP_IX) *collect = NULL;
+ TLS_GROUP_IX *gix;
+ uint16_t id = 0;
+ int ret = 0;
+ size_t ix;
+
+ if ((collect = sk_TLS_GROUP_IX_new(tls_group_ix_cmp)) == NULL)
+ return 0;
+
+ if (grps == NULL || out == NULL)
+ return 0;
+ for (ix = 0; ix < num; ++ix, ++grps) {
+ if (grps->mintls > 0 && max_proto_version > 0
+ && grps->mintls > max_proto_version)
+ continue;
+ if (grps->maxtls > 0 && min_proto_version > 0
+ && grps->maxtls < min_proto_version)
+ continue;
+
+ if ((gix = OPENSSL_malloc(sizeof(*gix))) == NULL)
+ goto end;
+ gix->grp = grps;
+ gix->ix = ix;
+ if (sk_TLS_GROUP_IX_push(collect, gix) <= 0)
+ goto end;
+ }
+
+ sk_TLS_GROUP_IX_sort(collect);
+ num = sk_TLS_GROUP_IX_num(collect);
+ for (ix = 0; ix < num; ++ix) {
+ gix = sk_TLS_GROUP_IX_value(collect, ix);
+ if (!all && gix->grp->group_id == id)
+ continue;
+ id = gix->grp->group_id;
+ if (sk_OPENSSL_CSTRING_push(out, gix->grp->tlsname) <= 0)
+ goto end;
+ }
+ return 1;
+
+ end:
+ sk_TLS_GROUP_IX_pop_free(collect, free_wrapper);
+ return ret;
+}
+
/*-
* For nmatch >= 0, return the id of the |nmatch|th shared group or 0
* if there is no match.
* Test 13 = Test MLKEM512
* Test 14 = Test MLKEM768
* Test 15 = Test MLKEM1024
- * Test 16 = Test all ML-KEM with TLSv1.2 client and server
- * Test 17 = Test all FFDHE with TLSv1.2 client and server
- * Test 18 = Test all ECDHE with TLSv1.2 client and server
+ * Test 16 = Test X25519MLKEM768
+ * Test 17 = Test SecP256r1MLKEM768
+ * Test 18 = Test SecP384r1MLKEM1024
+ * Test 19 = Test all ML-KEM with TLSv1.2 client and server
+ * Test 20 = Test all FFDHE with TLSv1.2 client and server
+ * Test 21 = Test all ECDHE with TLSv1.2 client and server
*/
# ifndef OPENSSL_NO_EC
static int ecdhe_kexch_groups[] = {NID_X9_62_prime256v1, NID_secp384r1,
switch (idx) {
# ifndef OPENSSL_NO_EC
# ifndef OPENSSL_NO_TLS1_2
- case 18:
+ case 21:
max_version = TLS1_2_VERSION;
# endif
/* Fall through */
# endif
# ifndef OPENSSL_NO_DH
# ifndef OPENSSL_NO_TLS1_2
- case 17:
+ case 20:
max_version = TLS1_2_VERSION;
kexch_name0 = "ffdhe2048";
# endif
# endif
# ifndef OPENSSL_NO_ML_KEM
# if !defined(OPENSSL_NO_TLS1_2)
- case 16:
+ case 19:
max_version = TLS1_2_VERSION;
# if !defined(OPENSSL_NO_EC)
/* Set at least one EC group so the handshake completes */
kexch_name0 = "MLKEM1024";
kexch_names = kexch_name0;
break;
+# ifndef OPENSSL_NO_EC
+# ifndef OPENSSL_NO_ECX
+ case 16:
+ kexch_groups = NULL;
+ kexch_name0 = "X25519MLKEM768";
+ kexch_names = kexch_name0;
+ break;
+# endif
+ case 17:
+ kexch_groups = NULL;
+ kexch_name0 = "SecP256r1MLKEM768";
+ kexch_names = kexch_name0;
+ break;
+ case 18:
+ kexch_groups = NULL;
+ kexch_name0 = "SecP384r1MLKEM1024";
+ kexch_names = kexch_name0;
+ break;
+# endif
# endif
default:
/* We're skipping this test */
}
/* ML-KEM not yet supported in the FIPS module */
- if (is_fips && idx >= 12 && idx <= 16) {
+ if (is_fips && idx >= 12 && idx <= 19) {
testresult = 1;
goto end;
};
goto end;
/*
- * If Handshake succeeds the negotiated kexch alg should be the first one in
- * configured, except in the case of FFDHE and ML-KEM groups (idx == 17, 18),
- * which are TLSv1.3 only so we expect no shared group to exist.
+ * If the handshake succeeds the negotiated kexch alg should be the first
+ * one in configured, except in the case of "all" FFDHE and "all" ML-KEM
+ * groups (idx == 19, 20), which are TLSv1.3 only so we expect no shared
+ * group to exist.
*/
shared_group0 = SSL_get_shared_group(serverssl, 0);
switch (idx) {
- case 16:
+ case 19:
# if !defined(OPENSSL_NO_EC)
/* MLKEM + TLS 1.2 and no DH => "secp526r1" */
if (!TEST_int_eq(shared_group0, NID_X9_62_prime256v1))
break;
# endif
/* Fall through */
- case 17:
+ case 20:
if (!TEST_int_eq(shared_group0, 0))
goto end;
break;
#endif /* OSSL_NO_USABLE_TLS1_3 */
# ifndef OPENSSL_NO_TLS1_2
/* Test with both TLSv1.3 and 1.2 versions */
- ADD_ALL_TESTS(test_key_exchange, 18);
+ ADD_ALL_TESTS(test_key_exchange, 21);
# if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_DH)
ADD_ALL_TESTS(test_negotiated_group,
4 * (OSSL_NELEM(ecdhe_kexch_groups)
# endif
# else
/* Test with only TLSv1.3 versions */
- ADD_ALL_TESTS(test_key_exchange, 15);
+ ADD_ALL_TESTS(test_key_exchange, 18);
# endif
ADD_ALL_TESTS(test_custom_exts, 6);
ADD_TEST(test_stateless);
SSL_CTX_generate_session_ticket_fn define
SSL_CTX_get0_chain_certs define
SSL_CTX_get0_chain_cert_store define
+SSL_CTX_get0_implemented_groups define
SSL_CTX_get0_verify_cert_store define
SSL_CTX_get_default_read_ahead define
SSL_CTX_get_extra_chain_certs define