Coverage Report

Created: 2024-06-20 06:28

/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 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_reallocarray(NULL, pcrt_list_size,
211
           sizeof(gnutls_x509_crt_t));
212
  if (xcrt_list == NULL) {
213
    ret = GNUTLS_E_MEMORY_ERROR;
214
    goto cleanup;
215
  }
216
217
  ret = gnutls_x509_crt_list_import_pkcs11(xcrt_list, pcrt_list_size,
218
             pcrt_list, 0);
219
  if (ret < 0) {
220
    gnutls_assert();
221
    goto cleanup;
222
  }
223
224
  ret = gnutls_x509_trust_list_add_cas(list, xcrt_list, pcrt_list_size,
225
               flags);
226
227
cleanup:
228
  for (i = 0; i < pcrt_list_size; i++)
229
    gnutls_pkcs11_obj_deinit(pcrt_list[i]);
230
  gnutls_free(pcrt_list);
231
  gnutls_free(xcrt_list);
232
233
  return ret;
234
}
235
236
static int remove_pkcs11_object_url(gnutls_x509_trust_list_t list,
237
            const char *url)
238
{
239
  gnutls_x509_crt_t *xcrt_list = NULL;
240
  gnutls_pkcs11_obj_t *pcrt_list = NULL;
241
  unsigned int pcrt_list_size = 0, i;
242
  int ret;
243
244
  ret = gnutls_pkcs11_obj_list_import_url2(
245
    &pcrt_list, &pcrt_list_size, url,
246
    GNUTLS_PKCS11_OBJ_FLAG_CRT |
247
      GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED,
248
    0);
249
  if (ret < 0)
250
    return gnutls_assert_val(ret);
251
252
  if (pcrt_list_size == 0) {
253
    ret = 0;
254
    goto cleanup;
255
  }
256
257
  xcrt_list = _gnutls_reallocarray(NULL, pcrt_list_size,
258
           sizeof(gnutls_x509_crt_t));
259
  if (xcrt_list == NULL) {
260
    ret = GNUTLS_E_MEMORY_ERROR;
261
    goto cleanup;
262
  }
263
264
  ret = gnutls_x509_crt_list_import_pkcs11(xcrt_list, pcrt_list_size,
265
             pcrt_list, 0);
266
  if (ret < 0) {
267
    gnutls_assert();
268
    goto cleanup;
269
  }
270
271
  ret = gnutls_x509_trust_list_remove_cas(list, xcrt_list,
272
            pcrt_list_size);
273
274
cleanup:
275
  for (i = 0; i < pcrt_list_size; i++) {
276
    gnutls_pkcs11_obj_deinit(pcrt_list[i]);
277
    if (xcrt_list)
278
      gnutls_x509_crt_deinit(xcrt_list[i]);
279
  }
280
  gnutls_free(pcrt_list);
281
  gnutls_free(xcrt_list);
282
283
  return ret;
284
}
285
#endif
286
287
/**
288
 * gnutls_x509_trust_list_add_trust_file:
289
 * @list: The list
290
 * @ca_file: A file containing a list of CAs (optional)
291
 * @crl_file: A file containing a list of CRLs (optional)
292
 * @type: The format of the certificates
293
 * @tl_flags: flags from %gnutls_trust_list_flags_t
294
 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
295
 *
296
 * This function will add the given certificate authorities
297
 * to the trusted list. PKCS #11 URLs are also accepted, instead
298
 * of files, by this function. A PKCS #11 URL implies a trust
299
 * database (a specially marked module in p11-kit); the URL "pkcs11:"
300
 * implies all trust databases in the system. Only a single URL specifying
301
 * trust databases can be set; they cannot be stacked with multiple calls.
302
 *
303
 * Returns: The number of added elements is returned.
304
 *
305
 * Since: 3.1
306
 **/
307
int gnutls_x509_trust_list_add_trust_file(gnutls_x509_trust_list_t list,
308
            const char *ca_file,
309
            const char *crl_file,
310
            gnutls_x509_crt_fmt_t type,
311
            unsigned int tl_flags,
312
            unsigned int tl_vflags)
313
0
{
314
0
  gnutls_datum_t cas = { NULL, 0 };
315
0
  gnutls_datum_t crls = { NULL, 0 };
316
0
  size_t size;
317
0
  int ret;
318
319
0
  if (ca_file != NULL) {
320
#ifdef ENABLE_PKCS11
321
    if (c_strncasecmp(ca_file, PKCS11_URL, PKCS11_URL_SIZE) == 0) {
322
      unsigned pcrt_list_size = 0;
323
324
      /* in case of a token URL import it as a PKCS #11 token,
325
       * otherwise import the individual certificates.
326
       */
327
      if (is_pkcs11_url_object(ca_file) != 0) {
328
        return add_trust_list_pkcs11_object_url(
329
          list, ca_file, tl_flags);
330
      } else { /* trusted token */
331
        if (list->pkcs11_token != NULL)
332
          return gnutls_assert_val(
333
            GNUTLS_E_INVALID_REQUEST);
334
        list->pkcs11_token = gnutls_strdup(ca_file);
335
336
        /* enumerate the certificates */
337
        ret = gnutls_pkcs11_obj_list_import_url(
338
          NULL, &pcrt_list_size, ca_file,
339
          (GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE |
340
           GNUTLS_PKCS11_OBJ_FLAG_CRT |
341
           GNUTLS_PKCS11_OBJ_FLAG_MARK_CA |
342
           GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED),
343
          0);
344
        if (ret < 0 &&
345
            ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
346
          return gnutls_assert_val(ret);
347
348
        return pcrt_list_size;
349
      }
350
    } else
351
#endif
352
0
    {
353
0
      cas.data = (void *)read_file(ca_file, RF_BINARY, &size);
354
0
      if (cas.data == NULL) {
355
0
        gnutls_assert();
356
0
        return GNUTLS_E_FILE_ERROR;
357
0
      }
358
0
      cas.size = size;
359
0
    }
360
0
  }
361
362
0
  if (crl_file) {
363
0
    crls.data = (void *)read_file(crl_file, RF_BINARY, &size);
364
0
    if (crls.data == NULL) {
365
0
      gnutls_assert();
366
0
      return GNUTLS_E_FILE_ERROR;
367
0
    }
368
0
    crls.size = size;
369
0
  }
370
371
0
  ret = gnutls_x509_trust_list_add_trust_mem(list, &cas, &crls, type,
372
0
               tl_flags, tl_vflags);
373
0
  free(crls.data);
374
0
  free(cas.data);
375
376
0
  return ret;
377
0
}
378
379
static int load_dir_certs(const char *dirname, gnutls_x509_trust_list_t list,
380
        unsigned int tl_flags, unsigned int tl_vflags,
381
        unsigned type, unsigned crl)
382
0
{
383
0
  int ret;
384
0
  int r = 0;
385
0
  struct gnutls_pathbuf_st pathbuf;
386
387
0
#if !defined(_WIN32) || !defined(_UNICODE)
388
0
  DIR *dirp;
389
0
  struct dirent *d;
390
391
0
  dirp = opendir(dirname);
392
0
  if (dirp != NULL) {
393
0
    size_t base_len;
394
395
0
    ret = _gnutls_pathbuf_init(&pathbuf, dirname);
396
0
    if (ret < 0) {
397
0
      return r;
398
0
    }
399
400
0
    base_len = pathbuf.len;
401
0
    while ((d = readdir(dirp)) != NULL) {
402
0
#ifdef _DIRENT_HAVE_D_TYPE
403
0
      switch (d->d_type) {
404
0
      case DT_REG:
405
0
      case DT_LNK:
406
0
      case DT_UNKNOWN:
407
0
        break;
408
0
      default:
409
0
        continue;
410
0
      }
411
0
#endif
412
0
      ret = _gnutls_pathbuf_append(&pathbuf, d->d_name);
413
0
      if (ret < 0) {
414
0
        continue;
415
0
      }
416
0
      if (crl != 0) {
417
0
        ret = gnutls_x509_trust_list_add_trust_file(
418
0
          list, NULL, pathbuf.ptr, type, tl_flags,
419
0
          tl_vflags);
420
0
      } else {
421
0
        ret = gnutls_x509_trust_list_add_trust_file(
422
0
          list, pathbuf.ptr, NULL, type, tl_flags,
423
0
          tl_vflags);
424
0
      }
425
0
      if (ret >= 0) {
426
0
        r += ret;
427
0
      }
428
0
      (void)_gnutls_pathbuf_truncate(&pathbuf, base_len);
429
0
    }
430
0
    _gnutls_pathbuf_deinit(&pathbuf);
431
0
    closedir(dirp);
432
0
  }
433
#else /* _WIN32 */
434
435
  _TDIR *dirp;
436
  struct _tdirent *d;
437
  gnutls_datum_t utf16 = { NULL, 0 };
438
439
#undef UCS2_ENDIAN
440
#ifdef WORDS_BIGENDIAN
441
#define UCS2_ENDIAN 1
442
#else
443
#define UCS2_ENDIAN 0
444
#endif
445
446
  ret = _gnutls_utf8_to_ucs2(dirname, strlen(dirname), &utf16,
447
           UCS2_ENDIAN);
448
  if (ret < 0) {
449
    return gnutls_assert_val(ret);
450
  }
451
  dirp = _topendir((_TCHAR *)utf16.data);
452
  gnutls_free(utf16.data);
453
  if (dirp != NULL) {
454
    size_t base_len;
455
456
    ret = _gnutls_pathbuf_init(&pathbuf, dirname);
457
    if (ret < 0) {
458
      return r;
459
    }
460
461
    base_len = pathbuf.len;
462
    while ((d = _treaddir(dirp)) != NULL) {
463
      gnutls_datum_t utf8 = { NULL, 0 };
464
#ifdef _DIRENT_HAVE_D_TYPE
465
      switch (d->d_type) {
466
      case DT_REG:
467
      case DT_LNK:
468
      case DT_UNKNOWN:
469
        break;
470
      default:
471
        continue;
472
      }
473
#endif
474
      ret = _gnutls_ucs2_to_utf8(
475
        d->d_name, d->d_namlen * sizeof(d->d_name[0]),
476
        &utf8, UCS2_ENDIAN);
477
      if (ret < 0) {
478
        continue;
479
      }
480
      ret = _gnutls_pathbuf_append(&pathbuf, utf8.data);
481
      gnutls_free(utf8.data);
482
      if (ret < 0) {
483
        continue;
484
      }
485
486
      if (crl != 0) {
487
        ret = gnutls_x509_trust_list_add_trust_file(
488
          list, NULL, pathbuf.ptr, type, tl_flags,
489
          tl_vflags);
490
      } else {
491
        ret = gnutls_x509_trust_list_add_trust_file(
492
          list, pathbuf.ptr, NULL, type, tl_flags,
493
          tl_vflags);
494
      }
495
      if (ret >= 0)
496
        r += ret;
497
      (void)_gnutls_pathbuf_truncate(&pathbuf, base_len);
498
    }
499
    _gnutls_pathbuf_deinit(&pathbuf);
500
    _tclosedir(dirp);
501
  }
502
#undef UCS2_ENDIAN
503
#endif /* _WIN32 */
504
0
  return r;
505
0
}
506
507
/**
508
 * gnutls_x509_trust_list_add_trust_dir:
509
 * @list: The list
510
 * @ca_dir: A directory containing the CAs (optional)
511
 * @crl_dir: A directory containing a list of CRLs (optional)
512
 * @type: The format of the certificates
513
 * @tl_flags: flags from %gnutls_trust_list_flags_t
514
 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
515
 *
516
 * This function will add the given certificate authorities
517
 * to the trusted list. Only directories are accepted by
518
 * this function.
519
 *
520
 * Returns: The number of added elements is returned.
521
 *
522
 * Since: 3.3.6
523
 **/
524
int gnutls_x509_trust_list_add_trust_dir(gnutls_x509_trust_list_t list,
525
           const char *ca_dir,
526
           const char *crl_dir,
527
           gnutls_x509_crt_fmt_t type,
528
           unsigned int tl_flags,
529
           unsigned int tl_vflags)
530
0
{
531
0
  int ret = 0;
532
533
0
  if (ca_dir != NULL) {
534
0
    int r = 0;
535
0
    r = load_dir_certs(ca_dir, list, tl_flags, tl_vflags, type, 0);
536
537
0
    if (r >= 0)
538
0
      ret += r;
539
0
  }
540
541
0
  if (crl_dir) {
542
0
    int r = 0;
543
0
    r = load_dir_certs(crl_dir, list, tl_flags, tl_vflags, type, 1);
544
545
0
    if (r >= 0)
546
0
      ret += r;
547
0
  }
548
549
0
  return ret;
550
0
}
551
552
/**
553
 * gnutls_x509_trust_list_remove_trust_file:
554
 * @list: The list
555
 * @ca_file: A file containing a list of CAs
556
 * @type: The format of the certificates
557
 *
558
 * This function will remove the given certificate authorities
559
 * from the trusted list, and add them into a block list when needed. 
560
 * PKCS 11 URLs are also accepted, instead
561
 * of files, by this function.
562
 *
563
 * See also gnutls_x509_trust_list_remove_cas().
564
 *
565
 * Returns: The number of added elements is returned.
566
 *
567
 * Since: 3.1.10
568
 **/
569
int gnutls_x509_trust_list_remove_trust_file(gnutls_x509_trust_list_t list,
570
               const char *ca_file,
571
               gnutls_x509_crt_fmt_t type)
572
0
{
573
0
  gnutls_datum_t cas = { NULL, 0 };
574
0
  size_t size;
575
0
  int ret;
576
577
#ifdef ENABLE_PKCS11
578
  if (c_strncasecmp(ca_file, PKCS11_URL, PKCS11_URL_SIZE) == 0) {
579
    if (is_pkcs11_url_object(ca_file) != 0) {
580
      return remove_pkcs11_object_url(list, ca_file);
581
    } else { /* token */
582
      return remove_pkcs11_url(list, ca_file);
583
    }
584
  } else
585
#endif
586
0
  {
587
0
    cas.data = (void *)read_file(ca_file, RF_BINARY, &size);
588
0
    if (cas.data == NULL) {
589
0
      gnutls_assert();
590
0
      return GNUTLS_E_FILE_ERROR;
591
0
    }
592
0
    cas.size = size;
593
0
  }
594
595
0
  ret = gnutls_x509_trust_list_remove_trust_mem(list, &cas, type);
596
0
  free(cas.data);
597
598
0
  return ret;
599
0
}