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