Skip to content

Commit

Permalink
Add API to retrieve the supported groups for a security policy
Browse files Browse the repository at this point in the history
  • Loading branch information
goatgoose committed Nov 1, 2023
1 parent 95753f0 commit e319a94
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 0 deletions.
21 changes: 21 additions & 0 deletions api/s2n.h
Original file line number Diff line number Diff line change
Expand Up @@ -3391,6 +3391,27 @@ S2N_API int s2n_offered_early_data_reject(struct s2n_offered_early_data *early_d
*/
S2N_API int s2n_offered_early_data_accept(struct s2n_offered_early_data *early_data);

/**
* Retrieves the list of supported groups configured by the security policy associated with `config`.
*
* IANA values for each of the supported groups are written to the provided `groups` array, and `groups_count` is
* set to the number of written supported groups.
*
* `groups_count_max` should be set to the maximum capacity of the `groups` array. If `groups_count_max` is less
* than the number of supported groups configured by the security policy, this function will error.
*
* Note that this API retrieves the supported groups from a local security policy. To instead get the supported
* groups sent by the client, use the `s2n_client_hello_get_supported_groups()` API.
*
* @param config A pointer to the s2n_config object from which the supported groups will be retrieved.
* @param groups The array to populate with the supported groups.
* @param groups_count_max The maximum number of supported groups that can fit in the `groups` array.
* @param groups_count Set to the number of supported groups written to `groups`.
* @returns S2N_SUCCESS on success. S2N_FAILURE on failure.
*/
S2N_API int s2n_config_get_supported_groups(struct s2n_config *config, uint16_t *groups, uint16_t groups_count_max,
uint16_t *groups_count);

#ifdef __cplusplus
}
#endif
100 changes: 100 additions & 0 deletions tests/unit/s2n_config_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@

#include "api/s2n.h"
#include "crypto/s2n_fips.h"
#include "pq-crypto/s2n_pq.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"
#include "tls/extensions/s2n_client_supported_groups.h"
#include "tls/s2n_connection.h"
#include "tls/s2n_internal.h"
#include "tls/s2n_record.h"
#include "tls/s2n_security_policies.h"
#include "tls/s2n_tls13.h"
#include "unstable/npn.h"

#define S2N_TEST_MAX_SUPPORTED_GROUPS_COUNT 30

static int s2n_test_select_psk_identity_callback(struct s2n_connection *conn, void *context,
struct s2n_offered_psk_list *psk_identity_list)
{
Expand Down Expand Up @@ -978,5 +982,101 @@ int main(int argc, char **argv)
}
}

/* Test s2n_config_get_supported_groups */
{
/* Safety */
{
DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_NOT_NULL(config);
uint16_t supported_groups[S2N_TEST_MAX_SUPPORTED_GROUPS_COUNT] = { 0 };
uint16_t supported_groups_count = 0;

int ret = s2n_config_get_supported_groups(NULL, supported_groups, s2n_array_len(supported_groups),
&supported_groups_count);
EXPECT_FAILURE_WITH_ERRNO(ret, S2N_ERR_NULL);
EXPECT_EQUAL(supported_groups_count, 0);

ret = s2n_config_get_supported_groups(config, NULL, s2n_array_len(supported_groups), &supported_groups_count);
EXPECT_FAILURE_WITH_ERRNO(ret, S2N_ERR_NULL);
EXPECT_EQUAL(supported_groups_count, 0);

ret = s2n_config_get_supported_groups(config, supported_groups, s2n_array_len(supported_groups), NULL);
EXPECT_FAILURE_WITH_ERRNO(ret, S2N_ERR_NULL);
EXPECT_EQUAL(supported_groups_count, 0);
}

/* Error if the provided supported groups array is too small */
{
DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_NOT_NULL(config);
const struct s2n_security_policy *security_policy = config->security_policy;
EXPECT_NOT_NULL(security_policy);

uint16_t policy_groups_count = security_policy->ecc_preferences->count;
if (s2n_pq_is_enabled()) {
policy_groups_count += security_policy->kem_preferences->tls13_kem_group_count;
}
EXPECT_TRUE(policy_groups_count > 0);

uint16_t supported_groups[S2N_TEST_MAX_SUPPORTED_GROUPS_COUNT] = { 0 };
uint16_t supported_groups_count = 11;
int ret = s2n_config_get_supported_groups(config, supported_groups, policy_groups_count - 1,
&supported_groups_count);
EXPECT_FAILURE_WITH_ERRNO(ret, S2N_ERR_INSUFFICIENT_MEM_SIZE);
EXPECT_EQUAL(supported_groups_count, 0);

EXPECT_SUCCESS(s2n_config_get_supported_groups(config, supported_groups, policy_groups_count,
&supported_groups_count));
EXPECT_EQUAL(supported_groups_count, policy_groups_count);
}

/* s2n_config_get_supported_groups should produce the same supported groups as sent in the
* supported groups extension
*/
for (size_t policy_idx = 0; security_policy_selection[policy_idx].version != NULL; policy_idx++) {
const struct s2n_security_policy *security_policy = security_policy_selection[policy_idx].security_policy;
EXPECT_NOT_NULL(security_policy);

uint16_t expected_groups_count = security_policy->ecc_preferences->count;
if (s2n_pq_is_enabled()) {
expected_groups_count += security_policy->kem_preferences->tls13_kem_group_count;
}

DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_NOT_NULL(config);
config->security_policy = security_policy;

uint16_t supported_groups[S2N_TEST_MAX_SUPPORTED_GROUPS_COUNT] = { 0 };
uint16_t supported_groups_count = 0;
EXPECT_SUCCESS(s2n_config_get_supported_groups(config, supported_groups, s2n_array_len(supported_groups),
&supported_groups_count));
EXPECT_EQUAL(supported_groups_count, expected_groups_count);

DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT), s2n_connection_ptr_free);
EXPECT_NOT_NULL(conn);
EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
/* PQ kem groups aren't sent in the supported groups extension before TLS 1.3. */
conn->actual_protocol_version = S2N_TLS13;

DEFER_CLEANUP(struct s2n_stuffer extension_stuffer = { 0 }, s2n_stuffer_free);
EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&extension_stuffer, 0));
EXPECT_SUCCESS(s2n_client_supported_groups_extension.send(conn, &extension_stuffer));

uint16_t extension_groups_count = 0;
EXPECT_OK(s2n_supported_groups_parse_count(&extension_stuffer, &extension_groups_count));
EXPECT_EQUAL(extension_groups_count, expected_groups_count);

for (size_t i = 0; i < supported_groups_count; i++) {
/* s2n_stuffer_read_uint16 is used to read each of the supported groups in
* network-order endianness.
*/
uint16_t group_iana = 0;
POSIX_GUARD(s2n_stuffer_read_uint16(&extension_stuffer, &group_iana));

EXPECT_EQUAL(group_iana, supported_groups[i]);
}
}
}

END_TEST();
}
41 changes: 41 additions & 0 deletions tls/s2n_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "crypto/s2n_fips.h"
#include "crypto/s2n_hkdf.h"
#include "error/s2n_errno.h"
#include "pq-crypto/s2n_pq.h"
#include "tls/s2n_cipher_preferences.h"
#include "tls/s2n_internal.h"
#include "tls/s2n_ktls.h"
Expand Down Expand Up @@ -1138,3 +1139,43 @@ int s2n_config_set_cert_validation_cb(struct s2n_config *config, s2n_cert_valida

return S2N_SUCCESS;
}

int s2n_config_get_supported_groups(struct s2n_config *config, uint16_t *groups, uint16_t groups_count_max,
uint16_t *groups_count_out)
{
POSIX_ENSURE_REF(groups_count_out);
*groups_count_out = 0;
POSIX_ENSURE_REF(config);
POSIX_ENSURE_REF(groups);

const struct s2n_security_policy *security_policy = config->security_policy;
POSIX_ENSURE_REF(security_policy);
const struct s2n_kem_preferences *kem_preferences = security_policy->kem_preferences;
POSIX_ENSURE_REF(kem_preferences);
const struct s2n_ecc_preferences *ecc_preferences = security_policy->ecc_preferences;
POSIX_ENSURE_REF(ecc_preferences);

uint16_t kem_group_count = 0;
if (s2n_pq_is_enabled()) {
kem_group_count = kem_preferences->tls13_kem_group_count;
}
uint16_t ecc_curve_count = ecc_preferences->count;
uint16_t total_group_count = kem_group_count + ecc_curve_count;
POSIX_ENSURE(total_group_count <= groups_count_max, S2N_ERR_INSUFFICIENT_MEM_SIZE);

for (size_t i = 0; i < kem_group_count; i++) {
const struct s2n_kem_group *kem_group = kem_preferences->tls13_kem_groups[i];
POSIX_ENSURE_REF(kem_group);
groups[i] = kem_group->iana_id;
}

for (size_t i = 0; i < ecc_curve_count; i++) {
const struct s2n_ecc_named_curve *ecc_curve = ecc_preferences->ecc_curves[i];
POSIX_ENSURE_REF(ecc_curve);
groups[kem_group_count + i] = ecc_curve->iana_id;
}

*groups_count_out = total_group_count;

return S2N_SUCCESS;
}

0 comments on commit e319a94

Please sign in to comment.