Line data Source code
1 : /*
2 : * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3 : * Copyright (C) 2017 Red Hat, Inc.
4 : *
5 : * Author: Nikos Mavrogiannopoulos
6 : *
7 : * This file is part of GnuTLS.
8 : *
9 : * The GnuTLS is free software; you can redistribute it and/or
10 : * modify it under the terms of the GNU Lesser General Public License
11 : * as published by the Free Software Foundation; either version 2.1 of
12 : * the License, or (at your option) any later version.
13 : *
14 : * This library is distributed in the hope that it will be useful, but
15 : * WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : * Lesser General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU Lesser General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>
21 : *
22 : */
23 :
24 : /* This file contains common stuff in Ephemeral Diffie-Hellman (DHE)
25 : * and Anonymous DH key exchange(DHA). These are used in the handshake
26 : * procedure of the certificate and anonymous authentication.
27 : */
28 :
29 : #include "gnutls_int.h"
30 : #include "auth.h"
31 : #include "errors.h"
32 : #include "dh.h"
33 : #include "num.h"
34 : #include "tls-sig.h"
35 : #include <state.h>
36 : #include <datum.h>
37 : #include <x509.h>
38 : #include <auth/ecdhe.h>
39 : #include <ecc.h>
40 : #include <ext/supported_groups.h>
41 : #include <algorithms.h>
42 : #include <auth/psk.h>
43 : #include <auth/cert.h>
44 : #include <pk.h>
45 :
46 : static int gen_ecdhe_server_kx(gnutls_session_t, gnutls_buffer_st *);
47 : static int
48 : proc_ecdhe_server_kx(gnutls_session_t session,
49 : uint8_t * data, size_t _data_size);
50 : static int
51 : proc_ecdhe_client_kx(gnutls_session_t session,
52 : uint8_t * data, size_t _data_size);
53 :
54 : #if defined(ENABLE_ECDHE)
55 : const mod_auth_st ecdhe_ecdsa_auth_struct = {
56 : "ECDHE_ECDSA",
57 : _gnutls_gen_cert_server_crt,
58 : _gnutls_gen_cert_client_crt,
59 : gen_ecdhe_server_kx,
60 : _gnutls_gen_ecdh_common_client_kx, /* This is the only difference */
61 : _gnutls_gen_cert_client_crt_vrfy,
62 : _gnutls_gen_cert_server_cert_req,
63 :
64 : _gnutls_proc_crt,
65 : _gnutls_proc_crt,
66 : proc_ecdhe_server_kx,
67 : proc_ecdhe_client_kx,
68 : _gnutls_proc_cert_client_crt_vrfy,
69 : _gnutls_proc_cert_cert_req
70 : };
71 :
72 : const mod_auth_st ecdhe_rsa_auth_struct = {
73 : "ECDHE_RSA",
74 : _gnutls_gen_cert_server_crt,
75 : _gnutls_gen_cert_client_crt,
76 : gen_ecdhe_server_kx,
77 : _gnutls_gen_ecdh_common_client_kx, /* This is the only difference */
78 : _gnutls_gen_cert_client_crt_vrfy,
79 : _gnutls_gen_cert_server_cert_req,
80 :
81 : _gnutls_proc_crt,
82 : _gnutls_proc_crt,
83 : proc_ecdhe_server_kx,
84 : proc_ecdhe_client_kx,
85 : _gnutls_proc_cert_client_crt_vrfy,
86 : _gnutls_proc_cert_cert_req
87 : };
88 :
89 3398 : static int calc_ecdh_key(gnutls_session_t session,
90 : gnutls_datum_t * psk_key,
91 : const gnutls_ecc_curve_entry_st *ecurve)
92 : {
93 3398 : gnutls_pk_params_st pub;
94 3398 : int ret;
95 3398 : gnutls_datum_t tmp_dh_key;
96 :
97 3398 : gnutls_pk_params_init(&pub);
98 3398 : pub.params[ECC_X] = session->key.proto.tls12.ecdh.x;
99 3398 : pub.params[ECC_Y] = session->key.proto.tls12.ecdh.y;
100 3398 : pub.raw_pub.data = session->key.proto.tls12.ecdh.raw.data;
101 3398 : pub.raw_pub.size = session->key.proto.tls12.ecdh.raw.size;
102 3398 : pub.curve = ecurve->id;
103 :
104 3398 : ret =
105 3398 : _gnutls_pk_derive(ecurve->pk, &tmp_dh_key,
106 : &session->key.proto.tls12.ecdh.params, &pub);
107 3398 : if (ret < 0) {
108 20 : ret = gnutls_assert_val(ret);
109 20 : goto cleanup;
110 : }
111 :
112 3378 : if (psk_key == NULL) {
113 3025 : memcpy(&session->key.key, &tmp_dh_key, sizeof(gnutls_datum_t));
114 3025 : tmp_dh_key.data = NULL; /* no longer needed */
115 : } else {
116 353 : ret =
117 353 : _gnutls_set_psk_session_key(session, psk_key,
118 : &tmp_dh_key);
119 353 : _gnutls_free_temp_key_datum(&tmp_dh_key);
120 :
121 353 : if (ret < 0) {
122 0 : ret = gnutls_assert_val(ret);
123 0 : goto cleanup;
124 : }
125 : }
126 :
127 : ret = 0;
128 :
129 3398 : cleanup:
130 : /* no longer needed */
131 3398 : _gnutls_mpi_release(&session->key.proto.tls12.ecdh.x);
132 3398 : _gnutls_mpi_release(&session->key.proto.tls12.ecdh.y);
133 3398 : _gnutls_free_datum(&session->key.proto.tls12.ecdh.raw);
134 3398 : gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params);
135 3398 : return ret;
136 : }
137 :
138 2630 : int _gnutls_proc_ecdh_common_client_kx(gnutls_session_t session,
139 : uint8_t * data, size_t _data_size,
140 : const struct gnutls_group_entry_st *group,
141 : gnutls_datum_t * psk_key)
142 : {
143 2630 : ssize_t data_size = _data_size;
144 2630 : int ret, i = 0;
145 2630 : unsigned point_size;
146 2630 : const gnutls_ecc_curve_entry_st *ecurve;
147 :
148 2630 : if (group == NULL)
149 0 : return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
150 :
151 2630 : ecurve = _gnutls_ecc_curve_get_params(group->curve);
152 2630 : if (ecurve == NULL)
153 0 : return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
154 :
155 2630 : DECR_LEN(data_size, 1);
156 2629 : point_size = data[i];
157 2629 : i += 1;
158 :
159 2629 : if (point_size == 0) {
160 5 : ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
161 5 : goto cleanup;
162 : }
163 :
164 2624 : DECR_LEN(data_size, point_size);
165 :
166 2615 : if (ecurve->pk == GNUTLS_PK_EC) {
167 2405 : ret =
168 2405 : _gnutls_ecc_ansi_x962_import(&data[i], point_size,
169 : &session->key.proto.tls12.ecdh.x,
170 : &session->key.proto.tls12.ecdh.y);
171 2405 : if (ret < 0) {
172 5 : gnutls_assert();
173 5 : goto cleanup;
174 : }
175 210 : } else if (ecurve->pk == GNUTLS_PK_ECDH_X25519 ||
176 : ecurve->pk == GNUTLS_PK_ECDH_X448) {
177 210 : if (ecurve->size != point_size)
178 10 : return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
179 :
180 408 : ret = _gnutls_set_datum(&session->key.proto.tls12.ecdh.raw,
181 204 : &data[i], point_size);
182 204 : if (ret < 0) {
183 0 : gnutls_assert();
184 0 : goto cleanup;
185 : }
186 :
187 : /* RFC7748 requires to mask the MSB in the final byte
188 : * for X25519 (not X448) */
189 204 : if (ecurve->id == GNUTLS_ECC_CURVE_X25519) {
190 200 : session->key.proto.tls12.ecdh.raw.data[point_size-1] &= 0x7f;
191 : }
192 : } else {
193 0 : return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
194 : }
195 :
196 2604 : if (data_size != 0)
197 5 : return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
198 :
199 : /* generate pre-shared key */
200 2600 : ret = calc_ecdh_key(session, psk_key, ecurve);
201 2600 : if (ret < 0) {
202 18 : gnutls_assert();
203 18 : goto cleanup;
204 : }
205 :
206 2582 : cleanup:
207 2610 : gnutls_pk_params_clear(&session->key.proto.tls12.ecdh.params);
208 2610 : return ret;
209 : }
210 :
211 : static int
212 1746 : proc_ecdhe_client_kx(gnutls_session_t session,
213 : uint8_t * data, size_t _data_size)
214 : {
215 1746 : gnutls_certificate_credentials_t cred;
216 :
217 1746 : cred = (gnutls_certificate_credentials_t)
218 1746 : _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
219 1746 : if (cred == NULL) {
220 0 : gnutls_assert();
221 0 : return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
222 : }
223 :
224 1746 : return _gnutls_proc_ecdh_common_client_kx(session, data,
225 : _data_size,
226 1746 : get_group
227 : (session), NULL);
228 : }
229 :
230 : int
231 770 : _gnutls_gen_ecdh_common_client_kx(gnutls_session_t session,
232 : gnutls_buffer_st * data)
233 : {
234 770 : return _gnutls_gen_ecdh_common_client_kx_int(session, data, NULL);
235 : }
236 :
237 : int
238 798 : _gnutls_gen_ecdh_common_client_kx_int(gnutls_session_t session,
239 : gnutls_buffer_st * data,
240 : gnutls_datum_t * psk_key)
241 : {
242 798 : int ret;
243 798 : gnutls_datum_t out;
244 798 : const gnutls_group_entry_st *group = get_group(session);
245 798 : const gnutls_ecc_curve_entry_st *ecurve;
246 798 : int pk;
247 798 : unsigned init_pos = data->length;
248 :
249 798 : if (group == NULL)
250 0 : return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
251 :
252 798 : ecurve = _gnutls_ecc_curve_get_params(group->curve);
253 798 : if (ecurve == NULL)
254 0 : return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
255 :
256 798 : pk = ecurve->pk;
257 :
258 : /* generate temporal key */
259 798 : ret =
260 798 : _gnutls_pk_generate_keys(pk, ecurve->id,
261 : &session->key.proto.tls12.ecdh.params, 1);
262 798 : if (ret < 0)
263 0 : return gnutls_assert_val(ret);
264 :
265 798 : if (pk == GNUTLS_PK_EC) {
266 772 : ret =
267 772 : _gnutls_ecc_ansi_x962_export(ecurve->id,
268 : session->key.proto.tls12.ecdh.params.
269 : params[ECC_X] /* x */ ,
270 : session->key.proto.tls12.ecdh.params.
271 : params[ECC_Y] /* y */ , &out);
272 :
273 772 : if (ret < 0) {
274 0 : gnutls_assert();
275 0 : goto cleanup;
276 : }
277 :
278 772 : ret =
279 772 : _gnutls_buffer_append_data_prefix(data, 8, out.data, out.size);
280 :
281 772 : _gnutls_free_datum(&out);
282 :
283 772 : if (ret < 0) {
284 0 : gnutls_assert();
285 0 : goto cleanup;
286 : }
287 26 : } else if (pk == GNUTLS_PK_ECDH_X25519 || pk == GNUTLS_PK_ECDH_X448) {
288 26 : ret =
289 52 : _gnutls_buffer_append_data_prefix(data, 8,
290 26 : session->key.proto.tls12.ecdh.params.raw_pub.data,
291 26 : session->key.proto.tls12.ecdh.params.raw_pub.size);
292 26 : if (ret < 0) {
293 0 : gnutls_assert();
294 0 : goto cleanup;
295 : }
296 : }
297 :
298 : /* generate pre-shared key */
299 798 : ret = calc_ecdh_key(session, psk_key, ecurve);
300 798 : if (ret < 0) {
301 2 : gnutls_assert();
302 2 : goto cleanup;
303 : }
304 :
305 796 : ret = data->length - init_pos;
306 798 : cleanup:
307 798 : gnutls_pk_params_clear(&session->key.proto.tls12.ecdh.params);
308 798 : return ret;
309 : }
310 :
311 : static int
312 688 : proc_ecdhe_server_kx(gnutls_session_t session,
313 : uint8_t * data, size_t _data_size)
314 : {
315 688 : int ret;
316 688 : gnutls_datum_t vparams;
317 :
318 688 : ret =
319 688 : _gnutls_proc_ecdh_common_server_kx(session, data, _data_size);
320 688 : if (ret < 0)
321 8 : return gnutls_assert_val(ret);
322 :
323 680 : vparams.data = data;
324 680 : vparams.size = ret;
325 :
326 680 : return _gnutls_proc_dhe_signature(session, data + ret,
327 : _data_size - ret, &vparams);
328 : }
329 :
330 : int
331 851 : _gnutls_proc_ecdh_common_server_kx(gnutls_session_t session,
332 : uint8_t * data, size_t _data_size)
333 : {
334 851 : int i, ret;
335 851 : unsigned point_size;
336 851 : const gnutls_group_entry_st *group;
337 851 : ssize_t data_size = _data_size;
338 851 : const gnutls_ecc_curve_entry_st *ecurve;
339 :
340 : /* just in case we are resuming a session */
341 851 : gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params);
342 :
343 851 : gnutls_pk_params_init(&session->key.proto.tls12.ecdh.params);
344 :
345 851 : i = 0;
346 851 : DECR_LEN(data_size, 1);
347 851 : if (data[i++] != 3)
348 2 : return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
349 :
350 849 : DECR_LEN(data_size, 2);
351 :
352 848 : group = _gnutls_tls_id_to_group(_gnutls_read_uint16(&data[i]));
353 848 : if (group == NULL || group->curve == 0) {
354 6 : _gnutls_debug_log("received unknown curve %u.%u\n", (unsigned)data[i], (unsigned)data[i+1]);
355 6 : return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
356 : } else {
357 842 : _gnutls_debug_log("received curve %s\n", group->name);
358 : }
359 :
360 842 : i += 2;
361 :
362 842 : ret = _gnutls_session_supports_group(session, group->id);
363 842 : if (ret < 0)
364 1 : return gnutls_assert_val(ret);
365 :
366 841 : ecurve = _gnutls_ecc_curve_get_params(group->curve);
367 841 : if (ecurve == NULL) {
368 0 : return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
369 : }
370 :
371 841 : _gnutls_session_group_set(session, group);
372 :
373 841 : DECR_LEN(data_size, 1);
374 841 : point_size = data[i];
375 841 : i++;
376 :
377 841 : DECR_LEN(data_size, point_size);
378 :
379 839 : if (ecurve->pk == GNUTLS_PK_EC) {
380 795 : ret =
381 795 : _gnutls_ecc_ansi_x962_import(&data[i], point_size,
382 : &session->key.proto.tls12.ecdh.x,
383 : &session->key.proto.tls12.ecdh.y);
384 795 : if (ret < 0)
385 3 : return gnutls_assert_val(ret);
386 :
387 44 : } else if (ecurve->pk == GNUTLS_PK_ECDH_X25519 ||
388 : ecurve->pk == GNUTLS_PK_ECDH_X448) {
389 44 : if (ecurve->size != point_size)
390 1 : return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
391 :
392 86 : ret = _gnutls_set_datum(&session->key.proto.tls12.ecdh.raw,
393 43 : &data[i], point_size);
394 43 : if (ret < 0)
395 0 : return gnutls_assert_val(ret);
396 :
397 : /* RFC7748 requires to mask the MSB in the final byte
398 : * for X25519 (not X448) */
399 43 : if (ecurve->id == GNUTLS_ECC_CURVE_X25519) {
400 43 : session->key.proto.tls12.ecdh.raw.data[point_size-1] &= 0x7f;
401 : }
402 : } else {
403 0 : return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
404 : }
405 :
406 835 : i += point_size;
407 :
408 835 : return i;
409 : }
410 :
411 : /* If the psk flag is set, then an empty psk_identity_hint will
412 : * be inserted */
413 2780 : int _gnutls_ecdh_common_print_server_kx(gnutls_session_t session,
414 : gnutls_buffer_st * data,
415 : const gnutls_group_entry_st *group)
416 : {
417 2780 : uint8_t p;
418 2780 : int ret;
419 2780 : gnutls_datum_t out;
420 2780 : unsigned init_pos = data->length;
421 :
422 2780 : if (group == NULL || group->curve == 0)
423 0 : return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
424 :
425 : /* just in case we are resuming a session */
426 2780 : gnutls_pk_params_release(&session->key.proto.tls12.ecdh.params);
427 :
428 2780 : gnutls_pk_params_init(&session->key.proto.tls12.ecdh.params);
429 :
430 : /* curve type */
431 2780 : p = 3;
432 :
433 2780 : ret = _gnutls_buffer_append_data(data, &p, 1);
434 2780 : if (ret < 0)
435 0 : return gnutls_assert_val(ret);
436 :
437 2780 : ret =
438 5560 : _gnutls_buffer_append_prefix(data, 16,
439 2780 : group->tls_id);
440 2780 : if (ret < 0)
441 0 : return gnutls_assert_val(ret);
442 :
443 :
444 : /* generate temporal key */
445 2780 : ret =
446 2780 : _gnutls_pk_generate_keys(group->pk, group->curve,
447 : &session->key.proto.tls12.ecdh.params, 1);
448 2780 : if (ret < 0)
449 0 : return gnutls_assert_val(ret);
450 :
451 2780 : if (group->pk == GNUTLS_PK_EC) {
452 2534 : ret =
453 2534 : _gnutls_ecc_ansi_x962_export(group->curve,
454 : session->key.proto.tls12.ecdh.params.
455 : params[ECC_X] /* x */ ,
456 : session->key.proto.tls12.ecdh.params.
457 : params[ECC_Y] /* y */ , &out);
458 2534 : if (ret < 0)
459 0 : return gnutls_assert_val(ret);
460 :
461 2534 : ret =
462 2534 : _gnutls_buffer_append_data_prefix(data, 8, out.data, out.size);
463 :
464 2534 : _gnutls_free_datum(&out);
465 :
466 2534 : if (ret < 0)
467 0 : return gnutls_assert_val(ret);
468 :
469 246 : } else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
470 : group->pk == GNUTLS_PK_ECDH_X448) {
471 246 : ret =
472 492 : _gnutls_buffer_append_data_prefix(data, 8,
473 246 : session->key.proto.tls12.ecdh.params.raw_pub.data,
474 246 : session->key.proto.tls12.ecdh.params.raw_pub.size);
475 246 : if (ret < 0)
476 0 : return gnutls_assert_val(ret);
477 : } else {
478 0 : return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
479 : }
480 :
481 :
482 2780 : return data->length - init_pos;
483 : }
484 :
485 : static int
486 1860 : gen_ecdhe_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
487 : {
488 1860 : int ret = 0;
489 1860 : gnutls_certificate_credentials_t cred;
490 1860 : unsigned sig_pos;
491 :
492 1860 : cred = (gnutls_certificate_credentials_t)
493 1860 : _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
494 1860 : if (cred == NULL) {
495 0 : gnutls_assert();
496 0 : return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
497 : }
498 :
499 1860 : if ((ret = _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
500 : sizeof(cert_auth_info_st),
501 : 1)) < 0) {
502 0 : gnutls_assert();
503 0 : return ret;
504 : }
505 :
506 1860 : sig_pos = data->length;
507 :
508 1860 : ret =
509 3720 : _gnutls_ecdh_common_print_server_kx(session, data,
510 1860 : get_group
511 : (session));
512 1860 : if (ret < 0) {
513 0 : gnutls_assert();
514 0 : return ret;
515 : }
516 :
517 : /* Generate the signature. */
518 1860 : return _gnutls_gen_dhe_signature(session, data, &data->data[sig_pos],
519 1860 : data->length-sig_pos);
520 : }
521 :
522 : #endif
|