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
, 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
,
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
, gnutls_buffer_st
* 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 ret
= _gnutls_buffer_append_data_prefix(data
, 16, username
.data
, username
.size
);
212 gnutls_free(username
.data
);
213 gnutls_free(key
.data
);
220 /* just read the username from the client key exchange.
223 _gnutls_proc_psk_client_kx (gnutls_session_t session
, opaque
* data
,
226 ssize_t data_size
= _data_size
;
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
);
238 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
242 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
243 sizeof (psk_auth_info_st
), 1)) < 0)
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
)
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
);
284 /* Generates the PSK server key exchange
287 * select (KeyExchangeAlgorithm) {
288 * // other cases for rsa, diffie_hellman, etc.
290 * opaque psk_identity_hint<0..2^16-1>;
292 * } ServerKeyExchange;
296 _gnutls_gen_psk_server_kx (gnutls_session_t session
, gnutls_buffer_st
* data
)
298 gnutls_psk_server_credentials_t cred
;
301 cred
= (gnutls_psk_server_credentials_t
)
302 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
307 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
310 /* Abort sending this message if there is no PSK identity hint. */
311 if (cred
->hint
== NULL
)
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
,
330 ssize_t data_size
= _data_size
;
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
);
342 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
346 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
347 sizeof (psk_auth_info_st
), 1)) < 0)
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
)
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
);
386 #endif /* ENABLE_PSK */