Fix memory leak.
[gnutls.git] / lib / gnutls_auth.c
blobdc201495665272b1eb91c8cda628d4028a5307ee
1 /*
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Free Software Foundation
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,
21 * USA
25 #include "gnutls_int.h"
26 #include "gnutls_errors.h"
27 #include "gnutls_auth.h"
28 #include "gnutls_auth_int.h"
29 #include "gnutls_algorithms.h"
30 #include "auth_cert.h"
31 #include <gnutls_datum.h>
33 #include "auth_anon.h"
34 /* The functions here are used in order for authentication algorithms
35 * to be able to retrieve the needed credentials eg public and private
36 * key etc.
39 /**
40 * gnutls_credentials_clear - Clears all the credentials previously set
41 * @session: is a #gnutls_session_t structure.
43 * Clears all the credentials previously set in this session.
45 **/
46 void
47 gnutls_credentials_clear (gnutls_session_t session)
49 if (session->key && session->key->cred)
50 { /* beginning of the list */
51 auth_cred_st *ccred, *ncred;
52 ccred = session->key->cred;
53 while (ccred != NULL)
55 ncred = ccred->next;
56 gnutls_free (ccred);
57 ccred = ncred;
59 session->key->cred = NULL;
63 /*
64 * This creates a linked list of the form:
65 * { algorithm, credentials, pointer to next }
67 /**
68 * gnutls_credentials_set - Sets the needed credentials for the specified authentication algorithm.
69 * @session: is a #gnutls_session_t structure.
70 * @type: is the type of the credentials
71 * @cred: is a pointer to a structure.
73 * Sets the needed credentials for the specified type.
74 * Eg username, password - or public and private keys etc.
75 * The (void* cred) parameter is a structure that depends on the
76 * specified type and on the current session (client or server).
77 * [ In order to minimize memory usage, and share credentials between
78 * several threads gnutls keeps a pointer to cred, and not the whole cred
79 * structure. Thus you will have to keep the structure allocated until
80 * you call gnutls_deinit(). ]
82 * For GNUTLS_CRD_ANON cred should be gnutls_anon_client_credentials_t in case of a client.
83 * In case of a server it should be gnutls_anon_server_credentials_t.
85 * For GNUTLS_CRD_SRP cred should be gnutls_srp_client_credentials_t
86 * in case of a client, and gnutls_srp_server_credentials_t, in case
87 * of a server.
89 * For GNUTLS_CRD_CERTIFICATE cred should be gnutls_certificate_credentials_t.
91 **/
92 int
93 gnutls_credentials_set (gnutls_session_t session,
94 gnutls_credentials_type_t type, void *cred)
96 auth_cred_st *ccred = NULL, *pcred = NULL;
97 int exists = 0;
99 if (session->key->cred == NULL)
100 { /* beginning of the list */
102 session->key->cred = gnutls_malloc (sizeof (auth_cred_st));
103 if (session->key->cred == NULL)
104 return GNUTLS_E_MEMORY_ERROR;
106 /* copy credentials locally */
107 session->key->cred->credentials = cred;
109 session->key->cred->next = NULL;
110 session->key->cred->algorithm = type;
112 else
114 ccred = session->key->cred;
115 while (ccred != NULL)
117 if (ccred->algorithm == type)
119 exists = 1;
120 break;
122 pcred = ccred;
123 ccred = ccred->next;
125 /* After this, pcred is not null.
128 if (exists == 0)
129 { /* new entry */
130 pcred->next = gnutls_malloc (sizeof (auth_cred_st));
131 if (pcred->next == NULL)
132 return GNUTLS_E_MEMORY_ERROR;
134 ccred = pcred->next;
136 /* copy credentials locally */
137 ccred->credentials = cred;
139 ccred->next = NULL;
140 ccred->algorithm = type;
142 else
143 { /* modify existing entry */
144 gnutls_free (ccred->credentials);
145 ccred->credentials = cred;
149 return 0;
153 * gnutls_auth_get_type - Returns the type of credentials for the current authentication schema.
154 * @session: is a #gnutls_session_t structure.
156 * Returns type of credentials for the current authentication schema.
157 * The returned information is to be used to distinguish the function used
158 * to access authentication data.
160 * Eg. for CERTIFICATE ciphersuites (key exchange algorithms: KX_RSA,
161 * KX_DHE_RSA), the same function are to be used to access the
162 * authentication data.
164 * Returns: The type of credentials for the current authentication
165 * schema, an #gnutls_credentials_type_t type.
167 gnutls_credentials_type_t
168 gnutls_auth_get_type (gnutls_session_t session)
170 /* This is not the credentials we must set, but the authentication data
171 * we get by the peer, so it should be reversed.
173 int server = session->security_parameters.entity == GNUTLS_SERVER ? 0 : 1;
175 return
176 _gnutls_map_kx_get_cred (_gnutls_cipher_suite_get_kx_algo
177 (&session->security_parameters.
178 current_cipher_suite), server);
182 * gnutls_auth_server_get_type - Returns the type of credentials for the server authentication schema.
183 * @session: is a #gnutls_session_t structure.
185 * Returns the type of credentials that were used for server authentication.
186 * The returned information is to be used to distinguish the function used
187 * to access authentication data.
189 * Returns: The type of credentials for the server authentication
190 * schema, an #gnutls_credentials_type_t type.
192 gnutls_credentials_type_t
193 gnutls_auth_server_get_type (gnutls_session_t session)
195 return
196 _gnutls_map_kx_get_cred (_gnutls_cipher_suite_get_kx_algo
197 (&session->security_parameters.
198 current_cipher_suite), 1);
202 * gnutls_auth_client_get_type - Returns the type of credentials for the client authentication schema.
203 * @session: is a #gnutls_session_t structure.
205 * Returns the type of credentials that were used for client authentication.
206 * The returned information is to be used to distinguish the function used
207 * to access authentication data.
209 * Returns: The type of credentials for the client authentication
210 * schema, an #gnutls_credentials_type_t type.
212 gnutls_credentials_type_t
213 gnutls_auth_client_get_type (gnutls_session_t session)
215 return
216 _gnutls_map_kx_get_cred (_gnutls_cipher_suite_get_kx_algo
217 (&session->security_parameters.
218 current_cipher_suite), 0);
223 * This returns a pointer to the linked list. Don't
224 * free that!!!
226 const void *
227 _gnutls_get_kx_cred (gnutls_session_t session,
228 gnutls_kx_algorithm_t algo, int *err)
230 int server = session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0;
232 return _gnutls_get_cred (session->key,
233 _gnutls_map_kx_get_cred (algo, server), err);
236 const void *
237 _gnutls_get_cred (gnutls_key_st key, gnutls_credentials_type_t type, int *err)
239 const void *retval = NULL;
240 int _err = -1;
241 auth_cred_st *ccred;
243 if (key == NULL)
244 goto out;
246 ccred = key->cred;
247 while (ccred != NULL)
249 if (ccred->algorithm == type)
251 break;
253 ccred = ccred->next;
255 if (ccred == NULL)
256 goto out;
258 _err = 0;
259 retval = ccred->credentials;
261 out:
262 if (err != NULL)
263 *err = _err;
264 return retval;
268 * _gnutls_get_auth_info - Returns a pointer to authentication information.
269 * @session: is a #gnutls_session_t structure.
271 * This function must be called after a succesful gnutls_handshake().
272 * Returns a pointer to authentication information. That information
273 * is data obtained by the handshake protocol, the key exchange algorithm,
274 * and the TLS extensions messages.
276 * In case of GNUTLS_CRD_ANON returns a type of &anon_(server/client)_auth_info_t;
277 * In case of GNUTLS_CRD_CERTIFICATE returns a type of &cert_auth_info_t;
278 * In case of GNUTLS_CRD_SRP returns a type of &srp_(server/client)_auth_info_t;
280 void *
281 _gnutls_get_auth_info (gnutls_session_t session)
283 return session->key->auth_info;
287 * _gnutls_free_auth_info - Frees the auth info structure
288 * @session: is a #gnutls_session_t structure.
290 * This function frees the auth info structure and sets it to
291 * null. It must be called since some structures contain malloced
292 * elements.
294 void
295 _gnutls_free_auth_info (gnutls_session_t session)
297 dh_info_st *dh_info;
298 rsa_info_st *rsa_info;
300 if (session == NULL || session->key == NULL)
302 gnutls_assert ();
303 return;
306 switch (session->key->auth_info_type)
308 case GNUTLS_CRD_SRP:
309 break;
310 case GNUTLS_CRD_ANON:
312 anon_auth_info_t info = _gnutls_get_auth_info (session);
314 if (info == NULL)
315 break;
317 dh_info = &info->dh;
318 _gnutls_free_dh_info (dh_info);
320 break;
321 case GNUTLS_CRD_CERTIFICATE:
323 unsigned int i;
324 cert_auth_info_t info = _gnutls_get_auth_info (session);
326 if (info == NULL)
327 break;
329 dh_info = &info->dh;
330 rsa_info = &info->rsa_export;
331 for (i = 0; i < info->ncerts; i++)
333 _gnutls_free_datum (&info->raw_certificate_list[i]);
336 gnutls_free (info->raw_certificate_list);
337 info->raw_certificate_list = NULL;
338 info->ncerts = 0;
340 _gnutls_free_dh_info (dh_info);
341 _gnutls_free_rsa_info (rsa_info);
345 break;
346 default:
347 return;
351 gnutls_free (session->key->auth_info);
352 session->key->auth_info = NULL;
353 session->key->auth_info_size = 0;
354 session->key->auth_info_type = 0;
358 /* This function will set the auth info structure in the key
359 * structure.
360 * If allow change is !=0 then this will allow changing the auth
361 * info structure to a different type.
364 _gnutls_auth_info_set (gnutls_session_t session,
365 gnutls_credentials_type_t type, int size,
366 int allow_change)
368 if (session->key->auth_info == NULL)
370 session->key->auth_info = gnutls_calloc (1, size);
371 if (session->key->auth_info == NULL)
373 gnutls_assert ();
374 return GNUTLS_E_MEMORY_ERROR;
376 session->key->auth_info_type = type;
377 session->key->auth_info_size = size;
379 else
381 if (allow_change == 0)
383 /* If the credentials for the current authentication scheme,
384 * are not the one we want to set, then it's an error.
385 * This may happen if a rehandshake is performed an the
386 * ciphersuite which is negotiated has different authentication
387 * schema.
389 if (gnutls_auth_get_type (session) != session->key->auth_info_type)
391 gnutls_assert ();
392 return GNUTLS_E_INVALID_REQUEST;
395 else
397 /* The new behaviour: Here we reallocate the auth info structure
398 * in order to be able to negotiate different authentication
399 * types. Ie. perform an auth_anon and then authenticate again using a
400 * certificate (in order to prevent revealing the certificate's contents,
401 * to passive eavesdropers.
403 if (gnutls_auth_get_type (session) != session->key->auth_info_type)
406 _gnutls_free_auth_info (session);
408 session->key->auth_info =
409 calloc( 1, size);
410 if (session->key->auth_info == NULL)
412 gnutls_assert ();
413 return GNUTLS_E_MEMORY_ERROR;
416 session->key->auth_info_type = type;
417 session->key->auth_info_size = size;
421 return 0;