Line data Source code
1 : /*
2 : * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2010
3 : * Free Software Foundation, Inc.
4 : *
5 : * Copyright (C) 2011
6 : * Bardenheuer GmbH, Munich and Bundesdruckerei GmbH, Berlin
7 : *
8 : * Copyright (C) 2013 Frank Morgner
9 : * Copyright (C) 2013 Nikos Mavrogiannopoulos
10 : *
11 : * This file is part of GnuTLS.
12 : *
13 : * The GnuTLS is free software; you can redistribute it and/or
14 : * modify it under the terms of the GNU Lesser General Public License
15 : * as published by the Free Software Foundation; either version 2.1 of
16 : * the License, or (at your option) any later version.
17 : *
18 : * This library is distributed in the hope that it will be useful, but
19 : * WITHOUT ANY WARRANTY; without even the implied warranty of
20 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 : * Lesser General Public License for more details.
22 : *
23 : * You should have received a copy of the GNU Lesser General Public
24 : * License along with this library; if not, write to the Free Software
25 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
26 : * USA
27 : *
28 : */
29 :
30 : #include "gnutls_int.h"
31 :
32 : #ifdef ENABLE_PSK
33 :
34 : #include "auth.h"
35 : #include "dh.h"
36 : #include "errors.h"
37 : #include "mpi.h"
38 : #include "num.h"
39 : #include "gnutls_int.h"
40 : #include "pk.h"
41 : #include "random.h"
42 : #include <abstract_int.h>
43 : #include <algorithms.h>
44 : #include <auth/dh_common.h>
45 : #include <auth/psk.h>
46 : #include <auth/psk_passwd.h>
47 : #include <auth/rsa_common.h>
48 : #include <cert.h>
49 : #include <datum.h>
50 : #include <state.h>
51 :
52 : static int _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session,
53 : gnutls_buffer_st * data);
54 : static int _gnutls_proc_rsa_psk_client_kx(gnutls_session_t, uint8_t *,
55 : size_t);
56 : static int
57 : _gnutls_proc_rsa_psk_server_kx(gnutls_session_t session, uint8_t * data,
58 : size_t _data_size);
59 :
60 : const mod_auth_st rsa_psk_auth_struct = {
61 : "RSA PSK",
62 : _gnutls_gen_cert_server_crt,
63 : NULL, /* generate_client_certificate */
64 : _gnutls_gen_psk_server_kx,
65 : _gnutls_gen_rsa_psk_client_kx,
66 : NULL, /* generate_client_cert_vrfy */
67 : NULL, /* generate_server_certificate_request */
68 : _gnutls_proc_crt,
69 : NULL, /* process_client_certificate */
70 : _gnutls_proc_rsa_psk_server_kx,
71 : _gnutls_proc_rsa_psk_client_kx,
72 : NULL, /* process_client_cert_vrfy */
73 : NULL /* process_server_certificate_reuqest */
74 : };
75 :
76 : /* Set the PSK premaster secret.
77 : */
78 : static int
79 33 : set_rsa_psk_session_key(gnutls_session_t session,
80 : gnutls_datum_t * ppsk, gnutls_datum_t * rsa_secret)
81 : {
82 33 : unsigned char *p;
83 33 : size_t rsa_secret_size;
84 33 : int ret;
85 :
86 :
87 33 : rsa_secret_size = rsa_secret->size;
88 :
89 : /* set the session key
90 : */
91 33 : session->key.key.size = 2 + rsa_secret_size + 2 + ppsk->size;
92 33 : session->key.key.data = gnutls_malloc(session->key.key.size);
93 33 : if (session->key.key.data == NULL) {
94 0 : gnutls_assert();
95 0 : ret = GNUTLS_E_MEMORY_ERROR;
96 0 : goto error;
97 : }
98 :
99 : /* format of the premaster secret:
100 : * (uint16_t) other_secret size (48)
101 : * other_secret: 2 byte version + 46 byte random
102 : * (uint16_t) psk_size
103 : * the psk
104 : */
105 33 : _gnutls_write_uint16(rsa_secret_size, session->key.key.data);
106 33 : memcpy(&session->key.key.data[2], rsa_secret->data,
107 33 : rsa_secret->size);
108 33 : p = &session->key.key.data[rsa_secret_size + 2];
109 33 : _gnutls_write_uint16(ppsk->size, p);
110 33 : if (ppsk->data != NULL)
111 33 : memcpy(p + 2, ppsk->data, ppsk->size);
112 :
113 : ret = 0;
114 :
115 33 : error:
116 33 : return ret;
117 : }
118 :
119 : /* Generate client key exchange message
120 : *
121 : *
122 : * struct {
123 : * select (KeyExchangeAlgorithm) {
124 : * uint8_t psk_identity<0..2^16-1>;
125 : * EncryptedPreMasterSecret;
126 : * } exchange_keys;
127 : * } ClientKeyExchange;
128 : */
129 : static int
130 10 : _gnutls_gen_rsa_psk_client_kx(gnutls_session_t session,
131 : gnutls_buffer_st * data)
132 : {
133 10 : cert_auth_info_t auth = session->key.auth_info;
134 10 : gnutls_datum_t sdata; /* data to send */
135 10 : gnutls_pk_params_st params;
136 10 : gnutls_psk_client_credentials_t cred;
137 10 : gnutls_datum_t username, key;
138 10 : int ret, free;
139 10 : unsigned init_pos;
140 :
141 10 : if (auth == NULL) {
142 : /* this shouldn't have happened. The proc_certificate
143 : * function should have detected that.
144 : */
145 0 : gnutls_assert();
146 0 : return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
147 : }
148 :
149 10 : gnutls_datum_t premaster_secret;
150 10 : premaster_secret.size = GNUTLS_MASTER_SIZE;
151 20 : premaster_secret.data =
152 10 : gnutls_malloc(premaster_secret.size);
153 :
154 10 : if (premaster_secret.data == NULL) {
155 0 : gnutls_assert();
156 0 : return GNUTLS_E_MEMORY_ERROR;
157 : }
158 :
159 : /* Generate random */
160 20 : ret = gnutls_rnd(GNUTLS_RND_RANDOM, premaster_secret.data,
161 10 : premaster_secret.size);
162 10 : if (ret < 0) {
163 0 : gnutls_assert();
164 0 : return ret;
165 : }
166 :
167 : /* Set version */
168 10 : if (session->internals.rsa_pms_version[0] == 0) {
169 10 : premaster_secret.data[0] =
170 10 : _gnutls_get_adv_version_major(session);
171 10 : premaster_secret.data[1] =
172 10 : _gnutls_get_adv_version_minor(session);
173 : } else { /* use the version provided */
174 0 : premaster_secret.data[0] =
175 : session->internals.rsa_pms_version[0];
176 0 : premaster_secret.data[1] =
177 0 : session->internals.rsa_pms_version[1];
178 : }
179 :
180 : /* move RSA parameters to key (session).
181 : */
182 10 : if ((ret = _gnutls_get_public_rsa_params(session, ¶ms)) < 0) {
183 0 : gnutls_assert();
184 0 : return ret;
185 : }
186 :
187 : /* Encrypt premaster secret */
188 20 : if ((ret =
189 10 : _gnutls_pk_encrypt(GNUTLS_PK_RSA, &sdata, &premaster_secret,
190 : ¶ms)) < 0) {
191 0 : gnutls_assert();
192 0 : return ret;
193 : }
194 :
195 10 : gnutls_pk_params_release(¶ms);
196 :
197 10 : cred = (gnutls_psk_client_credentials_t)
198 10 : _gnutls_get_cred(session, GNUTLS_CRD_PSK);
199 :
200 10 : if (cred == NULL) {
201 0 : gnutls_assert();
202 0 : return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
203 : }
204 :
205 10 : ret = _gnutls_find_psk_key(session, cred, &username, &key, &free);
206 10 : if (ret < 0)
207 0 : return gnutls_assert_val(ret);
208 :
209 : /* Here we set the PSK key */
210 10 : ret = set_rsa_psk_session_key(session, &key, &premaster_secret);
211 10 : if (ret < 0) {
212 0 : gnutls_assert();
213 0 : goto cleanup;
214 : }
215 :
216 : /* Create message for client key exchange
217 : *
218 : * struct {
219 : * uint8_t psk_identity<0..2^16-1>;
220 : * EncryptedPreMasterSecret;
221 : * }
222 : */
223 :
224 10 : init_pos = data->length;
225 :
226 : /* Write psk_identity and EncryptedPreMasterSecret into data stream
227 : */
228 10 : ret =
229 20 : _gnutls_buffer_append_data_prefix(data, 16,
230 10 : username.data,
231 10 : username.size);
232 10 : if (ret < 0) {
233 0 : gnutls_assert();
234 0 : goto cleanup;
235 : }
236 :
237 10 : ret =
238 20 : _gnutls_buffer_append_data_prefix(data, 16, sdata.data,
239 10 : sdata.size);
240 10 : if (ret < 0) {
241 0 : gnutls_assert();
242 0 : goto cleanup;
243 : }
244 :
245 10 : ret = data->length - init_pos;
246 :
247 10 : cleanup:
248 10 : _gnutls_free_datum(&sdata);
249 10 : _gnutls_free_temp_key_datum(&premaster_secret);
250 10 : if (free) {
251 1 : _gnutls_free_temp_key_datum(&key);
252 1 : gnutls_free(username.data);
253 : }
254 :
255 : return ret;
256 : }
257 :
258 : /*
259 : Process the client key exchange message
260 : */
261 : static int
262 28 : _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
263 : size_t _data_size)
264 : {
265 28 : gnutls_datum_t username;
266 28 : psk_auth_info_t info;
267 28 : gnutls_datum_t plaintext;
268 28 : gnutls_datum_t ciphertext;
269 28 : gnutls_datum_t pwd_psk = { NULL, 0 };
270 28 : int ret, dsize;
271 28 : int randomize_key = 0;
272 28 : ssize_t data_size = _data_size;
273 28 : gnutls_psk_server_credentials_t cred;
274 28 : gnutls_datum_t premaster_secret = { NULL, 0 };
275 :
276 28 : cred = (gnutls_psk_server_credentials_t)
277 28 : _gnutls_get_cred(session, GNUTLS_CRD_PSK);
278 :
279 28 : if (cred == NULL) {
280 0 : gnutls_assert();
281 0 : return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
282 : }
283 :
284 28 : ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
285 : sizeof(psk_auth_info_st), 1);
286 28 : if (ret < 0) {
287 0 : gnutls_assert();
288 0 : return ret;
289 : }
290 :
291 : /*** 1. Extract user psk_identity ***/
292 :
293 28 : DECR_LEN(data_size, 2);
294 27 : username.size = _gnutls_read_uint16(&data[0]);
295 :
296 27 : DECR_LEN(data_size, username.size);
297 :
298 26 : username.data = &data[2];
299 :
300 : /* copy the username to the auth info structures
301 : */
302 26 : info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
303 26 : if (info == NULL) {
304 0 : gnutls_assert();
305 0 : return GNUTLS_E_INTERNAL_ERROR;
306 : }
307 :
308 26 : if (username.size > MAX_USERNAME_SIZE) {
309 1 : gnutls_assert();
310 1 : return GNUTLS_E_ILLEGAL_SRP_USERNAME;
311 : }
312 :
313 25 : _gnutls_copy_psk_username(info, &username);
314 :
315 : /* Adjust data so it points to EncryptedPreMasterSecret */
316 25 : data += username.size + 2;
317 :
318 : /*** 2. Decrypt and extract EncryptedPreMasterSecret ***/
319 :
320 25 : DECR_LEN(data_size, 2);
321 24 : ciphertext.data = &data[2];
322 24 : dsize = _gnutls_read_uint16(data);
323 :
324 24 : if (dsize != data_size) {
325 1 : gnutls_assert();
326 1 : return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
327 : }
328 23 : ciphertext.size = dsize;
329 :
330 23 : ret =
331 23 : gnutls_privkey_decrypt_data(session->internals.selected_key, 0,
332 : &ciphertext, &plaintext);
333 23 : if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) {
334 : /* In case decryption fails then don't inform
335 : * the peer. Just use a random key. (in order to avoid
336 : * attack against pkcs-1 formatting).
337 : */
338 6 : gnutls_assert();
339 6 : _gnutls_debug_log
340 : ("auth_rsa_psk: Possible PKCS #1 format attack\n");
341 6 : if (ret >= 0) {
342 1 : gnutls_free(plaintext.data);
343 : }
344 6 : randomize_key = 1;
345 : } else {
346 : /* If the secret was properly formatted, then
347 : * check the version number.
348 : */
349 17 : if (_gnutls_get_adv_version_major(session) !=
350 17 : plaintext.data[0]
351 16 : || (session->internals.allow_wrong_pms == 0
352 14 : && _gnutls_get_adv_version_minor(session) !=
353 14 : plaintext.data[1])) {
354 : /* No error is returned here, if the version number check
355 : * fails. We proceed normally.
356 : * That is to defend against the attack described in the paper
357 : * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
358 : * Ondej Pokorny and Tomas Rosa.
359 : */
360 1 : gnutls_assert();
361 1 : _gnutls_debug_log
362 : ("auth_rsa: Possible PKCS #1 version check format attack\n");
363 : }
364 : }
365 :
366 :
367 0 : if (randomize_key != 0) {
368 6 : premaster_secret.size = GNUTLS_MASTER_SIZE;
369 12 : premaster_secret.data =
370 6 : gnutls_malloc(premaster_secret.size);
371 6 : if (premaster_secret.data == NULL) {
372 0 : gnutls_assert();
373 0 : return GNUTLS_E_MEMORY_ERROR;
374 : }
375 :
376 : /* we do not need strong random numbers here.
377 : */
378 12 : ret = gnutls_rnd(GNUTLS_RND_NONCE, premaster_secret.data,
379 6 : premaster_secret.size);
380 6 : if (ret < 0) {
381 0 : gnutls_assert();
382 0 : goto cleanup;
383 : }
384 : } else {
385 17 : premaster_secret.data = plaintext.data;
386 17 : premaster_secret.size = plaintext.size;
387 : }
388 :
389 : /* This is here to avoid the version check attack
390 : * discussed above.
391 : */
392 :
393 23 : premaster_secret.data[0] = _gnutls_get_adv_version_major(session);
394 23 : premaster_secret.data[1] = _gnutls_get_adv_version_minor(session);
395 :
396 : /* find the key of this username
397 : */
398 23 : ret =
399 23 : _gnutls_psk_pwd_find_entry(session, info->username, strlen(info->username), &pwd_psk);
400 23 : if (ret < 0) {
401 0 : gnutls_assert();
402 0 : goto cleanup;
403 : }
404 :
405 23 : ret =
406 23 : set_rsa_psk_session_key(session, &pwd_psk, &premaster_secret);
407 23 : if (ret < 0) {
408 0 : gnutls_assert();
409 0 : goto cleanup;
410 : }
411 :
412 : ret = 0;
413 23 : cleanup:
414 23 : _gnutls_free_key_datum(&pwd_psk);
415 23 : _gnutls_free_temp_key_datum(&premaster_secret);
416 :
417 23 : return ret;
418 : }
419 :
420 : static int
421 10 : _gnutls_proc_rsa_psk_server_kx(gnutls_session_t session, uint8_t * data,
422 : size_t _data_size)
423 : {
424 : /* In RSA-PSK the key is calculated elsewhere.
425 : * Moreover, since we only keep a single auth info structure, we cannot
426 : * store the hint (as we store certificate auth info).
427 : * Ideally we need to handle that by multiple auth info
428 : * structures or something similar.
429 : */
430 :
431 10 : return 0;
432 : }
433 :
434 : #endif /* ENABLE_PSK */
|