1 /*
2 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
3 *
4 * Author: Nikos Mavrogiannopoulos
5 *
6 * This file is part of GnuTLS.
7 *
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>
20 *
21 */
22
23 /* This file contains common stuff in Ephemeral Diffie-Hellman (DHE)
24 * and Anonymous DH key exchange(DHA). These are used in the handshake
25 * procedure of the certificate and anonymous authentication.
26 */
27
28 #include "gnutls_int.h"
29 #include "auth.h"
30 #include "errors.h"
31 #include "dh.h"
32 #include "num.h"
33 #include "tls-sig.h"
34 #include <datum.h>
35 #include <x509.h>
36 #include <state.h>
37 #include <pk.h>
38 #include <auth/dh_common.h>
39 #include <algorithms.h>
40 #include <auth/psk.h>
41
42 #if defined(ENABLE_DHE) || defined(ENABLE_ANON)
43
44 /* Frees the dh_info_st structure.
45 */
_gnutls_free_dh_info(dh_info_st * dh)46 void _gnutls_free_dh_info(dh_info_st * dh)
47 {
48 dh->secret_bits = 0;
49 _gnutls_free_datum(&dh->prime);
50 _gnutls_free_datum(&dh->generator);
51 _gnutls_free_datum(&dh->public_key);
52 }
53
54 int
_gnutls_proc_dh_common_client_kx(gnutls_session_t session,uint8_t * data,size_t _data_size,gnutls_datum_t * psk_key)55 _gnutls_proc_dh_common_client_kx(gnutls_session_t session,
56 uint8_t * data, size_t _data_size,
57 gnutls_datum_t * psk_key)
58 {
59 uint16_t n_Y;
60 size_t _n_Y;
61 int ret;
62 ssize_t data_size = _data_size;
63 gnutls_datum_t tmp_dh_key = {NULL, 0};
64 gnutls_pk_params_st peer_pub;
65
66 gnutls_pk_params_init(&peer_pub);
67
68 DECR_LEN(data_size, 2);
69 n_Y = _gnutls_read_uint16(&data[0]);
70 _n_Y = n_Y;
71
72 DECR_LEN(data_size, n_Y);
73
74 if (data_size != 0)
75 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
76
77 if (_gnutls_mpi_init_scan_nz(&session->key.proto.tls12.dh.client_Y, &data[2], _n_Y)) {
78 gnutls_assert();
79 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; /* most likely zero or illegal size */
80 }
81
82 _gnutls_dh_set_peer_public(session, session->key.proto.tls12.dh.client_Y);
83
84 peer_pub.params[DH_Y] = session->key.proto.tls12.dh.client_Y;
85
86 /* calculate the key after calculating the message */
87 ret = _gnutls_pk_derive(GNUTLS_PK_DH, &tmp_dh_key, &session->key.proto.tls12.dh.params, &peer_pub);
88 if (ret < 0) {
89 gnutls_assert();
90 goto error;
91 }
92
93 if (psk_key == NULL) {
94 session->key.key.data = tmp_dh_key.data;
95 session->key.key.size = tmp_dh_key.size;
96 } else { /* In DHE_PSK the key is set differently */
97 ret =
98 _gnutls_set_psk_session_key(session, psk_key,
99 &tmp_dh_key);
100 _gnutls_free_temp_key_datum(&tmp_dh_key);
101 }
102
103 if (ret < 0) {
104 gnutls_assert();
105 goto error;
106 }
107
108 ret = 0;
109 error:
110 _gnutls_mpi_release(&session->key.proto.tls12.dh.client_Y);
111 gnutls_pk_params_clear(&session->key.proto.tls12.dh.params);
112
113 return ret;
114 }
115
_gnutls_gen_dh_common_client_kx(gnutls_session_t session,gnutls_buffer_st * data)116 int _gnutls_gen_dh_common_client_kx(gnutls_session_t session,
117 gnutls_buffer_st * data)
118 {
119 return _gnutls_gen_dh_common_client_kx_int(session, data, NULL);
120 }
121
122 int
_gnutls_gen_dh_common_client_kx_int(gnutls_session_t session,gnutls_buffer_st * data,gnutls_datum_t * pskkey)123 _gnutls_gen_dh_common_client_kx_int(gnutls_session_t session,
124 gnutls_buffer_st * data,
125 gnutls_datum_t * pskkey)
126 {
127 int ret;
128 gnutls_pk_params_st peer_pub;
129 gnutls_datum_t tmp_dh_key = {NULL, 0};
130 unsigned init_pos = data->length;
131
132 gnutls_pk_params_init(&peer_pub);
133
134 ret =
135 _gnutls_pk_generate_keys(GNUTLS_PK_DH, 0,
136 &session->key.proto.tls12.dh.params, 1);
137 if (ret < 0)
138 return gnutls_assert_val(ret);
139
140 _gnutls_dh_set_secret_bits(session, _gnutls_mpi_get_nbits(session->key.proto.tls12.dh.params.params[DH_X]));
141
142 ret = _gnutls_buffer_append_mpi(data, 16, session->key.proto.tls12.dh.params.params[DH_Y], 0);
143 if (ret < 0) {
144 gnutls_assert();
145 goto error;
146 }
147
148 peer_pub.params[DH_Y] = session->key.proto.tls12.dh.client_Y;
149
150 /* calculate the key after calculating the message */
151 ret = _gnutls_pk_derive(GNUTLS_PK_DH, &tmp_dh_key, &session->key.proto.tls12.dh.params, &peer_pub);
152 if (ret < 0) {
153 gnutls_assert();
154 goto error;
155 }
156
157 if (session->security_parameters.cs->kx_algorithm != GNUTLS_KX_DHE_PSK) {
158 session->key.key.data = tmp_dh_key.data;
159 session->key.key.size = tmp_dh_key.size;
160 } else { /* In DHE_PSK the key is set differently */
161 ret =
162 _gnutls_set_psk_session_key(session, pskkey,
163 &tmp_dh_key);
164 _gnutls_free_temp_key_datum(&tmp_dh_key);
165 }
166
167 if (ret < 0) {
168 gnutls_assert();
169 goto error;
170 }
171
172 ret = data->length - init_pos;
173
174 error:
175 gnutls_pk_params_clear(&session->key.proto.tls12.dh.params);
176 return ret;
177 }
178
179 /* Returns the bytes parsed */
180 int
_gnutls_proc_dh_common_server_kx(gnutls_session_t session,uint8_t * data,size_t _data_size)181 _gnutls_proc_dh_common_server_kx(gnutls_session_t session,
182 uint8_t * data, size_t _data_size)
183 {
184 uint16_t n_Y, n_g, n_p;
185 size_t _n_Y, _n_g, _n_p, _n_q;
186 uint8_t *data_p;
187 uint8_t *data_g;
188 uint8_t *data_Y;
189 uint8_t *data_q = NULL;
190 int i, bits, ret, p_bits;
191 unsigned j;
192 ssize_t data_size = _data_size;
193
194 /* just in case we are resuming a session */
195 gnutls_pk_params_release(&session->key.proto.tls12.dh.params);
196
197 gnutls_pk_params_init(&session->key.proto.tls12.dh.params);
198
199 i = 0;
200
201 DECR_LEN(data_size, 2);
202 n_p = _gnutls_read_uint16(&data[i]);
203 i += 2;
204
205 DECR_LEN(data_size, n_p);
206 data_p = &data[i];
207 i += n_p;
208
209 DECR_LEN(data_size, 2);
210 n_g = _gnutls_read_uint16(&data[i]);
211 i += 2;
212
213 DECR_LEN(data_size, n_g);
214 data_g = &data[i];
215 i += n_g;
216
217 DECR_LEN(data_size, 2);
218 n_Y = _gnutls_read_uint16(&data[i]);
219 i += 2;
220
221 DECR_LEN(data_size, n_Y);
222 data_Y = &data[i];
223
224 _n_Y = n_Y;
225 _n_g = n_g;
226 _n_p = n_p;
227
228 if (_gnutls_mpi_init_scan_nz(&session->key.proto.tls12.dh.client_Y, data_Y, _n_Y) != 0) {
229 gnutls_assert();
230 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
231 }
232
233 /* if we are doing RFC7919 */
234 if (session->internals.priorities->groups.have_ffdhe != 0) {
235 /* verify whether the received parameters match the advertised, otherwise
236 * log that. */
237 for (j=0;j<session->internals.priorities->groups.size;j++) {
238 if (session->internals.priorities->groups.entry[j]->generator &&
239 session->internals.priorities->groups.entry[j]->generator->size == n_g &&
240 session->internals.priorities->groups.entry[j]->prime->size == n_p &&
241 memcmp(session->internals.priorities->groups.entry[j]->generator->data,
242 data_g, n_g) == 0 &&
243 memcmp(session->internals.priorities->groups.entry[j]->prime->data,
244 data_p, n_p) == 0) {
245
246 session->internals.hsk_flags |= HSK_USED_FFDHE;
247 _gnutls_session_group_set(session, session->internals.priorities->groups.entry[j]);
248 session->key.proto.tls12.dh.params.qbits = *session->internals.priorities->groups.entry[j]->q_bits;
249 data_q = session->internals.priorities->groups.entry[j]->q->data;
250 _n_q = session->internals.priorities->groups.entry[j]->q->size;
251 break;
252 }
253 }
254
255 if (!(session->internals.hsk_flags & HSK_USED_FFDHE)) {
256 _gnutls_audit_log(session, "FFDHE groups advertised, but server didn't support it; falling back to server's choice\n");
257 }
258 }
259
260 #ifdef ENABLE_FIPS140
261 if (gnutls_fips140_mode_enabled() &&
262 !_gnutls_dh_prime_match_fips_approved(data_p, n_p, data_g, n_g, NULL, NULL)) {
263 gnutls_assert();
264 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
265 }
266 #endif
267
268 if (_gnutls_mpi_init_scan_nz(&session->key.proto.tls12.dh.params.params[DH_G], data_g, _n_g) != 0) {
269 gnutls_assert();
270 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
271 }
272
273 if (_gnutls_mpi_init_scan_nz(&session->key.proto.tls12.dh.params.params[DH_P], data_p, _n_p) != 0) {
274 gnutls_assert();
275 /* we release now because session->key.proto.tls12.dh.params.params_nr is not yet set */
276 _gnutls_mpi_release(&session->key.proto.tls12.dh.params.params[DH_G]);
277 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
278 }
279 if (data_q && _gnutls_mpi_init_scan_nz(
280 &session->key.proto.tls12.dh.params.params[DH_Q],
281 data_q, _n_q) != 0) {
282 /* we release now because params_nr is not yet set */
283 _gnutls_mpi_release(
284 &session->key.proto.tls12.dh.params.params[DH_P]);
285 _gnutls_mpi_release(
286 &session->key.proto.tls12.dh.params.params[DH_G]);
287 return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
288 }
289
290 /* include, possibly empty, q */
291 session->key.proto.tls12.dh.params.params_nr = 3;
292 session->key.proto.tls12.dh.params.algo = GNUTLS_PK_DH;
293
294 if (!(session->internals.hsk_flags & HSK_USED_FFDHE)) {
295 bits = _gnutls_dh_get_min_prime_bits(session);
296 if (bits < 0) {
297 gnutls_assert();
298 return bits;
299 }
300
301 p_bits = _gnutls_mpi_get_nbits(session->key.proto.tls12.dh.params.params[DH_P]);
302 if (p_bits < bits) {
303 /* the prime used by the peer is not acceptable
304 */
305 gnutls_assert();
306 _gnutls_debug_log
307 ("Received a prime of %u bits, limit is %u\n",
308 (unsigned) _gnutls_mpi_get_nbits(session->key.proto.tls12.dh.params.params[DH_P]),
309 (unsigned) bits);
310 return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
311 }
312
313 if (p_bits >= DEFAULT_MAX_VERIFY_BITS) {
314 gnutls_assert();
315 _gnutls_debug_log
316 ("Received a prime of %u bits, limit is %u\n",
317 (unsigned) p_bits,
318 (unsigned) DEFAULT_MAX_VERIFY_BITS);
319 return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
320 }
321 }
322
323 _gnutls_dh_save_group(session, session->key.proto.tls12.dh.params.params[DH_G],
324 session->key.proto.tls12.dh.params.params[DH_P]);
325 _gnutls_dh_set_peer_public(session, session->key.proto.tls12.dh.client_Y);
326
327 ret = n_Y + n_p + n_g + 6;
328
329 return ret;
330 }
331
332 int
_gnutls_dh_common_print_server_kx(gnutls_session_t session,gnutls_buffer_st * data)333 _gnutls_dh_common_print_server_kx(gnutls_session_t session,
334 gnutls_buffer_st * data)
335 {
336 int ret;
337 unsigned q_bits = session->key.proto.tls12.dh.params.qbits;
338 unsigned init_pos = data->length;
339
340 if (q_bits < 192 && q_bits != 0) {
341 gnutls_assert();
342 _gnutls_debug_log("too small q_bits value for DH: %u\n", q_bits);
343 q_bits = 0; /* auto-detect */
344 }
345
346 /* Y=g^x mod p */
347 ret =
348 _gnutls_pk_generate_keys(GNUTLS_PK_DH, q_bits,
349 &session->key.proto.tls12.dh.params, 1);
350 if (ret < 0)
351 return gnutls_assert_val(ret);
352
353 _gnutls_dh_set_secret_bits(session, _gnutls_mpi_get_nbits(session->key.proto.tls12.dh.params.params[DH_X]));
354
355 ret = _gnutls_buffer_append_mpi(data, 16, session->key.proto.tls12.dh.params.params[DH_P], 0);
356 if (ret < 0) {
357 gnutls_assert();
358 goto cleanup;
359 }
360
361 ret = _gnutls_buffer_append_mpi(data, 16, session->key.proto.tls12.dh.params.params[DH_G], 0);
362 if (ret < 0) {
363 gnutls_assert();
364 goto cleanup;
365 }
366
367 ret = _gnutls_buffer_append_mpi(data, 16, session->key.proto.tls12.dh.params.params[DH_Y], 0);
368 if (ret < 0) {
369 gnutls_assert();
370 goto cleanup;
371 }
372
373 ret = data->length - init_pos;
374
375 cleanup:
376 return ret;
377 }
378
379 #endif
380