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_dhe.h"
17 : :
18 : : #include <openssl/bn.h>
19 : : #include <openssl/dh.h>
20 : : #include <openssl/evp.h>
21 : : #include <stdint.h>
22 : :
23 : : #include "crypto/s2n_openssl.h"
24 : : #include "error/s2n_errno.h"
25 : : #include "stuffer/s2n_stuffer.h"
26 : : #include "utils/s2n_blob.h"
27 : : #include "utils/s2n_mem.h"
28 : : #include "utils/s2n_safety.h"
29 : :
30 : : #define S2N_MIN_DH_PRIME_SIZE_BYTES (2048 / 8)
31 : :
32 : : /* Caller is not responsible for freeing values returned by these accessors
33 : : * Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html
34 : : */
35 : : static const BIGNUM *s2n_get_Ys_dh_param(struct s2n_dh_params *dh_params)
36 : 146 : {
37 : 146 : const BIGNUM *Ys = NULL;
38 : :
39 : : /* DH made opaque in Openssl 1.1.0 */
40 : 146 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
41 : 146 : DH_get0_key(dh_params->dh, &Ys, NULL);
42 : : #else
43 : : Ys = dh_params->dh->pub_key;
44 : : #endif
45 : :
46 : 146 : return Ys;
47 : 146 : }
48 : :
49 : : static const BIGNUM *s2n_get_p_dh_param(struct s2n_dh_params *dh_params)
50 : 280 : {
51 : 280 : const BIGNUM *p = NULL;
52 : 280 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
53 : 280 : DH_get0_pqg(dh_params->dh, &p, NULL, NULL);
54 : : #else
55 : : p = dh_params->dh->p;
56 : : #endif
57 : :
58 : 280 : return p;
59 : 280 : }
60 : :
61 : : static const BIGNUM *s2n_get_g_dh_param(struct s2n_dh_params *dh_params)
62 : 280 : {
63 : 280 : const BIGNUM *g = NULL;
64 : 280 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
65 : 280 : DH_get0_pqg(dh_params->dh, NULL, NULL, &g);
66 : : #else
67 : : g = dh_params->dh->g;
68 : : #endif
69 : :
70 : 280 : return g;
71 : 280 : }
72 : :
73 : : static int s2n_check_p_g_dh_params(struct s2n_dh_params *dh_params)
74 : 255 : {
75 [ - + ][ # # ]: 255 : POSIX_ENSURE_REF(dh_params);
76 [ # # ][ - + ]: 255 : POSIX_ENSURE_REF(dh_params->dh);
77 : :
78 : 255 : const BIGNUM *p = s2n_get_p_dh_param(dh_params);
79 : 255 : const BIGNUM *g = s2n_get_g_dh_param(dh_params);
80 : :
81 [ # # ][ - + ]: 255 : POSIX_ENSURE_REF(g);
82 [ # # ][ - + ]: 255 : POSIX_ENSURE_REF(p);
83 : :
84 [ - + ][ # # ]: 255 : S2N_ERROR_IF(DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_PARAMS_CREATE);
85 [ - + ][ # # ]: 255 : S2N_ERROR_IF(BN_is_zero(g), S2N_ERR_DH_PARAMS_CREATE);
86 [ - + ][ # # ]: 255 : S2N_ERROR_IF(BN_is_zero(p), S2N_ERR_DH_PARAMS_CREATE);
87 : :
88 : 255 : return S2N_SUCCESS;
89 : 255 : }
90 : :
91 : : static int s2n_check_pub_key_dh_params(struct s2n_dh_params *dh_params)
92 : 73 : {
93 : 73 : const BIGNUM *pub_key = s2n_get_Ys_dh_param(dh_params);
94 : :
95 [ - + ][ # # ]: 73 : POSIX_ENSURE_REF(pub_key);
96 : :
97 [ - + ][ # # ]: 73 : S2N_ERROR_IF(BN_is_zero(pub_key), S2N_ERR_DH_PARAMS_CREATE);
98 : :
99 : 73 : return S2N_SUCCESS;
100 : 73 : }
101 : :
102 : : static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g,
103 : : struct s2n_blob *Ys)
104 : 24 : {
105 [ - + ][ # # ]: 24 : POSIX_ENSURE(p->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
106 [ - + ][ # # ]: 24 : POSIX_ENSURE(g->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
107 [ # # ][ - + ]: 24 : POSIX_ENSURE(Ys->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
108 : 24 : BIGNUM *bn_p = BN_bin2bn((const unsigned char *) p->data, p->size, NULL);
109 : 24 : BIGNUM *bn_g = BN_bin2bn((const unsigned char *) g->data, g->size, NULL);
110 : 24 : BIGNUM *bn_Ys = BN_bin2bn((const unsigned char *) Ys->data, Ys->size, NULL);
111 : :
112 : 24 : #if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0)
113 : : /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html:
114 : : * values that have been passed in should not be freed directly after this function has been called
115 : : */
116 [ - + ][ # # ]: 24 : POSIX_GUARD_OSSL(DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g), S2N_ERR_DH_PARAMS_CREATE);
117 : :
118 : : /* Same as DH_set0_pqg */
119 [ - + ][ # # ]: 24 : POSIX_GUARD_OSSL(DH_set0_key(dh_params->dh, bn_Ys, NULL), S2N_ERR_DH_PARAMS_CREATE);
120 : : #else
121 : : dh_params->dh->p = bn_p;
122 : : dh_params->dh->g = bn_g;
123 : : dh_params->dh->pub_key = bn_Ys;
124 : : #endif
125 : :
126 : 24 : return S2N_SUCCESS;
127 : 24 : }
128 : :
129 : : int s2n_check_all_dh_params(struct s2n_dh_params *dh_params)
130 : 73 : {
131 [ - + ]: 73 : POSIX_GUARD(s2n_check_p_g_dh_params(dh_params));
132 [ - + ]: 73 : POSIX_GUARD(s2n_check_pub_key_dh_params(dh_params));
133 : :
134 : 73 : return S2N_SUCCESS;
135 : 73 : }
136 : :
137 : : int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3)
138 : 84 : {
139 [ # # ][ - + ]: 84 : POSIX_ENSURE_REF(dh_params);
140 [ - + ][ + - ]: 84 : POSIX_PRECONDITION(s2n_blob_validate(pkcs3));
141 : 84 : DEFER_CLEANUP(struct s2n_dh_params temp_dh_params = { 0 }, s2n_dh_params_free);
142 : :
143 : 84 : uint8_t *original_ptr = pkcs3->data;
144 : 84 : temp_dh_params.dh = d2i_DHparams(NULL, (const unsigned char **) (void *) &pkcs3->data, pkcs3->size);
145 : :
146 [ - + ]: 84 : POSIX_GUARD(s2n_check_p_g_dh_params(&temp_dh_params));
147 : :
148 [ + - ]: 84 : if (pkcs3->data) {
149 [ # # ][ - + ]: 84 : POSIX_ENSURE_GTE(pkcs3->data, original_ptr);
150 [ - + ][ # # ]: 84 : POSIX_ENSURE((uint32_t) (pkcs3->data - original_ptr) == pkcs3->size, S2N_ERR_INVALID_PKCS3);
151 : 84 : }
152 : :
153 : 84 : pkcs3->data = original_ptr;
154 : :
155 : : /* Require at least 2048 bits for the DH size */
156 [ # # ][ - + ]: 84 : POSIX_ENSURE(DH_size(temp_dh_params.dh) >= S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_TOO_SMALL);
157 : :
158 : : /* Check the generator and prime */
159 [ - + ]: 84 : POSIX_GUARD(s2n_dh_params_check(&temp_dh_params));
160 : :
161 : 84 : dh_params->dh = temp_dh_params.dh;
162 : :
163 : 84 : ZERO_TO_DISABLE_DEFER_CLEANUP(temp_dh_params);
164 : :
165 : 84 : return S2N_SUCCESS;
166 : 84 : }
167 : :
168 : : int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g,
169 : : struct s2n_blob *Ys)
170 : 24 : {
171 [ - + ][ # # ]: 24 : POSIX_ENSURE_REF(server_dh_params);
172 [ - + ][ + - ]: 24 : POSIX_PRECONDITION(s2n_blob_validate(p));
173 [ - + ][ + - ]: 24 : POSIX_PRECONDITION(s2n_blob_validate(g));
174 [ - + ][ + - ]: 24 : POSIX_PRECONDITION(s2n_blob_validate(Ys));
175 : :
176 : 24 : server_dh_params->dh = DH_new();
177 [ # # ][ - + ]: 24 : POSIX_ENSURE(server_dh_params->dh != NULL, S2N_ERR_DH_PARAMS_CREATE);
178 : :
179 [ - + ]: 24 : POSIX_GUARD(s2n_set_p_g_Ys_dh_params(server_dh_params, p, g, Ys));
180 [ - + ]: 24 : POSIX_GUARD(s2n_check_all_dh_params(server_dh_params));
181 : :
182 : 24 : return S2N_SUCCESS;
183 : 24 : }
184 : :
185 : : int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output)
186 : 25 : {
187 [ - + ]: 25 : POSIX_GUARD(s2n_check_all_dh_params(server_dh_params));
188 [ - + ][ + - ]: 25 : POSIX_PRECONDITION(s2n_stuffer_validate(out));
189 [ - + ][ + - ]: 25 : POSIX_PRECONDITION(s2n_blob_validate(output));
190 : :
191 : 25 : const BIGNUM *bn_p = s2n_get_p_dh_param(server_dh_params);
192 : 25 : const BIGNUM *bn_g = s2n_get_g_dh_param(server_dh_params);
193 : 25 : const BIGNUM *bn_Ys = s2n_get_Ys_dh_param(server_dh_params);
194 : :
195 : 25 : uint16_t p_size = BN_num_bytes(bn_p);
196 : 25 : uint16_t g_size = BN_num_bytes(bn_g);
197 : 25 : uint16_t Ys_size = BN_num_bytes(bn_Ys);
198 : 25 : uint8_t *p = NULL;
199 : 25 : uint8_t *g = NULL;
200 : 25 : uint8_t *Ys = NULL;
201 : :
202 : 25 : output->data = s2n_stuffer_raw_write(out, 0);
203 [ - + ][ # # ]: 25 : POSIX_ENSURE_REF(output->data);
204 : :
205 [ - + ]: 25 : POSIX_GUARD(s2n_stuffer_write_uint16(out, p_size));
206 : 25 : p = s2n_stuffer_raw_write(out, p_size);
207 [ - + ][ # # ]: 25 : POSIX_ENSURE_REF(p);
208 [ - + ][ # # ]: 25 : POSIX_ENSURE(BN_bn2bin(bn_p, p) == p_size, S2N_ERR_DH_SERIALIZING);
209 : :
210 [ - + ]: 25 : POSIX_GUARD(s2n_stuffer_write_uint16(out, g_size));
211 : 25 : g = s2n_stuffer_raw_write(out, g_size);
212 [ - + ][ # # ]: 25 : POSIX_ENSURE_REF(g);
213 [ - + ][ # # ]: 25 : POSIX_ENSURE(BN_bn2bin(bn_g, g) == g_size, S2N_ERR_DH_SERIALIZING);
214 : :
215 [ - + ]: 25 : POSIX_GUARD(s2n_stuffer_write_uint16(out, Ys_size));
216 : 25 : Ys = s2n_stuffer_raw_write(out, Ys_size);
217 [ # # ][ - + ]: 25 : POSIX_ENSURE_REF(Ys);
218 [ # # ][ - + ]: 25 : POSIX_ENSURE(BN_bn2bin(bn_Ys, Ys) == Ys_size, S2N_ERR_DH_SERIALIZING);
219 : :
220 : 25 : output->size = p_size + 2 + g_size + 2 + Ys_size + 2;
221 : :
222 : 25 : return S2N_SUCCESS;
223 : 25 : }
224 : :
225 : : int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out,
226 : : struct s2n_blob *shared_key)
227 : 24 : {
228 : 24 : struct s2n_dh_params client_params = { 0 };
229 : 24 : uint8_t *client_pub_key = NULL;
230 : 24 : uint16_t client_pub_key_size = 0;
231 : 24 : int shared_key_size = 0;
232 : :
233 [ - + ]: 24 : POSIX_GUARD(s2n_dh_params_check(server_dh_params));
234 [ - + ]: 24 : POSIX_GUARD(s2n_dh_params_copy(server_dh_params, &client_params));
235 [ - + ]: 24 : POSIX_GUARD(s2n_dh_generate_ephemeral_key(&client_params));
236 [ - + ]: 24 : POSIX_GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh)));
237 : :
238 : 24 : const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params);
239 [ - + ][ # # ]: 24 : POSIX_ENSURE_REF(client_pub_key_bn);
240 : 24 : client_pub_key_size = BN_num_bytes(client_pub_key_bn);
241 [ - + ]: 24 : POSIX_GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size));
242 : 24 : client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size);
243 [ - + ]: 24 : if (client_pub_key == NULL) {
244 [ # # ]: 0 : POSIX_GUARD(s2n_free(shared_key));
245 [ # # ]: 0 : POSIX_GUARD(s2n_dh_params_free(&client_params));
246 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_DH_WRITING_PUBLIC_KEY);
247 : 0 : }
248 : :
249 [ - + ]: 24 : if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) {
250 [ # # ]: 0 : POSIX_GUARD(s2n_free(shared_key));
251 [ # # ]: 0 : POSIX_GUARD(s2n_dh_params_free(&client_params));
252 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_DH_COPYING_PUBLIC_KEY);
253 : 0 : }
254 : :
255 : : /* server_dh_params already validated */
256 : 24 : const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params);
257 : 24 : shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh);
258 [ - + ]: 24 : if (shared_key_size < 0) {
259 [ # # ]: 0 : POSIX_GUARD(s2n_free(shared_key));
260 [ # # ]: 0 : POSIX_GUARD(s2n_dh_params_free(&client_params));
261 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_DH_SHARED_SECRET);
262 : 0 : }
263 : :
264 : 24 : shared_key->size = shared_key_size;
265 : :
266 [ - + ]: 24 : POSIX_GUARD(s2n_dh_params_free(&client_params));
267 : :
268 : 24 : return S2N_SUCCESS;
269 : 24 : }
270 : :
271 : : int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in,
272 : : struct s2n_blob *shared_key)
273 : 24 : {
274 : 24 : uint16_t Yc_length = 0;
275 : 24 : struct s2n_blob Yc = { 0 };
276 : 24 : int shared_key_size = 0;
277 : 24 : BIGNUM *pub_key = NULL;
278 : :
279 [ - + ]: 24 : POSIX_GUARD(s2n_check_all_dh_params(server_dh_params));
280 : :
281 [ - + ]: 24 : POSIX_GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length));
282 : 24 : Yc.size = Yc_length;
283 : 24 : Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size);
284 [ # # ][ - + ]: 24 : POSIX_ENSURE_REF(Yc.data);
285 : :
286 : 24 : pub_key = BN_bin2bn((const unsigned char *) Yc.data, Yc.size, NULL);
287 [ - + ][ # # ]: 24 : POSIX_ENSURE_REF(pub_key);
288 : 24 : int server_dh_params_size = DH_size(server_dh_params->dh);
289 [ - + ][ # # ]: 24 : POSIX_ENSURE(server_dh_params_size <= INT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
290 [ - + ]: 24 : POSIX_GUARD(s2n_alloc(shared_key, server_dh_params_size));
291 : :
292 : 24 : shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh);
293 [ - + ]: 24 : if (shared_key_size <= 0) {
294 : 0 : BN_free(pub_key);
295 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_DH_SHARED_SECRET);
296 : 0 : }
297 : :
298 : 24 : shared_key->size = shared_key_size;
299 : :
300 : 24 : BN_free(pub_key);
301 : :
302 : 24 : return S2N_SUCCESS;
303 : 24 : }
304 : :
305 : : int s2n_dh_params_check(struct s2n_dh_params *dh_params)
306 : 108 : {
307 [ # # ][ - + ]: 108 : POSIX_ENSURE_REF(dh_params);
308 [ - + ][ # # ]: 108 : POSIX_ENSURE_REF(dh_params->dh);
309 : 108 : int codes = 0;
310 : :
311 [ # # ][ - + ]: 108 : POSIX_GUARD_OSSL(DH_check(dh_params->dh, &codes), S2N_ERR_DH_PARAMETER_CHECK);
312 [ - + ][ # # ]: 108 : POSIX_ENSURE(codes == 0, S2N_ERR_DH_PARAMETER_CHECK);
313 : :
314 : 108 : return S2N_SUCCESS;
315 : 108 : }
316 : :
317 : : int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to)
318 : 48 : {
319 [ - + ]: 48 : POSIX_GUARD(s2n_check_p_g_dh_params(from));
320 [ - + ][ # # ]: 48 : POSIX_ENSURE_REF(to);
321 : :
322 : 48 : to->dh = DHparams_dup(from->dh);
323 [ - + ][ # # ]: 48 : POSIX_ENSURE(to->dh != NULL, S2N_ERR_DH_COPYING_PARAMETERS);
324 : :
325 : 48 : return S2N_SUCCESS;
326 : 48 : }
327 : :
328 : : int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params)
329 : 50 : {
330 [ - + ]: 50 : POSIX_GUARD(s2n_check_p_g_dh_params(dh_params));
331 : :
332 [ - + ][ # # ]: 50 : POSIX_GUARD_OSSL(DH_generate_key(dh_params->dh), S2N_ERR_DH_GENERATING_PARAMETERS);
333 : :
334 : 50 : return S2N_SUCCESS;
335 : 50 : }
336 : :
337 : : int s2n_dh_params_free(struct s2n_dh_params *dh_params)
338 : 3546057 : {
339 [ - + ][ # # ]: 3546057 : POSIX_ENSURE_REF(dh_params);
340 : 3546057 : DH_free(dh_params->dh);
341 : 3546057 : dh_params->dh = NULL;
342 : :
343 : 3546057 : return S2N_SUCCESS;
344 : 3546057 : }
|