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>
27 #include "gnutls_errors.h"
28 #include "gnutls_auth.h"
29 #include "gnutls_auth.h"
31 #include "gnutls_num.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
,
45 const mod_auth_st psk_auth_struct
= {
49 _gnutls_gen_psk_server_kx
,
50 _gnutls_gen_psk_client_kx
,
55 NULL
, /* certificate */
56 _gnutls_proc_psk_server_kx
,
57 _gnutls_proc_psk_client_kx
,
62 /* Set the PSK premaster secret.
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
;
73 if (dh_secret
== NULL
)
74 dh_secret_size
= ppsk
->size
;
76 dh_secret_size
= dh_secret
->size
;
78 /* set the session key
80 session
->key
->key
.size
= 4 + dh_secret_size
+ ppsk
->size
;
81 session
->key
->key
.data
= gnutls_malloc (session
->key
->key
.size
);
82 if (session
->key
->key
.data
== NULL
)
85 ret
= GNUTLS_E_MEMORY_ERROR
;
89 /* format of the premaster secret:
91 * psk_size bytes of (0)s
95 _gnutls_write_uint16 (dh_secret_size
, session
->key
->key
.data
);
96 if (dh_secret
== NULL
)
97 memset (&session
->key
->key
.data
[2], 0, dh_secret_size
);
99 memcpy (&session
->key
->key
.data
[2], dh_secret
->data
, dh_secret
->size
);
100 _gnutls_write_datum16 (&session
->key
->key
.data
[dh_secret_size
+ 2], *ppsk
);
105 _gnutls_free_datum (&pwd_psk
);
109 /* returns the username and they key for the PSK session.
110 * Free is non (0) if they have to be freed.
112 int _gnutls_find_psk_key( gnutls_session_t session
, gnutls_psk_client_credentials_t cred
,
113 gnutls_datum_t
* username
, gnutls_datum_t
* key
, int* free
)
120 if (cred
->username
.data
!= NULL
&& cred
->key
.data
!= NULL
)
122 username
->data
= cred
->username
.data
;
123 username
->size
= cred
->username
.size
;
124 key
->data
= cred
->key
.data
;
125 key
->size
= cred
->key
.size
;
127 else if (cred
->get_function
!= NULL
)
129 ret
= cred
->get_function (session
, &user_p
, key
);
131 return gnutls_assert_val(ret
);
133 username
->data
= (uint8_t*)user_p
;
134 username
->size
= strlen(user_p
);
139 return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS
);
145 /* Generates the PSK client key exchange
149 * select (KeyExchangeAlgorithm) {
150 * uint8_t psk_identity<0..2^16-1>;
152 * } ClientKeyExchange;
156 _gnutls_gen_psk_client_kx (gnutls_session_t session
, gnutls_buffer_st
* data
)
159 gnutls_datum_t username
;
161 gnutls_psk_client_credentials_t cred
;
163 cred
= (gnutls_psk_client_credentials_t
)
164 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
169 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
172 ret
= _gnutls_find_psk_key( session
, cred
, &username
, &key
, &free
);
174 return gnutls_assert_val(ret
);
176 ret
= _gnutls_set_psk_session_key (session
, &key
, NULL
);
183 ret
= _gnutls_buffer_append_data_prefix(data
, 16, username
.data
, username
.size
);
192 gnutls_free(username
.data
);
193 gnutls_free(key
.data
);
200 /* just read the username from the client key exchange.
203 _gnutls_proc_psk_client_kx (gnutls_session_t session
, uint8_t * data
,
206 ssize_t data_size
= _data_size
;
208 gnutls_datum_t username
, psk_key
;
209 gnutls_psk_server_credentials_t cred
;
210 psk_auth_info_t info
;
212 cred
= (gnutls_psk_server_credentials_t
)
213 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
218 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
222 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
223 sizeof (psk_auth_info_st
), 1)) < 0)
229 DECR_LEN (data_size
, 2);
230 username
.size
= _gnutls_read_uint16 (&data
[0]);
232 DECR_LEN (data_size
, username
.size
);
234 username
.data
= &data
[2];
237 /* copy the username to the auth info structures
239 info
= _gnutls_get_auth_info (session
);
241 if (username
.size
> MAX_USERNAME_SIZE
)
244 return GNUTLS_E_ILLEGAL_SRP_USERNAME
;
247 memcpy (info
->username
, username
.data
, username
.size
);
248 info
->username
[username
.size
] = 0;
250 ret
= _gnutls_psk_pwd_find_entry(session
, info
->username
, &psk_key
);
252 return gnutls_assert_val(ret
);
254 ret
= _gnutls_set_psk_session_key (session
, &psk_key
, NULL
);
264 _gnutls_free_datum(&psk_key
);
270 /* Generates the PSK server key exchange
273 * select (KeyExchangeAlgorithm) {
274 * // other cases for rsa, diffie_hellman, etc.
276 * uint8_t psk_identity_hint<0..2^16-1>;
278 * } ServerKeyExchange;
282 _gnutls_gen_psk_server_kx (gnutls_session_t session
, gnutls_buffer_st
* data
)
284 gnutls_psk_server_credentials_t cred
;
287 cred
= (gnutls_psk_server_credentials_t
)
288 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
293 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
296 /* Abort sending this message if there is no PSK identity hint. */
297 if (cred
->hint
== NULL
)
300 return GNUTLS_E_INT_RET_0
;
303 hint
.data
= (uint8_t*)cred
->hint
;
304 hint
.size
= strlen (cred
->hint
);
306 return _gnutls_buffer_append_data_prefix(data
, 16, hint
.data
, hint
.size
);
310 /* just read the hint from the server key exchange.
313 _gnutls_proc_psk_server_kx (gnutls_session_t session
, uint8_t * data
,
316 ssize_t data_size
= _data_size
;
319 gnutls_psk_client_credentials_t cred
;
320 psk_auth_info_t info
;
322 cred
= (gnutls_psk_client_credentials_t
)
323 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
328 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
332 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
333 sizeof (psk_auth_info_st
), 1)) < 0)
339 DECR_LENGTH_RET (data_size
, 2, 0);
340 hint
.size
= _gnutls_read_uint16 (&data
[0]);
342 DECR_LEN (data_size
, hint
.size
);
344 hint
.data
= &data
[2];
346 /* copy the hint to the auth info structures
348 info
= _gnutls_get_auth_info (session
);
350 if (hint
.size
> MAX_USERNAME_SIZE
)
353 return GNUTLS_E_ILLEGAL_SRP_USERNAME
;
356 memcpy (info
->hint
, hint
.data
, hint
.size
);
357 info
->hint
[hint
.size
] = 0;
359 ret
= _gnutls_set_psk_session_key (session
, &cred
->key
, NULL
);
372 #endif /* ENABLE_PSK */