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 "tls/s2n_security_rules.h"
17 : :
18 : : #include <stdarg.h>
19 : :
20 : : #include "crypto/s2n_fips.h"
21 : : #include "tls/s2n_cipher_suites.h"
22 : : #include "tls/s2n_signature_scheme.h"
23 : : #include "utils/s2n_result.h"
24 : : #include "utils/s2n_safety.h"
25 : :
26 : : static S2N_RESULT s2n_security_rule_result_process(struct s2n_security_rule_result *result,
27 : : bool condition, const char *format, ...)
28 : 1897 : {
29 [ # # ][ - + ]: 1897 : RESULT_ENSURE_REF(result);
30 [ + + ]: 1897 : if (condition) {
31 : 1809 : return S2N_RESULT_OK;
32 : 1809 : }
33 : 88 : result->found_error = true;
34 : :
35 [ + + ]: 88 : if (!result->write_output) {
36 : 16 : return S2N_RESULT_OK;
37 : 16 : }
38 : :
39 : 72 : va_list vargs;
40 : 72 : va_start(vargs, format);
41 : 72 : int ret = s2n_stuffer_vprintf(&result->output, format, vargs);
42 : 72 : va_end(vargs);
43 [ - + ]: 72 : RESULT_GUARD_POSIX(ret);
44 [ - + ]: 72 : RESULT_GUARD_POSIX(s2n_stuffer_write_char(&result->output, '\n'));
45 : 72 : return S2N_RESULT_OK;
46 : 72 : }
47 : :
48 : : static S2N_RESULT s2n_security_rule_validate_forward_secret(
49 : : const struct s2n_cipher_suite *cipher_suite, bool *valid)
50 : 396 : {
51 [ - + ][ # # ]: 396 : RESULT_ENSURE_REF(cipher_suite);
52 [ - + ][ # # ]: 396 : RESULT_ENSURE_REF(cipher_suite->key_exchange_alg);
53 : 396 : *valid = cipher_suite->key_exchange_alg->is_ephemeral;
54 : 396 : return S2N_RESULT_OK;
55 : 396 : }
56 : :
57 : : static S2N_RESULT s2n_security_rule_all_sig_schemes(
58 : : const struct s2n_signature_scheme *sig_scheme, bool *valid)
59 : 758 : {
60 [ - + ][ # # ]: 758 : RESULT_ENSURE_REF(valid);
61 : 758 : *valid = true;
62 : 758 : return S2N_RESULT_OK;
63 : 758 : }
64 : :
65 : : static S2N_RESULT s2n_security_rule_all_curves(
66 : : const struct s2n_ecc_named_curve *curve, bool *valid)
67 : 126 : {
68 [ # # ][ - + ]: 126 : RESULT_ENSURE_REF(valid);
69 : 126 : *valid = true;
70 : 126 : return S2N_RESULT_OK;
71 : 126 : }
72 : :
73 : : static S2N_RESULT s2n_security_rule_all_hybrid_groups(
74 : : const struct s2n_kem_group *hybrid_group, bool *valid)
75 : 46 : {
76 [ - + ][ # # ]: 46 : RESULT_ENSURE_REF(valid);
77 : 46 : *valid = true;
78 : 46 : return S2N_RESULT_OK;
79 : 46 : }
80 : :
81 : : static S2N_RESULT s2n_security_rule_all_versions(uint8_t version, bool *valid)
82 : 45 : {
83 [ # # ][ - + ]: 45 : RESULT_ENSURE_REF(valid);
84 : 45 : *valid = true;
85 : 45 : return S2N_RESULT_OK;
86 : 45 : }
87 : :
88 : : const struct s2n_security_rule security_rule_definitions[S2N_SECURITY_RULES_COUNT] = {
89 : : [S2N_PERFECT_FORWARD_SECRECY] = {
90 : : .name = "Perfect Forward Secrecy",
91 : : .validate_cipher_suite = s2n_security_rule_validate_forward_secret,
92 : : .validate_sig_scheme = s2n_security_rule_all_sig_schemes,
93 : : .validate_cert_sig_scheme = s2n_security_rule_all_sig_schemes,
94 : : .validate_curve = s2n_security_rule_all_curves,
95 : : .validate_hybrid_group = s2n_security_rule_all_hybrid_groups,
96 : : .validate_version = s2n_security_rule_all_versions,
97 : : },
98 : : [S2N_FIPS_140_3] = {
99 : : .name = "FIPS 140-3 (2019)",
100 : : .validate_cipher_suite = s2n_fips_validate_cipher_suite,
101 : : .validate_sig_scheme = s2n_fips_validate_signature_scheme,
102 : : .validate_cert_sig_scheme = s2n_fips_validate_signature_scheme,
103 : : .validate_curve = s2n_fips_validate_curve,
104 : : .validate_hybrid_group = s2n_fips_validate_hybrid_group,
105 : : .validate_version = s2n_fips_validate_version,
106 : : },
107 : : };
108 : :
109 : : S2N_RESULT s2n_security_rule_validate_policy(const struct s2n_security_rule *rule,
110 : : const struct s2n_security_policy *policy, struct s2n_security_rule_result *result)
111 : 72 : {
112 [ # # ][ - + ]: 72 : RESULT_ENSURE_REF(rule);
113 [ - + ][ # # ]: 72 : RESULT_ENSURE_REF(policy);
114 [ - + ][ # # ]: 72 : RESULT_ENSURE_REF(result);
115 : :
116 : 72 : const char *policy_name = NULL;
117 : 72 : s2n_result_ignore(s2n_security_policy_get_version(policy, &policy_name));
118 [ + + ]: 72 : if (policy_name == NULL) {
119 : 15 : policy_name = "unnamed";
120 : 15 : }
121 : :
122 : 72 : const char *error_msg_format_name = "%s: policy %s: %s: %s (#%i)";
123 : 72 : const char *error_msg_format_basic = "%s: policy %s: %s: %i";
124 : :
125 : 72 : const struct s2n_cipher_preferences *cipher_prefs = policy->cipher_preferences;
126 [ - + ][ # # ]: 72 : RESULT_ENSURE_REF(cipher_prefs);
127 [ + + ]: 632 : for (size_t i = 0; i < cipher_prefs->count; i++) {
128 : 560 : const struct s2n_cipher_suite *cipher_suite = cipher_prefs->suites[i];
129 [ - + ][ # # ]: 560 : RESULT_ENSURE_REF(cipher_suite);
130 : 560 : bool is_valid = false;
131 [ - + ][ # # ]: 560 : RESULT_ENSURE_REF(rule->validate_cipher_suite);
132 [ - + ]: 560 : RESULT_GUARD(rule->validate_cipher_suite(cipher_suite, &is_valid));
133 [ - + ]: 560 : RESULT_GUARD(s2n_security_rule_result_process(result, is_valid,
134 : 560 : error_msg_format_name, rule->name, policy_name,
135 : 560 : "cipher suite", cipher_suite->iana_name, i + 1));
136 : 560 : }
137 : :
138 : 72 : const struct s2n_signature_preferences *sig_prefs = policy->signature_preferences;
139 [ - + ][ # # ]: 72 : RESULT_ENSURE_REF(sig_prefs);
140 [ + + ]: 790 : for (size_t i = 0; i < sig_prefs->count; i++) {
141 : 718 : const struct s2n_signature_scheme *sig_scheme = sig_prefs->signature_schemes[i];
142 [ # # ][ - + ]: 718 : RESULT_ENSURE_REF(sig_scheme);
143 : 718 : bool is_valid = false;
144 [ # # ][ - + ]: 718 : RESULT_ENSURE_REF(rule->validate_sig_scheme);
145 [ - + ]: 718 : RESULT_GUARD(rule->validate_sig_scheme(sig_scheme, &is_valid));
146 [ - + ]: 718 : RESULT_GUARD(s2n_security_rule_result_process(result, is_valid,
147 : 718 : error_msg_format_name, rule->name, policy_name,
148 : 718 : "signature scheme", sig_scheme->iana_name));
149 : 718 : }
150 : :
151 : 72 : const struct s2n_signature_preferences *cert_sig_prefs = policy->certificate_signature_preferences;
152 [ + + ]: 72 : if (cert_sig_prefs) {
153 [ + + ]: 330 : for (size_t i = 0; i < cert_sig_prefs->count; i++) {
154 : 295 : const struct s2n_signature_scheme *sig_scheme = cert_sig_prefs->signature_schemes[i];
155 [ # # ][ - + ]: 295 : RESULT_ENSURE_REF(sig_scheme);
156 : 295 : bool is_valid = false;
157 [ - + ][ # # ]: 295 : RESULT_ENSURE_REF(rule->validate_cert_sig_scheme);
158 [ - + ]: 295 : RESULT_GUARD(rule->validate_cert_sig_scheme(sig_scheme, &is_valid));
159 [ - + ]: 295 : RESULT_GUARD(s2n_security_rule_result_process(result, is_valid,
160 : 295 : error_msg_format_name, rule->name, policy_name,
161 : 295 : "certificate signature scheme", sig_scheme->iana_name));
162 : 295 : }
163 : 35 : }
164 : :
165 : 72 : const struct s2n_ecc_preferences *ecc_prefs = policy->ecc_preferences;
166 [ - + ][ # # ]: 72 : RESULT_ENSURE_REF(ecc_prefs);
167 [ + + ]: 246 : for (size_t i = 0; i < ecc_prefs->count; i++) {
168 : 174 : const struct s2n_ecc_named_curve *curve = ecc_prefs->ecc_curves[i];
169 [ # # ][ - + ]: 174 : RESULT_ENSURE_REF(curve);
170 : 174 : bool is_valid = false;
171 [ # # ][ - + ]: 174 : RESULT_ENSURE_REF(rule->validate_curve);
172 [ - + ]: 174 : RESULT_GUARD(rule->validate_curve(curve, &is_valid));
173 [ - + ]: 174 : RESULT_GUARD(s2n_security_rule_result_process(result, is_valid,
174 : 174 : error_msg_format_name, rule->name, policy_name,
175 : 174 : "curve", curve->name, i + 1));
176 : 174 : }
177 : :
178 : 72 : const struct s2n_kem_preferences *kem_prefs = policy->kem_preferences;
179 [ - + ][ # # ]: 72 : RESULT_ENSURE_REF(kem_prefs);
180 [ + + ]: 150 : for (size_t i = 0; i < kem_prefs->tls13_kem_group_count; i++) {
181 : 78 : const struct s2n_kem_group *kem_group = kem_prefs->tls13_kem_groups[i];
182 [ - + ][ # # ]: 78 : RESULT_ENSURE_REF(kem_group);
183 : 78 : bool is_valid = false;
184 [ # # ][ - + ]: 78 : RESULT_ENSURE_REF(rule->validate_hybrid_group);
185 [ - + ]: 78 : RESULT_GUARD(rule->validate_hybrid_group(kem_group, &is_valid));
186 [ - + ]: 78 : RESULT_GUARD(s2n_security_rule_result_process(result, is_valid,
187 : 78 : error_msg_format_name, rule->name, policy_name,
188 : 78 : "kem_group", kem_group->name, i + 1));
189 : 78 : }
190 : :
191 : 72 : bool is_valid = false;
192 [ - + ][ # # ]: 72 : RESULT_ENSURE_REF(rule->validate_version);
193 [ - + ]: 72 : RESULT_GUARD(rule->validate_version(policy->minimum_protocol_version, &is_valid));
194 [ - + ]: 72 : RESULT_GUARD(s2n_security_rule_result_process(result, is_valid,
195 : 72 : error_msg_format_basic, rule->name, policy_name,
196 : 72 : "min version", policy->minimum_protocol_version));
197 : :
198 : 72 : return S2N_RESULT_OK;
199 : 72 : }
200 : :
201 : : S2N_RESULT s2n_security_policy_validate_security_rules(
202 : : const struct s2n_security_policy *policy, struct s2n_security_rule_result *result)
203 : 129 : {
204 [ - + ][ # # ]: 129 : RESULT_ENSURE_REF(policy);
205 [ + + ]: 387 : for (size_t rule_id = 0; rule_id < s2n_array_len(policy->rules); rule_id++) {
206 [ + + ]: 258 : if (!policy->rules[rule_id]) {
207 : 200 : continue;
208 : 200 : }
209 [ # # ][ - + ]: 58 : RESULT_ENSURE_LT(rule_id, s2n_array_len(security_rule_definitions));
210 : 58 : const struct s2n_security_rule *rule = &security_rule_definitions[rule_id];
211 [ - + ]: 58 : RESULT_GUARD(s2n_security_rule_validate_policy(rule, policy, result));
212 : 58 : }
213 : 129 : return S2N_RESULT_OK;
214 : 129 : }
215 : :
216 : : S2N_RESULT s2n_security_rule_result_init_output(struct s2n_security_rule_result *result)
217 : 5 : {
218 : : /* For the expected, happy case, the rule isn't violated, so nothing is written
219 : : * to the stuffer, so no memory is allocated.
220 : : */
221 [ - + ]: 5 : RESULT_GUARD_POSIX(s2n_stuffer_growable_alloc(&result->output, 0));
222 : 5 : result->write_output = true;
223 : 5 : return S2N_RESULT_OK;
224 : 5 : }
225 : :
226 : : S2N_CLEANUP_RESULT s2n_security_rule_result_free(struct s2n_security_rule_result *result)
227 : 6 : {
228 [ + - ]: 6 : if (result) {
229 [ - + ]: 6 : RESULT_GUARD_POSIX(s2n_stuffer_free(&result->output));
230 : 6 : *result = (struct s2n_security_rule_result){ 0 };
231 : 6 : }
232 : 6 : return S2N_RESULT_OK;
233 : 6 : }
|