Fixed leaks in key generation and other cleanups. Patch by Tomas Mraz.
[gnutls.git] / lib / gnutls_auth.c
bloba6003af3f32f4dd2fa659c581676472d2b76444c
1 /*
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010 Free
3 * Software Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 #include "gnutls_int.h"
27 #include "gnutls_errors.h"
28 #include "gnutls_auth.h"
29 #include "gnutls_auth.h"
30 #include "gnutls_algorithms.h"
31 #include "auth_cert.h"
32 #include "auth_psk.h"
33 #include <gnutls_datum.h>
35 #include "auth_anon.h"
36 /* The functions here are used in order for authentication algorithms
37 * to be able to retrieve the needed credentials eg public and private
38 * key etc.
41 /**
42 * gnutls_credentials_clear:
43 * @session: is a #gnutls_session_t structure.
45 * Clears all the credentials previously set in this session.
46 **/
47 void
48 gnutls_credentials_clear (gnutls_session_t session)
50 if (session->key && session->key->cred)
51 { /* beginning of the list */
52 auth_cred_st *ccred, *ncred;
53 ccred = session->key->cred;
54 while (ccred != NULL)
56 ncred = ccred->next;
57 gnutls_free (ccred);
58 ccred = ncred;
60 session->key->cred = NULL;
64 /*
65 * This creates a linked list of the form:
66 * { algorithm, credentials, pointer to next }
68 /**
69 * gnutls_credentials_set:
70 * @session: is a #gnutls_session_t structure.
71 * @type: is the type of the credentials
72 * @cred: is a pointer to a structure.
74 * Sets the needed credentials for the specified type. Eg username,
75 * password - or public and private keys etc. The @cred parameter is
76 * a structure that depends on the specified type and on the current
77 * session (client or server).
79 * In order to minimize memory usage, and share credentials between
80 * several threads gnutls keeps a pointer to cred, and not the whole
81 * cred structure. Thus you will have to keep the structure allocated
82 * until you call gnutls_deinit().
84 * For %GNUTLS_CRD_ANON, @cred should be
85 * #gnutls_anon_client_credentials_t in case of a client. In case of
86 * a server it should be #gnutls_anon_server_credentials_t.
88 * For %GNUTLS_CRD_SRP, @cred should be #gnutls_srp_client_credentials_t
89 * in case of a client, and #gnutls_srp_server_credentials_t, in case
90 * of a server.
92 * For %GNUTLS_CRD_CERTIFICATE, @cred should be
93 * #gnutls_certificate_credentials_t.
95 * Returns: On success, %GNUTLS_E_SUCCESS (zero) is returned,
96 * otherwise an error code is returned.
97 **/
98 int
99 gnutls_credentials_set (gnutls_session_t session,
100 gnutls_credentials_type_t type, void *cred)
102 auth_cred_st *ccred = NULL, *pcred = NULL;
103 int exists = 0;
105 if (session->key->cred == NULL)
106 { /* beginning of the list */
108 session->key->cred = gnutls_malloc (sizeof (auth_cred_st));
109 if (session->key->cred == NULL)
110 return GNUTLS_E_MEMORY_ERROR;
112 /* copy credentials locally */
113 session->key->cred->credentials = cred;
115 session->key->cred->next = NULL;
116 session->key->cred->algorithm = type;
118 else
120 ccred = session->key->cred;
121 while (ccred != NULL)
123 if (ccred->algorithm == type)
125 exists = 1;
126 break;
128 pcred = ccred;
129 ccred = ccred->next;
131 /* After this, pcred is not null.
134 if (exists == 0)
135 { /* new entry */
136 pcred->next = gnutls_malloc (sizeof (auth_cred_st));
137 if (pcred->next == NULL)
138 return GNUTLS_E_MEMORY_ERROR;
140 ccred = pcred->next;
142 /* copy credentials locally */
143 ccred->credentials = cred;
145 ccred->next = NULL;
146 ccred->algorithm = type;
148 else
149 { /* modify existing entry */
150 ccred->credentials = cred;
154 return 0;
158 * gnutls_auth_get_type:
159 * @session: is a #gnutls_session_t structure.
161 * Returns type of credentials for the current authentication schema.
162 * The returned information is to be used to distinguish the function used
163 * to access authentication data.
165 * Eg. for CERTIFICATE ciphersuites (key exchange algorithms:
166 * %GNUTLS_KX_RSA, %GNUTLS_KX_DHE_RSA), the same function are to be
167 * used to access the authentication data.
169 * Returns: The type of credentials for the current authentication
170 * schema, a #gnutls_credentials_type_t type.
172 gnutls_credentials_type_t
173 gnutls_auth_get_type (gnutls_session_t session)
175 /* This is not the credentials we must set, but the authentication data
176 * we get by the peer, so it should be reversed.
178 int server = session->security_parameters.entity == GNUTLS_SERVER ? 0 : 1;
180 return
181 _gnutls_map_kx_get_cred (_gnutls_cipher_suite_get_kx_algo
182 (&session->
183 security_parameters.current_cipher_suite),
184 server);
188 * gnutls_auth_server_get_type:
189 * @session: is a #gnutls_session_t structure.
191 * Returns the type of credentials that were used for server authentication.
192 * The returned information is to be used to distinguish the function used
193 * to access authentication data.
195 * Returns: The type of credentials for the server authentication
196 * schema, a #gnutls_credentials_type_t type.
198 gnutls_credentials_type_t
199 gnutls_auth_server_get_type (gnutls_session_t session)
201 return
202 _gnutls_map_kx_get_cred (_gnutls_cipher_suite_get_kx_algo
203 (&session->
204 security_parameters.current_cipher_suite), 1);
208 * gnutls_auth_client_get_type:
209 * @session: is a #gnutls_session_t structure.
211 * Returns the type of credentials that were used for client authentication.
212 * The returned information is to be used to distinguish the function used
213 * to access authentication data.
215 * Returns: The type of credentials for the client authentication
216 * schema, a #gnutls_credentials_type_t type.
218 gnutls_credentials_type_t
219 gnutls_auth_client_get_type (gnutls_session_t session)
221 return
222 _gnutls_map_kx_get_cred (_gnutls_cipher_suite_get_kx_algo
223 (&session->
224 security_parameters.current_cipher_suite), 0);
229 * This returns a pointer to the linked list. Don't
230 * free that!!!
232 const void *
233 _gnutls_get_kx_cred (gnutls_session_t session,
234 gnutls_kx_algorithm_t algo, int *err)
236 int server = session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0;
238 return _gnutls_get_cred (session->key,
239 _gnutls_map_kx_get_cred (algo, server), err);
242 const void *
243 _gnutls_get_cred (gnutls_key_st key, gnutls_credentials_type_t type, int *err)
245 const void *retval = NULL;
246 int _err = -1;
247 auth_cred_st *ccred;
249 if (key == NULL)
250 goto out;
252 ccred = key->cred;
253 while (ccred != NULL)
255 if (ccred->algorithm == type)
257 break;
259 ccred = ccred->next;
261 if (ccred == NULL)
262 goto out;
264 _err = 0;
265 retval = ccred->credentials;
267 out:
268 if (err != NULL)
269 *err = _err;
270 return retval;
274 * _gnutls_get_auth_info - Returns a pointer to authentication information.
275 * @session: is a #gnutls_session_t structure.
277 * This function must be called after a successful gnutls_handshake().
278 * Returns a pointer to authentication information. That information
279 * is data obtained by the handshake protocol, the key exchange algorithm,
280 * and the TLS extensions messages.
282 * In case of GNUTLS_CRD_ANON returns a type of &anon_(server/client)_auth_info_t;
283 * In case of GNUTLS_CRD_CERTIFICATE returns a type of &cert_auth_info_t;
284 * In case of GNUTLS_CRD_SRP returns a type of &srp_(server/client)_auth_info_t;
286 void *
287 _gnutls_get_auth_info (gnutls_session_t session)
289 return session->key->auth_info;
293 * _gnutls_free_auth_info - Frees the auth info structure
294 * @session: is a #gnutls_session_t structure.
296 * This function frees the auth info structure and sets it to
297 * null. It must be called since some structures contain malloced
298 * elements.
300 void
301 _gnutls_free_auth_info (gnutls_session_t session)
303 dh_info_st *dh_info;
304 rsa_info_st *rsa_info;
306 if (session == NULL || session->key == NULL)
308 gnutls_assert ();
309 return;
312 switch (session->key->auth_info_type)
314 case GNUTLS_CRD_SRP:
315 break;
316 case GNUTLS_CRD_ANON:
318 anon_auth_info_t info = _gnutls_get_auth_info (session);
320 if (info == NULL)
321 break;
323 dh_info = &info->dh;
324 _gnutls_free_dh_info (dh_info);
326 break;
327 case GNUTLS_CRD_PSK:
329 psk_auth_info_t info = _gnutls_get_auth_info (session);
331 if (info == NULL)
332 break;
334 dh_info = &info->dh;
335 _gnutls_free_dh_info (dh_info);
337 break;
338 case GNUTLS_CRD_CERTIFICATE:
340 unsigned int i;
341 cert_auth_info_t info = _gnutls_get_auth_info (session);
343 if (info == NULL)
344 break;
346 dh_info = &info->dh;
347 rsa_info = &info->rsa_export;
348 for (i = 0; i < info->ncerts; i++)
350 _gnutls_free_datum (&info->raw_certificate_list[i]);
353 gnutls_free (info->raw_certificate_list);
354 info->raw_certificate_list = NULL;
355 info->ncerts = 0;
357 _gnutls_free_dh_info (dh_info);
358 _gnutls_free_rsa_info (rsa_info);
362 break;
363 default:
364 return;
368 gnutls_free (session->key->auth_info);
369 session->key->auth_info = NULL;
370 session->key->auth_info_size = 0;
371 session->key->auth_info_type = 0;
375 /* This function will set the auth info structure in the key
376 * structure.
377 * If allow change is !=0 then this will allow changing the auth
378 * info structure to a different type.
381 _gnutls_auth_info_set (gnutls_session_t session,
382 gnutls_credentials_type_t type, int size,
383 int allow_change)
385 if (session->key->auth_info == NULL)
387 session->key->auth_info = gnutls_calloc (1, size);
388 if (session->key->auth_info == NULL)
390 gnutls_assert ();
391 return GNUTLS_E_MEMORY_ERROR;
393 session->key->auth_info_type = type;
394 session->key->auth_info_size = size;
396 else
398 if (allow_change == 0)
400 /* If the credentials for the current authentication scheme,
401 * are not the one we want to set, then it's an error.
402 * This may happen if a rehandshake is performed an the
403 * ciphersuite which is negotiated has different authentication
404 * schema.
406 if (gnutls_auth_get_type (session) != session->key->auth_info_type)
408 gnutls_assert ();
409 return GNUTLS_E_INVALID_REQUEST;
412 else
414 /* The new behaviour: Here we reallocate the auth info structure
415 * in order to be able to negotiate different authentication
416 * types. Ie. perform an auth_anon and then authenticate again using a
417 * certificate (in order to prevent revealing the certificate's contents,
418 * to passive eavesdropers.
420 if (gnutls_auth_get_type (session) != session->key->auth_info_type)
423 _gnutls_free_auth_info (session);
425 session->key->auth_info = calloc (1, size);
426 if (session->key->auth_info == NULL)
428 gnutls_assert ();
429 return GNUTLS_E_MEMORY_ERROR;
432 session->key->auth_info_type = type;
433 session->key->auth_info_size = size;
437 return 0;