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/policy/s2n_policy_feature.h"
17 : : #include "tls/s2n_security_policies.h"
18 : :
19 : : struct s2n_security_policy_builder {
20 : : const struct s2n_security_policy *base_policy;
21 : : };
22 : :
23 : : /* All our lists behave the same, but use different types and field names.
24 : : * Use a macro to avoid writing multiple copies of the same basic methods.
25 : : */
26 : : #define S2N_DEFINE_PREFERENCE_LIST_FUNCTIONS(pref_type, entry_type, list_name, count_name) \
27 : : static S2N_RESULT pref_type##_copy(const struct pref_type *original, const struct pref_type **copy) \
28 : 822 : { \
29 [ # # ][ - + ]: 822 : RESULT_ENSURE_REF(copy); \
[ # # ][ - + ]
[ - + ][ # # ]
[ # # ][ - + ]
[ - + ][ # # ]
30 [ - + ][ + + ]: 822 : if (original == NULL) { \
[ - + ][ + + ]
[ - + ]
31 : 251 : *copy = NULL; \
32 : 251 : return S2N_RESULT_OK; \
33 : 251 : } \
34 : 822 : DEFER_CLEANUP(struct s2n_blob pref_mem = { 0 }, s2n_free); \
35 [ - + ][ - + ]: 571 : RESULT_GUARD_POSIX(s2n_alloc(&pref_mem, sizeof(struct pref_type))); \
[ - + ][ - + ]
[ - + ]
36 [ - + ][ # # ]: 571 : RESULT_CHECKED_MEMCPY(pref_mem.data, original, pref_mem.size); \
[ - + ][ - + ]
[ # # ][ - + ]
[ # # ][ - + ]
[ # # ][ # # ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
37 : 571 : \
38 : 571 : DEFER_CLEANUP(struct s2n_blob list_mem = { 0 }, s2n_free); \
39 : 571 : size_t list_mem_size = original->count_name * sizeof(entry_type); \
40 [ - + ][ - + ]: 571 : RESULT_GUARD_POSIX(s2n_alloc(&list_mem, list_mem_size)); \
[ - + ][ - + ]
[ - + ]
41 [ # # ][ # # ]: 571 : RESULT_CHECKED_MEMCPY(list_mem.data, original->list_name, list_mem.size); \
[ - + ][ # # ]
[ - + ][ - + ]
[ # # ][ # # ]
[ - + ][ - + ]
[ + + ][ + - ]
[ + + ][ + + ]
[ + - ]
42 : 571 : \
43 : 571 : struct pref_type *prefs = (struct pref_type *) (void *) pref_mem.data; \
44 : 571 : prefs->list_name = (entry_type *) (void *) list_mem.data; \
45 : 571 : *copy = prefs; \
46 : 571 : \
47 : 571 : ZERO_TO_DISABLE_DEFER_CLEANUP(pref_mem); \
48 : 571 : ZERO_TO_DISABLE_DEFER_CLEANUP(list_mem); \
49 : 571 : return S2N_RESULT_OK; \
50 : 571 : } \
51 : : \
52 : : static S2N_CLEANUP_RESULT pref_type##_free(const struct pref_type **prefs_ptr) \
53 : 822 : { \
54 [ - + ][ - + ]: 822 : if (!prefs_ptr) { \
[ - + ][ - + ]
[ - + ]
55 : 0 : return S2N_RESULT_OK; \
56 : 0 : } \
57 : 822 : const struct pref_type *prefs = *prefs_ptr; \
58 [ + + ][ - + ]: 822 : if (!prefs) { \
[ - + ][ + + ]
[ - + ]
59 : 251 : return S2N_RESULT_OK; \
60 : 251 : } \
61 : 822 : size_t size = prefs->count_name * sizeof(entry_type); \
62 : 571 : /* Safety: we only free preferences allocated by the builder, so stripping
63 : 571 : * the `const` in order to free is a known safe mutation.
64 : 571 : */ \
65 [ - + ][ - + ]: 571 : RESULT_GUARD_POSIX(s2n_free_object( \
[ - + ][ - + ]
[ - + ]
66 : 571 : (uint8_t **) (void *) (uintptr_t) (const void *) &prefs->list_name, size)); \
67 [ - + ][ - + ]: 571 : RESULT_GUARD_POSIX(s2n_free_object( \
[ - + ][ - + ]
[ - + ]
68 : 571 : (uint8_t **) (void *) (uintptr_t) (const void *) prefs_ptr, sizeof(struct pref_type))); \
69 : 571 : return S2N_RESULT_OK; \
70 : 571 : }
71 : :
72 : : S2N_DEFINE_PREFERENCE_LIST_FUNCTIONS(
73 : : s2n_cipher_preferences, struct s2n_cipher_suite *, suites, count)
74 : : S2N_DEFINE_PREFERENCE_LIST_FUNCTIONS(
75 : : s2n_signature_preferences, const struct s2n_signature_scheme *const, signature_schemes, count)
76 : : S2N_DEFINE_PREFERENCE_LIST_FUNCTIONS(
77 : : s2n_ecc_preferences, const struct s2n_ecc_named_curve *const, ecc_curves, count)
78 : : S2N_DEFINE_PREFERENCE_LIST_FUNCTIONS(
79 : : s2n_certificate_key_preferences, const struct s2n_certificate_key *const, certificate_keys, count)
80 : : /* s2n_kem_preferences actually has two lists, but the `kems` list is deprecated
81 : : * and no longer set for any policies. */
82 : : S2N_DEFINE_PREFERENCE_LIST_FUNCTIONS(
83 : : s2n_kem_preferences, const struct s2n_kem_group *, tls13_kem_groups, tls13_kem_group_count)
84 : :
85 : : /* Safety: this method does not break if new lists are added to s2n_security_policy.
86 : : * The copy will simply inherit the static version of the new list from the original,
87 : : * just like it inherits the values of non-list fields.
88 : : * The only requirement is that s2n_security_policy_free free every list created
89 : : * by s2n_security_policy_copy.
90 : : */
91 : : static S2N_RESULT s2n_security_policy_copy(const struct s2n_security_policy *original, struct s2n_security_policy **copy)
92 : 137 : {
93 [ - + ][ # # ]: 137 : RESULT_ENSURE_REF(original);
94 [ # # ][ - + ]: 137 : RESULT_ENSURE_REF(copy);
95 [ # # ][ - + ]: 137 : RESULT_ENSURE_EQ(*copy, NULL);
96 : :
97 : 137 : struct s2n_blob mem = { 0 };
98 [ - + ]: 137 : RESULT_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_security_policy)));
99 : 137 : DEFER_CLEANUP(struct s2n_security_policy *policy =
100 : 137 : (struct s2n_security_policy *) (void *) mem.data,
101 : 137 : s2n_security_policy_free);
102 [ - + ][ # # ]: 137 : RESULT_CHECKED_MEMCPY(mem.data, original, mem.size);
[ + - ]
103 : 137 : policy->alloced = true;
104 : :
105 : : /* No existing policy still has TLS1.2 KEMs. Ignore them for simplicity. */
106 [ - + ][ # # ]: 137 : RESULT_ENSURE(original->kem_preferences->kem_count == 0, S2N_ERR_DEPRECATED_SECURITY_POLICY);
107 : :
108 [ - + ]: 137 : RESULT_GUARD(s2n_cipher_preferences_copy(
109 : 137 : original->cipher_preferences, &policy->cipher_preferences));
110 [ - + ]: 137 : RESULT_GUARD(s2n_signature_preferences_copy(
111 : 137 : original->signature_preferences, &policy->signature_preferences));
112 [ - + ]: 137 : RESULT_GUARD(s2n_signature_preferences_copy(
113 : 137 : original->certificate_signature_preferences, &policy->certificate_signature_preferences));
114 [ - + ]: 137 : RESULT_GUARD(s2n_ecc_preferences_copy(
115 : 137 : original->ecc_preferences, &policy->ecc_preferences));
116 [ - + ]: 137 : RESULT_GUARD(s2n_certificate_key_preferences_copy(
117 : 137 : original->certificate_key_preferences, &policy->certificate_key_preferences));
118 [ - + ]: 137 : RESULT_GUARD(s2n_kem_preferences_copy(
119 : 137 : original->kem_preferences, &policy->kem_preferences));
120 : :
121 : 137 : *copy = policy;
122 : 137 : ZERO_TO_DISABLE_DEFER_CLEANUP(policy);
123 : 137 : return S2N_RESULT_OK;
124 : 137 : }
125 : :
126 : : int s2n_security_policy_free(struct s2n_security_policy **policy_ptr)
127 : 412 : {
128 [ + + ]: 412 : if (!policy_ptr) {
129 : 1 : return S2N_SUCCESS;
130 : 1 : }
131 : 411 : struct s2n_security_policy *policy = *policy_ptr;
132 [ + + ]: 411 : if (!policy) {
133 : 139 : return S2N_SUCCESS;
134 : 139 : }
135 : :
136 : : /* Static policies should always be const, so this method's non-const
137 : : * argument should prevent mistakes. However, there are ways to circumvent
138 : : * const in C, so add an extra safety check.
139 : : */
140 [ + + ][ + - ]: 272 : POSIX_ENSURE(policy->alloced, S2N_ERR_INVALID_ARGUMENT);
141 : :
142 [ - + ]: 137 : POSIX_GUARD_RESULT(s2n_cipher_preferences_free(&policy->cipher_preferences));
143 [ - + ]: 137 : POSIX_GUARD_RESULT(s2n_signature_preferences_free(&policy->signature_preferences));
144 [ - + ]: 137 : POSIX_GUARD_RESULT(s2n_signature_preferences_free(&policy->certificate_signature_preferences));
145 [ - + ]: 137 : POSIX_GUARD_RESULT(s2n_ecc_preferences_free(&policy->ecc_preferences));
146 [ - + ]: 137 : POSIX_GUARD_RESULT(s2n_certificate_key_preferences_free(&policy->certificate_key_preferences));
147 [ - + ]: 137 : POSIX_GUARD_RESULT(s2n_kem_preferences_free(&policy->kem_preferences));
148 : :
149 [ - + ]: 137 : POSIX_GUARD(s2n_free_object((uint8_t **) policy_ptr, sizeof(struct s2n_security_policy)));
150 : 137 : return S2N_SUCCESS;
151 : 137 : }
152 : :
153 : : struct s2n_security_policy_builder *s2n_security_policy_builder_from_version(const char *version)
154 : 275 : {
155 [ + + ][ + - ]: 275 : PTR_ENSURE(version, S2N_ERR_INVALID_ARGUMENT);
156 : 274 : DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
157 [ - + ]: 274 : PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_security_policy_builder)));
158 : 274 : struct s2n_security_policy_builder *builder =
159 : 274 : (struct s2n_security_policy_builder *) (void *) mem.data;
160 : :
161 [ + + ]: 274 : PTR_GUARD_POSIX(s2n_find_security_policy_from_version(version, &builder->base_policy));
162 [ - + ][ # # ]: 273 : PTR_ENSURE_REF(builder->base_policy);
163 [ - + ][ # # ]: 273 : PTR_ENSURE_EQ(builder->base_policy->alloced, false);
164 : :
165 : 273 : ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
166 : 273 : return builder;
167 : 273 : }
168 : :
169 : : int s2n_security_policy_builder_free(struct s2n_security_policy_builder **builder_ptr)
170 : 276 : {
171 [ + + ]: 276 : if (!builder_ptr) {
172 : 1 : return S2N_SUCCESS;
173 : 1 : }
174 [ - + ]: 275 : POSIX_GUARD(s2n_free_object((uint8_t **) builder_ptr, sizeof(struct s2n_security_policy_builder)));
175 : 275 : return S2N_SUCCESS;
176 : 275 : }
177 : :
178 : : /* For now, "build" just copies the input policy.
179 : : * We will add functionality later.
180 : : */
181 : : struct s2n_security_policy *s2n_security_policy_build(struct s2n_security_policy_builder *builder)
182 : 138 : {
183 [ + + ][ + - ]: 138 : PTR_ENSURE(builder, S2N_ERR_INVALID_ARGUMENT);
184 : 137 : struct s2n_security_policy *policy = NULL;
185 [ - + ]: 137 : PTR_GUARD_RESULT(s2n_security_policy_copy(builder->base_policy, &policy));
186 [ - + ][ # # ]: 137 : PTR_ENSURE_REF(policy);
187 : 137 : return policy;
188 : 137 : }
|