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 library 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
, opaque
** data
);
40 int _gnutls_gen_psk_client_kx (gnutls_session_t
, opaque
**);
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
* dh_secret
)
70 gnutls_datum_t pwd_psk
= { NULL
, 0 };
72 size_t dh_secret_size
;
75 if (session
->security_parameters
.entity
== GNUTLS_CLIENT
)
77 gnutls_psk_client_credentials_t cred
;
79 cred
= (gnutls_psk_client_credentials_t
)
80 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
85 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
95 info
= _gnutls_get_auth_info (session
);
97 /* find the key of this username
99 ret
= _gnutls_psk_pwd_find_entry (session
, info
->username
, &pwd_psk
);
109 if (dh_secret
== NULL
)
110 dh_secret_size
= ppsk
->size
;
112 dh_secret_size
= dh_secret
->size
;
114 /* set the session key
116 session
->key
->key
.size
= 4 + dh_secret_size
+ ppsk
->size
;
117 session
->key
->key
.data
= gnutls_malloc (session
->key
->key
.size
);
118 if (session
->key
->key
.data
== NULL
)
121 ret
= GNUTLS_E_MEMORY_ERROR
;
125 /* format of the premaster secret:
126 * (uint16_t) psk_size
127 * psk_size bytes of zeros
128 * (uint16_t) psk_size
131 _gnutls_write_uint16 (dh_secret_size
, session
->key
->key
.data
);
132 if (dh_secret
== NULL
)
133 memset (&session
->key
->key
.data
[2], 0, dh_secret_size
);
135 memcpy (&session
->key
->key
.data
[2], dh_secret
->data
, dh_secret
->size
);
136 _gnutls_write_datum16 (&session
->key
->key
.data
[dh_secret_size
+ 2], *ppsk
);
141 _gnutls_free_datum (&pwd_psk
);
146 /* Generates the PSK client key exchange
150 * select (KeyExchangeAlgorithm) {
151 * opaque psk_identity<0..2^16-1>;
153 * } ClientKeyExchange;
157 _gnutls_gen_psk_client_kx (gnutls_session_t session
, opaque
** data
)
160 gnutls_psk_client_credentials_t cred
;
162 cred
= (gnutls_psk_client_credentials_t
)
163 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
168 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
171 if (cred
->username
.data
== NULL
&& cred
->key
.data
== NULL
&&
172 cred
->get_function
!= NULL
)
177 ret
= cred
->get_function (session
, &username
, &key
);
184 ret
= _gnutls_set_datum (&cred
->username
, username
, strlen (username
));
185 gnutls_free (username
);
189 _gnutls_free_datum (&key
);
193 ret
= _gnutls_set_datum (&cred
->key
, key
.data
, key
.size
);
194 _gnutls_free_datum (&key
);
198 return GNUTLS_E_MEMORY_ERROR
;
201 else if (cred
->username
.data
== NULL
|| cred
->key
.data
== NULL
)
204 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
207 ret
= _gnutls_set_psk_session_key (session
, NULL
);
214 (*data
) = gnutls_malloc (2 + cred
->username
.size
);
218 return GNUTLS_E_MEMORY_ERROR
;
221 _gnutls_write_datum16 (*data
, cred
->username
);
223 return (cred
->username
.size
+ 2);
227 /* just read the username from the client key exchange.
230 _gnutls_proc_psk_client_kx (gnutls_session_t session
, opaque
* data
,
233 ssize_t data_size
= _data_size
;
235 gnutls_datum_t username
;
236 gnutls_psk_server_credentials_t cred
;
237 psk_auth_info_t info
;
239 cred
= (gnutls_psk_server_credentials_t
)
240 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
245 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
249 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
250 sizeof (psk_auth_info_st
), 1)) < 0)
256 DECR_LEN (data_size
, 2);
257 username
.size
= _gnutls_read_uint16 (&data
[0]);
259 DECR_LEN (data_size
, username
.size
);
261 username
.data
= &data
[2];
264 /* copy the username to the auth info structures
266 info
= _gnutls_get_auth_info (session
);
268 if (username
.size
> MAX_SRP_USERNAME
)
271 return GNUTLS_E_ILLEGAL_SRP_USERNAME
;
274 memcpy (info
->username
, username
.data
, username
.size
);
275 info
->username
[username
.size
] = 0;
277 ret
= _gnutls_set_psk_session_key (session
, NULL
);
291 /* Generates the PSK server key exchange
294 * select (KeyExchangeAlgorithm) {
295 * // other cases for rsa, diffie_hellman, etc.
297 * opaque psk_identity_hint<0..2^16-1>;
299 * } ServerKeyExchange;
303 _gnutls_gen_psk_server_kx (gnutls_session_t session
, opaque
** data
)
305 gnutls_psk_server_credentials_t cred
;
308 cred
= (gnutls_psk_server_credentials_t
)
309 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
314 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
317 /* Abort sending this message if there is no PSK identity hint. */
318 if (cred
->hint
== NULL
)
321 return GNUTLS_E_INT_RET_0
;
324 hint
.data
= cred
->hint
;
325 hint
.size
= strlen (cred
->hint
);
327 (*data
) = gnutls_malloc (2 + hint
.size
);
331 return GNUTLS_E_MEMORY_ERROR
;
334 _gnutls_write_datum16 (*data
, hint
);
336 return hint
.size
+ 2;
340 /* just read the hint from the server key exchange.
343 _gnutls_proc_psk_server_kx (gnutls_session_t session
, opaque
* data
,
346 ssize_t data_size
= _data_size
;
349 gnutls_psk_server_credentials_t cred
;
350 psk_auth_info_t info
;
352 cred
= (gnutls_psk_server_credentials_t
)
353 _gnutls_get_cred (session
->key
, GNUTLS_CRD_PSK
, NULL
);
358 return GNUTLS_E_INSUFFICIENT_CREDENTIALS
;
362 _gnutls_auth_info_set (session
, GNUTLS_CRD_PSK
,
363 sizeof (psk_auth_info_st
), 1)) < 0)
369 DECR_LENGTH_RET (data_size
, 2, 0);
370 hint
.size
= _gnutls_read_uint16 (&data
[0]);
372 DECR_LEN (data_size
, hint
.size
);
374 hint
.data
= &data
[2];
376 /* copy the hint to the auth info structures
378 info
= _gnutls_get_auth_info (session
);
380 if (hint
.size
> MAX_SRP_USERNAME
)
383 return GNUTLS_E_ILLEGAL_SRP_USERNAME
;
386 memcpy (info
->hint
, hint
.data
, hint
.size
);
387 info
->hint
[hint
.size
] = 0;
389 ret
= _gnutls_set_psk_session_key (session
, NULL
);
402 #endif /* ENABLE_SRP */