documented updates
[gnutls.git] / lib / auth / psk.c
blob858f2f9978b60c5a65efe0a9975b480b2bc8eb08
1 /*
2 * Copyright (C) 2005-2012 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 3 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 License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <gnutls_int.h>
25 #ifdef ENABLE_PSK
27 #include "gnutls_errors.h"
28 #include "gnutls_auth.h"
29 #include "gnutls_auth.h"
30 #include "debug.h"
31 #include "gnutls_num.h"
32 #include <auth/psk.h>
33 #include <auth/psk_passwd.h>
34 #include <gnutls_str.h>
35 #include <gnutls_datum.h>
37 int _gnutls_gen_psk_server_kx (gnutls_session_t session, gnutls_buffer_st* data);
38 int _gnutls_gen_psk_client_kx (gnutls_session_t, gnutls_buffer_st*);
40 int _gnutls_proc_psk_client_kx (gnutls_session_t, uint8_t *, size_t);
42 int _gnutls_proc_psk_server_kx (gnutls_session_t session, uint8_t * data,
43 size_t _data_size);
45 const mod_auth_st psk_auth_struct = {
46 "PSK",
47 NULL,
48 NULL,
49 _gnutls_gen_psk_server_kx,
50 _gnutls_gen_psk_client_kx,
51 NULL,
52 NULL,
54 NULL,
55 NULL, /* certificate */
56 _gnutls_proc_psk_server_kx,
57 _gnutls_proc_psk_client_kx,
58 NULL,
59 NULL
62 /* Set the PSK premaster secret.
64 int
65 _gnutls_set_psk_session_key (gnutls_session_t session,
66 gnutls_datum_t * ppsk /* key */,
67 gnutls_datum_t * dh_secret)
69 gnutls_datum_t pwd_psk = { NULL, 0 };
70 size_t dh_secret_size;
71 uint8_t * p;
72 int ret;
74 if (dh_secret == NULL)
75 dh_secret_size = ppsk->size;
76 else
77 dh_secret_size = dh_secret->size;
79 /* set the session key
81 session->key->key.size = 4 + dh_secret_size + ppsk->size;
82 session->key->key.data = gnutls_malloc (session->key->key.size);
83 if (session->key->key.data == NULL)
85 gnutls_assert ();
86 ret = GNUTLS_E_MEMORY_ERROR;
87 goto error;
90 /* format of the premaster secret:
91 * (uint16_t) psk_size
92 * psk_size bytes of (0)s
93 * (uint16_t) psk_size
94 * the psk
96 p = session->key->key.data;
97 _gnutls_write_uint16 (dh_secret_size, p);
98 p+=2;
99 if (dh_secret == NULL)
100 memset (p, 0, dh_secret_size);
101 else
102 memcpy (p, dh_secret->data, dh_secret->size);
104 p += dh_secret_size;
105 _gnutls_write_uint16 (ppsk->size, p);
106 if (ppsk->data != NULL)
107 memcpy (p+2, ppsk->data, ppsk->size);
109 ret = 0;
111 error:
112 _gnutls_free_datum (&pwd_psk);
113 return ret;
116 /* returns the username and they key for the PSK session.
117 * Free is non (0) if they have to be freed.
119 int _gnutls_find_psk_key( gnutls_session_t session, gnutls_psk_client_credentials_t cred,
120 gnutls_datum_t * username, gnutls_datum_t* key, int* free)
122 char* user_p;
123 int ret;
125 *free = 0;
127 if (cred->username.data != NULL && cred->key.data != NULL)
129 username->data = cred->username.data;
130 username->size = cred->username.size;
131 key->data = cred->key.data;
132 key->size = cred->key.size;
134 else if (cred->get_function != NULL)
136 ret = cred->get_function (session, &user_p, key);
137 if (ret)
138 return gnutls_assert_val(ret);
140 username->data = (uint8_t*)user_p;
141 username->size = strlen(user_p);
143 *free = 1;
145 else
146 return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
148 return 0;
152 /* Generates the PSK client key exchange
155 * struct {
156 * select (KeyExchangeAlgorithm) {
157 * uint8_t psk_identity<0..2^16-1>;
158 * } exchange_keys;
159 * } ClientKeyExchange;
163 _gnutls_gen_psk_client_kx (gnutls_session_t session, gnutls_buffer_st* data)
165 int ret, free;
166 gnutls_datum_t username;
167 gnutls_datum_t key;
168 gnutls_psk_client_credentials_t cred;
170 cred = (gnutls_psk_client_credentials_t)
171 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
173 if (cred == NULL)
175 gnutls_assert ();
176 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
179 ret = _gnutls_find_psk_key( session, cred, &username, &key, &free);
180 if (ret < 0)
181 return gnutls_assert_val(ret);
183 ret = _gnutls_set_psk_session_key (session, &key, NULL);
184 if (ret < 0)
186 gnutls_assert();
187 goto cleanup;
190 ret = _gnutls_buffer_append_data_prefix(data, 16, username.data, username.size);
191 if (ret < 0)
193 gnutls_assert();
196 cleanup:
197 if (free)
199 gnutls_free(username.data);
200 gnutls_free(key.data);
203 return ret;
207 /* just read the username from the client key exchange.
210 _gnutls_proc_psk_client_kx (gnutls_session_t session, uint8_t * data,
211 size_t _data_size)
213 ssize_t data_size = _data_size;
214 int ret;
215 gnutls_datum_t username, psk_key;
216 gnutls_psk_server_credentials_t cred;
217 psk_auth_info_t info;
219 cred = (gnutls_psk_server_credentials_t)
220 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
222 if (cred == NULL)
224 gnutls_assert ();
225 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
228 if ((ret =
229 _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
230 sizeof (psk_auth_info_st), 1)) < 0)
232 gnutls_assert ();
233 return ret;
236 DECR_LEN (data_size, 2);
237 username.size = _gnutls_read_uint16 (&data[0]);
239 DECR_LEN (data_size, username.size);
241 username.data = &data[2];
244 /* copy the username to the auth info structures
246 info = _gnutls_get_auth_info (session);
248 if (username.size > MAX_USERNAME_SIZE)
250 gnutls_assert ();
251 return GNUTLS_E_ILLEGAL_SRP_USERNAME;
254 memcpy (info->username, username.data, username.size);
255 info->username[username.size] = 0;
257 ret = _gnutls_psk_pwd_find_entry(session, info->username, &psk_key);
258 if (ret < 0)
259 return gnutls_assert_val(ret);
261 ret = _gnutls_set_psk_session_key (session, &psk_key, NULL);
262 if (ret < 0)
264 gnutls_assert ();
265 goto error;
268 ret = 0;
270 error:
271 _gnutls_free_datum(&psk_key);
273 return ret;
277 /* Generates the PSK server key exchange
279 * struct {
280 * select (KeyExchangeAlgorithm) {
281 * // other cases for rsa, diffie_hellman, etc.
282 * case psk: // NEW
283 * uint8_t psk_identity_hint<0..2^16-1>;
284 * };
285 * } ServerKeyExchange;
289 _gnutls_gen_psk_server_kx (gnutls_session_t session, gnutls_buffer_st* data)
291 gnutls_psk_server_credentials_t cred;
292 gnutls_datum_t hint;
294 cred = (gnutls_psk_server_credentials_t)
295 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
297 if (cred == NULL)
299 gnutls_assert ();
300 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
303 /* Abort sending this message if there is no PSK identity hint. */
304 if (cred->hint == NULL)
306 gnutls_assert ();
307 return GNUTLS_E_INT_RET_0;
310 hint.data = (uint8_t*)cred->hint;
311 hint.size = strlen (cred->hint);
313 return _gnutls_buffer_append_data_prefix(data, 16, hint.data, hint.size);
317 /* just read the hint from the server key exchange.
320 _gnutls_proc_psk_server_kx (gnutls_session_t session, uint8_t * data,
321 size_t _data_size)
323 ssize_t data_size = _data_size;
324 int ret;
325 gnutls_datum_t hint;
326 gnutls_psk_client_credentials_t cred;
327 psk_auth_info_t info;
329 cred = (gnutls_psk_client_credentials_t)
330 _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
332 if (cred == NULL)
334 gnutls_assert ();
335 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
338 if ((ret =
339 _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
340 sizeof (psk_auth_info_st), 1)) < 0)
342 gnutls_assert ();
343 return ret;
346 DECR_LENGTH_RET (data_size, 2, 0);
347 hint.size = _gnutls_read_uint16 (&data[0]);
349 DECR_LEN (data_size, hint.size);
351 hint.data = &data[2];
353 /* copy the hint to the auth info structures
355 info = _gnutls_get_auth_info (session);
357 if (hint.size > MAX_USERNAME_SIZE)
359 gnutls_assert ();
360 return GNUTLS_E_ILLEGAL_SRP_USERNAME;
363 memcpy (info->hint, hint.data, hint.size);
364 info->hint[hint.size] = 0;
366 ret = _gnutls_set_psk_session_key (session, &cred->key, NULL);
367 if (ret < 0)
369 gnutls_assert ();
370 goto error;
373 ret = 0;
375 error:
376 return ret;
379 #endif /* ENABLE_PSK */