1 /*
2  * Copyright (C) 2001-2012 Free Software Foundation, Inc.
3  * Copyright (C) 2017 Red Hat, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
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.
13  *
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.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program.  If not, see <https://www.gnu.org/licenses/>
21  *
22  */
23 
24 #include "gnutls_int.h"
25 #include "errors.h"
26 #include "auth.h"
27 #include "auth.h"
28 #include "algorithms.h"
29 #include <auth/cert.h>
30 #include <auth/psk.h>
31 #include <auth/anon.h>
32 #include <datum.h>
33 
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.
37  */
38 
39 /**
40  * gnutls_credentials_clear:
41  * @session: is a #gnutls_session_t type.
42  *
43  * Clears all the credentials previously set in this session.
44  **/
gnutls_credentials_clear(gnutls_session_t session)45 void gnutls_credentials_clear(gnutls_session_t session)
46 {
47 	if (session->key.cred) {	/* beginning of the list */
48 		auth_cred_st *ccred, *ncred;
49 		ccred = session->key.cred;
50 		while (ccred != NULL) {
51 			ncred = ccred->next;
52 			gnutls_free(ccred);
53 			ccred = ncred;
54 		}
55 		session->key.cred = NULL;
56 	}
57 }
58 
59 /*
60  * This creates a linked list of the form:
61  * { algorithm, credentials, pointer to next }
62  */
63 /**
64  * gnutls_credentials_set:
65  * @session: is a #gnutls_session_t type.
66  * @type: is the type of the credentials
67  * @cred: the credentials to set
68  *
69  * Sets the needed credentials for the specified type.  E.g. username,
70  * password - or public and private keys etc.  The @cred parameter is
71  * a structure that depends on the specified type and on the current
72  * session (client or server).
73  *
74  * In order to minimize memory usage, and share credentials between
75  * several threads gnutls keeps a pointer to cred, and not the whole
76  * cred structure.  Thus you will have to keep the structure allocated
77  * until you call gnutls_deinit().
78  *
79  * For %GNUTLS_CRD_ANON, @cred should be
80  * #gnutls_anon_client_credentials_t in case of a client.  In case of
81  * a server it should be #gnutls_anon_server_credentials_t.
82  *
83  * For %GNUTLS_CRD_SRP, @cred should be #gnutls_srp_client_credentials_t
84  * in case of a client, and #gnutls_srp_server_credentials_t, in case
85  * of a server.
86  *
87  * For %GNUTLS_CRD_CERTIFICATE, @cred should be
88  * #gnutls_certificate_credentials_t.
89  *
90  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
91  *   otherwise a negative error code is returned.
92  **/
93 int
gnutls_credentials_set(gnutls_session_t session,gnutls_credentials_type_t type,void * cred)94 gnutls_credentials_set(gnutls_session_t session,
95 		       gnutls_credentials_type_t type, void *cred)
96 {
97 	auth_cred_st *ccred = NULL, *pcred = NULL;
98 	int exists = 0;
99 
100 	if (session->key.cred == NULL) {	/* beginning of the list */
101 
102 		session->key.cred = gnutls_malloc(sizeof(auth_cred_st));
103 		if (session->key.cred == NULL)
104 			return GNUTLS_E_MEMORY_ERROR;
105 
106 		/* copy credentials locally */
107 		session->key.cred->credentials = cred;
108 
109 		session->key.cred->next = NULL;
110 		session->key.cred->algorithm = type;
111 	} else {
112 		ccred = session->key.cred;
113 		while (ccred != NULL) {
114 			if (ccred->algorithm == type) {
115 				exists = 1;
116 				break;
117 			}
118 			pcred = ccred;
119 			ccred = ccred->next;
120 		}
121 		/* After this, pcred is not null.
122 		 */
123 
124 		if (exists == 0) {	/* new entry */
125 			pcred->next = gnutls_malloc(sizeof(auth_cred_st));
126 			if (pcred->next == NULL)
127 				return GNUTLS_E_MEMORY_ERROR;
128 
129 			ccred = pcred->next;
130 
131 			/* copy credentials locally */
132 			ccred->credentials = cred;
133 
134 			ccred->next = NULL;
135 			ccred->algorithm = type;
136 		} else {	/* modify existing entry */
137 			ccred->credentials = cred;
138 		}
139 	}
140 
141 	/* sanity tests */
142 	if (type == GNUTLS_CRD_CERTIFICATE) {
143 		gnutls_certificate_credentials_t c = cred;
144 		unsigned i;
145 		bool allow_tls13 = 0;
146 		unsigned key_usage;
147 
148 		if (c != NULL && c->ncerts != 0) {
149 			for (i = 0; i < c->ncerts; i++) {
150 				key_usage = get_key_usage(session, c->certs[i].cert_list[0].pubkey);
151 				if (key_usage == 0 || (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
152 					allow_tls13 = 1;
153 					break;
154 				}
155 			}
156 
157 			if (session->security_parameters.entity == GNUTLS_SERVER &&
158 			    !c->tls13_ok)
159 				allow_tls13 = 0;
160 
161 			if (!allow_tls13) {
162 				/* to prevent the server random indicate TLS1.3 support */
163 				session->internals.flags |= INT_FLAG_NO_TLS13;
164 			}
165 		}
166 	}
167 
168 	return 0;
169 }
170 
171 /**
172  * gnutls_credentials_get:
173  * @session: is a #gnutls_session_t type.
174  * @type: is the type of the credentials to return
175  * @cred: will contain the credentials.
176  *
177  * Returns the previously provided credentials structures.
178  *
179  * For %GNUTLS_CRD_ANON, @cred will be
180  * #gnutls_anon_client_credentials_t in case of a client.  In case of
181  * a server it should be #gnutls_anon_server_credentials_t.
182  *
183  * For %GNUTLS_CRD_SRP, @cred will be #gnutls_srp_client_credentials_t
184  * in case of a client, and #gnutls_srp_server_credentials_t, in case
185  * of a server.
186  *
187  * For %GNUTLS_CRD_CERTIFICATE, @cred will be
188  * #gnutls_certificate_credentials_t.
189  *
190  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
191  *   otherwise a negative error code is returned.
192  *
193  * Since: 3.3.3
194  **/
195 int
gnutls_credentials_get(gnutls_session_t session,gnutls_credentials_type_t type,void ** cred)196 gnutls_credentials_get(gnutls_session_t session,
197 		       gnutls_credentials_type_t type, void **cred)
198 {
199 	const void *_cred;
200 
201 	_cred = _gnutls_get_cred(session, type);
202 	if (_cred == NULL)
203 		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
204 
205 	if (cred)
206 		*cred = (void*)_cred;
207 
208 	return 0;
209 }
210 
211 /**
212  * gnutls_auth_get_type:
213  * @session: is a #gnutls_session_t type.
214  *
215  * Returns type of credentials for the current authentication schema.
216  * The returned information is to be used to distinguish the function used
217  * to access authentication data.
218  *
219  * Eg. for CERTIFICATE ciphersuites (key exchange algorithms:
220  * %GNUTLS_KX_RSA, %GNUTLS_KX_DHE_RSA), the same function are to be
221  * used to access the authentication data.
222  *
223  * Note that on resumed sessions, this function returns the schema
224  * used in the original session authentication.
225  *
226  * Returns: The type of credentials for the current authentication
227  *   schema, a #gnutls_credentials_type_t type.
228  **/
gnutls_auth_get_type(gnutls_session_t session)229 gnutls_credentials_type_t gnutls_auth_get_type(gnutls_session_t session)
230 {
231 	if (session->security_parameters.entity == GNUTLS_SERVER)
232 		return gnutls_auth_client_get_type(session);
233 	else
234 		return gnutls_auth_server_get_type(session);
235 }
236 
237 /**
238  * gnutls_auth_server_get_type:
239  * @session: is a #gnutls_session_t type.
240  *
241  * Returns the type of credentials that were used for server authentication.
242  * The returned information is to be used to distinguish the function used
243  * to access authentication data.
244  *
245  * Note that on resumed sessions, this function returns the schema
246  * used in the original session authentication.
247  *
248  * Returns: The type of credentials for the server authentication
249  *   schema, a #gnutls_credentials_type_t type.
250  **/
251 gnutls_credentials_type_t
gnutls_auth_server_get_type(gnutls_session_t session)252 gnutls_auth_server_get_type(gnutls_session_t session)
253 {
254 	return session->security_parameters.server_auth_type;
255 }
256 
257 /**
258  * gnutls_auth_client_get_type:
259  * @session: is a #gnutls_session_t type.
260  *
261  * Returns the type of credentials that were used for client authentication.
262  * The returned information is to be used to distinguish the function used
263  * to access authentication data.
264  *
265  * Note that on resumed sessions, this function returns the schema
266  * used in the original session authentication.
267  *
268  * Returns: The type of credentials for the client authentication
269  *   schema, a #gnutls_credentials_type_t type.
270  **/
271 gnutls_credentials_type_t
gnutls_auth_client_get_type(gnutls_session_t session)272 gnutls_auth_client_get_type(gnutls_session_t session)
273 {
274 	return session->security_parameters.client_auth_type;
275 }
276 
277 
278 /*
279  * This returns a pointer to the linked list. Don't
280  * free that!!!
281  */
_gnutls_get_kx_cred(gnutls_session_t session,gnutls_kx_algorithm_t algo)282 const void *_gnutls_get_kx_cred(gnutls_session_t session,
283 				gnutls_kx_algorithm_t algo)
284 {
285 	int server =
286 	    session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0;
287 
288 	return _gnutls_get_cred(session,
289 				_gnutls_map_kx_get_cred(algo, server));
290 }
291 
_gnutls_get_cred(gnutls_session_t session,gnutls_credentials_type_t type)292 const void *_gnutls_get_cred(gnutls_session_t session,
293 			     gnutls_credentials_type_t type)
294 {
295 	auth_cred_st *ccred;
296 	gnutls_key_st *key = &session->key;
297 
298 	ccred = key->cred;
299 	while (ccred != NULL) {
300 		if (ccred->algorithm == type) {
301 			break;
302 		}
303 		ccred = ccred->next;
304 	}
305 	if (ccred == NULL)
306 		return NULL;
307 
308 	return ccred->credentials;
309 }
310 
311 /*-
312  * _gnutls_free_auth_info - Frees the auth info structure
313  * @session: is a #gnutls_session_t type.
314  *
315  * This function frees the auth info structure and sets it to
316  * null. It must be called since some structures contain malloced
317  * elements.
318  -*/
_gnutls_free_auth_info(gnutls_session_t session)319 void _gnutls_free_auth_info(gnutls_session_t session)
320 {
321 	dh_info_st *dh_info;
322 
323 	if (session == NULL) {
324 		gnutls_assert();
325 		return;
326 	}
327 
328 	switch (session->key.auth_info_type) {
329 	case GNUTLS_CRD_SRP:
330 		break;
331 #ifdef ENABLE_ANON
332 	case GNUTLS_CRD_ANON:
333 		{
334 			anon_auth_info_t info =
335 			    _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
336 
337 			if (info == NULL)
338 				break;
339 
340 			dh_info = &info->dh;
341 			_gnutls_free_dh_info(dh_info);
342 		}
343 		break;
344 #endif
345 	case GNUTLS_CRD_PSK:
346 		{
347 			psk_auth_info_t info =
348 			    _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
349 
350 			if (info == NULL)
351 				break;
352 
353 #ifdef ENABLE_DHE
354 			dh_info = &info->dh;
355 			_gnutls_free_dh_info(dh_info);
356 #endif
357 		}
358 		break;
359 	case GNUTLS_CRD_CERTIFICATE:
360 		{
361 			unsigned int i;
362 			cert_auth_info_t info =
363 			    _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
364 
365 			if (info == NULL)
366 				break;
367 
368 			dh_info = &info->dh;
369 			for (i = 0; i < info->ncerts; i++) {
370 				_gnutls_free_datum(&info->raw_certificate_list[i]);
371 			}
372 
373 			for (i = 0; i < info->nocsp; i++) {
374 				_gnutls_free_datum(&info->raw_ocsp_list[i]);
375 			}
376 
377 			gnutls_free(info->raw_certificate_list);
378 			gnutls_free(info->raw_ocsp_list);
379 			info->ncerts = 0;
380 			info->nocsp = 0;
381 
382 #ifdef ENABLE_DHE
383 			_gnutls_free_dh_info(dh_info);
384 #endif
385 		}
386 
387 
388 		break;
389 	default:
390 		return;
391 
392 	}
393 
394 	gnutls_free(session->key.auth_info);
395 	session->key.auth_info_size = 0;
396 	session->key.auth_info_type = 0;
397 
398 }
399 
400 /* This function will create the auth info structure in the key
401  * structure if needed.
402  *
403  * If allow change is !=0 then this will allow changing the auth
404  * info structure to a different type.
405  */
406 int
_gnutls_auth_info_init(gnutls_session_t session,gnutls_credentials_type_t type,int size,int allow_change)407 _gnutls_auth_info_init(gnutls_session_t session,
408 		      gnutls_credentials_type_t type, int size,
409 		      int allow_change)
410 {
411 	if (session->key.auth_info == NULL) {
412 		session->key.auth_info = gnutls_calloc(1, size);
413 		if (session->key.auth_info == NULL) {
414 			gnutls_assert();
415 			return GNUTLS_E_MEMORY_ERROR;
416 		}
417 		session->key.auth_info_type = type;
418 		session->key.auth_info_size = size;
419 	} else {
420 		if (allow_change == 0) {
421 			/* If the credentials for the current authentication scheme,
422 			 * are not the one we want to set, then it's an error.
423 			 * This may happen if a rehandshake is performed an the
424 			 * ciphersuite which is negotiated has different authentication
425 			 * schema.
426 			 */
427 			if (type != session->key.auth_info_type) {
428 				gnutls_assert();
429 				return GNUTLS_E_INVALID_REQUEST;
430 			}
431 		} else {
432 			/* The new behaviour: Here we reallocate the auth info structure
433 			 * in order to be able to negotiate different authentication
434 			 * types. Ie. perform an auth_anon and then authenticate again using a
435 			 * certificate (in order to prevent revealing the certificate's contents,
436 			 * to passive eavesdropers.
437 			 */
438 			if (type != session->key.auth_info_type) {
439 
440 				_gnutls_free_auth_info(session);
441 
442 				session->key.auth_info = calloc(1, size);
443 				if (session->key.auth_info == NULL) {
444 					gnutls_assert();
445 					return GNUTLS_E_MEMORY_ERROR;
446 				}
447 
448 				session->key.auth_info_type = type;
449 				session->key.auth_info_size = size;
450 			}
451 		}
452 	}
453 	return 0;
454 }
455