Coverage Report

Created: 2023-03-26 07:33

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