Line data Source code
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 : **/
45 23002 : void gnutls_credentials_clear(gnutls_session_t session)
46 : {
47 23002 : if (session->key.cred) { /* beginning of the list */
48 : auth_cred_st *ccred, *ncred;
49 : ccred = session->key.cred;
50 59642 : while (ccred != NULL) {
51 36679 : ncred = ccred->next;
52 36679 : gnutls_free(ccred);
53 36679 : ccred = ncred;
54 : }
55 22963 : session->key.cred = NULL;
56 : }
57 23002 : }
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
94 36868 : gnutls_credentials_set(gnutls_session_t session,
95 : gnutls_credentials_type_t type, void *cred)
96 : {
97 36868 : auth_cred_st *ccred = NULL, *pcred = NULL;
98 36868 : int exists = 0;
99 :
100 36868 : if (session->key.cred == NULL) { /* beginning of the list */
101 :
102 23056 : session->key.cred = gnutls_malloc(sizeof(auth_cred_st));
103 23056 : if (session->key.cred == NULL)
104 : return GNUTLS_E_MEMORY_ERROR;
105 :
106 : /* copy credentials locally */
107 23056 : session->key.cred->credentials = cred;
108 :
109 23056 : session->key.cred->next = NULL;
110 23056 : session->key.cred->algorithm = type;
111 : } else {
112 : ccred = session->key.cred;
113 28457 : while (ccred != NULL) {
114 14661 : if (ccred->algorithm == type) {
115 : exists = 1;
116 : break;
117 : }
118 14645 : pcred = ccred;
119 14645 : ccred = ccred->next;
120 : }
121 : /* After this, pcred is not null.
122 : */
123 :
124 13812 : if (exists == 0) { /* new entry */
125 13796 : pcred->next = gnutls_malloc(sizeof(auth_cred_st));
126 13796 : if (pcred->next == NULL)
127 : return GNUTLS_E_MEMORY_ERROR;
128 :
129 13796 : ccred = pcred->next;
130 :
131 : /* copy credentials locally */
132 13796 : ccred->credentials = cred;
133 :
134 13796 : ccred->next = NULL;
135 13796 : ccred->algorithm = type;
136 : } else { /* modify existing entry */
137 16 : ccred->credentials = cred;
138 : }
139 : }
140 :
141 : /* sanity tests */
142 36868 : if (type == GNUTLS_CRD_CERTIFICATE) {
143 17439 : gnutls_certificate_credentials_t c = cred;
144 17439 : unsigned i;
145 17439 : bool allow_tls13 = 0;
146 17439 : unsigned key_usage;
147 :
148 17439 : if (c != NULL && c->ncerts != 0) {
149 14686 : for (i = 0; i < c->ncerts; i++) {
150 14674 : key_usage = get_key_usage(session, c->certs[i].cert_list[0].pubkey);
151 14668 : if (key_usage == 0 || (key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) {
152 : allow_tls13 = 1;
153 : break;
154 : }
155 : }
156 :
157 14662 : if (session->security_parameters.entity == GNUTLS_SERVER &&
158 14534 : !c->tls13_ok)
159 : allow_tls13 = 0;
160 :
161 14556 : if (!allow_tls13) {
162 : /* to prevent the server random indicate TLS1.3 support */
163 117 : 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
196 7 : gnutls_credentials_get(gnutls_session_t session,
197 : gnutls_credentials_type_t type, void **cred)
198 : {
199 7 : const void *_cred;
200 :
201 7 : _cred = _gnutls_get_cred(session, type);
202 7 : if (_cred == NULL)
203 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
204 :
205 7 : if (cred)
206 7 : *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 : **/
229 52384 : gnutls_credentials_type_t gnutls_auth_get_type(gnutls_session_t session)
230 : {
231 52384 : if (session->security_parameters.entity == GNUTLS_SERVER)
232 49320 : return gnutls_auth_client_get_type(session);
233 : else
234 3064 : 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
252 8909 : gnutls_auth_server_get_type(gnutls_session_t session)
253 : {
254 8909 : 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
272 58407 : gnutls_auth_client_get_type(gnutls_session_t session)
273 : {
274 58407 : 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 : */
282 12850 : const void *_gnutls_get_kx_cred(gnutls_session_t session,
283 : gnutls_kx_algorithm_t algo)
284 : {
285 12850 : int server =
286 12850 : session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0;
287 :
288 12850 : return _gnutls_get_cred(session,
289 : _gnutls_map_kx_get_cred(algo, server));
290 : }
291 :
292 203847 : const void *_gnutls_get_cred(gnutls_session_t session,
293 : gnutls_credentials_type_t type)
294 : {
295 203847 : auth_cred_st *ccred;
296 203847 : gnutls_key_st *key = &session->key;
297 :
298 203847 : ccred = key->cred;
299 314095 : while (ccred != NULL) {
300 283024 : if (ccred->algorithm == type) {
301 : break;
302 : }
303 110248 : ccred = ccred->next;
304 : }
305 203847 : if (ccred == NULL)
306 : return NULL;
307 :
308 172776 : 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 : -*/
319 23021 : void _gnutls_free_auth_info(gnutls_session_t session)
320 : {
321 23021 : dh_info_st *dh_info;
322 :
323 23021 : if (session == NULL) {
324 0 : gnutls_assert();
325 0 : return;
326 : }
327 :
328 23021 : switch (session->key.auth_info_type) {
329 : case GNUTLS_CRD_SRP:
330 : break;
331 : #ifdef ENABLE_ANON
332 : case GNUTLS_CRD_ANON:
333 : {
334 1002 : anon_auth_info_t info =
335 14536 : _gnutls_get_auth_info(session, GNUTLS_CRD_ANON);
336 :
337 1002 : if (info == NULL)
338 : break;
339 :
340 1002 : dh_info = &info->dh;
341 1002 : _gnutls_free_dh_info(dh_info);
342 : }
343 1002 : break;
344 : #endif
345 : case GNUTLS_CRD_PSK:
346 : {
347 4419 : psk_auth_info_t info =
348 17953 : _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
349 :
350 4419 : if (info == NULL)
351 : break;
352 :
353 : #ifdef ENABLE_DHE
354 4419 : dh_info = &info->dh;
355 4419 : _gnutls_free_dh_info(dh_info);
356 : #endif
357 : }
358 4419 : break;
359 : case GNUTLS_CRD_CERTIFICATE:
360 : {
361 7943 : unsigned int i;
362 7943 : cert_auth_info_t info =
363 21477 : _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
364 :
365 7943 : if (info == NULL)
366 : break;
367 :
368 7943 : dh_info = &info->dh;
369 11343 : for (i = 0; i < info->ncerts; i++) {
370 6800 : _gnutls_free_datum(&info->raw_certificate_list[i]);
371 : }
372 :
373 8798 : for (i = 0; i < info->nocsp; i++) {
374 1710 : _gnutls_free_datum(&info->raw_ocsp_list[i]);
375 : }
376 :
377 7943 : gnutls_free(info->raw_certificate_list);
378 7943 : gnutls_free(info->raw_ocsp_list);
379 7943 : info->ncerts = 0;
380 7943 : info->nocsp = 0;
381 :
382 : #ifdef ENABLE_DHE
383 7943 : _gnutls_free_dh_info(dh_info);
384 : #endif
385 : }
386 :
387 :
388 7943 : break;
389 : default:
390 : return;
391 :
392 : }
393 :
394 13534 : gnutls_free(session->key.auth_info);
395 13534 : session->key.auth_info_size = 0;
396 13534 : 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
407 16101 : _gnutls_auth_info_init(gnutls_session_t session,
408 : gnutls_credentials_type_t type, int size,
409 : int allow_change)
410 : {
411 16101 : if (session->key.auth_info == NULL) {
412 13594 : session->key.auth_info = gnutls_calloc(1, size);
413 13594 : if (session->key.auth_info == NULL) {
414 0 : gnutls_assert();
415 0 : return GNUTLS_E_MEMORY_ERROR;
416 : }
417 13594 : session->key.auth_info_type = type;
418 13594 : session->key.auth_info_size = size;
419 : } else {
420 2507 : 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 424 : if (type != session->key.auth_info_type) {
428 0 : gnutls_assert();
429 0 : 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 2083 : if (type != session->key.auth_info_type) {
439 :
440 15 : _gnutls_free_auth_info(session);
441 :
442 15 : session->key.auth_info = calloc(1, size);
443 15 : if (session->key.auth_info == NULL) {
444 0 : gnutls_assert();
445 0 : return GNUTLS_E_MEMORY_ERROR;
446 : }
447 :
448 15 : session->key.auth_info_type = type;
449 15 : session->key.auth_info_size = size;
450 : }
451 : }
452 : }
453 : return 0;
454 : }
|