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