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