Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #include "crypto/s2n_fips.h"
17 : : #include "tls/s2n_cipher_suites.h"
18 : : #include "tls/s2n_tls_parameters.h"
19 : : #include "utils/s2n_result.h"
20 : :
21 : : /* FIPS requires at least 112 bits of security.
22 : : * https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-107r1.pdf */
23 : : const s2n_hash_algorithm fips_hash_algs[] = {
24 : : S2N_HASH_SHA224,
25 : : S2N_HASH_SHA256,
26 : : S2N_HASH_SHA384,
27 : : S2N_HASH_SHA512,
28 : : /* ML-DSA is FIPS-validated: https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf */
29 : : S2N_HASH_SHAKE256_64,
30 : : };
31 : : S2N_RESULT s2n_fips_validate_hash_algorithm(s2n_hash_algorithm hash_alg, bool *valid)
32 : 315 : {
33 [ + + ][ + - ]: 315 : RESULT_ENSURE_REF(valid);
34 : 314 : *valid = false;
35 [ + + ]: 943 : for (size_t i = 0; i < s2n_array_len(fips_hash_algs); i++) {
36 [ + + ]: 936 : if (fips_hash_algs[i] == hash_alg) {
37 : 307 : *valid = true;
38 : 307 : return S2N_RESULT_OK;
39 : 307 : }
40 : 936 : }
41 : 7 : return S2N_RESULT_OK;
42 : 314 : }
43 : :
44 : : /* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-52r2.pdf */
45 : : const uint8_t fips_cipher_suite_ianas[][2] = {
46 : : /* 3.3.1.1.1 Cipher Suites for ECDSA Certificates */
47 : : { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 },
48 : : { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 },
49 : : { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 },
50 : : { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 },
51 : : { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA },
52 : : { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA },
53 : :
54 : : /* 3.3.1.1.2 Cipher Suites for RSA Certificates */
55 : : { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 },
56 : : { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 },
57 : : { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 },
58 : : { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 },
59 : : { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 },
60 : : { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 },
61 : : { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 },
62 : : { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 },
63 : : { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA },
64 : : { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA },
65 : : { TLS_DHE_RSA_WITH_AES_128_CBC_SHA },
66 : : { TLS_DHE_RSA_WITH_AES_256_CBC_SHA },
67 : :
68 : : /* 3.3.1.2 Cipher Suites for TLS 1.3 */
69 : : { TLS_AES_128_GCM_SHA256 },
70 : : { TLS_AES_256_GCM_SHA384 },
71 : : };
72 : :
73 : : S2N_RESULT s2n_fips_validate_cipher_suite(const struct s2n_cipher_suite *cipher_suite, bool *valid)
74 : 162 : {
75 [ + - ][ + + ]: 162 : RESULT_ENSURE_REF(cipher_suite);
76 [ + + ][ + - ]: 161 : RESULT_ENSURE_REF(valid);
77 : :
78 : 160 : *valid = false;
79 [ + + ]: 1736 : for (size_t i = 0; i < s2n_array_len(fips_cipher_suite_ianas); i++) {
80 [ + + ]: 1717 : if (fips_cipher_suite_ianas[i][0] != cipher_suite->iana_value[0]) {
81 : 952 : continue;
82 : 952 : }
83 [ + + ]: 765 : if (fips_cipher_suite_ianas[i][1] != cipher_suite->iana_value[1]) {
84 : 624 : continue;
85 : 624 : }
86 : 141 : *valid = true;
87 : 141 : return S2N_RESULT_OK;
88 : 765 : }
89 : 19 : return S2N_RESULT_OK;
90 : 160 : }
91 : :
92 : : S2N_RESULT s2n_fips_validate_signature_scheme(const struct s2n_signature_scheme *sig_alg, bool *valid)
93 : 296 : {
94 [ + - ][ + + ]: 296 : RESULT_ENSURE_REF(sig_alg);
95 [ + + ]: 295 : RESULT_GUARD(s2n_fips_validate_hash_algorithm(sig_alg->hash_alg, valid));
96 : 294 : return S2N_RESULT_OK;
97 : 295 : }
98 : :
99 : : /* https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar3.pdf */
100 : : const struct s2n_ecc_named_curve *fips_curves[] = {
101 : : &s2n_ecc_curve_secp256r1,
102 : : &s2n_ecc_curve_secp384r1,
103 : : &s2n_ecc_curve_secp521r1,
104 : : };
105 : : S2N_RESULT s2n_fips_validate_curve(const struct s2n_ecc_named_curve *curve, bool *valid)
106 : 52 : {
107 [ + - ][ + + ]: 52 : RESULT_ENSURE_REF(curve);
108 [ + + ][ + - ]: 51 : RESULT_ENSURE_REF(valid);
109 : 50 : *valid = false;
110 [ + + ]: 94 : for (size_t i = 0; i < s2n_array_len(fips_curves); i++) {
111 [ + + ]: 92 : if (fips_curves[i] == curve) {
112 : 48 : *valid = true;
113 : 48 : return S2N_RESULT_OK;
114 : 48 : }
115 : 92 : }
116 : 2 : return S2N_RESULT_OK;
117 : 50 : }
118 : :
119 : : /* https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf */
120 : : const struct s2n_kem *fips_kems[] = {
121 : : &s2n_mlkem_768,
122 : : &s2n_mlkem_1024
123 : : };
124 : :
125 : : S2N_RESULT s2n_fips_validate_kem(const struct s2n_kem *kem, bool *valid)
126 : 8 : {
127 [ - + ][ # # ]: 8 : RESULT_ENSURE_REF(kem);
128 [ # # ][ - + ]: 8 : RESULT_ENSURE_REF(valid);
129 : 8 : *valid = false;
130 : :
131 [ + - ]: 11 : for (size_t i = 0; i < s2n_array_len(fips_kems); i++) {
132 [ + + ]: 11 : if (fips_kems[i] == kem) {
133 : 8 : *valid = true;
134 : 8 : return S2N_RESULT_OK;
135 : 8 : }
136 : 11 : }
137 : 0 : return S2N_RESULT_OK;
138 : 8 : }
139 : :
140 : : S2N_RESULT s2n_fips_validate_hybrid_group(const struct s2n_kem_group *hybrid_group, bool *valid)
141 : 16 : {
142 [ # # ][ - + ]: 16 : RESULT_ENSURE_REF(hybrid_group);
143 [ # # ][ - + ]: 16 : RESULT_ENSURE_REF(valid);
144 : 16 : *valid = false;
145 : :
146 : : /* The first share in a Hybrid Group must be FIPS-approved, see page 33 of NIST 800-56Cr2.
147 : : *
148 : : * "Recommendation is expanded to permit the use of “hybrid” shared secrets of the form Z' = Z || T,
149 : : * which is a concatenation consisting of a “standard” shared secret Z that was generated during the
150 : : * execution of a key-establishment scheme as currently specified in [SP 800-56A] or [SP 800-56B],
151 : : * followed by an auxiliary shared secret T that has been generated using some other method."
152 : : *
153 : : * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Cr2.pdf
154 : : */
155 : :
156 [ + + ][ + + ]: 16 : if (hybrid_group->send_kem_first || hybrid_group->curve == &s2n_ecc_curve_none) {
157 [ - + ]: 8 : RESULT_GUARD(s2n_fips_validate_kem(hybrid_group->kem, valid));
158 : 8 : } else {
159 [ - + ]: 8 : RESULT_GUARD(s2n_fips_validate_curve(hybrid_group->curve, valid));
160 : 8 : }
161 : :
162 : 16 : return S2N_RESULT_OK;
163 : 16 : }
164 : :
165 : : S2N_RESULT s2n_fips_validate_version(uint8_t version, bool *valid)
166 : 282 : {
167 [ + + ][ + - ]: 282 : RESULT_ENSURE_REF(valid);
168 : : /* Technically FIPS 140-3 still allows TLS1.0 and TLS1.1 for some use cases,
169 : : * but for simplicity s2n-tls does not.
170 : : */
171 : 281 : *valid = (version >= S2N_TLS12);
172 : 281 : return S2N_RESULT_OK;
173 : 282 : }
|