Skip to content

Commit

Permalink
Update FIPS rules for ML-KEM (#4829)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexw91 authored Oct 14, 2024
1 parent 6ca63e4 commit 21656e3
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 7 deletions.
2 changes: 2 additions & 0 deletions crypto/s2n_fips.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <stdbool.h>

#include "api/s2n.h"
#include "tls/s2n_kem.h"
#include "utils/s2n_result.h"

#pragma once
Expand All @@ -30,4 +31,5 @@ struct s2n_signature_scheme;
S2N_RESULT s2n_fips_validate_signature_scheme(const struct s2n_signature_scheme *sig_alg, bool *valid);
struct s2n_ecc_named_curve;
S2N_RESULT s2n_fips_validate_curve(const struct s2n_ecc_named_curve *curve, bool *valid);
S2N_RESULT s2n_fips_validate_hybrid_group(const struct s2n_kem_group *hybrid_group, bool *valid);
S2N_RESULT s2n_fips_validate_version(uint8_t version, bool *valid);
44 changes: 44 additions & 0 deletions crypto/s2n_fips_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,50 @@ S2N_RESULT s2n_fips_validate_curve(const struct s2n_ecc_named_curve *curve, bool
return S2N_RESULT_OK;
}

/* https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf */
const struct s2n_kem *fips_kems[] = {
&s2n_mlkem_768
};

S2N_RESULT s2n_fips_validate_kem(const struct s2n_kem *kem, bool *valid)
{
RESULT_ENSURE_REF(kem);
RESULT_ENSURE_REF(valid);
*valid = false;

for (size_t i = 0; i < s2n_array_len(fips_kems); i++) {
if (fips_kems[i] == kem) {
*valid = true;
return S2N_RESULT_OK;
}
}
return S2N_RESULT_OK;
}

S2N_RESULT s2n_fips_validate_hybrid_group(const struct s2n_kem_group *hybrid_group, bool *valid)
{
RESULT_ENSURE_REF(hybrid_group);
RESULT_ENSURE_REF(valid);
*valid = false;

/* The first share in a Hybrid Group must be FIPS-approved, see page 33 of NIST 800-56Cr2.
*
* "Recommendation is expanded to permit the use of “hybrid” shared secrets of the form Z' = Z || T,
* which is a concatenation consisting of a “standard” shared secret Z that was generated during the
* execution of a key-establishment scheme as currently specified in [SP 800-56A] or [SP 800-56B],
* followed by an auxiliary shared secret T that has been generated using some other method."
*
* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf
*/
if (hybrid_group->send_kem_first) {
RESULT_GUARD(s2n_fips_validate_kem(hybrid_group->kem, valid));
} else {
RESULT_GUARD(s2n_fips_validate_curve(hybrid_group->curve, valid));
}

return S2N_RESULT_OK;
}

S2N_RESULT s2n_fips_validate_version(uint8_t version, bool *valid)
{
RESULT_ENSURE_REF(valid);
Expand Down
44 changes: 42 additions & 2 deletions tests/unit/s2n_security_rules_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ static S2N_RESULT s2n_test_curve_rule(const struct s2n_ecc_named_curve *curve, b
return S2N_RESULT_OK;
}

const struct s2n_kem_group *VALID_HYBRID_GROUP = &s2n_secp256r1_mlkem_768;
const struct s2n_kem_group *EXAMPLE_INVALID_HYBRID_GROUP = &s2n_x25519_kyber_512_r3;
static S2N_RESULT s2n_test_hybrid_group_rule(const struct s2n_kem_group *hybrid_group, bool *valid)
{
RESULT_ENSURE_REF(valid);
if (hybrid_group == VALID_HYBRID_GROUP) {
*valid = true;
} else {
*valid = false;
}
return S2N_RESULT_OK;
}

const uint8_t VALID_VERSION = S2N_TLS12;
const uint8_t EXAMPLE_INVALID_VERSION = S2N_TLS11;
static S2N_RESULT s2n_test_version(uint8_t version, bool *valid)
Expand All @@ -86,6 +99,7 @@ int main(int argc, char **argv)
.validate_sig_scheme = s2n_test_sig_scheme_rule,
.validate_cert_sig_scheme = s2n_test_sig_scheme_rule,
.validate_curve = s2n_test_curve_rule,
.validate_hybrid_group = s2n_test_hybrid_group_rule,
.validate_version = s2n_test_version,
};

Expand Down Expand Up @@ -121,20 +135,35 @@ int main(int argc, char **argv)
.count = 1,
};

const struct s2n_kem_preferences valid_kem_preferences = {
.kem_count = 0,
.kems = NULL,
.tls13_kem_groups = &VALID_HYBRID_GROUP,
.tls13_kem_group_count = 1,
};

const struct s2n_kem_preferences invalid_kem_preferences = {
.kem_count = 0,
.kems = NULL,
.tls13_kem_groups = &EXAMPLE_INVALID_HYBRID_GROUP,
.tls13_kem_group_count = 1,
};

const struct s2n_security_policy valid_policy = {
.cipher_preferences = &valid_cipher_prefs,
.signature_preferences = &valid_sig_prefs,
.certificate_signature_preferences = &valid_sig_prefs,
.ecc_preferences = &valid_ecc_prefs,
.kem_preferences = &kem_preferences_null,
.kem_preferences = &valid_kem_preferences,
.minimum_protocol_version = VALID_VERSION,
};

const struct s2n_security_policy invalid_policy = {
.cipher_preferences = &invalid_cipher_prefs,
.signature_preferences = &invalid_sig_prefs,
.certificate_signature_preferences = &invalid_sig_prefs,
.ecc_preferences = &invalid_ecc_prefs,
.kem_preferences = &kem_preferences_null,
.kem_preferences = &invalid_kem_preferences,
.minimum_protocol_version = EXAMPLE_INVALID_VERSION,
};

Expand Down Expand Up @@ -202,6 +231,17 @@ int main(int argc, char **argv)
EXPECT_TRUE(result.found_error);
};

/* Test: only hybrid group invalid */
{
struct s2n_security_policy test_policy = valid_policy;
test_policy.kem_preferences = &invalid_kem_preferences;

struct s2n_security_rule_result result = { 0 };
EXPECT_OK(s2n_security_rule_validate_policy(
&test_rule, &test_policy, &result));
EXPECT_TRUE(result.found_error);
};

/* Test: only version invalid */
{
struct s2n_security_policy test_policy = valid_policy;
Expand Down
19 changes: 14 additions & 5 deletions tls/s2n_security_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ static S2N_RESULT s2n_security_rule_all_curves(
return S2N_RESULT_OK;
}

static S2N_RESULT s2n_security_rule_all_hybrid_groups(
const struct s2n_kem_group *hybrid_group, bool *valid)
{
RESULT_ENSURE_REF(valid);
*valid = true;
return S2N_RESULT_OK;
}

static S2N_RESULT s2n_security_rule_all_versions(uint8_t version, bool *valid)
{
RESULT_ENSURE_REF(valid);
Expand All @@ -84,6 +92,7 @@ const struct s2n_security_rule security_rule_definitions[S2N_SECURITY_RULES_COUN
.validate_sig_scheme = s2n_security_rule_all_sig_schemes,
.validate_cert_sig_scheme = s2n_security_rule_all_sig_schemes,
.validate_curve = s2n_security_rule_all_curves,
.validate_hybrid_group = s2n_security_rule_all_hybrid_groups,
.validate_version = s2n_security_rule_all_versions,
},
[S2N_FIPS_140_3] = {
Expand All @@ -92,6 +101,7 @@ const struct s2n_security_rule security_rule_definitions[S2N_SECURITY_RULES_COUN
.validate_sig_scheme = s2n_fips_validate_signature_scheme,
.validate_cert_sig_scheme = s2n_fips_validate_signature_scheme,
.validate_curve = s2n_fips_validate_curve,
.validate_hybrid_group = s2n_fips_validate_hybrid_group,
.validate_version = s2n_fips_validate_version,
},
};
Expand Down Expand Up @@ -169,14 +179,13 @@ S2N_RESULT s2n_security_rule_validate_policy(const struct s2n_security_rule *rul
RESULT_ENSURE_REF(kem_prefs);
for (size_t i = 0; i < kem_prefs->tls13_kem_group_count; i++) {
const struct s2n_kem_group *kem_group = kem_prefs->tls13_kem_groups[i];
const struct s2n_ecc_named_curve *curve = kem_group->curve;
RESULT_ENSURE_REF(curve);
RESULT_ENSURE_REF(kem_group);
bool is_valid = false;
RESULT_ENSURE_REF(rule->validate_curve);
RESULT_GUARD(rule->validate_curve(curve, &is_valid));
RESULT_ENSURE_REF(rule->validate_hybrid_group);
RESULT_GUARD(rule->validate_hybrid_group(kem_group, &is_valid));
RESULT_GUARD(s2n_security_rule_result_process(result, is_valid,
error_msg_format_name, rule->name, policy_name,
"curve", curve->name, i + 1));
"kem_group", kem_group->name, i + 1));
}

bool is_valid = false;
Expand Down
2 changes: 2 additions & 0 deletions tls/s2n_security_rules.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#pragma once

#include "stuffer/s2n_stuffer.h"
#include "tls/s2n_kem.h"
#include "utils/s2n_result.h"

typedef enum {
Expand Down Expand Up @@ -43,6 +44,7 @@ struct s2n_security_rule {
S2N_RESULT (*validate_sig_scheme)(const struct s2n_signature_scheme *sig_scheme, bool *valid);
S2N_RESULT (*validate_cert_sig_scheme)(const struct s2n_signature_scheme *sig_scheme, bool *valid);
S2N_RESULT (*validate_curve)(const struct s2n_ecc_named_curve *curve, bool *valid);
S2N_RESULT (*validate_hybrid_group)(const struct s2n_kem_group *hybrid_group, bool *valid);
S2N_RESULT (*validate_version)(uint8_t version, bool *valid);
};

Expand Down

0 comments on commit 21656e3

Please sign in to comment.