Coverage Report

Created: 2026-05-16 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/x509/verify-high2.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2012-2014 Free Software Foundation, Inc.
3
 * Copyright (C) 2014 Nikos Mavrogiannopoulos
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 <libtasn1.h>
27
#include "global.h"
28
#include "num.h"
29
#include "tls-sig.h"
30
#include "str.h"
31
#include <c-strcase.h>
32
#include "datum.h"
33
#include "x509_int.h"
34
#include "common.h"
35
#include "verify-high.h"
36
#include "read-file.h"
37
#include "pkcs11_int.h"
38
#include "urls.h"
39
40
#include <dirent.h>
41
42
#if !defined(_DIRENT_HAVE_D_TYPE) && !defined(__native_client__)
43
#ifdef DT_UNKNOWN
44
#define _DIRENT_HAVE_D_TYPE
45
#endif
46
#endif
47
48
#ifdef _WIN32
49
#include <tchar.h>
50
#endif
51
52
/* Convenience functions for verify-high functionality 
53
 */
54
55
/**
56
 * gnutls_x509_trust_list_add_trust_mem:
57
 * @list: The list
58
 * @cas: A buffer containing a list of CAs (optional)
59
 * @crls: A buffer containing a list of CRLs (optional)
60
 * @type: The format of the certificates
61
 * @tl_flags: flags from %gnutls_trust_list_flags_t
62
 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
63
 *
64
 * This function will add the given certificate authorities
65
 * to the trusted list. 
66
 *
67
 * If this function is used gnutls_x509_trust_list_deinit() must be called
68
 * with parameter @all being 1.
69
 *
70
 * Returns: The number of added elements is returned.
71
 *
72
 * Since: 3.1
73
 **/
74
int gnutls_x509_trust_list_add_trust_mem(gnutls_x509_trust_list_t list,
75
           const gnutls_datum_t *cas,
76
           const gnutls_datum_t *crls,
77
           gnutls_x509_crt_fmt_t type,
78
           unsigned int tl_flags,
79
           unsigned int tl_vflags)
80
0
{
81
0
  int ret;
82
0
  gnutls_x509_crt_t *x509_ca_list = NULL;
83
0
  gnutls_x509_crl_t *x509_crl_list = NULL;
84
0
  unsigned int x509_ncas, x509_ncrls;
85
0
  unsigned int r = 0;
86
87
  /* When adding CAs or CRLs, we use the GNUTLS_TL_NO_DUPLICATES flag to ensure
88
   * that unaccounted certificates/CRLs are deinitialized. */
89
90
0
  if (cas != NULL && cas->data != NULL) {
91
0
    ret = gnutls_x509_crt_list_import2(&x509_ca_list, &x509_ncas,
92
0
               cas, type, 0);
93
0
    if (ret < 0)
94
0
      return gnutls_assert_val(ret);
95
96
0
    ret = gnutls_x509_trust_list_add_cas(
97
0
      list, x509_ca_list, x509_ncas,
98
0
      tl_flags | GNUTLS_TL_NO_DUPLICATES);
99
0
    gnutls_free(x509_ca_list);
100
101
0
    if (ret < 0)
102
0
      return gnutls_assert_val(ret);
103
0
    else
104
0
      r += ret;
105
0
  }
106
107
0
  if (crls != NULL && crls->data != NULL) {
108
0
    ret = gnutls_x509_crl_list_import2(&x509_crl_list, &x509_ncrls,
109
0
               crls, type, 0);
110
0
    if (ret < 0)
111
0
      return gnutls_assert_val(ret);
112
113
0
    ret = gnutls_x509_trust_list_add_crls(
114
0
      list, x509_crl_list, x509_ncrls,
115
0
      tl_flags | GNUTLS_TL_NO_DUPLICATES, tl_vflags);
116
0
    gnutls_free(x509_crl_list);
117
118
0
    if (ret < 0)
119
0
      return gnutls_assert_val(ret);
120
0
    else
121
0
      r += ret;
122
0
  }
123
124
0
  return r;
125
0
}
126
127
/**
128
 * gnutls_x509_trust_list_remove_trust_mem:
129
 * @list: The list
130
 * @cas: A buffer containing a list of CAs (optional)
131
 * @type: The format of the certificates
132
 *
133
 * This function will remove the provided certificate authorities
134
 * from the trusted list, and add them into a block list when needed. 
135
 *
136
 * See also gnutls_x509_trust_list_remove_cas().
137
 *
138
 * Returns: The number of removed elements is returned.
139
 *
140
 * Since: 3.1.10
141
 **/
142
int gnutls_x509_trust_list_remove_trust_mem(gnutls_x509_trust_list_t list,
143
              const gnutls_datum_t *cas,
144
              gnutls_x509_crt_fmt_t type)
145
0
{
146
0
  int ret;
147
0
  gnutls_x509_crt_t *x509_ca_list = NULL;
148
0
  unsigned int x509_ncas;
149
0
  unsigned int r = 0, i;
150
151
0
  if (cas != NULL && cas->data != NULL) {
152
0
    ret = gnutls_x509_crt_list_import2(&x509_ca_list, &x509_ncas,
153
0
               cas, type, 0);
154
0
    if (ret < 0)
155
0
      return gnutls_assert_val(ret);
156
157
0
    ret = gnutls_x509_trust_list_remove_cas(list, x509_ca_list,
158
0
              x509_ncas);
159
160
0
    for (i = 0; i < x509_ncas; i++)
161
0
      gnutls_x509_crt_deinit(x509_ca_list[i]);
162
0
    gnutls_free(x509_ca_list);
163
164
0
    if (ret < 0)
165
0
      return gnutls_assert_val(ret);
166
0
    else
167
0
      r += ret;
168
0
  }
169
170
0
  return r;
171
0
}
172
173
#ifdef ENABLE_PKCS11
174
static int remove_pkcs11_url(gnutls_x509_trust_list_t list, const char *ca_file)
175
{
176
  if (strcmp(ca_file, list->pkcs11_token) == 0) {
177
    gnutls_free(list->pkcs11_token);
178
  }
179
  return 0;
180
}
181
182
/* This function does add a PKCS #11 object URL into trust list. The
183
 * CA certificates are imported directly, rather than using it as a
184
 * trusted PKCS#11 token.
185
 */
186
static int add_trust_list_pkcs11_object_url(gnutls_x509_trust_list_t list,
187
              const char *url, unsigned flags)
188
{
189
  gnutls_x509_crt_t *xcrt_list = NULL;
190
  gnutls_pkcs11_obj_t *pcrt_list = NULL;
191
  unsigned int pcrt_list_size = 0, i;
192
  int ret;
193
194
  /* here we don't use the flag GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE,
195
   * as we want to explicitly load from any module available in the system.
196
   */
197
  ret = gnutls_pkcs11_obj_list_import_url2(
198
    &pcrt_list, &pcrt_list_size, url,
199
    GNUTLS_PKCS11_OBJ_FLAG_CRT |
200
      GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED,
201
    0);
202
  if (ret < 0)
203
    return gnutls_assert_val(ret);
204
205
  if (pcrt_list_size == 0) {
206
    ret = 0;
207
    goto cleanup;
208
  }
209
210
  xcrt_list = gnutls_calloc(pcrt_list_size, sizeof(gnutls_x509_crt_t));
211
  if (xcrt_list == NULL) {
212
    ret = GNUTLS_E_MEMORY_ERROR;
213
    goto cleanup;
214
  }
215
216
  ret = gnutls_x509_crt_list_import_pkcs11(xcrt_list, pcrt_list_size,
217
             pcrt_list, 0);
218
  if (ret < 0) {
219
    gnutls_assert();
220
    goto cleanup;
221
  }
222
223
  ret = gnutls_x509_trust_list_add_cas(list, xcrt_list, pcrt_list_size,
224
               flags);
225
226
cleanup:
227
  for (i = 0; i < pcrt_list_size; i++)
228
    gnutls_pkcs11_obj_deinit(pcrt_list[i]);
229
  gnutls_free(pcrt_list);
230
  gnutls_free(xcrt_list);
231
232
  return ret;
233
}
234
235
static int remove_pkcs11_object_url(gnutls_x509_trust_list_t list,
236
            const char *url)
237
{
238
  gnutls_x509_crt_t *xcrt_list = NULL;
239
  gnutls_pkcs11_obj_t *pcrt_list = NULL;
240
  unsigned int pcrt_list_size = 0, i;
241
  int ret;
242
243
  ret = gnutls_pkcs11_obj_list_import_url2(
244
    &pcrt_list, &pcrt_list_size, url,
245
    GNUTLS_PKCS11_OBJ_FLAG_CRT |
246
      GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED,
247
    0);
248
  if (ret < 0)
249
    return gnutls_assert_val(ret);
250
251
  if (pcrt_list_size == 0) {
252
    ret = 0;
253
    goto cleanup;
254
  }
255
256
  xcrt_list = gnutls_calloc(pcrt_list_size, sizeof(gnutls_x509_crt_t));
257
  if (xcrt_list == NULL) {
258
    ret = GNUTLS_E_MEMORY_ERROR;
259
    goto cleanup;
260
  }
261
262
  ret = gnutls_x509_crt_list_import_pkcs11(xcrt_list, pcrt_list_size,
263
             pcrt_list, 0);
264
  if (ret < 0) {
265
    gnutls_assert();
266
    goto cleanup;
267
  }
268
269
  ret = gnutls_x509_trust_list_remove_cas(list, xcrt_list,
270
            pcrt_list_size);
271
272
cleanup:
273
  for (i = 0; i < pcrt_list_size; i++) {
274
    gnutls_pkcs11_obj_deinit(pcrt_list[i]);
275
    if (xcrt_list)
276
      gnutls_x509_crt_deinit(xcrt_list[i]);
277
  }
278
  gnutls_free(pcrt_list);
279
  gnutls_free(xcrt_list);
280
281
  return ret;
282
}
283
#endif
284
285
/**
286
 * gnutls_x509_trust_list_add_trust_file:
287
 * @list: The list
288
 * @ca_file: A file containing a list of CAs (optional)
289
 * @crl_file: A file containing a list of CRLs (optional)
290
 * @type: The format of the certificates
291
 * @tl_flags: flags from %gnutls_trust_list_flags_t
292
 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
293
 *
294
 * This function will add the given certificate authorities
295
 * to the trusted list. PKCS #11 URLs are also accepted, instead
296
 * of files, by this function. A PKCS #11 URL implies a trust
297
 * database (a specially marked module in p11-kit); the URL "pkcs11:"
298
 * implies all trust databases in the system. Only a single URL specifying
299
 * trust databases can be set; they cannot be stacked with multiple calls.
300
 *
301
 * Returns: The number of added elements is returned.
302
 *
303
 * Since: 3.1
304
 **/
305
int gnutls_x509_trust_list_add_trust_file(gnutls_x509_trust_list_t list,
306
            const char *ca_file,
307
            const char *crl_file,
308
            gnutls_x509_crt_fmt_t type,
309
            unsigned int tl_flags,
310
            unsigned int tl_vflags)
311
0
{
312
0
  gnutls_datum_t cas = { NULL, 0 };
313
0
  gnutls_datum_t crls = { NULL, 0 };
314
0
  size_t size;
315
0
  int ret;
316
317
0
  if (ca_file != NULL) {
318
#ifdef ENABLE_PKCS11
319
    if (c_strncasecmp(ca_file, PKCS11_URL, PKCS11_URL_SIZE) == 0) {
320
      unsigned pcrt_list_size = 0;
321
322
      /* in case of a token URL import it as a PKCS #11 token,
323
       * otherwise import the individual certificates.
324
       */
325
      if (is_pkcs11_url_object(ca_file) != 0) {
326
        return add_trust_list_pkcs11_object_url(
327
          list, ca_file, tl_flags);
328
      } else { /* trusted token */
329
        if (list->pkcs11_token != NULL)
330
          return gnutls_assert_val(
331
            GNUTLS_E_INVALID_REQUEST);
332
        list->pkcs11_token = gnutls_strdup(ca_file);
333
334
        /* enumerate the certificates */
335
        ret = gnutls_pkcs11_obj_list_import_url(
336
          NULL, &pcrt_list_size, ca_file,
337
          (GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE |
338
           GNUTLS_PKCS11_OBJ_FLAG_CRT |
339
           GNUTLS_PKCS11_OBJ_FLAG_MARK_CA |
340
           GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED),
341
          0);
342
        if (ret < 0 &&
343
            ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
344
          return gnutls_assert_val(ret);
345
346
        return pcrt_list_size;
347
      }
348
    } else
349
#endif
350
0
    {
351
0
      cas.data = (void *)read_file(ca_file, RF_BINARY, &size);
352
0
      if (cas.data == NULL) {
353
0
        gnutls_assert();
354
0
        return GNUTLS_E_FILE_ERROR;
355
0
      }
356
0
      cas.size = size;
357
0
    }
358
0
  }
359
360
0
  if (crl_file) {
361
0
    crls.data = (void *)read_file(crl_file, RF_BINARY, &size);
362
0
    if (crls.data == NULL) {
363
0
      gnutls_assert();
364
0
      return GNUTLS_E_FILE_ERROR;
365
0
    }
366
0
    crls.size = size;
367
0
  }
368
369
0
  ret = gnutls_x509_trust_list_add_trust_mem(list, &cas, &crls, type,
370
0
               tl_flags, tl_vflags);
371
0
  free(crls.data);
372
0
  free(cas.data);
373
374
0
  return ret;
375
0
}
376
377
static int load_dir_certs(const char *dirname, gnutls_x509_trust_list_t list,
378
        unsigned int tl_flags, unsigned int tl_vflags,
379
        unsigned type, unsigned crl)
380
0
{
381
0
  int ret;
382
0
  int r = 0;
383
0
  struct gnutls_pathbuf_st pathbuf;
384
385
0
#if !defined(_WIN32) || !defined(_UNICODE)
386
0
  DIR *dirp;
387
0
  struct dirent *d;
388
389
0
  dirp = opendir(dirname);
390
0
  if (dirp != NULL) {
391
0
    size_t base_len;
392
393
0
    ret = _gnutls_pathbuf_init(&pathbuf, dirname);
394
0
    if (ret < 0) {
395
0
      closedir(dirp);
396
0
      return r;
397
0
    }
398
399
0
    base_len = pathbuf.len;
400
0
    while ((d = readdir(dirp)) != NULL) {
401
0
#ifdef _DIRENT_HAVE_D_TYPE
402
0
      switch (d->d_type) {
403
0
      case DT_REG:
404
0
      case DT_LNK:
405
0
      case DT_UNKNOWN:
406
0
        break;
407
0
      default:
408
0
        continue;
409
0
      }
410
0
#endif
411
0
      ret = _gnutls_pathbuf_append(&pathbuf, d->d_name);
412
0
      if (ret < 0) {
413
0
        continue;
414
0
      }
415
0
      if (crl != 0) {
416
0
        ret = gnutls_x509_trust_list_add_trust_file(
417
0
          list, NULL, pathbuf.ptr, type, tl_flags,
418
0
          tl_vflags);
419
0
      } else {
420
0
        ret = gnutls_x509_trust_list_add_trust_file(
421
0
          list, pathbuf.ptr, NULL, type, tl_flags,
422
0
          tl_vflags);
423
0
      }
424
0
      if (ret >= 0) {
425
0
        r += ret;
426
0
      }
427
0
      (void)_gnutls_pathbuf_truncate(&pathbuf, base_len);
428
0
    }
429
0
    _gnutls_pathbuf_deinit(&pathbuf);
430
0
    closedir(dirp);
431
0
  }
432
#else /* _WIN32 */
433
434
  _TDIR *dirp;
435
  struct _tdirent *d;
436
  gnutls_datum_t utf16 = { NULL, 0 };
437
438
#undef UCS2_ENDIAN
439
#ifdef WORDS_BIGENDIAN
440
#define UCS2_ENDIAN 1
441
#else
442
#define UCS2_ENDIAN 0
443
#endif
444
445
  ret = _gnutls_utf8_to_ucs2(dirname, strlen(dirname), &utf16,
446
           UCS2_ENDIAN);
447
  if (ret < 0) {
448
    return gnutls_assert_val(ret);
449
  }
450
  dirp = _topendir((_TCHAR *)utf16.data);
451
  gnutls_free(utf16.data);
452
  if (dirp != NULL) {
453
    size_t base_len;
454
455
    ret = _gnutls_pathbuf_init(&pathbuf, dirname);
456
    if (ret < 0) {
457
      return r;
458
    }
459
460
    base_len = pathbuf.len;
461
    while ((d = _treaddir(dirp)) != NULL) {
462
      gnutls_datum_t utf8 = { NULL, 0 };
463
#ifdef _DIRENT_HAVE_D_TYPE
464
      switch (d->d_type) {
465
      case DT_REG:
466
      case DT_LNK:
467
      case DT_UNKNOWN:
468
        break;
469
      default:
470
        continue;
471
      }
472
#endif
473
      ret = _gnutls_ucs2_to_utf8(
474
        d->d_name, d->d_namlen * sizeof(d->d_name[0]),
475
        &utf8, UCS2_ENDIAN);
476
      if (ret < 0) {
477
        continue;
478
      }
479
      ret = _gnutls_pathbuf_append(&pathbuf, utf8.data);
480
      gnutls_free(utf8.data);
481
      if (ret < 0) {
482
        continue;
483
      }
484
485
      if (crl != 0) {
486
        ret = gnutls_x509_trust_list_add_trust_file(
487
          list, NULL, pathbuf.ptr, type, tl_flags,
488
          tl_vflags);
489
      } else {
490
        ret = gnutls_x509_trust_list_add_trust_file(
491
          list, pathbuf.ptr, NULL, type, tl_flags,
492
          tl_vflags);
493
      }
494
      if (ret >= 0)
495
        r += ret;
496
      (void)_gnutls_pathbuf_truncate(&pathbuf, base_len);
497
    }
498
    _gnutls_pathbuf_deinit(&pathbuf);
499
    _tclosedir(dirp);
500
  }
501
#undef UCS2_ENDIAN
502
#endif /* _WIN32 */
503
0
  return r;
504
0
}
505
506
/**
507
 * gnutls_x509_trust_list_add_trust_dir:
508
 * @list: The list
509
 * @ca_dir: A directory containing the CAs (optional)
510
 * @crl_dir: A directory containing a list of CRLs (optional)
511
 * @type: The format of the certificates
512
 * @tl_flags: flags from %gnutls_trust_list_flags_t
513
 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
514
 *
515
 * This function will add the given certificate authorities
516
 * to the trusted list. Only directories are accepted by
517
 * this function.
518
 *
519
 * Returns: The number of added elements is returned.
520
 *
521
 * Since: 3.3.6
522
 **/
523
int gnutls_x509_trust_list_add_trust_dir(gnutls_x509_trust_list_t list,
524
           const char *ca_dir,
525
           const char *crl_dir,
526
           gnutls_x509_crt_fmt_t type,
527
           unsigned int tl_flags,
528
           unsigned int tl_vflags)
529
0
{
530
0
  int ret = 0;
531
532
0
  if (ca_dir != NULL) {
533
0
    int r = 0;
534
0
    r = load_dir_certs(ca_dir, list, tl_flags, tl_vflags, type, 0);
535
536
0
    if (r >= 0)
537
0
      ret += r;
538
0
  }
539
540
0
  if (crl_dir) {
541
0
    int r = 0;
542
0
    r = load_dir_certs(crl_dir, list, tl_flags, tl_vflags, type, 1);
543
544
0
    if (r >= 0)
545
0
      ret += r;
546
0
  }
547
548
0
  return ret;
549
0
}
550
551
/**
552
 * gnutls_x509_trust_list_remove_trust_file:
553
 * @list: The list
554
 * @ca_file: A file containing a list of CAs
555
 * @type: The format of the certificates
556
 *
557
 * This function will remove the given certificate authorities
558
 * from the trusted list, and add them into a block list when needed. 
559
 * PKCS 11 URLs are also accepted, instead
560
 * of files, by this function.
561
 *
562
 * See also gnutls_x509_trust_list_remove_cas().
563
 *
564
 * Returns: The number of added elements is returned.
565
 *
566
 * Since: 3.1.10
567
 **/
568
int gnutls_x509_trust_list_remove_trust_file(gnutls_x509_trust_list_t list,
569
               const char *ca_file,
570
               gnutls_x509_crt_fmt_t type)
571
0
{
572
0
  gnutls_datum_t cas = { NULL, 0 };
573
0
  size_t size;
574
0
  int ret;
575
576
#ifdef ENABLE_PKCS11
577
  if (c_strncasecmp(ca_file, PKCS11_URL, PKCS11_URL_SIZE) == 0) {
578
    if (is_pkcs11_url_object(ca_file) != 0) {
579
      return remove_pkcs11_object_url(list, ca_file);
580
    } else { /* token */
581
      return remove_pkcs11_url(list, ca_file);
582
    }
583
  } else
584
#endif
585
0
  {
586
0
    cas.data = (void *)read_file(ca_file, RF_BINARY, &size);
587
0
    if (cas.data == NULL) {
588
0
      gnutls_assert();
589
0
      return GNUTLS_E_FILE_ERROR;
590
0
    }
591
0
    cas.size = size;
592
0
  }
593
594
0
  ret = gnutls_x509_trust_list_remove_trust_mem(list, &cas, type);
595
0
  free(cas.data);
596
597
0
  return ret;
598
0
}