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
;
74 if (dh_secret
== NULL
)
75 dh_secret_size
= ppsk
->size
;
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
)
86 ret
= GNUTLS_E_MEMORY_ERROR
;
90 /* format of the premaster secret:
92 * psk_size bytes of (0)s
96 p
= session
->key
.key
.data
;
97 _gnutls_write_uint16 (dh_secret_size
, p
);
99 if (dh_secret
== NULL
)
100 memset (p
, 0, dh_secret_size
);
102 memcpy (p
, dh_secret
->data
, dh_secret
->size
);
105 _gnutls_write_uint16 (ppsk
->size
, p
);
106 if (ppsk
->data
!= NULL
)
107 memcpy (p
+2, ppsk
->data
, ppsk
->size
);
112 _gnutls_free_datum (&pwd_psk
);
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
)
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
);
138 return gnutls_assert_val(ret
);
140 username
->data
= (uint8_t*)user_p
;
141 username
->size
= strlen(user_p
);
146 return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS
);
152 /* Generates the PSK client key exchange
156 * select (KeyExchangeAlgorithm) {
157 * uint8_t psk_identity<0..2^16-1>;
159 * } ClientKeyExchange;
163 _gnutls_gen_psk_client_kx (gnutls_session_t session
, gnutls_buffer_st
* data
)
166 gnutls_datum_t username
;
168 gnutls_psk_client_credentials_t cred
;
170 cred
= (gnutls_psk_client_credentials_t
)
171 _gnutls_get_cred (session
, GNUTLS_CRD_PSK
, NULL
);
176 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
179 ret
= _gnutls_find_psk_key( session
, cred
, &username
, &key
, &free
);
181 return gnutls_assert_val(ret
);
183 ret
= _gnutls_set_psk_session_key (session
, &key
, NULL
);
190 ret
= _gnutls_buffer_append_data_prefix(data
, 16, username
.data
, username
.size
);
199 gnutls_free(username
.data
);
200 gnutls_free(key
.data
);
207 /* just read the username from the client key exchange.
210 _gnutls_proc_psk_client_kx (gnutls_session_t session
, uint8_t * data
,
213 ssize_t data_size
= _data_size
;
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
, GNUTLS_CRD_PSK
, NULL
);
225 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
229 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
230 sizeof (psk_auth_info_st
), 1)) < 0)
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
)
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
);
259 return gnutls_assert_val(ret
);
261 ret
= _gnutls_set_psk_session_key (session
, &psk_key
, NULL
);
271 _gnutls_free_datum(&psk_key
);
277 /* Generates the PSK server key exchange
280 * select (KeyExchangeAlgorithm) {
281 * // other cases for rsa, diffie_hellman, etc.
283 * uint8_t psk_identity_hint<0..2^16-1>;
285 * } ServerKeyExchange;
289 _gnutls_gen_psk_server_kx (gnutls_session_t session
, gnutls_buffer_st
* data
)
291 gnutls_psk_server_credentials_t cred
;
294 cred
= (gnutls_psk_server_credentials_t
)
295 _gnutls_get_cred (session
, GNUTLS_CRD_PSK
, NULL
);
300 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
303 /* Abort sending this message if there is no PSK identity hint. */
304 if (cred
->hint
== NULL
)
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
,
323 ssize_t data_size
= _data_size
;
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
, GNUTLS_CRD_PSK
, NULL
);
335 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
339 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
340 sizeof (psk_auth_info_st
), 1)) < 0)
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
)
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
);
379 #endif /* ENABLE_PSK */