Add `gnutls/dtls.h' to the distribution.
[gnutls.git] / lib / auth_psk.c
blob17d9403e9c9e408368c458ac9e38d48b6ffcc9f1
1 /*
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,
21 * USA
25 #include <gnutls_int.h>
27 #ifdef ENABLE_PSK
29 #include "gnutls_errors.h"
30 #include "gnutls_auth.h"
31 #include "gnutls_auth.h"
32 #include "debug.h"
33 #include "gnutls_num.h"
34 #include <auth_psk.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, gnutls_buffer_st* data);
40 int _gnutls_gen_psk_client_kx (gnutls_session_t, gnutls_buffer_st*);
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,
45 size_t _data_size);
47 const mod_auth_st psk_auth_struct = {
48 "PSK",
49 NULL,
50 NULL,
51 _gnutls_gen_psk_server_kx,
52 _gnutls_gen_psk_client_kx,
53 NULL,
54 NULL,
56 NULL,
57 NULL, /* certificate */
58 _gnutls_proc_psk_server_kx,
59 _gnutls_proc_psk_client_kx,
60 NULL,
61 NULL
64 /* Set the PSK premaster secret.
66 int
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;
73 int ret;
75 if (session->security_parameters.entity == GNUTLS_SERVER)
76 { /* SERVER side */
77 psk_auth_info_t info;
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);
84 if (ret < 0)
86 gnutls_assert ();
87 return ret;
89 ppsk = &pwd_psk;
93 if (dh_secret == NULL)
94 dh_secret_size = ppsk->size;
95 else
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)
104 gnutls_assert ();
105 ret = GNUTLS_E_MEMORY_ERROR;
106 goto error;
109 /* format of the premaster secret:
110 * (uint16_t) psk_size
111 * psk_size bytes of zeros
112 * (uint16_t) psk_size
113 * the psk
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);
118 else
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);
122 ret = 0;
124 error:
125 _gnutls_free_datum (&pwd_psk);
126 return ret;
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)
135 char* user_p;
136 int ret;
138 *free = 0;
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);
150 if (ret)
151 return gnutls_assert_val(ret);
153 username->data = user_p;
154 username->size = strlen(user_p);
156 *free = 1;
158 else
159 return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
161 return 0;
165 /* Generates the PSK client key exchange
168 * struct {
169 * select (KeyExchangeAlgorithm) {
170 * opaque psk_identity<0..2^16-1>;
171 * } exchange_keys;
172 * } ClientKeyExchange;
176 _gnutls_gen_psk_client_kx (gnutls_session_t session, gnutls_buffer_st* data)
178 int ret, free;
179 gnutls_datum_t username;
180 gnutls_datum_t key;
181 gnutls_psk_client_credentials_t cred;
183 cred = (gnutls_psk_client_credentials_t)
184 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
186 if (cred == NULL)
188 gnutls_assert ();
189 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
192 ret = _gnutls_find_psk_key( session, cred, &username, &key, &free);
193 if (ret < 0)
194 return gnutls_assert_val(ret);
196 ret = _gnutls_set_psk_session_key (session, &key, NULL);
197 if (ret < 0)
199 gnutls_assert();
200 goto cleanup;
203 ret = _gnutls_buffer_append_data_prefix(data, 16, username.data, username.size);
204 if (ret < 0)
206 gnutls_assert();
209 cleanup:
210 if (free)
212 gnutls_free(username.data);
213 gnutls_free(key.data);
216 return ret;
220 /* just read the username from the client key exchange.
223 _gnutls_proc_psk_client_kx (gnutls_session_t session, opaque * data,
224 size_t _data_size)
226 ssize_t data_size = _data_size;
227 int ret;
228 gnutls_datum_t username;
229 gnutls_psk_server_credentials_t cred;
230 psk_auth_info_t info;
232 cred = (gnutls_psk_server_credentials_t)
233 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
235 if (cred == NULL)
237 gnutls_assert ();
238 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
241 if ((ret =
242 _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
243 sizeof (psk_auth_info_st), 1)) < 0)
245 gnutls_assert ();
246 return ret;
249 DECR_LEN (data_size, 2);
250 username.size = _gnutls_read_uint16 (&data[0]);
252 DECR_LEN (data_size, username.size);
254 username.data = &data[2];
257 /* copy the username to the auth info structures
259 info = _gnutls_get_auth_info (session);
261 if (username.size > MAX_USERNAME_SIZE)
263 gnutls_assert ();
264 return GNUTLS_E_ILLEGAL_SRP_USERNAME;
267 memcpy (info->username, username.data, username.size);
268 info->username[username.size] = 0;
270 ret = _gnutls_set_psk_session_key (session, NULL, NULL);
271 if (ret < 0)
273 gnutls_assert ();
274 goto error;
277 ret = 0;
279 error:
280 return ret;
284 /* Generates the PSK server key exchange
286 * struct {
287 * select (KeyExchangeAlgorithm) {
288 * // other cases for rsa, diffie_hellman, etc.
289 * case psk: // NEW
290 * opaque psk_identity_hint<0..2^16-1>;
291 * };
292 * } ServerKeyExchange;
296 _gnutls_gen_psk_server_kx (gnutls_session_t session, gnutls_buffer_st* data)
298 gnutls_psk_server_credentials_t cred;
299 gnutls_datum_t hint;
301 cred = (gnutls_psk_server_credentials_t)
302 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
304 if (cred == NULL)
306 gnutls_assert ();
307 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
310 /* Abort sending this message if there is no PSK identity hint. */
311 if (cred->hint == NULL)
313 gnutls_assert ();
314 return GNUTLS_E_INT_RET_0;
317 hint.data = cred->hint;
318 hint.size = strlen (cred->hint);
320 return _gnutls_buffer_append_data_prefix(data, 16, hint.data, hint.size);
324 /* just read the hint from the server key exchange.
327 _gnutls_proc_psk_server_kx (gnutls_session_t session, opaque * data,
328 size_t _data_size)
330 ssize_t data_size = _data_size;
331 int ret;
332 gnutls_datum_t hint;
333 gnutls_psk_client_credentials_t cred;
334 psk_auth_info_t info;
336 cred = (gnutls_psk_client_credentials_t)
337 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
339 if (cred == NULL)
341 gnutls_assert ();
342 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
345 if ((ret =
346 _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
347 sizeof (psk_auth_info_st), 1)) < 0)
349 gnutls_assert ();
350 return ret;
353 DECR_LENGTH_RET (data_size, 2, 0);
354 hint.size = _gnutls_read_uint16 (&data[0]);
356 DECR_LEN (data_size, hint.size);
358 hint.data = &data[2];
360 /* copy the hint to the auth info structures
362 info = _gnutls_get_auth_info (session);
364 if (hint.size > MAX_USERNAME_SIZE)
366 gnutls_assert ();
367 return GNUTLS_E_ILLEGAL_SRP_USERNAME;
370 memcpy (info->hint, hint.data, hint.size);
371 info->hint[hint.size] = 0;
373 ret = _gnutls_set_psk_session_key (session, &cred->key, NULL);
374 if (ret < 0)
376 gnutls_assert ();
377 goto error;
380 ret = 0;
382 error:
383 return ret;
386 #endif /* ENABLE_PSK */