Coverage Report

Created: 2025-11-16 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/x509/name_constraints.c
Line
Count
Source
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
418
0
      if (t->type == t2->type)
419
0
        used = 1;
420
421
      // if intersection is not empty
422
0
      if (tmp !=
423
0
          NULL) { // intersection for this type is not empty
424
        // check bounds
425
0
        if (tmp->type > GNUTLS_SAN_MAX ||
426
0
            tmp->type == 0) {
427
0
          gnutls_free(tmp);
428
0
          return gnutls_assert_val(
429
0
            GNUTLS_E_INTERNAL_ERROR);
430
0
        }
431
        // we will not add universal excluded constraint for this type
432
0
        types_with_empty_intersection[tmp->type - 1] =
433
0
          0;
434
        // add intersection node to PERMITTED
435
0
        ret = name_constraints_node_list_add(permitted,
436
0
                     tmp);
437
0
        if (ret < 0) {
438
0
          gnutls_assert();
439
0
          goto cleanup;
440
0
        }
441
0
      }
442
0
    }
443
    // if the node from PERMITTED2 was not used for intersection, copy it to DEST
444
    // Beware: also copies nodes other than DNS, email, IP,
445
    //       since their counterpart may have been moved in phase 1.
446
0
    if (!used) {
447
0
      tmp = name_constraints_node_new(
448
0
        nc, t2->type, t2->name.data, t2->name.size);
449
0
      if (tmp == NULL) {
450
0
        gnutls_assert();
451
0
        ret = GNUTLS_E_MEMORY_ERROR;
452
0
        goto cleanup;
453
0
      }
454
0
      ret = name_constraints_node_list_add(permitted, tmp);
455
0
      if (ret < 0) {
456
0
        gnutls_assert();
457
0
        goto cleanup;
458
0
      }
459
0
    }
460
0
  }
461
462
  /* Phase 3
463
   * For each type: If we have empty permitted name constraints now
464
   * and we didn't have at the beginning, we have to add a new
465
   * excluded constraint with universal wildcard
466
   * (since the intersection of permitted is now empty). */
467
0
  for (type = 1; type <= GNUTLS_SAN_MAX; type++) {
468
0
    if (types_with_empty_intersection[type - 1] == 0)
469
0
      continue;
470
0
    _gnutls_hard_log(
471
0
      "Adding universal excluded name constraint for type %d.\n",
472
0
      type);
473
0
    switch (type) {
474
0
    case GNUTLS_SAN_IPADDRESS:
475
      // add universal restricted range for IPv4
476
0
      tmp = name_constraints_node_new(
477
0
        nc, GNUTLS_SAN_IPADDRESS, NULL, 8);
478
0
      if (tmp == NULL) {
479
0
        gnutls_assert();
480
0
        ret = GNUTLS_E_MEMORY_ERROR;
481
0
        goto cleanup;
482
0
      }
483
0
      ret = name_constraints_node_list_add(excluded, tmp);
484
0
      if (ret < 0) {
485
0
        gnutls_assert();
486
0
        goto cleanup;
487
0
      }
488
      // add universal restricted range for IPv6
489
0
      tmp = name_constraints_node_new(
490
0
        nc, GNUTLS_SAN_IPADDRESS, NULL, 32);
491
0
      if (tmp == NULL) {
492
0
        gnutls_assert();
493
0
        ret = GNUTLS_E_MEMORY_ERROR;
494
0
        goto cleanup;
495
0
      }
496
0
      ret = name_constraints_node_list_add(excluded, tmp);
497
0
      if (ret < 0) {
498
0
        gnutls_assert();
499
0
        goto cleanup;
500
0
      }
501
0
      break;
502
0
    case GNUTLS_SAN_DNSNAME:
503
0
    case GNUTLS_SAN_RFC822NAME:
504
0
      tmp = name_constraints_node_new(nc, type, NULL, 0);
505
0
      if (tmp == NULL) {
506
0
        gnutls_assert();
507
0
        ret = GNUTLS_E_MEMORY_ERROR;
508
0
        goto cleanup;
509
0
      }
510
0
      ret = name_constraints_node_list_add(excluded, tmp);
511
0
      if (ret < 0) {
512
0
        gnutls_assert();
513
0
        goto cleanup;
514
0
      }
515
0
      break;
516
0
    default: // do nothing, at least one node was already moved in phase 1
517
0
      break;
518
0
    }
519
0
  }
520
0
  ret = GNUTLS_E_SUCCESS;
521
522
0
cleanup:
523
0
  gnutls_free(removed.data);
524
0
  return ret;
525
0
}
526
527
static int name_constraints_node_list_concat(
528
  gnutls_x509_name_constraints_t nc,
529
  struct name_constraints_node_list_st *nodes,
530
  const struct name_constraints_node_list_st *nodes2)
531
0
{
532
0
  for (size_t i = 0; i < nodes2->size; i++) {
533
0
    const struct name_constraints_node_st *node = nodes2->data[i];
534
0
    struct name_constraints_node_st *tmp;
535
0
    int ret;
536
537
0
    tmp = name_constraints_node_new(nc, node->type, node->name.data,
538
0
            node->name.size);
539
0
    if (tmp == NULL) {
540
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
541
0
    }
542
0
    ret = name_constraints_node_list_add(nodes, tmp);
543
0
    if (ret < 0) {
544
0
      name_constraints_node_free(tmp);
545
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
546
0
    }
547
0
  }
548
549
0
  return 0;
550
0
}
551
552
/**
553
 * gnutls_x509_crt_get_name_constraints:
554
 * @crt: should contain a #gnutls_x509_crt_t type
555
 * @nc: The nameconstraints intermediate type
556
 * @flags: zero or %GNUTLS_EXT_FLAG_APPEND
557
 * @critical: the extension status
558
 *
559
 * This function will return an intermediate type containing
560
 * the name constraints of the provided CA certificate. That
561
 * structure can be used in combination with gnutls_x509_name_constraints_check()
562
 * to verify whether a server's name is in accordance with the constraints.
563
 *
564
 * When the @flags is set to %GNUTLS_EXT_FLAG_APPEND,
565
 * then if the @nc structure is empty this function will behave
566
 * identically as if the flag was not set.
567
 * Otherwise if there are elements in the @nc structure then the
568
 * constraints will be merged with the existing constraints following
569
 * RFC5280 p6.1.4 (excluded constraints will be appended, permitted
570
 * will be intersected).
571
 *
572
 * Note that @nc must be initialized prior to calling this function.
573
 *
574
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
575
 * if the extension is not present, otherwise a negative error value.
576
 *
577
 * Since: 3.3.0
578
 **/
579
int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
580
           gnutls_x509_name_constraints_t nc,
581
           unsigned int flags,
582
           unsigned int *critical)
583
0
{
584
0
  int ret;
585
0
  gnutls_datum_t der = { NULL, 0 };
586
587
0
  if (crt == NULL) {
588
0
    gnutls_assert();
589
0
    return GNUTLS_E_INVALID_REQUEST;
590
0
  }
591
592
0
  ret = _gnutls_x509_crt_get_extension(crt, "2.5.29.30", 0, &der,
593
0
               critical);
594
0
  if (ret < 0)
595
0
    return gnutls_assert_val(ret);
596
597
0
  if (der.size == 0 || der.data == NULL)
598
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
599
600
0
  ret = gnutls_x509_ext_import_name_constraints(&der, nc, flags);
601
0
  if (ret < 0) {
602
0
    gnutls_assert();
603
0
    goto cleanup;
604
0
  }
605
606
0
  ret = 0;
607
608
0
cleanup:
609
0
  _gnutls_free_datum(&der);
610
611
0
  return ret;
612
0
}
613
614
void _gnutls_x509_name_constraints_clear(gnutls_x509_name_constraints_t nc)
615
0
{
616
0
  for (size_t i = 0; i < nc->nodes.size; i++) {
617
0
    struct name_constraints_node_st *node = nc->nodes.data[i];
618
0
    name_constraints_node_free(node);
619
0
  }
620
0
  gnutls_free(nc->nodes.data);
621
0
  nc->nodes.capacity = 0;
622
0
  nc->nodes.size = 0;
623
624
0
  gnutls_free(nc->permitted.data);
625
0
  nc->permitted.capacity = 0;
626
0
  nc->permitted.size = 0;
627
628
0
  gnutls_free(nc->excluded.data);
629
0
  nc->excluded.capacity = 0;
630
0
  nc->excluded.size = 0;
631
0
}
632
633
/**
634
 * gnutls_x509_name_constraints_deinit:
635
 * @nc: The nameconstraints
636
 *
637
 * This function will deinitialize a name constraints type.
638
 *
639
 * Since: 3.3.0
640
 **/
641
void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc)
642
0
{
643
0
  _gnutls_x509_name_constraints_clear(nc);
644
0
  gnutls_free(nc);
645
0
}
646
647
/**
648
 * gnutls_x509_name_constraints_init:
649
 * @nc: The nameconstraints
650
 *
651
 * This function will initialize a name constraints type.
652
 *
653
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
654
 *
655
 * Since: 3.3.0
656
 **/
657
int gnutls_x509_name_constraints_init(gnutls_x509_name_constraints_t *nc)
658
0
{
659
0
  struct gnutls_name_constraints_st *tmp;
660
661
0
  tmp = gnutls_calloc(1, sizeof(struct gnutls_name_constraints_st));
662
0
  if (tmp == NULL) {
663
0
    gnutls_assert();
664
0
    return GNUTLS_E_MEMORY_ERROR;
665
0
  }
666
667
0
  *nc = tmp;
668
0
  return 0;
669
0
}
670
671
static int name_constraints_add(gnutls_x509_name_constraints_t nc,
672
        gnutls_x509_subject_alt_name_t type,
673
        const gnutls_datum_t *name, unsigned permitted)
674
0
{
675
0
  struct name_constraints_node_st *tmp;
676
0
  struct name_constraints_node_list_st *nodes;
677
0
  int ret;
678
679
0
  ret = validate_name_constraints_node(type, name);
680
0
  if (ret < 0)
681
0
    return gnutls_assert_val(ret);
682
683
0
  nodes = permitted ? &nc->permitted : &nc->excluded;
684
685
0
  tmp = name_constraints_node_new(nc, type, name->data, name->size);
686
0
  if (tmp == NULL)
687
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
688
689
0
  ret = name_constraints_node_list_add(nodes, tmp);
690
0
  if (ret < 0) {
691
0
    name_constraints_node_free(tmp);
692
0
    return gnutls_assert_val(ret);
693
0
  }
694
695
0
  return 0;
696
0
}
697
698
/*-
699
 * _gnutls_x509_name_constraints_merge:
700
 * @nc: The nameconstraints
701
 * @nc2: The name constraints to be merged with
702
 *
703
 * This function will merge the provided name constraints structures
704
 * as per RFC5280 p6.1.4. That is, the excluded constraints will be appended,
705
 * and permitted will be intersected. The intersection assumes that @nc
706
 * is the root CA constraints.
707
 *
708
 * The merged constraints will be placed in @nc.
709
 *
710
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
711
 *
712
 * Since: 3.5.0
713
 -*/
714
int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc,
715
          gnutls_x509_name_constraints_t nc2)
716
0
{
717
0
  int ret;
718
719
0
  ret = name_constraints_node_list_intersect(
720
0
    nc, &nc->permitted, &nc2->permitted, &nc->excluded);
721
0
  if (ret < 0) {
722
0
    gnutls_assert();
723
0
    return ret;
724
0
  }
725
726
0
  ret = name_constraints_node_list_concat(nc, &nc->excluded,
727
0
            &nc2->excluded);
728
0
  if (ret < 0) {
729
0
    gnutls_assert();
730
0
    return ret;
731
0
  }
732
733
0
  return 0;
734
0
}
735
736
/**
737
 * gnutls_x509_name_constraints_add_permitted:
738
 * @nc: The nameconstraints
739
 * @type: The type of the constraints
740
 * @name: The data of the constraints
741
 *
742
 * This function will add a name constraint to the list of permitted
743
 * constraints. The constraints @type can be any of the following types:
744
 * %GNUTLS_SAN_DNSNAME, %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DN,
745
 * %GNUTLS_SAN_URI, %GNUTLS_SAN_IPADDRESS. For the latter, an IP address
746
 * in network byte order is expected, followed by its network mask.
747
 *
748
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
749
 *
750
 * Since: 3.3.0
751
 **/
752
int gnutls_x509_name_constraints_add_permitted(
753
  gnutls_x509_name_constraints_t nc, gnutls_x509_subject_alt_name_t type,
754
  const gnutls_datum_t *name)
755
0
{
756
0
  return name_constraints_add(nc, type, name, 1);
757
0
}
758
759
/**
760
 * gnutls_x509_name_constraints_add_excluded:
761
 * @nc: The nameconstraints
762
 * @type: The type of the constraints
763
 * @name: The data of the constraints
764
 *
765
 * This function will add a name constraint to the list of excluded
766
 * constraints. The constraints @type can be any of the following types:
767
 * %GNUTLS_SAN_DNSNAME, %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DN,
768
 * %GNUTLS_SAN_URI, %GNUTLS_SAN_IPADDRESS. For the latter, an IP address
769
 * in network byte order is expected, followed by its network mask (which is
770
 * 4 bytes in IPv4 or 16-bytes in IPv6).
771
 *
772
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
773
 *
774
 * Since: 3.3.0
775
 **/
776
int gnutls_x509_name_constraints_add_excluded(
777
  gnutls_x509_name_constraints_t nc, gnutls_x509_subject_alt_name_t type,
778
  const gnutls_datum_t *name)
779
0
{
780
0
  return name_constraints_add(nc, type, name, 0);
781
0
}
782
783
/**
784
 * gnutls_x509_crt_set_name_constraints:
785
 * @crt: The certificate
786
 * @nc: The nameconstraints structure
787
 * @critical: whether this extension will be critical
788
 *
789
 * This function will set the provided name constraints to
790
 * the certificate extension list. This extension is always
791
 * marked as critical.
792
 *
793
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
794
 *
795
 * Since: 3.3.0
796
 **/
797
int gnutls_x509_crt_set_name_constraints(gnutls_x509_crt_t crt,
798
           gnutls_x509_name_constraints_t nc,
799
           unsigned int critical)
800
0
{
801
0
  int ret;
802
0
  gnutls_datum_t der;
803
804
0
  ret = gnutls_x509_ext_export_name_constraints(nc, &der);
805
0
  if (ret < 0)
806
0
    return gnutls_assert_val(ret);
807
808
0
  ret = _gnutls_x509_crt_set_extension(crt, "2.5.29.30", &der, critical);
809
0
  if (ret < 0) {
810
0
    gnutls_assert();
811
0
    goto cleanup;
812
0
  }
813
814
0
  ret = 0;
815
0
  crt->use_extensions = 1;
816
817
0
cleanup:
818
0
  _gnutls_free_datum(&der);
819
0
  return ret;
820
0
}
821
822
static unsigned ends_with(const gnutls_datum_t *str,
823
        const gnutls_datum_t *suffix)
824
0
{
825
0
  unsigned char *tree;
826
0
  unsigned int treelen;
827
828
0
  if (suffix->size >= str->size)
829
0
    return 0;
830
831
0
  tree = suffix->data;
832
0
  treelen = suffix->size;
833
0
  if ((treelen > 0) && (tree[0] == '.')) {
834
0
    tree++;
835
0
    treelen--;
836
0
  }
837
838
0
  if (memcmp(str->data + str->size - treelen, tree, treelen) == 0 &&
839
0
      str->data[str->size - treelen - 1] == '.')
840
0
    return 1; /* match */
841
842
0
  return 0;
843
0
}
844
845
static unsigned email_ends_with(const gnutls_datum_t *str,
846
        const gnutls_datum_t *suffix)
847
0
{
848
0
  if (suffix->size >= str->size) {
849
0
    return 0;
850
0
  }
851
852
0
  if (suffix->size > 0 && memcmp(str->data + str->size - suffix->size,
853
0
               suffix->data, suffix->size) != 0) {
854
0
    return 0;
855
0
  }
856
857
0
  if (suffix->size > 1 && suffix->data[0] == '.') { /* .domain.com */
858
0
    return 1; /* match */
859
0
  } else if (str->data[str->size - suffix->size - 1] == '@') {
860
0
    return 1; /* match */
861
0
  }
862
863
0
  return 0;
864
0
}
865
866
static unsigned dnsname_matches(const gnutls_datum_t *name,
867
        const gnutls_datum_t *suffix)
868
0
{
869
0
  _gnutls_hard_log("matching %.*s with DNS constraint %.*s\n", name->size,
870
0
       name->data, suffix->size, suffix->data);
871
872
0
  if (suffix->size == name->size &&
873
0
      memcmp(suffix->data, name->data, suffix->size) == 0)
874
0
    return 1; /* match */
875
876
0
  return ends_with(name, suffix);
877
0
}
878
879
static unsigned email_matches(const gnutls_datum_t *name,
880
            const gnutls_datum_t *suffix)
881
0
{
882
0
  _gnutls_hard_log("matching %.*s with e-mail constraint %.*s\n",
883
0
       name->size, name->data, suffix->size, suffix->data);
884
885
0
  if (suffix->size == name->size &&
886
0
      memcmp(suffix->data, name->data, suffix->size) == 0)
887
0
    return 1; /* match */
888
889
0
  return email_ends_with(name, suffix);
890
0
}
891
892
/*-
893
 * name_constraints_intersect_nodes:
894
 * @nc1: name constraints node 1
895
 * @nc2: name constraints node 2
896
 * @_intersection: newly allocated node with intersected constraints,
897
 *     NULL if the intersection is empty
898
 *
899
 * Inspect 2 name constraints nodes (of possibly different types) and allocate
900
 * a new node with intersection of given constraints.
901
 *
902
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
903
 -*/
904
static int name_constraints_intersect_nodes(
905
  gnutls_x509_name_constraints_t nc,
906
  const struct name_constraints_node_st *node1,
907
  const struct name_constraints_node_st *node2,
908
  struct name_constraints_node_st **_intersection)
909
0
{
910
  // presume empty intersection
911
0
  struct name_constraints_node_st *intersection = NULL;
912
0
  const struct name_constraints_node_st *to_copy = NULL;
913
0
  unsigned iplength = 0;
914
0
  unsigned byte;
915
916
0
  *_intersection = NULL;
917
918
0
  if (node1->type != node2->type) {
919
0
    return GNUTLS_E_SUCCESS;
920
0
  }
921
0
  switch (node1->type) {
922
0
  case GNUTLS_SAN_DNSNAME:
923
0
    if (!dnsname_matches(&node2->name, &node1->name))
924
0
      return GNUTLS_E_SUCCESS;
925
0
    to_copy = node2;
926
0
    break;
927
0
  case GNUTLS_SAN_RFC822NAME:
928
0
    if (!email_matches(&node2->name, &node1->name))
929
0
      return GNUTLS_E_SUCCESS;
930
0
    to_copy = node2;
931
0
    break;
932
0
  case GNUTLS_SAN_IPADDRESS:
933
0
    if (node1->name.size != node2->name.size)
934
0
      return GNUTLS_E_SUCCESS;
935
0
    iplength = node1->name.size / 2;
936
0
    for (byte = 0; byte < iplength; byte++) {
937
0
      if (((node1->name.data[byte] ^
938
0
            node2->name.data[byte]) // XOR of addresses
939
0
           & node1->name.data[byte +
940
0
            iplength] // AND mask from nc1
941
0
           & node2->name.data[byte +
942
0
            iplength]) // AND mask from nc2
943
0
          != 0) {
944
        // CIDRS do not intersect
945
0
        return GNUTLS_E_SUCCESS;
946
0
      }
947
0
    }
948
0
    to_copy = node2;
949
0
    break;
950
0
  default:
951
    // for other types, we don't know how to do the intersection, assume empty
952
0
    return GNUTLS_E_SUCCESS;
953
0
  }
954
955
  // copy existing node if applicable
956
0
  if (to_copy != NULL) {
957
0
    *_intersection = name_constraints_node_new(nc, to_copy->type,
958
0
                 to_copy->name.data,
959
0
                 to_copy->name.size);
960
0
    if (*_intersection == NULL)
961
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
962
0
    intersection = *_intersection;
963
964
0
    assert(intersection->name.data != NULL);
965
966
0
    if (intersection->type == GNUTLS_SAN_IPADDRESS) {
967
      // make sure both IP addresses are correctly masked
968
0
      _gnutls_mask_ip(intersection->name.data,
969
0
          intersection->name.data + iplength,
970
0
          iplength);
971
0
      _gnutls_mask_ip(node1->name.data,
972
0
          node1->name.data + iplength, iplength);
973
      // update intersection, if necessary (we already know one is subset of other)
974
0
      for (byte = 0; byte < 2 * iplength; byte++) {
975
0
        intersection->name.data[byte] |=
976
0
          node1->name.data[byte];
977
0
      }
978
0
    }
979
0
  }
980
981
0
  return GNUTLS_E_SUCCESS;
982
0
}
983
984
/*
985
 * Returns: true if the certification is acceptable, and false otherwise.
986
 */
987
static unsigned
988
check_unsupported_constraint(gnutls_x509_name_constraints_t nc,
989
           gnutls_x509_subject_alt_name_t type)
990
0
{
991
0
  unsigned i;
992
0
  int ret;
993
0
  unsigned rtype;
994
0
  gnutls_datum_t rname;
995
996
  /* check if there is a restrictions with that type, if
997
   * yes, then reject the name.
998
   */
999
0
  i = 0;
1000
0
  do {
1001
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
1002
0
                &rname);
1003
0
    if (ret >= 0) {
1004
0
      if (rtype != type)
1005
0
        continue;
1006
0
      else
1007
0
        return gnutls_assert_val(0);
1008
0
    }
1009
1010
0
  } while (ret == 0);
1011
1012
0
  return 1;
1013
0
}
1014
1015
static unsigned check_dns_constraints(gnutls_x509_name_constraints_t nc,
1016
              const gnutls_datum_t *name)
1017
0
{
1018
0
  unsigned i;
1019
0
  int ret;
1020
0
  unsigned rtype;
1021
0
  unsigned allowed_found = 0;
1022
0
  gnutls_datum_t rname;
1023
1024
  /* check restrictions */
1025
0
  i = 0;
1026
0
  do {
1027
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
1028
0
                &rname);
1029
0
    if (ret >= 0) {
1030
0
      if (rtype != GNUTLS_SAN_DNSNAME)
1031
0
        continue;
1032
1033
      /* a name of value 0 means that the CA shouldn't have issued
1034
       * a certificate with a DNSNAME. */
1035
0
      if (rname.size == 0)
1036
0
        return gnutls_assert_val(0);
1037
1038
0
      if (dnsname_matches(name, &rname) != 0)
1039
0
        return gnutls_assert_val(0); /* rejected */
1040
0
    }
1041
0
  } while (ret == 0);
1042
1043
  /* check allowed */
1044
0
  i = 0;
1045
0
  do {
1046
0
    ret = gnutls_x509_name_constraints_get_permitted(
1047
0
      nc, i++, &rtype, &rname);
1048
0
    if (ret >= 0) {
1049
0
      if (rtype != GNUTLS_SAN_DNSNAME)
1050
0
        continue;
1051
1052
0
      if (rname.size == 0)
1053
0
        continue;
1054
1055
0
      allowed_found = 1;
1056
1057
0
      if (dnsname_matches(name, &rname) != 0)
1058
0
        return 1; /* accepted */
1059
0
    }
1060
0
  } while (ret == 0);
1061
1062
0
  if (allowed_found !=
1063
0
      0) /* there are allowed directives but this host wasn't found */
1064
0
    return gnutls_assert_val(0);
1065
1066
0
  return 1;
1067
0
}
1068
1069
static unsigned check_email_constraints(gnutls_x509_name_constraints_t nc,
1070
          const gnutls_datum_t *name)
1071
0
{
1072
0
  unsigned i;
1073
0
  int ret;
1074
0
  unsigned rtype;
1075
0
  unsigned allowed_found = 0;
1076
0
  gnutls_datum_t rname;
1077
1078
  /* check restrictions */
1079
0
  i = 0;
1080
0
  do {
1081
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
1082
0
                &rname);
1083
0
    if (ret >= 0) {
1084
0
      if (rtype != GNUTLS_SAN_RFC822NAME)
1085
0
        continue;
1086
1087
      /* a name of value 0 means that the CA shouldn't have issued
1088
       * a certificate with an e-mail. */
1089
0
      if (rname.size == 0)
1090
0
        return gnutls_assert_val(0);
1091
1092
0
      if (email_matches(name, &rname) != 0)
1093
0
        return gnutls_assert_val(0); /* rejected */
1094
0
    }
1095
0
  } while (ret == 0);
1096
1097
  /* check allowed */
1098
0
  i = 0;
1099
0
  do {
1100
0
    ret = gnutls_x509_name_constraints_get_permitted(
1101
0
      nc, i++, &rtype, &rname);
1102
0
    if (ret >= 0) {
1103
0
      if (rtype != GNUTLS_SAN_RFC822NAME)
1104
0
        continue;
1105
1106
0
      if (rname.size == 0)
1107
0
        continue;
1108
1109
0
      allowed_found = 1;
1110
1111
0
      if (email_matches(name, &rname) != 0)
1112
0
        return 1; /* accepted */
1113
0
    }
1114
0
  } while (ret == 0);
1115
1116
0
  if (allowed_found !=
1117
0
      0) /* there are allowed directives but this host wasn't found */
1118
0
    return gnutls_assert_val(0);
1119
1120
0
  return 1;
1121
0
}
1122
1123
static unsigned check_ip_constraints(gnutls_x509_name_constraints_t nc,
1124
             const gnutls_datum_t *name)
1125
0
{
1126
0
  unsigned i;
1127
0
  int ret;
1128
0
  unsigned rtype;
1129
0
  unsigned allowed_found = 0;
1130
0
  gnutls_datum_t rname;
1131
1132
  /* check restrictions */
1133
0
  i = 0;
1134
0
  do {
1135
0
    ret = gnutls_x509_name_constraints_get_excluded(nc, i++, &rtype,
1136
0
                &rname);
1137
0
    if (ret >= 0) {
1138
0
      if (rtype != GNUTLS_SAN_IPADDRESS)
1139
0
        continue;
1140
1141
      /* do not check IPv4 against IPv6 constraints and vice versa */
1142
0
      if (name->size != rname.size / 2)
1143
0
        continue;
1144
1145
0
      if (ip_in_cidr(name, &rname) != 0)
1146
0
        return gnutls_assert_val(0); /* rejected */
1147
0
    }
1148
0
  } while (ret == 0);
1149
1150
  /* check allowed */
1151
0
  i = 0;
1152
0
  do {
1153
0
    ret = gnutls_x509_name_constraints_get_permitted(
1154
0
      nc, i++, &rtype, &rname);
1155
0
    if (ret >= 0) {
1156
0
      if (rtype != GNUTLS_SAN_IPADDRESS)
1157
0
        continue;
1158
1159
      /* do not check IPv4 against IPv6 constraints and vice versa */
1160
0
      if (name->size != rname.size / 2)
1161
0
        continue;
1162
1163
0
      allowed_found = 1;
1164
1165
0
      if (ip_in_cidr(name, &rname) != 0)
1166
0
        return 1; /* accepted */
1167
0
    }
1168
0
  } while (ret == 0);
1169
1170
0
  if (allowed_found !=
1171
0
      0) /* there are allowed directives but this host wasn't found */
1172
0
    return gnutls_assert_val(0);
1173
1174
0
  return 1;
1175
0
}
1176
1177
/**
1178
 * gnutls_x509_name_constraints_check:
1179
 * @nc: the extracted name constraints
1180
 * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t)
1181
 * @name: the name to be checked
1182
 *
1183
 * This function will check the provided name against the constraints in
1184
 * @nc using the RFC5280 rules. Currently this function is limited to DNS
1185
 * names, emails and IP addresses (of type %GNUTLS_SAN_DNSNAME,
1186
 * %GNUTLS_SAN_RFC822NAME and %GNUTLS_SAN_IPADDRESS).
1187
 *
1188
 * Returns: zero if the provided name is not acceptable, and non-zero otherwise.
1189
 *
1190
 * Since: 3.3.0
1191
 **/
1192
unsigned gnutls_x509_name_constraints_check(gnutls_x509_name_constraints_t nc,
1193
              gnutls_x509_subject_alt_name_t type,
1194
              const gnutls_datum_t *name)
1195
0
{
1196
0
  if (type == GNUTLS_SAN_DNSNAME)
1197
0
    return check_dns_constraints(nc, name);
1198
1199
0
  if (type == GNUTLS_SAN_RFC822NAME)
1200
0
    return check_email_constraints(nc, name);
1201
1202
0
  if (type == GNUTLS_SAN_IPADDRESS)
1203
0
    return check_ip_constraints(nc, name);
1204
1205
0
  return check_unsupported_constraint(nc, type);
1206
0
}
1207
1208
/* This function checks for unsupported constraints, that we also
1209
 * know their structure. That is it will fail only if the constraint
1210
 * is present in the CA, _and_ the name in the end certificate contains
1211
 * the constrained element.
1212
 *
1213
 * Returns: true if the certification is acceptable, and false otherwise
1214
 */
1215
static unsigned
1216
check_unsupported_constraint2(gnutls_x509_crt_t cert,
1217
            gnutls_x509_name_constraints_t nc,
1218
            gnutls_x509_subject_alt_name_t type)
1219
0
{
1220
0
  unsigned idx, found_one;
1221
0
  char name[MAX_CN];
1222
0
  size_t name_size;
1223
0
  unsigned san_type;
1224
0
  int ret;
1225
1226
0
  found_one = 0;
1227
1228
0
  for (idx = 0;; idx++) {
1229
0
    name_size = sizeof(name);
1230
0
    ret = gnutls_x509_crt_get_subject_alt_name2(
1231
0
      cert, idx, name, &name_size, &san_type, NULL);
1232
0
    if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1233
0
      break;
1234
0
    else if (ret < 0)
1235
0
      return gnutls_assert_val(0);
1236
1237
0
    if (san_type != GNUTLS_SAN_URI)
1238
0
      continue;
1239
1240
0
    found_one = 1;
1241
0
    break;
1242
0
  }
1243
1244
0
  if (found_one != 0)
1245
0
    return check_unsupported_constraint(nc, type);
1246
1247
  /* no name was found in the certificate, so accept */
1248
0
  return 1;
1249
0
}
1250
1251
/**
1252
 * gnutls_x509_name_constraints_check_crt:
1253
 * @nc: the extracted name constraints
1254
 * @type: the type of the constraint to check (of type gnutls_x509_subject_alt_name_t)
1255
 * @cert: the certificate to be checked
1256
 *
1257
 * This function will check the provided certificate names against the constraints in
1258
 * @nc using the RFC5280 rules. It will traverse all the certificate's names and
1259
 * alternative names.
1260
 *
1261
 * Currently this function is limited to DNS
1262
 * names and emails (of type %GNUTLS_SAN_DNSNAME and %GNUTLS_SAN_RFC822NAME).
1263
 *
1264
 * Returns: zero if the provided name is not acceptable, and non-zero otherwise.
1265
 *
1266
 * Since: 3.3.0
1267
 **/
1268
unsigned
1269
gnutls_x509_name_constraints_check_crt(gnutls_x509_name_constraints_t nc,
1270
               gnutls_x509_subject_alt_name_t type,
1271
               gnutls_x509_crt_t cert)
1272
0
{
1273
0
  char name[MAX_CN];
1274
0
  size_t name_size;
1275
0
  int ret;
1276
0
  unsigned idx, t, san_type;
1277
0
  gnutls_datum_t n;
1278
0
  unsigned found_one;
1279
0
  size_t checks;
1280
1281
0
  if (_gnutls_x509_name_constraints_is_empty(nc, type) != 0)
1282
0
    return 1; /* shortcut; no constraints to check */
1283
1284
0
  if (!INT_ADD_OK(nc->permitted.size, nc->excluded.size, &checks) ||
1285
0
      !INT_MULTIPLY_OK(checks, cert->san->size, &checks) ||
1286
0
      checks > MAX_NC_CHECKS) {
1287
0
    return gnutls_assert_val(0);
1288
0
  }
1289
1290
0
  if (type == GNUTLS_SAN_RFC822NAME) {
1291
0
    found_one = 0;
1292
0
    for (idx = 0;; idx++) {
1293
0
      name_size = sizeof(name);
1294
0
      ret = gnutls_x509_crt_get_subject_alt_name2(
1295
0
        cert, idx, name, &name_size, &san_type, NULL);
1296
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1297
0
        break;
1298
0
      else if (ret < 0)
1299
0
        return gnutls_assert_val(0);
1300
1301
0
      if (san_type != GNUTLS_SAN_RFC822NAME)
1302
0
        continue;
1303
1304
0
      found_one = 1;
1305
0
      n.data = (void *)name;
1306
0
      n.size = name_size;
1307
0
      t = gnutls_x509_name_constraints_check(
1308
0
        nc, GNUTLS_SAN_RFC822NAME, &n);
1309
0
      if (t == 0)
1310
0
        return gnutls_assert_val(t);
1311
0
    }
1312
1313
    /* there is at least a single e-mail. That means that the EMAIL field will
1314
     * not be used for verifying the identity of the holder. */
1315
0
    if (found_one != 0)
1316
0
      return 1;
1317
1318
0
    do {
1319
      /* ensure there is only a single EMAIL, similarly to CN handling (rfc6125) */
1320
0
      name_size = sizeof(name);
1321
0
      ret = gnutls_x509_crt_get_dn_by_oid(
1322
0
        cert, GNUTLS_OID_PKCS9_EMAIL, 1, 0, name,
1323
0
        &name_size);
1324
0
      if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1325
0
        return gnutls_assert_val(0);
1326
1327
0
      name_size = sizeof(name);
1328
0
      ret = gnutls_x509_crt_get_dn_by_oid(
1329
0
        cert, GNUTLS_OID_PKCS9_EMAIL, 0, 0, name,
1330
0
        &name_size);
1331
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1332
0
        break;
1333
0
      else if (ret < 0)
1334
0
        return gnutls_assert_val(0);
1335
1336
0
      found_one = 1;
1337
0
      n.data = (void *)name;
1338
0
      n.size = name_size;
1339
0
      t = gnutls_x509_name_constraints_check(
1340
0
        nc, GNUTLS_SAN_RFC822NAME, &n);
1341
0
      if (t == 0)
1342
0
        return gnutls_assert_val(t);
1343
0
    } while (0);
1344
1345
    /* passed */
1346
0
    if (found_one != 0)
1347
0
      return 1;
1348
0
    else {
1349
      /* no name was found. According to RFC5280: 
1350
       * If no name of the type is in the certificate, the certificate is acceptable.
1351
       */
1352
0
      return gnutls_assert_val(1);
1353
0
    }
1354
0
  } else if (type == GNUTLS_SAN_DNSNAME) {
1355
0
    found_one = 0;
1356
0
    for (idx = 0;; idx++) {
1357
0
      name_size = sizeof(name);
1358
0
      ret = gnutls_x509_crt_get_subject_alt_name2(
1359
0
        cert, idx, name, &name_size, &san_type, NULL);
1360
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1361
0
        break;
1362
0
      else if (ret < 0)
1363
0
        return gnutls_assert_val(0);
1364
1365
0
      if (san_type != GNUTLS_SAN_DNSNAME)
1366
0
        continue;
1367
1368
0
      found_one = 1;
1369
0
      n.data = (void *)name;
1370
0
      n.size = name_size;
1371
0
      t = gnutls_x509_name_constraints_check(
1372
0
        nc, GNUTLS_SAN_DNSNAME, &n);
1373
0
      if (t == 0)
1374
0
        return gnutls_assert_val(t);
1375
0
    }
1376
1377
    /* there is at least a single DNS name. That means that the CN will
1378
     * not be used for verifying the identity of the holder. */
1379
0
    if (found_one != 0)
1380
0
      return 1;
1381
1382
    /* verify the name constraints against the CN, if the certificate is
1383
     * not a CA. We do this check only on certificates marked as WWW server,
1384
     * because that's where the CN check is only performed. */
1385
0
    if (_gnutls_check_key_purpose(cert, GNUTLS_KP_TLS_WWW_SERVER,
1386
0
                0) != 0)
1387
0
      do {
1388
        /* ensure there is only a single CN, according to rfc6125 */
1389
0
        name_size = sizeof(name);
1390
0
        ret = gnutls_x509_crt_get_dn_by_oid(
1391
0
          cert, GNUTLS_OID_X520_COMMON_NAME, 1, 0,
1392
0
          name, &name_size);
1393
0
        if (ret !=
1394
0
            GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1395
0
          return gnutls_assert_val(0);
1396
1397
0
        name_size = sizeof(name);
1398
0
        ret = gnutls_x509_crt_get_dn_by_oid(
1399
0
          cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0,
1400
0
          name, &name_size);
1401
0
        if (ret ==
1402
0
            GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1403
0
          break;
1404
0
        else if (ret < 0)
1405
0
          return gnutls_assert_val(0);
1406
1407
0
        found_one = 1;
1408
0
        n.data = (void *)name;
1409
0
        n.size = name_size;
1410
0
        t = gnutls_x509_name_constraints_check(
1411
0
          nc, GNUTLS_SAN_DNSNAME, &n);
1412
0
        if (t == 0)
1413
0
          return gnutls_assert_val(t);
1414
0
      } while (0);
1415
1416
    /* passed */
1417
0
    if (found_one != 0)
1418
0
      return 1;
1419
0
    else {
1420
      /* no name was found. According to RFC5280: 
1421
       * If no name of the type is in the certificate, the certificate is acceptable.
1422
       */
1423
0
      return gnutls_assert_val(1);
1424
0
    }
1425
0
  } else if (type == GNUTLS_SAN_IPADDRESS) {
1426
0
    found_one = 0;
1427
0
    for (idx = 0;; idx++) {
1428
0
      name_size = sizeof(name);
1429
0
      ret = gnutls_x509_crt_get_subject_alt_name2(
1430
0
        cert, idx, name, &name_size, &san_type, NULL);
1431
0
      if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1432
0
        break;
1433
0
      else if (ret < 0)
1434
0
        return gnutls_assert_val(0);
1435
1436
0
      if (san_type != GNUTLS_SAN_IPADDRESS)
1437
0
        continue;
1438
1439
0
      found_one = 1;
1440
0
      n.data = (void *)name;
1441
0
      n.size = name_size;
1442
0
      t = gnutls_x509_name_constraints_check(
1443
0
        nc, GNUTLS_SAN_IPADDRESS, &n);
1444
0
      if (t == 0)
1445
0
        return gnutls_assert_val(t);
1446
0
    }
1447
1448
    /* there is at least a single IP address. */
1449
1450
0
    if (found_one != 0) {
1451
0
      return 1;
1452
0
    } else {
1453
      /* no name was found. According to RFC5280:
1454
       * If no name of the type is in the certificate, the certificate is acceptable.
1455
       */
1456
0
      return gnutls_assert_val(1);
1457
0
    }
1458
0
  } else if (type == GNUTLS_SAN_URI) {
1459
0
    return check_unsupported_constraint2(cert, nc, type);
1460
0
  } else
1461
0
    return check_unsupported_constraint(nc, type);
1462
0
}
1463
1464
/**
1465
 * gnutls_x509_name_constraints_get_permitted:
1466
 * @nc: the extracted name constraints
1467
 * @idx: the index of the constraint
1468
 * @type: the type of the constraint (of type gnutls_x509_subject_alt_name_t)
1469
 * @name: the name in the constraint (of the specific type)
1470
 *
1471
 * This function will return an intermediate type containing
1472
 * the name constraints of the provided CA certificate. That
1473
 * structure can be used in combination with gnutls_x509_name_constraints_check()
1474
 * to verify whether a server's name is in accordance with the constraints.
1475
 *
1476
 * The name should be treated as constant and valid for the lifetime of @nc.
1477
 *
1478
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1479
 * if the extension is not present, otherwise a negative error value.
1480
 *
1481
 * Since: 3.3.0
1482
 **/
1483
int gnutls_x509_name_constraints_get_permitted(gnutls_x509_name_constraints_t nc,
1484
                 unsigned idx, unsigned *type,
1485
                 gnutls_datum_t *name)
1486
0
{
1487
0
  const struct name_constraints_node_st *tmp;
1488
1489
0
  if (idx >= nc->permitted.size)
1490
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1491
1492
0
  tmp = nc->permitted.data[idx];
1493
1494
0
  *type = tmp->type;
1495
0
  *name = tmp->name;
1496
1497
0
  return 0;
1498
0
}
1499
1500
/**
1501
 * gnutls_x509_name_constraints_get_excluded:
1502
 * @nc: the extracted name constraints
1503
 * @idx: the index of the constraint
1504
 * @type: the type of the constraint (of type gnutls_x509_subject_alt_name_t)
1505
 * @name: the name in the constraint (of the specific type)
1506
 *
1507
 * This function will return an intermediate type containing
1508
 * the name constraints of the provided CA certificate. That
1509
 * structure can be used in combination with gnutls_x509_name_constraints_check()
1510
 * to verify whether a server's name is in accordance with the constraints.
1511
 *
1512
 * The name should be treated as constant and valid for the lifetime of @nc.
1513
 *
1514
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1515
 * if the extension is not present, otherwise a negative error value.
1516
 *
1517
 * Since: 3.3.0
1518
 **/
1519
int gnutls_x509_name_constraints_get_excluded(gnutls_x509_name_constraints_t nc,
1520
                unsigned idx, unsigned *type,
1521
                gnutls_datum_t *name)
1522
0
{
1523
0
  const struct name_constraints_node_st *tmp;
1524
1525
0
  if (idx >= nc->excluded.size)
1526
0
    return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1527
1528
0
  tmp = nc->excluded.data[idx];
1529
1530
0
  *type = tmp->type;
1531
0
  *name = tmp->name;
1532
1533
0
  return 0;
1534
0
}