2 * Copyright (C) 2005, 2007, 2008, 2010 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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.
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.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
25 #include <gnutls_int.h>
29 #include "gnutls_errors.h"
30 #include "gnutls_auth.h"
31 #include "gnutls_auth.h"
33 #include "gnutls_num.h"
35 #include <auth_psk_passwd.h>
36 #include <gnutls_str.h>
37 #include <gnutls_datum.h>
39 int _gnutls_gen_psk_server_kx (gnutls_session_t session, opaque ** data);
40 int _gnutls_gen_psk_client_kx (gnutls_session_t, opaque **);
42 int _gnutls_proc_psk_client_kx (gnutls_session_t, opaque *, size_t);
44 int _gnutls_proc_psk_server_kx (gnutls_session_t session, opaque * data,
47 const mod_auth_st psk_auth_struct = {
51 _gnutls_gen_psk_server_kx,
52 _gnutls_gen_psk_client_kx,
57 NULL, /* certificate */
58 _gnutls_proc_psk_server_kx,
59 _gnutls_proc_psk_client_kx,
64 /* Set the PSK premaster secret.
67 _gnutls_set_psk_session_key (gnutls_session_t session,
68 gnutls_datum_t * ppsk /* key */,
69 gnutls_datum_t * dh_secret)
71 gnutls_datum_t pwd_psk = { NULL, 0 };
72 size_t dh_secret_size;
75 if (session->security_parameters.entity == GNUTLS_SERVER)
79 info = _gnutls_get_auth_info (session);
81 /* find the key of this username
83 ret = _gnutls_psk_pwd_find_entry (session, info->username, &pwd_psk);
93 if (dh_secret == NULL)
94 dh_secret_size = ppsk->size;
96 dh_secret_size = dh_secret->size;
98 /* set the session key
100 session->key->key.size = 4 + dh_secret_size + ppsk->size;
101 session->key->key.data = gnutls_malloc (session->key->key.size);
102 if (session->key->key.data == NULL)
105 ret = GNUTLS_E_MEMORY_ERROR;
109 /* format of the premaster secret:
110 * (uint16_t) psk_size
111 * psk_size bytes of zeros
112 * (uint16_t) psk_size
115 _gnutls_write_uint16 (dh_secret_size, session->key->key.data);
116 if (dh_secret == NULL)
117 memset (&session->key->key.data[2], 0, dh_secret_size);
119 memcpy (&session->key->key.data[2], dh_secret->data, dh_secret->size);
120 _gnutls_write_datum16 (&session->key->key.data[dh_secret_size + 2], *ppsk);
125 _gnutls_free_datum (&pwd_psk);
129 /* returns the username and they key for the PSK session.
130 * Free is non zero if they have to be freed.
132 int _gnutls_find_psk_key( gnutls_session_t session, gnutls_psk_client_credentials_t cred,
133 gnutls_datum_t * username, gnutls_datum* key, int* free)
140 if (cred->username.data != NULL && cred->key.data != NULL)
142 username->data = cred->username.data;
143 username->size = cred->username.size;
144 key->data = cred->key.data;
145 key->size = cred->key.size;
147 else if (cred->get_function != NULL)
149 ret = cred->get_function (session, &user_p, key);
151 return gnutls_assert_val(ret);
153 username->data = user_p;
154 username->size = strlen(user_p);
159 return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
165 /* Generates the PSK client key exchange
169 * select (KeyExchangeAlgorithm) {
170 * opaque psk_identity<0..2^16-1>;
172 * } ClientKeyExchange;
176 _gnutls_gen_psk_client_kx (gnutls_session_t session, opaque ** data)
179 gnutls_datum_t username;
181 gnutls_psk_client_credentials_t cred;
183 cred = (gnutls_psk_client_credentials_t)
184 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
189 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
192 ret = _gnutls_find_psk_key( session, cred, &username, &key, &free);
194 return gnutls_assert_val(ret);
196 ret = _gnutls_set_psk_session_key (session, &key, NULL);
203 (*data) = gnutls_malloc (2 + username.size);
207 ret = GNUTLS_E_MEMORY_ERROR;
211 _gnutls_write_datum16 (*data, username);
216 gnutls_free(username.data);
217 gnutls_free(key.data);
220 return (username.size + 2);
224 /* just read the username from the client key exchange.
227 _gnutls_proc_psk_client_kx (gnutls_session_t session, opaque * data,
230 ssize_t data_size = _data_size;
232 gnutls_datum_t username;
233 gnutls_psk_server_credentials_t cred;
234 psk_auth_info_t info;
236 cred = (gnutls_psk_server_credentials_t)
237 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
242 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
246 _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
247 sizeof (psk_auth_info_st), 1)) < 0)
253 DECR_LEN (data_size, 2);
254 username.size = _gnutls_read_uint16 (&data[0]);
256 DECR_LEN (data_size, username.size);
258 username.data = &data[2];
261 /* copy the username to the auth info structures
263 info = _gnutls_get_auth_info (session);
265 if (username.size > MAX_USERNAME_SIZE)
268 return GNUTLS_E_ILLEGAL_SRP_USERNAME;
271 memcpy (info->username, username.data, username.size);
272 info->username[username.size] = 0;
274 ret = _gnutls_set_psk_session_key (session, NULL, NULL);
288 /* Generates the PSK server key exchange
291 * select (KeyExchangeAlgorithm) {
292 * // other cases for rsa, diffie_hellman, etc.
294 * opaque psk_identity_hint<0..2^16-1>;
296 * } ServerKeyExchange;
300 _gnutls_gen_psk_server_kx (gnutls_session_t session, opaque ** data)
302 gnutls_psk_server_credentials_t cred;
305 cred = (gnutls_psk_server_credentials_t)
306 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
311 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
314 /* Abort sending this message if there is no PSK identity hint. */
315 if (cred->hint == NULL)
318 return GNUTLS_E_INT_RET_0;
321 hint.data = cred->hint;
322 hint.size = strlen (cred->hint);
324 (*data) = gnutls_malloc (2 + hint.size);
328 return GNUTLS_E_MEMORY_ERROR;
331 _gnutls_write_datum16 (*data, hint);
333 return hint.size + 2;
337 /* just read the hint from the server key exchange.
340 _gnutls_proc_psk_server_kx (gnutls_session_t session, opaque * data,
343 ssize_t data_size = _data_size;
346 gnutls_psk_client_credentials_t cred;
347 psk_auth_info_t info;
349 cred = (gnutls_psk_client_credentials_t)
350 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
355 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
359 _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
360 sizeof (psk_auth_info_st), 1)) < 0)
366 DECR_LENGTH_RET (data_size, 2, 0);
367 hint.size = _gnutls_read_uint16 (&data[0]);
369 DECR_LEN (data_size, hint.size);
371 hint.data = &data[2];
373 /* copy the hint to the auth info structures
375 info = _gnutls_get_auth_info (session);
377 if (hint.size > MAX_USERNAME_SIZE)
380 return GNUTLS_E_ILLEGAL_SRP_USERNAME;
383 memcpy (info->hint, hint.data, hint.size);
384 info->hint[hint.size] = 0;
386 ret = _gnutls_set_psk_session_key (session, &cred->key, NULL);
399 #endif /* ENABLE_PSK */