Tizen 2.0 Release
[external/libgnutls26.git] / lib / auth_psk.c
1 /*
2  * Copyright (C) 2005, 2007, 2008, 2010 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
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
22  *
23  */
24
25 #include <gnutls_int.h>
26
27 #ifdef ENABLE_PSK
28
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>
38
39 int _gnutls_gen_psk_server_kx (gnutls_session_t session, opaque ** data);
40 int _gnutls_gen_psk_client_kx (gnutls_session_t, opaque **);
41
42 int _gnutls_proc_psk_client_kx (gnutls_session_t, opaque *, size_t);
43
44 int _gnutls_proc_psk_server_kx (gnutls_session_t session, opaque * data,
45                                 size_t _data_size);
46
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,
55
56   NULL,
57   NULL,                         /* certificate */
58   _gnutls_proc_psk_server_kx,
59   _gnutls_proc_psk_client_kx,
60   NULL,
61   NULL
62 };
63
64 /* Set the PSK premaster secret.
65  */
66 int
67 _gnutls_set_psk_session_key (gnutls_session_t session,
68     gnutls_datum_t * ppsk /* key */,
69     gnutls_datum_t * dh_secret)
70 {
71   gnutls_datum_t pwd_psk = { NULL, 0 };
72   size_t dh_secret_size;
73   int ret;
74
75   if (session->security_parameters.entity == GNUTLS_SERVER)
76     {                           /* SERVER side */
77       psk_auth_info_t info;
78
79       info = _gnutls_get_auth_info (session);
80
81       /* find the key of this username
82        */
83       ret = _gnutls_psk_pwd_find_entry (session, info->username, &pwd_psk);
84       if (ret < 0)
85         {
86           gnutls_assert ();
87           return ret;
88         }
89       ppsk = &pwd_psk;
90     }
91
92
93   if (dh_secret == NULL)
94     dh_secret_size = ppsk->size;
95   else
96     dh_secret_size = dh_secret->size;
97
98   /* set the session key
99    */
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)
103     {
104       gnutls_assert ();
105       ret = GNUTLS_E_MEMORY_ERROR;
106       goto error;
107     }
108
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
114    */
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);
121
122   ret = 0;
123
124 error:
125   _gnutls_free_datum (&pwd_psk);
126   return ret;
127 }
128
129 /* returns the username and they key for the PSK session.
130  * Free is non zero if they have to be freed.
131  */
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)
134 {
135 char* user_p;
136 int ret;
137
138    *free = 0;
139
140   if (cred->username.data != NULL && cred->key.data != NULL)
141     {
142       username->data = cred->username.data;
143       username->size = cred->username.size;
144       key->data = cred->key.data;
145       key->size = cred->key.size;
146     }
147   else if (cred->get_function != NULL)
148     {
149       ret = cred->get_function (session, &user_p, key);
150       if (ret)
151         return gnutls_assert_val(ret);
152       
153       username->data = user_p;
154       username->size = strlen(user_p);
155       
156       *free = 1;
157     }
158   else
159     return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
160   
161   return 0;
162 }
163
164
165 /* Generates the PSK client key exchange
166  *
167  * 
168  * struct {
169  *    select (KeyExchangeAlgorithm) {
170  *       opaque psk_identity<0..2^16-1>;
171  *    } exchange_keys;
172  * } ClientKeyExchange;
173  *
174  */
175 int
176 _gnutls_gen_psk_client_kx (gnutls_session_t session, opaque ** data)
177 {
178   int ret, free;
179   gnutls_datum_t username;
180   gnutls_datum_t key;
181   gnutls_psk_client_credentials_t cred;
182
183   cred = (gnutls_psk_client_credentials_t)
184     _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
185
186   if (cred == NULL)
187     {
188       gnutls_assert ();
189       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
190     }
191
192   ret = _gnutls_find_psk_key( session, cred, &username, &key, &free);
193   if (ret < 0)
194     return gnutls_assert_val(ret);
195
196   ret = _gnutls_set_psk_session_key (session, &key, NULL);
197   if (ret < 0)
198     {
199       gnutls_assert();
200       goto cleanup;
201     }
202   
203   (*data) = gnutls_malloc (2 + username.size);
204   if ((*data) == NULL)
205     {
206       gnutls_assert ();
207       ret = GNUTLS_E_MEMORY_ERROR;
208       goto cleanup;
209     }
210
211   _gnutls_write_datum16 (*data, username);
212
213 cleanup:
214   if (free) 
215     {
216       gnutls_free(username.data);
217       gnutls_free(key.data);
218     }
219   
220   return (username.size + 2);
221 }
222
223
224 /* just read the username from the client key exchange.
225  */
226 int
227 _gnutls_proc_psk_client_kx (gnutls_session_t session, opaque * data,
228                             size_t _data_size)
229 {
230   ssize_t data_size = _data_size;
231   int ret;
232   gnutls_datum_t username;
233   gnutls_psk_server_credentials_t cred;
234   psk_auth_info_t info;
235
236   cred = (gnutls_psk_server_credentials_t)
237     _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
238
239   if (cred == NULL)
240     {
241       gnutls_assert ();
242       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
243     }
244
245   if ((ret =
246        _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
247                               sizeof (psk_auth_info_st), 1)) < 0)
248     {
249       gnutls_assert ();
250       return ret;
251     }
252
253   DECR_LEN (data_size, 2);
254   username.size = _gnutls_read_uint16 (&data[0]);
255
256   DECR_LEN (data_size, username.size);
257
258   username.data = &data[2];
259
260
261   /* copy the username to the auth info structures
262    */
263   info = _gnutls_get_auth_info (session);
264
265   if (username.size > MAX_USERNAME_SIZE)
266     {
267       gnutls_assert ();
268       return GNUTLS_E_ILLEGAL_SRP_USERNAME;
269     }
270
271   memcpy (info->username, username.data, username.size);
272   info->username[username.size] = 0;
273
274   ret = _gnutls_set_psk_session_key (session, NULL, NULL);
275   if (ret < 0)
276     {
277       gnutls_assert ();
278       goto error;
279     }
280
281   ret = 0;
282
283 error:
284   return ret;
285 }
286
287
288 /* Generates the PSK server key exchange
289  *
290  * struct {
291  *     select (KeyExchangeAlgorithm) {
292  *         // other cases for rsa, diffie_hellman, etc.
293  *         case psk:  // NEW
294  *             opaque psk_identity_hint<0..2^16-1>;
295  *     };
296  * } ServerKeyExchange;
297  *
298  */
299 int
300 _gnutls_gen_psk_server_kx (gnutls_session_t session, opaque ** data)
301 {
302   gnutls_psk_server_credentials_t cred;
303   gnutls_datum_t hint;
304
305   cred = (gnutls_psk_server_credentials_t)
306     _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
307
308   if (cred == NULL)
309     {
310       gnutls_assert ();
311       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
312     }
313
314   /* Abort sending this message if there is no PSK identity hint. */
315   if (cred->hint == NULL)
316     {
317       gnutls_assert ();
318       return GNUTLS_E_INT_RET_0;
319     }
320
321   hint.data = cred->hint;
322   hint.size = strlen (cred->hint);
323
324   (*data) = gnutls_malloc (2 + hint.size);
325   if ((*data) == NULL)
326     {
327       gnutls_assert ();
328       return GNUTLS_E_MEMORY_ERROR;
329     }
330
331   _gnutls_write_datum16 (*data, hint);
332
333   return hint.size + 2;
334 }
335
336
337 /* just read the hint from the server key exchange.
338  */
339 int
340 _gnutls_proc_psk_server_kx (gnutls_session_t session, opaque * data,
341                             size_t _data_size)
342 {
343   ssize_t data_size = _data_size;
344   int ret;
345   gnutls_datum_t hint;
346   gnutls_psk_client_credentials_t cred;
347   psk_auth_info_t info;
348
349   cred = (gnutls_psk_client_credentials_t)
350     _gnutls_get_cred (session->key, GNUTLS_CRD_PSK, NULL);
351
352   if (cred == NULL)
353     {
354       gnutls_assert ();
355       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
356     }
357
358   if ((ret =
359        _gnutls_auth_info_set (session, GNUTLS_CRD_PSK,
360                               sizeof (psk_auth_info_st), 1)) < 0)
361     {
362       gnutls_assert ();
363       return ret;
364     }
365
366   DECR_LENGTH_RET (data_size, 2, 0);
367   hint.size = _gnutls_read_uint16 (&data[0]);
368
369   DECR_LEN (data_size, hint.size);
370
371   hint.data = &data[2];
372
373   /* copy the hint to the auth info structures
374    */
375   info = _gnutls_get_auth_info (session);
376
377   if (hint.size > MAX_USERNAME_SIZE)
378     {
379       gnutls_assert ();
380       return GNUTLS_E_ILLEGAL_SRP_USERNAME;
381     }
382
383   memcpy (info->hint, hint.data, hint.size);
384   info->hint[hint.size] = 0;
385
386   ret = _gnutls_set_psk_session_key (session, &cred->key, NULL);
387   if (ret < 0)
388     {
389       gnutls_assert ();
390       goto error;
391     }
392
393   ret = 0;
394
395 error:
396   return ret;
397 }
398
399 #endif /* ENABLE_PSK */