Coverage Report

Created: 2025-03-06 07:58

/src/gnutls/lib/x509/name_constraints.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2014-2016 Free Software Foundation, Inc.
3
 * Copyright (C) 2016 Red Hat, Inc.
4
 *
5
 * Authors: Nikos Mavrogiannopoulos, Daiki Ueno, Martin Ukrop
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
/* Functions on X.509 Certificate parsing
25
 */
26
27
#include "gnutls_int.h"
28
#include "datum.h"
29
#include "global.h"
30
#include "errors.h"
31
#include "common.h"
32
#include "x509.h"
33
#include <gnutls/x509-ext.h>
34
#include "x509_b64.h"
35
#include "x509_int.h"
36
#include "x509_ext_int.h"
37
#include <libtasn1.h>
38
39
#include "ip.h"
40
#include "ip-in-cidr.h"
41
#include "intprops.h"
42
43
0
#define MAX_NC_CHECKS (1 << 20)
44
45
struct name_constraints_node_st {
46
  unsigned type;
47
  gnutls_datum_t name;
48
};
49
50
struct name_constraints_node_list_st {
51
  struct name_constraints_node_st **data;
52
  size_t size;
53
  size_t capacity;
54
};
55
56
struct gnutls_name_constraints_st {
57
  struct name_constraints_node_list_st nodes; /* owns elements */
58
  struct name_constraints_node_list_st permitted; /* borrows elements */
59
  struct name_constraints_node_list_st excluded; /* borrows elements */
60
};
61
62
static struct name_constraints_node_st *
63
name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type,
64
        unsigned char *data, unsigned int size);
65
66
static int
67
name_constraints_node_list_add(struct name_constraints_node_list_st *list,
68
             struct name_constraints_node_st *node)
69
0
{
70
0
  if (!list->capacity || list->size == list->capacity) {
71
0
    size_t new_capacity = list->capacity;
72
0
    struct name_constraints_node_st **new_data;
73
74
0
    if (!INT_MULTIPLY_OK(new_capacity, 2, &new_capacity) ||
75
0
        !INT_ADD_OK(new_capacity, 1, &new_capacity))
76
0
      return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
77
0
    new_data = _gnutls_reallocarray(
78
0
      list->data, new_capacity,
79
0
      sizeof(struct name_constraints_node_st *));
80
0
    if (!new_data)
81
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
82
0
    list->capacity = new_capacity;
83
0
    list->data = new_data;
84
0
  }
85
0
  list->data[list->size++] = node;
86
0
  return 0;
87
0
}
88
89
// for documentation see the implementation
90
static int name_constraints_intersect_nodes(
91
  gnutls_x509_name_constraints_t nc,
92
  const struct name_constraints_node_st *node1,
93
  const struct name_constraints_node_st *node2,
94
  struct name_constraints_node_st **intersection);
95
96
/*-
97
 * _gnutls_x509_name_constraints_is_empty:
98
 * @nc: name constraints structure
99
 * @type: type (gnutls_x509_subject_alt_name_t or 0)
100
 *
101
 * Test whether given name constraints structure has any constraints (permitted
102
 * or excluded) of a given type. @nc must be allocated (not NULL) before the call.
103
 * If @type is 0, type checking will be skipped.
104
 *
105
 * Returns: false if @nc contains constraints of type @type, true otherwise
106
 -*/
107
bool _gnutls_x509_name_constraints_is_empty(gnutls_x509_name_constraints_t nc,
108
              unsigned type)
109
0
{
110
0
  if (nc->permitted.size == 0 && nc->excluded.size == 0)
111
0
    return true;
112
113
0
  if (type == 0)
114
0
    return false;
115
116
0
  for (size_t i = 0; i < nc->permitted.size; i++) {
117
0
    if (nc->permitted.data[i]->type == type)
118
0
      return false;
119
0
  }
120
121
0
  for (size_t i = 0; i < nc->excluded.size; i++) {
122
0
    if (nc->excluded.data[i]->type == type)
123
0
      return false;
124
0
  }
125
126
  /* no constraint for that type exists */
127
0
  return true;
128
0
}
129
130
/*-
131
 * validate_name_constraints_node:
132
 * @type: type of name constraints
133
 * @name: datum of name constraint
134
 *
135
 * Check the validity of given name constraints node (@type and @name).
136
 * The supported types are GNUTLS_SAN_DNSNAME, GNUTLS_SAN_RFC822NAME,
137
 * GNUTLS_SAN_DN, GNUTLS_SAN_URI and GNUTLS_SAN_IPADDRESS.
138
 *
139
 * CIDR ranges are checked for correct length (IPv4/IPv6) and correct mask format.
140
 *
141
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
142
 -*/
143
static int validate_name_constraints_node(gnutls_x509_subject_alt_name_t type,
144
            const gnutls_datum_t *name)
145
0
{
146
0
  if (type != GNUTLS_SAN_DNSNAME && type != GNUTLS_SAN_RFC822NAME &&
147
0
      type != GNUTLS_SAN_DN && type != GNUTLS_SAN_URI &&
148
0
      type != GNUTLS_SAN_IPADDRESS &&
149
0
      type != GNUTLS_SAN_OTHERNAME_MSUSERPRINCIPAL) {
150
0
    return gnutls_assert_val(GNUTLS_E_X509_UNKNOWN_SAN);
151
0
  }
152
153
0
  if (type == GNUTLS_SAN_IPADDRESS) {
154
0
    if (name->size != 8 && name->size != 32)
155
0
      return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
156
0
    int prefix = _gnutls_mask_to_prefix(name->data + name->size / 2,
157
0
                name->size / 2);
158
0
    if (prefix < 0)
159
0
      return gnutls_assert_val(GNUTLS_E_MALFORMED_CIDR);
160
0
  }
161
162
0
  return GNUTLS_E_SUCCESS;
163
0
}
164
165
static int extract_name_constraints(gnutls_x509_name_constraints_t nc,
166
            asn1_node c2, const char *vstr,
167
            struct name_constraints_node_list_st *nodes)
168
0
{
169
0
  int ret;
170
0
  char tmpstr[128];
171
0
  unsigned indx;
172
0
  gnutls_datum_t tmp = { NULL, 0 };
173
0
  unsigned int type;
174
0
  struct name_constraints_node_st *node;
175
176
0
  for (indx = 1;; indx++) {
177
0
    snprintf(tmpstr, sizeof(tmpstr), "%s.?%u.base", vstr, indx);
178
179
0
    ret = _gnutls_parse_general_name2(c2, tmpstr, -1, &tmp, &type,
180
0
              0);
181
182
0
    if (ret < 0) {
183
0
      gnutls_assert();
184
0
      break;
185
0
    }
186
187
0
    if (type == GNUTLS_SAN_OTHERNAME) {
188
0
      gnutls_datum_t oid = { NULL, 0 };
189
0
      gnutls_datum_t parsed_othername = { NULL, 0 };
190
0
      ret = _gnutls_parse_general_name2(c2, tmpstr, -1, &oid,
191
0
                &type, 1);
192
0
      if (ret < 0) {
193
0
        gnutls_assert();
194
0
        goto cleanup;
195
0
      }
196
197
0
      ret = gnutls_x509_othername_to_virtual(
198
0
        (char *)oid.data, &tmp, &type,
199
0
        &parsed_othername);
200
0
      if (ret < 0) {
201
0
        gnutls_assert();
202
0
        goto cleanup;
203
0
      }
204
205
0
      gnutls_free(oid.data);
206
0
      gnutls_free(tmp.data);
207
208
0
      memcpy(&tmp, &parsed_othername, sizeof(gnutls_datum_t));
209
0
    }
210
211
0
    ret = validate_name_constraints_node(type, &tmp);
212
0
    if (ret < 0) {
213
0
      gnutls_assert();
214
0
      goto cleanup;
215
0
    }
216
217
0
    node = name_constraints_node_new(nc, type, tmp.data, tmp.size);
218
0
    _gnutls_free_datum(&tmp);
219
0
    if (node == NULL) {
220
0
      gnutls_assert();
221
0
      ret = GNUTLS_E_MEMORY_ERROR;
222
0
      goto cleanup;
223
0
    }
224
225
0
    ret = name_constraints_node_list_add(nodes, node);
226
0
    if (ret < 0) {
227
0
      gnutls_assert();
228
0
      goto cleanup;
229
0
    }
230
0
  }
231
232
0
  assert(ret < 0);
233
0
  if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
234
0
    gnutls_assert();
235
0
    goto cleanup;
236
0
  }
237
238
0
  ret = 0;
239
0
cleanup:
240
0
  gnutls_free(tmp.data);
241
0
  return ret;
242
0
}
243
244
int _gnutls_x509_name_constraints_extract(asn1_node c2,
245
            const char *permitted_name,
246
            const char *excluded_name,
247
            gnutls_x509_name_constraints_t nc)
248
0
{
249
0
  int ret;
250
251
0
  ret = extract_name_constraints(nc, c2, permitted_name, &nc->permitted);
252
0
  if (ret < 0)
253
0
    return gnutls_assert_val(ret);
254
0
  ret = extract_name_constraints(nc, c2, excluded_name, &nc->excluded);
255
0
  if (ret < 0)
256
0
    return gnutls_assert_val(ret);
257
258
0
  return ret;
259
0
}
260
261
/*-
262
 * name_constraints_node_free:
263
 * @node: name constraints node
264
 *
265
 * Deallocate a name constraints node.
266
 -*/
267
static void name_constraints_node_free(struct name_constraints_node_st *node)
268
0
{
269
0
  if (node) {
270
0
    gnutls_free(node->name.data);
271
0
    gnutls_free(node);
272
0
  }
273
0
}
274
275
/*-
276
 * name_constraints_node_new:
277
 * @type: name constraints type to set (gnutls_x509_subject_alt_name_t)
278
 * @nc: a %gnutls_x509_name_constraints_t
279
 * @data: name.data to set or NULL
280
 * @size: name.size to set
281
 *
282
 * Allocate a new name constraints node and set its type, name size and name data.
283
 *
284
 * Returns: Pointer to newly allocated node or NULL in case of memory error.
285
 -*/
286
static struct name_constraints_node_st *
287
name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type,
288
        unsigned char *data, unsigned int size)
289
0
{
290
0
  struct name_constraints_node_st *tmp;
291
0
  int ret;
292
293
0
  tmp = gnutls_calloc(1, sizeof(struct name_constraints_node_st));
294
0
  if (tmp == NULL)
295
0
    return NULL;
296
0
  tmp->type = type;
297
298
0
  if (data) {
299
0
    ret = _gnutls_set_strdatum(&tmp->name, data, size);
300
0
    if (ret < 0) {
301
0
      gnutls_assert();
302
0
      gnutls_free(tmp);
303
0
      return NULL;
304
0
    }
305
0
  }
306
307
0
  ret = name_constraints_node_list_add(&nc->nodes, tmp);
308
0
  if (ret < 0) {
309
0
    gnutls_assert();
310
0
    name_constraints_node_free(tmp);
311
0
    return NULL;
312
0
  }
313
314
0
  return tmp;
315
0
}
316
317
/*-
318
 * @brief name_constraints_node_list_intersect:
319
 * @nc: %gnutls_x509_name_constraints_t
320
 * @permitted: first name constraints list (permitted)
321
 * @permitted2: name constraints list to merge with (permitted)
322
 * @excluded: Corresponding excluded name constraints list
323
 *
324
 * This function finds the intersection of @permitted and @permitted2. The result is placed in @permitted,
325
 * the original @permitted is modified. @permitted2 is not changed. If necessary, a universal
326
 * excluded name constraint node of the right type is added to the list provided
327
 * in @excluded.
328
 *
329
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
330
 -*/
331
static int name_constraints_node_list_intersect(
332
  gnutls_x509_name_constraints_t nc,
333
  struct name_constraints_node_list_st *permitted,
334
  const struct name_constraints_node_list_st *permitted2,
335
  struct name_constraints_node_list_st *excluded)
336
0
{
337
0
  struct name_constraints_node_st *tmp;
338
0
  int ret, type, used;
339
0
  struct name_constraints_node_list_st removed = { .data = NULL,
340
0
               .size = 0,
341
0
               .capacity = 0 };
342
343
  /* temporary array to see, if we need to add universal excluded constraints
344
   * (see phase 3 for details)
345
   * indexed directly by (gnutls_x509_subject_alt_name_t enum - 1) */
346
0
  unsigned char types_with_empty_intersection[GNUTLS_SAN_MAX];
347
0
  memset(types_with_empty_intersection, 0,
348
0
         sizeof(types_with_empty_intersection));
349
350
0
  if (permitted->size == 0 || permitted2->size == 0)
351
0
    return 0;
352
353
  /* Phase 1
354
   * For each name in PERMITTED, if a PERMITTED2 does not contain a name
355
   * with the same type, move the original name to REMOVED.
356
   * Do this also for node of unknown type (not DNS, email, IP) */
357
0
  for (size_t i = 0; i < permitted->size;) {
358
0
    struct name_constraints_node_st *t = permitted->data[i];
359
0
    const struct name_constraints_node_st *found = NULL;
360
361
0
    for (size_t j = 0; j < permitted2->size; j++) {
362
0
      const struct name_constraints_node_st *t2 =
363
0
        permitted2->data[j];
364
0
      if (t->type == t2->type) {
365
        // check bounds (we will use 't->type' as index)
366
0
        if (t->type > GNUTLS_SAN_MAX || t->type == 0) {
367
0
          gnutls_assert();
368
0
          ret = GNUTLS_E_INTERNAL_ERROR;
369
0
          goto cleanup;
370
0
        }
371
        // note the possibility of empty intersection for this type
372
        // if we add something to the intersection in phase 2,
373
        // we will reset this flag back to 0 then
374
0
        types_with_empty_intersection[t->type - 1] = 1;
375
0
        found = t2;
376
0
        break;
377
0
      }
378
0
    }
379
380
0
    if (found != NULL && (t->type == GNUTLS_SAN_DNSNAME ||
381
0
              t->type == GNUTLS_SAN_RFC822NAME ||
382
0
              t->type == GNUTLS_SAN_IPADDRESS)) {
383
      /* move node from PERMITTED to REMOVED */
384
0
      ret = name_constraints_node_list_add(&removed, t);
385
0
      if (ret < 0) {
386
0
        gnutls_assert();
387
0
        goto cleanup;
388
0
      }
389
      /* remove node by swapping */
390
0
      if (i < permitted->size - 1)
391
0
        permitted->data[i] =
392
0
          permitted->data[permitted->size - 1];
393
0
      permitted->size--;
394
0
      continue;
395
0
    }
396
0
    i++;
397
0
  }
398
399
  /* Phase 2
400
   * iterate through all combinations from PERMITTED2 and PERMITTED
401
   * and create intersections of nodes with same type */
402
0
  for (size_t i = 0; i < permitted2->size; i++) {
403
0
    const struct name_constraints_node_st *t2 = permitted2->data[i];
404
405
    // current PERMITTED2 node has not yet been used for any intersection
406
    // (and is not in REMOVED either)
407
0
    used = 0;
408
0
    for (size_t j = 0; j < removed.size; j++) {
409
0
      const struct name_constraints_node_st *t =
410
0
        removed.data[j];
411
      // save intersection of name constraints into tmp
412
0
      ret = name_constraints_intersect_nodes(nc, t, t2, &tmp);
413
0
      if (ret < 0) {
414
0
        gnutls_assert();
415
0
        goto cleanup;
416
0
      }
417
0
      used = 1;
418
      // if intersection is not empty
419
0
      if (tmp !=
420
0
          NULL) { // intersection for this type is not empty
421
        // check bounds
422
0
        if (tmp->type > GNUTLS_SAN_MAX ||
423
0
            tmp->type == 0) {
424
0
          gnutls_free(tmp);
425
0
          return gnutls_assert_val(
426
0
            GNUTLS_E_INTERNAL_ERROR);
427
0
        }
428
        // we will not add universal excluded constraint for this type
429
0
        types_with_empty_intersection[tmp->type - 1] =
430
0
          0;
431
        // add intersection node to PERMITTED
432
0
        ret = name_constraints_node_list_add(permitted,
433
0
                     tmp);
434
0
        if (ret < 0) {
435
0
          gnutls_assert();
436
0
          goto cleanup;
437
0
        }
438
0
      }
439
0
    }
440
    // if the node from PERMITTED2 was not used for intersection, copy it to DEST
441
    // Beware: also copies nodes other than DNS, email, IP,
442
    //       since their counterpart may have been moved in phase 1.
443
0
    if (!used) {
444
0
      tmp = name_constraints_node_new(
445
0
        nc, t2->type, t2->name.data, t2->name.size);
446
0
      if (tmp == NULL) {
447
0
        gnutls_assert();
448
0
        ret = GNUTLS_E_MEMORY_ERROR;
449
0
        goto cleanup;
450
0
      }
451
0
      ret = name_constraints_node_list_add(permitted, tmp);
452
0
      if (ret < 0) {
453
0
        gnutls_assert();
454
0
        goto cleanup;
455
0
      }
456
0
    }
457
0
  }
458
459
  /* Phase 3
460
   * For each type: If we have empty permitted name constraints now
461
   * and we didn't have at the beginning, we have to add a new
462
   * excluded constraint with universal wildcard
463
   * (since the intersection of permitted is now empty). */
464
0
  for (type = 1; type <= GNUTLS_SAN_MAX; type++) {
465
0
    if (types_with_empty_intersection[type - 1] == 0)
466
0
      continue;
467
0
    _gnutls_hard_log(
468
0
      "Adding universal excluded name constraint for type %d.\n",
469
0
      type);
470
0
    switch (type) {
471
0
    case GNUTLS_SAN_IPADDRESS:
472
      // add universal restricted range for IPv4
473
0
      tmp = name_constraints_node_new(
474
0
        nc, GNUTLS_SAN_IPADDRESS, NULL, 8);
475
0
      if (tmp == NULL) {
476
0
        gnutls_assert();
477
0
        ret = GNUTLS_E_MEMORY_ERROR;
478
0
        goto cleanup;
479
0
      }
480
0
      ret = name_constraints_node_list_add(excluded, tmp);
481
0
      if (ret < 0) {
482
0
        gnutls_assert();
483
0
        goto cleanup;
484
0
      }
485
      // add universal restricted range for IPv6
486
0
      tmp = name_constraints_node_new(
487
0
        nc, GNUTLS_SAN_IPADDRESS, NULL, 32);
488
0
      if (tmp == NULL) {
489
0
        gnutls_assert();
490
0
        ret = GNUTLS_E_MEMORY_ERROR;
491
0
        goto cleanup;
492
0
      }
493
0
      ret = name_constraints_node_list_add(excluded, tmp);
494
0
      if (ret < 0) {
495
0
        gnutls_assert();
496
0
        goto cleanup;
497
0
      }
498
0
      break;
499
0
    case GNUTLS_SAN_DNSNAME:
500
0
    case GNUTLS_SAN_RFC822NAME:
501
0
      tmp = name_constraints_node_new(nc, type, NULL, 0);
502
0
      if (tmp == NULL) {
503
0
        gnutls_assert();
504
0
        ret = GNUTLS_E_MEMORY_ERROR;
505
0
        goto cleanup;
506
0
      }
507
0
      ret = name_constraints_node_list_add(excluded, tmp);
508
0
      if (ret < 0) {
509
0
        gnutls_assert();
510
0
        goto cleanup;
511
0
      }
512
0
      break;
513
0
    default: // do nothing, at least one node was already moved in phase 1
514
0
      break;
515
0
    }
516
0
  }
517
0
  ret = GNUTLS_E_SUCCESS;
518
519
0
cleanup:
520
0
  gnutls_free(removed.data);
521
0
  return ret;
522
0
}
523
524
static int name_constraints_node_list_concat(
525
  gnutls_x509_name_constraints_t nc,
526
  struct name_constraints_node_list_st *nodes,
527
  const struct name_constraints_node_list_st *nodes2)
528
0
{
529
0
  for (size_t i = 0; i < nodes2->size; i++) {
530
0
    const struct name_constraints_node_st *node = nodes2->data[i];
531
0
    struct name_constraints_node_st *tmp;
532
0
    int ret;
533
534
0
    tmp = name_constraints_node_new(nc, node->type, node->name.data,
535
0
            node->name.size);
536
0
    if (tmp == NULL) {
537
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
538
0
    }
539
0
    ret = name_constraints_node_list_add(nodes, tmp);
540
0
    if (ret < 0) {
541
0
      name_constraints_node_free(tmp);
542
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
543
0
    }
544
0
  }
545
546
0
  return 0;
547
0
}
548
549
/**
550
 * gnutls_x509_crt_get_name_constraints:
551
 * @crt: should contain a #gnutls_x509_crt_t type
552
 * @nc: The nameconstraints intermediate type
553
 * @flags: zero or %GNUTLS_EXT_FLAG_APPEND
554
 * @critical: the extension status
555
 *
556
 * This function will return an intermediate type containing
557
 * the name constraints of the provided CA certificate. That
558
 * structure can be used in combination with gnutls_x509_name_constraints_check()
559
 * to verify whether a server's name is in accordance with the constraints.
560
 *
561
 * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND,
562
 * then if the @nc structure is empty this function will behave
563
 * identically as if the flag was not set.
564
 * Otherwise if there are elements in the @nc structure then the
565
 * constraints will be merged with the existing constraints following
566
 * RFC5280 p6.1.4 (excluded constraints will be appended, permitted
567
 * will be intersected).
568
 *
569
 * Note that @nc must be initialized prior to calling this function.
570
 *
571
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
572
 * if the extension is not present, otherwise a negative error value.
573
 *
574
 * Since: 3.3.0
575
 **/
576
int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
577
           gnutls_x509_name_constraints_t nc,
578
           unsigned int flags,
579
           unsigned int *critical)
580
0
{
581
0
  int ret;
582
0
  gnutls_datum_t der = { NULL, 0 };
583
584
0
  if (crt == NULL) {
585
0
    gnutls_assert();
586
0
    return GNUTLS_E_INVALID_REQUEST;
587
0
  }
588
589
0
  ret = _gnutls_x509_crt_get_extension(crt, "2.5.29.30", 0, &der,
590
0
               critical);
591
0
  if (ret < 0)
592
0
    return gnutls_assert_val(ret);
593
594
0
  if (der.size == 0 || der.data == NULL)
595
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
596
597
0
  ret = gnutls_x509_ext_import_name_constraints(&der, nc, flags);
598
0
  if (ret < 0) {
599
0
    gnutls_assert();
600
0
    goto cleanup;
601
0
  }
602
603
0
  ret = 0;
604
605
0
cleanup:
606
0
  _gnutls_free_datum(&der);
607
608
0
  return ret;
609
0
}
610
611
void _gnutls_x509_name_constraints_clear(gnutls_x509_name_constraints_t nc)
612
0
{
613
0
  for (size_t i = 0; i < nc->nodes.size; i++) {
614
0
    struct name_constraints_node_st *node = nc->nodes.data[i];
615
0
    name_constraints_node_free(node);
616
0
  }
617
0
  gnutls_free(nc->nodes.data);
618
0
  nc->nodes.capacity = 0;
619
0
  nc->nodes.size = 0;
620
621
0
  gnutls_free(nc->permitted.data);
622
0
  nc->permitted.capacity = 0;
623
0
  nc->permitted.size = 0;
624
625
0
  gnutls_free(nc->excluded.data);
626
0
  nc->excluded.capacity = 0;
627
0
  nc->excluded.size = 0;
628
0
}
629
630
/**
631
 * gnutls_x509_name_constraints_deinit:
632
 * @nc: The nameconstraints
633
 *
634
 * This function will deinitialize a name constraints type.
635
 *
636
 * Since: 3.3.0
637
 **/
638
void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc)
639
0
{
640
0
  _gnutls_x509_name_constraints_clear(nc);
641
0
  gnutls_free(nc);
642
0
}
643
644
/**
645
 * gnutls_x509_name_constraints_init:
646
 * @nc: The nameconstraints
647
 *
648
 * This function will initialize a name constraints type.
649
 *
650
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
651
 *
652
 * Since: 3.3.0
653
 **/
654
int gnutls_x509_name_constraints_init(gnutls_x509_name_constraints_t *nc)
655
0
{
656
0
  struct gnutls_name_constraints_st *tmp;
657
658
0
  tmp = gnutls_calloc(1, sizeof(struct gnutls_name_constraints_st));
659
0
  if (tmp == NULL) {
660
0
    gnutls_assert();
661
0
    return GNUTLS_E_MEMORY_ERROR;
662
0
  }
663
664
0
  *nc = tmp;
665
0
  return 0;
666
0
}
667
668
static int name_constraints_add(gnutls_x509_name_constraints_t nc,
669
        gnutls_x509_subject_alt_name_t type,
670
        const gnutls_datum_t *name, unsigned permitted)
671
0
{
672
0
  struct name_constraints_node_st *tmp;
673
0
  struct name_constraints_node_list_st *nodes;
674
0
  int ret;
675
676
0
  ret = validate_name_constraints_node(type, name);
677
0
  if (ret < 0)
678
0
    return gnutls_assert_val(ret);
679
680
0
  nodes = permitted ? &nc->permitted : &nc->excluded;
681
682
0
  tmp = name_constraints_node_new(nc, type, name->data, name->size);
683
0
  if (tmp == NULL)
684
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
685
686
0
  ret = name_constraints_node_list_add(nodes, tmp);
687
0
  if (ret < 0) {
688
0
    name_constraints_node_free(tmp);
689
0
    return gnutls_assert_val(ret);
690
0
  }
691
692
0
  return 0;
693
0
}
694
695
/*-
696
 * _gnutls_x509_name_constraints_merge:
697
 * @nc: The nameconstraints
698
 * @nc2: The name constraints to be merged with
699
 *
700
 * This function will merge the provided name constraints structures
701
 * as per RFC5280 p6.1.4. That is, the excluded constraints will be appended,
702
 * and permitted will be intersected. The intersection assumes that @nc
703
 * is the root CA constraints.
704
 *
705
 * The merged constraints will be placed in @nc.
706
 *
707
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
708
 *
709
 * Since: 3.5.0
710
 -*/
711
int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc,
712
          gnutls_x509_name_constraints_t nc2)
713
0
{
714
0
  int ret;
715
716
0
  ret = name_constraints_node_list_intersect(
717
0
    nc, &nc->permitted, &nc2->permitted, &nc->excluded);
718
0
  if (ret < 0) {
719
0
    gnutls_assert();
720
0
    return ret;
721
0
  }
722
723
0
  ret = name_constraints_node_list_concat(nc, &nc->excluded,
724
0
            &nc2->excluded);
725
0
  if (ret < 0) {
726
0
    gnutls_assert();
727
0
    return ret;
728
0
  }
729
730
0
  return 0;
731
0
}
732
733
/**
734
 * gnutls_x509_name_constraints_add_permitted:
735
 * @nc: The nameconstraints
736
 * @type: The type of the constraints
737
 * @name: The data of the constraints
738
 *
739
 * This function will add a name constraint to the list of permitted
740
 * constraints. The constraints @type can be any of the following types:
741
 * %GNUTLS_SAN_DNSNAME, %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DN,
742
 * %GNUTLS_SAN_URI, %GNUTLS_SAN_IPADDRESS. For the latter, an IP address
743
 * in network byte order is expected, followed by its network mask.
744
 *
745
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
746
 *
747
 * Since: 3.3.0
748
 **/
749
int gnutls_x509_name_constraints_add_permitted(
750
  gnutls_x509_name_constraints_t nc, gnutls_x509_subject_alt_name_t type,
751
  const gnutls_datum_t *name)
752
0
{
753
0
  return name_constraints_add(nc, type, name, 1);
754
0
}
755
756
/**
757
 * gnutls_x509_name_constraints_add_excluded:
758
 * @nc: The nameconstraints
759
 * @type: The type of the constraints
760
 * @name: The data of the constraints
761
 *
762
 * This function will add a name constraint to the list of excluded
763
 * constraints. The constraints @type can be any of the following types:
764
 * %GNUTLS_SAN_DNSNAME, %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DN,
765
 * %GNUTLS_SAN_URI, %GNUTLS_SAN_IPADDRESS. For the latter, an IP address
766
 * in network byte order is expected, followed by its network mask (which is
767
 * 4 bytes in IPv4 or 16-bytes in IPv6).
768
 *
769
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
770
 *
771
 * Since: 3.3.0
772
 **/
773
int gnutls_x509_name_constraints_add_excluded(
774
  gnutls_x509_name_constraints_t nc, gnutls_x509_subject_alt_name_t type,
775
  const gnutls_datum_t *name)
776
0
{
777
0
  return name_constraints_add(nc, type, name, 0);
778
0
}
779
780
/**
781
 * gnutls_x509_crt_set_name_constraints:
782
 * @crt: The certificate
783
 * @nc: The nameconstraints structure
784
 * @critical: whether this extension will be critical
785
 *
786
 * This function will set the provided name constraints to
787
 * the certificate extension list. This extension is always
788
 * marked as critical.
789
 *
790
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
791
 *
792
 * Since: 3.3.0
793
 **/
794
int gnutls_x509_crt_set_name_constraints(gnutls_x509_crt_t crt,
795
           gnutls_x509_name_constraints_t nc,
796
           unsigned int critical)
797
0
{
798
0
  int ret;
799
0
  gnutls_datum_t der;
800
801
0
  ret = gnutls_x509_ext_export_name_constraints(nc, &der);
802
0
  if (ret < 0)
803
0
    return gnutls_assert_val(ret);
804
805
0
  ret = _gnutls_x509_crt_set_extension(crt, "2.5.29.30", &der, critical);
806
0
  if (ret < 0) {
807
0
    gnutls_assert();
808
0
    goto cleanup;
809
0
  }
810
811
0
  ret = 0;
812
0
  crt->use_extensions = 1;
813
814
0
cleanup:
815
0
  _gnutls_free_datum(&der);
816
0
  return ret;
817
0
}
818
819
static unsigned ends_with(const gnutls_datum_t *str,
820
        const gnutls_datum_t *suffix)
821
0
{
822
0
  unsigned char *tree;
823
0
  unsigned int treelen;
824
825
0
  if (suffix->size >= str->size)
826
0
    return 0;
827
828
0
  tree = suffix->data;
829
0
  treelen = suffix->size;
830
0
  if ((treelen > 0) && (tree[0] == '.')) {
831
0
    tree++;
832
0
    treelen--;
833
0
  }
834
835
0
  if (memcmp(str->data + str->size - treelen, tree, treelen) == 0 &&
836
0
      str->data[str->size - treelen - 1] == '.')
837
0
    return 1; /* match */
838
839
0
  return 0;
840
0
}
841
842
static unsigned email_ends_with(const gnutls_datum_t *str,
843
        const gnutls_datum_t *suffix)
844
0
{
845
0
  if (suffix->size >= str->size) {
846
0
    return 0;
847
0
  }
848
849
0
  if (suffix->size > 0 && memcmp(str->data + str->size - suffix->size,
850
0
               suffix->data, suffix->size) != 0) {
851
0
    return 0;
852
0
  }
853
854
0
  if (suffix->size > 1 && suffix->data[0] == '.') { /* .domain.com */
855
0
    return 1; /* match */
856
0
  } else if (str->data[str->size - suffix->size - 1] == '@') {
857
0
    return 1; /* match */
858
0
  }
859
860
0
  return 0;
861
0
}
862
863
static unsigned dnsname_matches(const gnutls_datum_t *name,
864
        const gnutls_datum_t *suffix)
865
0
{
866
0
  _gnutls_hard_log("matching %.*s with DNS constraint %.*s\n", name->size,
867
0
       name->data, suffix->size, suffix->data);
868
869
0
  if (suffix->size == name->size &&
870
0
      memcmp(suffix->data, name->data, suffix->size) == 0)
871
0
    return 1; /* match */
872
873
0
  return ends_with(name, suffix);
874
0
}
875
876
static unsigned email_matches(const gnutls_datum_t *name,
877
            const gnutls_datum_t *suffix)
878
0
{
879
0
  _gnutls_hard_log("matching %.*s with e-mail constraint %.*s\n",
880
0
       name->size, name->data, suffix->size, suffix->data);
881
882
0
  if (suffix->size == name->size &&
883
0
      memcmp(suffix->data, name->data, suffix->size) == 0)
884
0
    return 1; /* match */
885
886
0
  return email_ends_with(name, suffix);
887
0
}
888
889
/*-
890
 * name_constraints_intersect_nodes:
891
 * @nc1: name constraints node 1
892
 * @nc2: name constraints node 2
893
 * @_intersection: newly allocated node with intersected constraints,
894
 *     NULL if the intersection is empty
895
 *
896
 * Inspect 2 name constraints nodes (of possibly different types) and allocate
897
 * a new node with intersection of given constraints.
898
 *
899
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
900
 -*/
901
static int name_constraints_intersect_nodes(
902
  gnutls_x509_name_constraints_t nc,
903
  const struct name_constraints_node_st *node1,
904
  const struct name_constraints_node_st *node2,
905
  struct name_constraints_node_st **_intersection)
906
0
{
907
  // presume empty intersection
908
0
  struct name_constraints_node_st *intersection = NULL;
909
0
  const struct name_constraints_node_st *to_copy = NULL;
910
0
  unsigned iplength = 0;
911
0
  unsigned byte;
912
913
0
  *_intersection = NULL;
914
915
0
  if (node1->type != node2->type) {
916
0
    return GNUTLS_E_SUCCESS;
917
0
  }
918
0
  switch (node1->type) {
919
0
  case GNUTLS_SAN_DNSNAME:
920
0
    if (!dnsname_matches(&node2->name, &node1->name))
921
0
      return GNUTLS_E_SUCCESS;
922
0
    to_copy = node2;
923
0
    break;
924
0
  case GNUTLS_SAN_RFC822NAME:
925
0
    if (!email_matches(&node2->name, &node1->name))
926
0
      return GNUTLS_E_SUCCESS;
927
0
    to_copy = node2;
928
0
    break;
929
0
  case GNUTLS_SAN_IPADDRESS:
930
0
    if (node1->name.size != node2->name.size)
931
0
      return GNUTLS_E_SUCCESS;
932
0
    iplength = node1->name.size / 2;
933
0
    for (byte = 0; byte < iplength; byte++) {
934
0
      if (((node1->name.data[byte] ^
935
0
            node2->name.data[byte]) // XOR of addresses
936
0
           & node1->name.data[byte +
937
0
            iplength] // AND mask from nc1
938
0
           & node2->name.data[byte +
939
0
            iplength]) // AND mask from nc2
940
0
          != 0) {
941
        // CIDRS do not intersect
942
0
        return GNUTLS_E_SUCCESS;
943
0
      }
944
0
    }
945
0
    to_copy = node2;
946
0
    break;
947
0
  default:
948
    // for other types, we don't know how to do the intersection, assume empty
949
0
    return GNUTLS_E_SUCCESS;
950
0
  }
951
952
  // copy existing node if applicable
953
0
  if (to_copy != NULL) {
954
0
    *_intersection = name_constraints_node_new(nc, to_copy->type,
955
0
                 to_copy->name.data,
956
0
                 to_copy->name.size);
957
0
    if (*_intersection == NULL)
958
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
959
0
    intersection = *_intersection;
960
961
0
    assert(intersection->name.data != NULL);
962
963
0
    if (intersection->type == GNUTLS_SAN_IPADDRESS) {
964
      // make sure both IP addresses are correctly masked
965
0
      _gnutls_mask_ip(intersection->name.data,
966
0
          intersection->name.data + iplength,
967
0
          iplength);
968
0
      _gnutls_mask_ip(node1->name.data,
969
0
          node1->name.data + iplength, iplength);
970
      // update intersection, if necessary (we already know one is subset of other)
971
0
      for (byte = 0; byte < 2 * iplength; byte++) {
972
0
        intersection->name.data[byte] |=
973
0
          node1->name.data[byte];
974
0
      }
975
0
    }
976
0
  }
977
978
0
  return GNUTLS_E_SUCCESS;
979
0
}
980
981
/*
982
 * Returns: true if the certification is acceptable, and false otherwise.
983
 */
984
static unsigned
985
check_unsupported_constraint(gnutls_x509_name_constraints_t nc,
986
           gnutls_x509_subject_alt_name_t type)
987
0
{
988
0
  unsigned i;
989
0
  int ret;
990
0
  unsigned rtype;
991
0
  gnutls_datum_t rname;
992
993
  /* check if there is a restrictions with that type, if
994
   * yes, then reject the name.
995
   */
996
0
  i = 0;
997
0
  do {
998
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
999
0
                &rname);
1000
0
    if (ret >= 0) {
1001
0
      if (rtype != type)
1002
0
        continue;
1003
0
      else
1004
0
        return gnutls_assert_val(0);
1005
0
    }
1006
1007
0
  } while (ret == 0);
1008
1009
0
  return 1;
1010
0
}
1011
1012
static unsigned check_dns_constraints(gnutls_x509_name_constraints_t nc,
1013
              const gnutls_datum_t *name)
1014
0
{
1015
0
  unsigned i;
1016
0
  int ret;
1017
0
  unsigned rtype;
1018
0
  unsigned allowed_found = 0;
1019
0
  gnutls_datum_t rname;
1020
1021
  /* check restrictions */
1022
0
  i = 0;
1023
0
  do {
1024
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
1025
0
                &rname);
1026
0
    if (ret >= 0) {
1027
0
      if (rtype != GNUTLS_SAN_DNSNAME)
1028
0
        continue;
1029
1030
      /* a name of value 0 means that the CA shouldn't have issued
1031
       * a certificate with a DNSNAME. */
1032
0
      if (rname.size == 0)
1033
0
        return gnutls_assert_val(0);
1034
1035
0
      if (dnsname_matches(name, &rname) != 0)
1036
0
        return gnutls_assert_val(0); /* rejected */
1037
0
    }
1038
0
  } while (ret == 0);
1039
1040
  /* check allowed */
1041
0
  i = 0;
1042
0
  do {
1043
0
    ret = gnutls_x509_name_constraints_get_permitted(
1044
0
      nc, i++, &rtype, &rname);
1045
0
    if (ret >= 0) {
1046
0
      if (rtype != GNUTLS_SAN_DNSNAME)
1047
0
        continue;
1048
1049
0
      if (rname.size == 0)
1050
0
        continue;
1051
1052
0
      allowed_found = 1;
1053
1054
0
      if (dnsname_matches(name, &rname) != 0)
1055
0
        return 1; /* accepted */
1056
0
    }
1057
0
  } while (ret == 0);
1058
1059
0
  if (allowed_found !=
1060
0
      0) /* there are allowed directives but this host wasn't found */
1061
0
    return gnutls_assert_val(0);
1062
1063
0
  return 1;
1064
0
}
1065
1066
static unsigned check_email_constraints(gnutls_x509_name_constraints_t nc,
1067
          const gnutls_datum_t *name)
1068
0
{
1069
0
  unsigned i;
1070
0
  int ret;
1071
0
  unsigned rtype;
1072
0
  unsigned allowed_found = 0;
1073
0
  gnutls_datum_t rname;
1074
1075
  /* check restrictions */
1076
0
  i = 0;
1077
0
  do {
1078
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
1079
0
                &rname);
1080
0
    if (ret >= 0) {
1081
0
      if (rtype != GNUTLS_SAN_RFC822NAME)
1082
0
        continue;
1083
1084
      /* a name of value 0 means that the CA shouldn't have issued
1085
       * a certificate with an e-mail. */
1086
0
      if (rname.size == 0)
1087
0
        return gnutls_assert_val(0);
1088
1089
0
      if (email_matches(name, &rname) != 0)
1090
0
        return gnutls_assert_val(0); /* rejected */
1091
0
    }
1092
0
  } while (ret == 0);
1093
1094
  /* check allowed */
1095
0
  i = 0;
1096
0
  do {
1097
0
    ret = gnutls_x509_name_constraints_get_permitted(
1098
0
      nc, i++, &rtype, &rname);
1099
0
    if (ret >= 0) {
1100
0
      if (rtype != GNUTLS_SAN_RFC822NAME)
1101
0
        continue;
1102
1103
0
      if (rname.size == 0)
1104
0
        continue;
1105
1106
0
      allowed_found = 1;
1107
1108
0
      if (email_matches(name, &rname) != 0)
1109
0
        return 1; /* accepted */
1110
0
    }
1111
0
  } while (ret == 0);
1112
1113
0
  if (allowed_found !=
1114
0
      0) /* there are allowed directives but this host wasn't found */
1115
0
    return gnutls_assert_val(0);
1116
1117
0
  return 1;
1118
0
}
1119
1120
static unsigned check_ip_constraints(gnutls_x509_name_constraints_t nc,
1121
             const gnutls_datum_t *name)
1122
0
{
1123
0
  unsigned i;
1124
0
  int ret;
1125
0
  unsigned rtype;
1126
0
  unsigned allowed_found = 0;
1127
0
  gnutls_datum_t rname;
1128
1129
  /* check restrictions */
1130
0
  i = 0;
1131
0
  do {
1132
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
1133
0
                &rname);
1134
0
    if (ret >= 0) {
1135
0
      if (rtype != GNUTLS_SAN_IPADDRESS)
1136
0
        continue;
1137
1138
      /* do not check IPv4 against IPv6 constraints and vice versa */
1139
0
      if (name->size != rname.size / 2)
1140
0
        continue;
1141
1142
0
      if (ip_in_cidr(name, &rname) != 0)
1143
0
        return gnutls_assert_val(0); /* rejected */
1144
0
    }
1145
0
  } while (ret == 0);
1146
1147
  /* check allowed */
1148
0
  i = 0;
1149
0
  do {
1150
0
    ret = gnutls_x509_name_constraints_get_permitted(
1151
0
      nc, i++, &rtype, &rname);
1152
0
    if (ret >= 0) {
1153
0
      if (rtype != GNUTLS_SAN_IPADDRESS)
1154
0
        continue;
1155
1156
      /* do not check IPv4 against IPv6 constraints and vice versa */
1157
0
      if (name->size != rname.size / 2)
1158
0
        continue;
1159
1160
0
      allowed_found = 1;
1161
1162
0
      if (ip_in_cidr(name, &rname) != 0)
1163
0
        return 1; /* accepted */
1164
0
    }
1165
0
  } while (ret == 0);
1166
1167
0
  if (allowed_found !=
1168
0
      0) /* there are allowed directives but this host wasn't found */
1169
0
    return gnutls_assert_val(0);
1170
1171
0
  return 1;
1172
0
}
1173
1174
/**
1175
 * gnutls_x509_name_constraints_check:
1176
 * @nc: the extracted name constraints
1177
 * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t)
1178
 * @name: the name to be checked
1179
 *
1180
 * This function will check the provided name against the constraints in
1181
 * @nc using the RFC5280 rules. Currently this function is limited to DNS
1182
 * names, emails and IP addresses (of type %GNUTLS_SAN_DNSNAME,
1183
 * %GNUTLS_SAN_RFC822NAME and %GNUTLS_SAN_IPADDRESS).
1184
 *
1185
 * Returns: zero if the provided name is not acceptable, and non-zero otherwise.
1186
 *
1187
 * Since: 3.3.0
1188
 **/
1189
unsigned gnutls_x509_name_constraints_check(gnutls_x509_name_constraints_t nc,
1190
              gnutls_x509_subject_alt_name_t type,
1191
              const gnutls_datum_t *name)
1192
0
{
1193
0
  if (type == GNUTLS_SAN_DNSNAME)
1194
0
    return check_dns_constraints(nc, name);
1195
1196
0
  if (type == GNUTLS_SAN_RFC822NAME)
1197
0
    return check_email_constraints(nc, name);
1198
1199
0
  if (type == GNUTLS_SAN_IPADDRESS)
1200
0
    return check_ip_constraints(nc, name);
1201
1202
0
  return check_unsupported_constraint(nc, type);
1203
0
}
1204
1205
/* This function checks for unsupported constraints, that we also
1206
 * know their structure. That is it will fail only if the constraint
1207
 * is present in the CA, _and_ the name in the end certificate contains
1208
 * the constrained element.
1209
 *
1210
 * Returns: true if the certification is acceptable, and false otherwise
1211
 */
1212
static unsigned
1213
check_unsupported_constraint2(gnutls_x509_crt_t cert,
1214
            gnutls_x509_name_constraints_t nc,
1215
            gnutls_x509_subject_alt_name_t type)
1216
0
{
1217
0
  unsigned idx, found_one;
1218
0
  char name[MAX_CN];
1219
0
  size_t name_size;
1220
0
  unsigned san_type;
1221
0
  int ret;
1222
1223
0
  found_one = 0;
1224
1225
0
  for (idx = 0;; idx++) {
1226
0
    name_size = sizeof(name);
1227
0
    ret = gnutls_x509_crt_get_subject_alt_name2(
1228
0
      cert, idx, name, &name_size, &san_type, NULL);
1229
0
    if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1230
0
      break;
1231
0
    else if (ret < 0)
1232
0
      return gnutls_assert_val(0);
1233
1234
0
    if (san_type != GNUTLS_SAN_URI)
1235
0
      continue;
1236
1237
0
    found_one = 1;
1238
0
    break;
1239
0
  }
1240
1241
0
  if (found_one != 0)
1242
0
    return check_unsupported_constraint(nc, type);
1243
1244
  /* no name was found in the certificate, so accept */
1245
0
  return 1;
1246
0
}
1247
1248
/**
1249
 * gnutls_x509_name_constraints_check_crt:
1250
 * @nc: the extracted name constraints
1251
 * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t)
1252
 * @cert: the certificate to be checked
1253
 *
1254
 * This function will check the provided certificate names against the constraints in
1255
 * @nc using the RFC5280 rules. It will traverse all the certificate's names and
1256
 * alternative names.
1257
 *
1258
 * Currently this function is limited to DNS
1259
 * names and emails (of type %GNUTLS_SAN_DNSNAME and %GNUTLS_SAN_RFC822NAME).
1260
 *
1261
 * Returns: zero if the provided name is not acceptable, and non-zero otherwise.
1262
 *
1263
 * Since: 3.3.0
1264
 **/
1265
unsigned
1266
gnutls_x509_name_constraints_check_crt(gnutls_x509_name_constraints_t nc,
1267
               gnutls_x509_subject_alt_name_t type,
1268
               gnutls_x509_crt_t cert)
1269
0
{
1270
0
  char name[MAX_CN];
1271
0
  size_t name_size;
1272
0
  int ret;
1273
0
  unsigned idx, t, san_type;
1274
0
  gnutls_datum_t n;
1275
0
  unsigned found_one;
1276
0
  size_t checks;
1277
1278
0
  if (_gnutls_x509_name_constraints_is_empty(nc, type) != 0)
1279
0
    return 1; /* shortcut; no constraints to check */
1280
1281
0
  if (!INT_ADD_OK(nc->permitted.size, nc->excluded.size, &checks) ||
1282
0
      !INT_MULTIPLY_OK(checks, cert->san->size, &checks) ||
1283
0
      checks > MAX_NC_CHECKS) {
1284
0
    return gnutls_assert_val(0);
1285
0
  }
1286
1287
0
  if (type == GNUTLS_SAN_RFC822NAME) {
1288
0
    found_one = 0;
1289
0
    for (idx = 0;; idx++) {
1290
0
      name_size = sizeof(name);
1291
0
      ret = gnutls_x509_crt_get_subject_alt_name2(
1292
0
        cert, idx, name, &name_size, &san_type, NULL);
1293
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1294
0
        break;
1295
0
      else if (ret < 0)
1296
0
        return gnutls_assert_val(0);
1297
1298
0
      if (san_type != GNUTLS_SAN_RFC822NAME)
1299
0
        continue;
1300
1301
0
      found_one = 1;
1302
0
      n.data = (void *)name;
1303
0
      n.size = name_size;
1304
0
      t = gnutls_x509_name_constraints_check(
1305
0
        nc, GNUTLS_SAN_RFC822NAME, &n);
1306
0
      if (t == 0)
1307
0
        return gnutls_assert_val(t);
1308
0
    }
1309
1310
    /* there is at least a single e-mail. That means that the EMAIL field will
1311
     * not be used for verifying the identity of the holder. */
1312
0
    if (found_one != 0)
1313
0
      return 1;
1314
1315
0
    do {
1316
      /* ensure there is only a single EMAIL, similarly to CN handling (rfc6125) */
1317
0
      name_size = sizeof(name);
1318
0
      ret = gnutls_x509_crt_get_dn_by_oid(
1319
0
        cert, GNUTLS_OID_PKCS9_EMAIL, 1, 0, name,
1320
0
        &name_size);
1321
0
      if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1322
0
        return gnutls_assert_val(0);
1323
1324
0
      name_size = sizeof(name);
1325
0
      ret = gnutls_x509_crt_get_dn_by_oid(
1326
0
        cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, name,
1327
0
        &name_size);
1328
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1329
0
        break;
1330
0
      else if (ret < 0)
1331
0
        return gnutls_assert_val(0);
1332
1333
0
      found_one = 1;
1334
0
      n.data = (void *)name;
1335
0
      n.size = name_size;
1336
0
      t = gnutls_x509_name_constraints_check(
1337
0
        nc, GNUTLS_SAN_RFC822NAME, &n);
1338
0
      if (t == 0)
1339
0
        return gnutls_assert_val(t);
1340
0
    } while (0);
1341
1342
    /* passed */
1343
0
    if (found_one != 0)
1344
0
      return 1;
1345
0
    else {
1346
      /* no name was found. According to RFC5280: 
1347
       * If no name of the type is in the certificate, the certificate is acceptable.
1348
       */
1349
0
      return gnutls_assert_val(1);
1350
0
    }
1351
0
  } else if (type == GNUTLS_SAN_DNSNAME) {
1352
0
    found_one = 0;
1353
0
    for (idx = 0;; idx++) {
1354
0
      name_size = sizeof(name);
1355
0
      ret = gnutls_x509_crt_get_subject_alt_name2(
1356
0
        cert, idx, name, &name_size, &san_type, NULL);
1357
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1358
0
        break;
1359
0
      else if (ret < 0)
1360
0
        return gnutls_assert_val(0);
1361
1362
0
      if (san_type != GNUTLS_SAN_DNSNAME)
1363
0
        continue;
1364
1365
0
      found_one = 1;
1366
0
      n.data = (void *)name;
1367
0
      n.size = name_size;
1368
0
      t = gnutls_x509_name_constraints_check(
1369
0
        nc, GNUTLS_SAN_DNSNAME, &n);
1370
0
      if (t == 0)
1371
0
        return gnutls_assert_val(t);
1372
0
    }
1373
1374
    /* there is at least a single DNS name. That means that the CN will
1375
     * not be used for verifying the identity of the holder. */
1376
0
    if (found_one != 0)
1377
0
      return 1;
1378
1379
    /* verify the name constraints against the CN, if the certificate is
1380
     * not a CA. We do this check only on certificates marked as WWW server,
1381
     * because that's where the CN check is only performed. */
1382
0
    if (_gnutls_check_key_purpose(cert, GNUTLS_KP_TLS_WWW_SERVER,
1383
0
                0) != 0)
1384
0
      do {
1385
        /* ensure there is only a single CN, according to rfc6125 */
1386
0
        name_size = sizeof(name);
1387
0
        ret = gnutls_x509_crt_get_dn_by_oid(
1388
0
          cert, GNUTLS_OID_X520_COMMON_NAME, 1, 0,
1389
0
          name, &name_size);
1390
0
        if (ret !=
1391
0
            GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1392
0
          return gnutls_assert_val(0);
1393
1394
0
        name_size = sizeof(name);
1395
0
        ret = gnutls_x509_crt_get_dn_by_oid(
1396
0
          cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
1397
0
          name, &name_size);
1398
0
        if (ret ==
1399
0
            GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1400
0
          break;
1401
0
        else if (ret < 0)
1402
0
          return gnutls_assert_val(0);
1403
1404
0
        found_one = 1;
1405
0
        n.data = (void *)name;
1406
0
        n.size = name_size;
1407
0
        t = gnutls_x509_name_constraints_check(
1408
0
          nc, GNUTLS_SAN_DNSNAME, &n);
1409
0
        if (t == 0)
1410
0
          return gnutls_assert_val(t);
1411
0
      } while (0);
1412
1413
    /* passed */
1414
0
    if (found_one != 0)
1415
0
      return 1;
1416
0
    else {
1417
      /* no name was found. According to RFC5280: 
1418
       * If no name of the type is in the certificate, the certificate is acceptable.
1419
       */
1420
0
      return gnutls_assert_val(1);
1421
0
    }
1422
0
  } else if (type == GNUTLS_SAN_IPADDRESS) {
1423
0
    found_one = 0;
1424
0
    for (idx = 0;; idx++) {
1425
0
      name_size = sizeof(name);
1426
0
      ret = gnutls_x509_crt_get_subject_alt_name2(
1427
0
        cert, idx, name, &name_size, &san_type, NULL);
1428
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1429
0
        break;
1430
0
      else if (ret < 0)
1431
0
        return gnutls_assert_val(0);
1432
1433
0
      if (san_type != GNUTLS_SAN_IPADDRESS)
1434
0
        continue;
1435
1436
0
      found_one = 1;
1437
0
      n.data = (void *)name;
1438
0
      n.size = name_size;
1439
0
      t = gnutls_x509_name_constraints_check(
1440
0
        nc, GNUTLS_SAN_IPADDRESS, &n);
1441
0
      if (t == 0)
1442
0
        return gnutls_assert_val(t);
1443
0
    }
1444
1445
    /* there is at least a single IP address. */
1446
1447
0
    if (found_one != 0) {
1448
0
      return 1;
1449
0
    } else {
1450
      /* no name was found. According to RFC5280:
1451
       * If no name of the type is in the certificate, the certificate is acceptable.
1452
       */
1453
0
      return gnutls_assert_val(1);
1454
0
    }
1455
0
  } else if (type == GNUTLS_SAN_URI) {
1456
0
    return check_unsupported_constraint2(cert, nc, type);
1457
0
  } else
1458
0
    return check_unsupported_constraint(nc, type);
1459
0
}
1460
1461
/**
1462
 * gnutls_x509_name_constraints_get_permitted:
1463
 * @nc: the extracted name constraints
1464
 * @idx: the index of the constraint
1465
 * @type: the type of the constraint (of type gnutls_x509_subject_alt_name_t)
1466
 * @name: the name in the constraint (of the specific type)
1467
 *
1468
 * This function will return an intermediate type containing
1469
 * the name constraints of the provided CA certificate. That
1470
 * structure can be used in combination with gnutls_x509_name_constraints_check()
1471
 * to verify whether a server's name is in accordance with the constraints.
1472
 *
1473
 * The name should be treated as constant and valid for the lifetime of @nc.
1474
 *
1475
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1476
 * if the extension is not present, otherwise a negative error value.
1477
 *
1478
 * Since: 3.3.0
1479
 **/
1480
int gnutls_x509_name_constraints_get_permitted(gnutls_x509_name_constraints_t nc,
1481
                 unsigned idx, unsigned *type,
1482
                 gnutls_datum_t *name)
1483
0
{
1484
0
  const struct name_constraints_node_st *tmp;
1485
1486
0
  if (idx >= nc->permitted.size)
1487
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1488
1489
0
  tmp = nc->permitted.data[idx];
1490
1491
0
  *type = tmp->type;
1492
0
  *name = tmp->name;
1493
1494
0
  return 0;
1495
0
}
1496
1497
/**
1498
 * gnutls_x509_name_constraints_get_excluded:
1499
 * @nc: the extracted name constraints
1500
 * @idx: the index of the constraint
1501
 * @type: the type of the constraint (of type gnutls_x509_subject_alt_name_t)
1502
 * @name: the name in the constraint (of the specific type)
1503
 *
1504
 * This function will return an intermediate type containing
1505
 * the name constraints of the provided CA certificate. That
1506
 * structure can be used in combination with gnutls_x509_name_constraints_check()
1507
 * to verify whether a server's name is in accordance with the constraints.
1508
 *
1509
 * The name should be treated as constant and valid for the lifetime of @nc.
1510
 *
1511
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1512
 * if the extension is not present, otherwise a negative error value.
1513
 *
1514
 * Since: 3.3.0
1515
 **/
1516
int gnutls_x509_name_constraints_get_excluded(gnutls_x509_name_constraints_t nc,
1517
                unsigned idx, unsigned *type,
1518
                gnutls_datum_t *name)
1519
0
{
1520
0
  const struct name_constraints_node_st *tmp;
1521
1522
0
  if (idx >= nc->excluded.size)
1523
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1524
1525
0
  tmp = nc->excluded.data[idx];
1526
1527
0
  *type = tmp->type;
1528
0
  *name = tmp->name;
1529
1530
0
  return 0;
1531
0
}