Coverage Report

Created: 2023-11-19 07:41

/src/gnutls/lib/x509/dn.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2003-2014 Free Software Foundation, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include "gnutls_int.h"
24
#include <libtasn1.h>
25
#include "datum.h"
26
#include "global.h"
27
#include "errors.h"
28
#include "str.h"
29
#include "common.h"
30
#include "num.h"
31
32
/* This file includes all the required to parse an X.509 Distriguished
33
 * Name (you need a parser just to read a name in the X.509 protocols!!!)
34
 */
35
36
static int append_elements(asn1_node asn1_struct, const char *asn1_rdn_name,
37
         gnutls_buffer_st *str, int k1, unsigned last)
38
530k
{
39
530k
  int k2, result, max_k2;
40
530k
  int len;
41
530k
  uint8_t value[MAX_STRING_LEN];
42
530k
  char tmpbuffer1[MAX_NAME_SIZE];
43
530k
  char tmpbuffer2[MAX_NAME_SIZE];
44
530k
  char tmpbuffer3[MAX_NAME_SIZE];
45
530k
  const char *ldap_desc;
46
530k
  char oid[MAX_OID_SIZE];
47
530k
  gnutls_datum_t td = { NULL, 0 };
48
530k
  gnutls_datum_t tvd = { NULL, 0 };
49
50
  /* create a string like "tbsCertList.issuer.rdnSequence.?1"
51
   */
52
530k
  if (asn1_rdn_name[0] != 0)
53
530k
    snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%d",
54
530k
       asn1_rdn_name, k1);
55
0
  else
56
0
    snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%d", k1);
57
58
530k
  len = sizeof(value) - 1;
59
530k
  result = asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
60
61
530k
  if (result != ASN1_VALUE_NOT_FOUND &&
62
530k
      result != ASN1_SUCCESS) { /* expected */
63
0
    gnutls_assert();
64
0
    result = _gnutls_asn2err(result);
65
0
    goto cleanup;
66
0
  }
67
68
530k
  k2 = 0;
69
70
530k
  result = asn1_number_of_elements(asn1_struct, tmpbuffer1, &max_k2);
71
530k
  if (result != ASN1_SUCCESS) {
72
0
    gnutls_assert();
73
0
    result = _gnutls_asn2err(result);
74
0
    goto cleanup;
75
0
  }
76
77
977k
  do { /* Move to the attribute type and values
78
         */
79
977k
    k2++;
80
81
977k
    if (tmpbuffer1[0] != 0)
82
977k
      snprintf(tmpbuffer2, sizeof(tmpbuffer2), "%s.?%d",
83
977k
         tmpbuffer1, k2);
84
0
    else
85
0
      snprintf(tmpbuffer2, sizeof(tmpbuffer2), "?%d", k2);
86
87
    /* Try to read the RelativeDistinguishedName attributes.
88
     */
89
90
977k
    len = sizeof(value) - 1;
91
977k
    result = asn1_read_value(asn1_struct, tmpbuffer2, value, &len);
92
93
977k
    if (result == ASN1_ELEMENT_NOT_FOUND)
94
512k
      break;
95
465k
    if (result != ASN1_VALUE_NOT_FOUND &&
96
465k
        result != ASN1_SUCCESS) { /* expected */
97
0
      gnutls_assert();
98
0
      result = _gnutls_asn2err(result);
99
0
      goto cleanup;
100
0
    }
101
102
    /* Read the OID 
103
     */
104
465k
    _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3), tmpbuffer2);
105
465k
    _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3), ".type");
106
107
465k
    len = sizeof(oid) - 1;
108
465k
    result = asn1_read_value(asn1_struct, tmpbuffer3, oid, &len);
109
110
465k
    if (result == ASN1_ELEMENT_NOT_FOUND)
111
16.5k
      break;
112
448k
    else if (result != ASN1_SUCCESS) {
113
425
      gnutls_assert();
114
425
      result = _gnutls_asn2err(result);
115
425
      goto cleanup;
116
425
    }
117
118
    /* Read the Value 
119
     */
120
448k
    _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3), tmpbuffer2);
121
448k
    _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3), ".value");
122
123
448k
    len = 0;
124
125
448k
    result = _gnutls_x509_read_value(asn1_struct, tmpbuffer3, &tvd);
126
448k
    if (result < 0) {
127
0
      gnutls_assert();
128
0
      goto cleanup;
129
0
    }
130
448k
#define STR_APPEND(y)                                           \
131
1.26M
  if ((result = _gnutls_buffer_append_str(str, y)) < 0) { \
132
0
    gnutls_assert();                                \
133
0
    goto cleanup;                                   \
134
0
  }
135
448k
#define DATA_APPEND(x, y)                                           \
136
448k
  if ((result = _gnutls_buffer_append_data(str, x, y)) < 0) { \
137
0
    gnutls_assert();                                    \
138
0
    goto cleanup;                                       \
139
0
  }
140
    /*   The encodings of adjoining RelativeDistinguishedNames are separated
141
     *   by a comma character (',' ASCII 44).
142
     */
143
144
448k
    ldap_desc = gnutls_x509_dn_oid_name(
145
448k
      oid, GNUTLS_X509_DN_OID_RETURN_OID);
146
147
448k
    STR_APPEND(ldap_desc);
148
448k
    STR_APPEND("=");
149
150
    /* DirectoryString by definition in RFC 5280 cannot be empty.
151
     * If asn_node.value_len = 0 the parser correctly rejects such DirectoryString.
152
     * However, if asn_node.value contains ASN.1 TLV triplet with length = 0,
153
     * such DirectoryString is not rejected by the parser as the node itself is not empty.
154
     * Explicitly reject DirectoryString in such case.
155
     */
156
448k
    const char *asn_desc = _gnutls_oid_get_asn_desc(oid);
157
448k
    if (asn_desc && !strcmp(asn_desc, "PKIX1.DirectoryString") &&
158
448k
        tvd.data[1] == 0) {
159
106
      gnutls_assert();
160
106
      result = GNUTLS_E_ASN1_VALUE_NOT_VALID;
161
106
      _gnutls_debug_log("Empty DirectoryString\n");
162
106
      goto cleanup;
163
106
    }
164
165
448k
    result =
166
448k
      _gnutls_x509_dn_to_string(oid, tvd.data, tvd.size, &td);
167
448k
    if (result < 0) {
168
665
      gnutls_assert();
169
665
      _gnutls_debug_log(
170
665
        "Cannot parse OID: '%s' with value '%s'\n", oid,
171
665
        _gnutls_bin2hex(tvd.data, tvd.size, tmpbuffer3,
172
665
            sizeof(tmpbuffer3), NULL));
173
665
      goto cleanup;
174
665
    }
175
176
447k
    DATA_APPEND(td.data, td.size);
177
447k
    _gnutls_free_datum(&td);
178
447k
    _gnutls_free_datum(&tvd);
179
180
    /*   Where there is a multi-valued RDN, the outputs from adjoining
181
     *   AttributeTypeAndValues are separated by a plus ('+' ASCII 43)
182
     *   character.
183
     */
184
447k
    if (k2 < max_k2) {
185
18.0k
      STR_APPEND("+");
186
429k
    } else if (!last) {
187
354k
      STR_APPEND(",");
188
354k
    }
189
447k
  } while (1);
190
191
528k
  result = 0;
192
193
530k
cleanup:
194
530k
  _gnutls_free_datum(&td);
195
530k
  _gnutls_free_datum(&tvd);
196
530k
  return result;
197
528k
}
198
199
int _gnutls_x509_get_dn(asn1_node asn1_struct, const char *asn1_rdn_name,
200
      gnutls_datum_t *dn, unsigned flags)
201
81.0k
{
202
81.0k
  gnutls_buffer_st out_str;
203
81.0k
  int i, k1, result;
204
205
81.0k
  _gnutls_buffer_init(&out_str);
206
207
81.0k
  result = asn1_number_of_elements(asn1_struct, asn1_rdn_name, &k1);
208
81.0k
  if (result != ASN1_SUCCESS) {
209
629
    if (result == ASN1_ELEMENT_NOT_FOUND ||
210
629
        result == ASN1_VALUE_NOT_FOUND) {
211
629
      result = gnutls_assert_val(
212
629
        GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
213
629
    } else {
214
0
      gnutls_assert();
215
0
      result = _gnutls_asn2err(result);
216
0
    }
217
629
    goto cleanup;
218
629
  }
219
220
80.4k
  if (k1 == 0) {
221
3.47k
    gnutls_assert();
222
3.47k
    result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
223
3.47k
    goto cleanup;
224
3.47k
  }
225
226
76.9k
  if (flags & GNUTLS_X509_DN_FLAG_COMPAT) {
227
90.8k
    for (i = 0; i < k1; i++) {
228
87.1k
      result = append_elements(asn1_struct, asn1_rdn_name,
229
87.1k
             &out_str, i + 1,
230
87.1k
             (i == (k1 - 1)) ? 1 : 0);
231
87.1k
      if (result < 0) {
232
125
        gnutls_assert();
233
125
        goto cleanup;
234
125
      }
235
87.1k
    }
236
73.0k
  } else {
237
515k
    while (k1 > 0) {
238
443k
      result = append_elements(asn1_struct, asn1_rdn_name,
239
443k
             &out_str, k1, k1 == 1 ? 1 : 0);
240
443k
      if (result < 0) {
241
1.07k
        gnutls_assert();
242
1.07k
        goto cleanup;
243
1.07k
      }
244
441k
      k1--;
245
441k
    }
246
73.0k
  }
247
248
75.7k
  return _gnutls_buffer_to_datum(&out_str, dn, 1);
249
250
5.29k
cleanup:
251
5.29k
  _gnutls_buffer_clear(&out_str);
252
5.29k
  return result;
253
76.9k
}
254
255
/* Parses an X509 DN in the asn1_struct, and puts the output into
256
 * the string buf. The output is an LDAP encoded DN.
257
 *
258
 * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
259
 * That is to point in the rndSequence.
260
 */
261
int _gnutls_x509_parse_dn(asn1_node asn1_struct, const char *asn1_rdn_name,
262
        char *buf, size_t *buf_size, unsigned flags)
263
0
{
264
0
  int ret;
265
0
  gnutls_datum_t dn = { NULL, 0 };
266
267
0
  if (buf_size == NULL) {
268
0
    gnutls_assert();
269
0
    return GNUTLS_E_INVALID_REQUEST;
270
0
  }
271
272
0
  if (*buf_size > 0 && buf)
273
0
    buf[0] = 0;
274
0
  else
275
0
    *buf_size = 0;
276
277
0
  ret = _gnutls_x509_get_dn(asn1_struct, asn1_rdn_name, &dn, flags);
278
0
  if (ret < 0)
279
0
    return gnutls_assert_val(ret);
280
281
0
  if (dn.size >= (unsigned int)*buf_size) {
282
0
    gnutls_assert();
283
0
    *buf_size = dn.size + 1;
284
0
    ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
285
0
    goto cleanup;
286
0
  }
287
288
0
  assert(dn.data != NULL);
289
290
0
  if (buf) {
291
0
    memcpy(buf, dn.data, dn.size);
292
0
    buf[dn.size] = 0;
293
0
    *buf_size = dn.size;
294
0
  } else
295
0
    *buf_size = dn.size + 1;
296
297
0
  ret = 0;
298
0
cleanup:
299
0
  _gnutls_free_datum(&dn);
300
0
  return ret;
301
0
}
302
303
/* Parses an X509 DN in the asn1_struct, and searches for the
304
 * given OID in the DN.
305
 *
306
 * If raw_flag == 0, the output will be encoded in the LDAP way. (#hex for non printable)
307
 * Otherwise the raw DER data are returned.
308
 *
309
 * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
310
 * That is to point in the rndSequence.
311
 *
312
 * indx specifies which OID to return. Ie 0 means return the first specified
313
 * OID found, 1 the second etc.
314
 */
315
int _gnutls_x509_parse_dn_oid(asn1_node asn1_struct, const char *asn1_rdn_name,
316
            const char *given_oid, int indx,
317
            unsigned int raw_flag, gnutls_datum_t *out)
318
10.5k
{
319
10.5k
  int k2, k1, result;
320
10.5k
  char tmpbuffer1[MAX_NAME_SIZE];
321
10.5k
  char tmpbuffer2[MAX_NAME_SIZE];
322
10.5k
  char tmpbuffer3[MAX_NAME_SIZE];
323
10.5k
  gnutls_datum_t td;
324
10.5k
  uint8_t value[256];
325
10.5k
  char oid[MAX_OID_SIZE];
326
10.5k
  int len;
327
10.5k
  int i = 0;
328
329
10.5k
  k1 = 0;
330
10.5k
  do {
331
10.5k
    k1++;
332
    /* create a string like "tbsCertList.issuer.rdnSequence.?1"
333
     */
334
10.5k
    if (asn1_rdn_name[0] != 0)
335
10.5k
      snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%d",
336
10.5k
         asn1_rdn_name, k1);
337
0
    else
338
0
      snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%d", k1);
339
340
10.5k
    len = sizeof(value) - 1;
341
10.5k
    result = asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
342
343
10.5k
    if (result == ASN1_ELEMENT_NOT_FOUND) {
344
0
      gnutls_assert();
345
0
      break;
346
0
    }
347
348
10.5k
    if (result != ASN1_VALUE_NOT_FOUND) {
349
0
      gnutls_assert();
350
0
      result = _gnutls_asn2err(result);
351
0
      goto cleanup;
352
0
    }
353
354
10.5k
    k2 = 0;
355
356
10.5k
    do { /* Move to the attribute type and values
357
         */
358
10.5k
      k2++;
359
360
10.5k
      if (tmpbuffer1[0] != 0)
361
10.5k
        snprintf(tmpbuffer2, sizeof(tmpbuffer2),
362
10.5k
           "%s.?%d", tmpbuffer1, k2);
363
0
      else
364
0
        snprintf(tmpbuffer2, sizeof(tmpbuffer2), "?%d",
365
0
           k2);
366
367
      /* Try to read the RelativeDistinguishedName attributes.
368
       */
369
370
10.5k
      len = sizeof(value) - 1;
371
10.5k
      result = asn1_read_value(asn1_struct, tmpbuffer2, value,
372
10.5k
             &len);
373
374
10.5k
      if (result == ASN1_ELEMENT_NOT_FOUND) {
375
0
        break;
376
0
      }
377
10.5k
      if (result != ASN1_VALUE_NOT_FOUND) {
378
0
        gnutls_assert();
379
0
        result = _gnutls_asn2err(result);
380
0
        goto cleanup;
381
0
      }
382
383
      /* Read the OID 
384
       */
385
10.5k
      _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
386
10.5k
          tmpbuffer2);
387
10.5k
      _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
388
10.5k
          ".type");
389
390
10.5k
      len = sizeof(oid) - 1;
391
10.5k
      result = asn1_read_value(asn1_struct, tmpbuffer3, oid,
392
10.5k
             &len);
393
394
10.5k
      if (result == ASN1_ELEMENT_NOT_FOUND)
395
0
        break;
396
10.5k
      else if (result != ASN1_SUCCESS) {
397
0
        gnutls_assert();
398
0
        result = _gnutls_asn2err(result);
399
0
        goto cleanup;
400
0
      }
401
402
10.5k
      if (strcmp(oid, given_oid) == 0 &&
403
10.5k
          indx == i++) { /* Found the OID */
404
405
        /* Read the Value 
406
         */
407
10.5k
        _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
408
10.5k
            tmpbuffer2);
409
10.5k
        _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
410
10.5k
            ".value");
411
412
10.5k
        result = _gnutls_x509_read_value(
413
10.5k
          asn1_struct, tmpbuffer3, &td);
414
10.5k
        if (result < 0) {
415
0
          gnutls_assert();
416
0
          goto cleanup;
417
0
        }
418
419
10.5k
        if (raw_flag != 0) {
420
0
          out->data = td.data;
421
0
          out->size = td.size;
422
0
          return 0;
423
424
10.5k
        } else { /* parse data. raw_flag == 0 */
425
10.5k
          result = _gnutls_x509_dn_to_string(
426
10.5k
            oid, td.data, td.size, out);
427
428
10.5k
          _gnutls_free_datum(&td);
429
10.5k
          if (result < 0) {
430
0
            gnutls_assert();
431
0
            goto cleanup;
432
0
          }
433
434
10.5k
          return 0;
435
436
10.5k
        } /* raw_flag == 0 */
437
10.5k
      }
438
10.5k
    } while (1);
439
440
10.5k
  } while (1);
441
442
0
  gnutls_assert();
443
444
0
  result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
445
446
0
cleanup:
447
0
  return result;
448
0
}
449
450
/* Parses an X509 DN in the asn1_struct, and returns the requested
451
 * DN OID.
452
 *
453
 * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence".
454
 * That is to point in the rndSequence.
455
 *
456
 * indx specifies which OID to return. Ie 0 means return the first specified
457
 * OID found, 1 the second etc.
458
 */
459
int _gnutls_x509_get_dn_oid(asn1_node asn1_struct, const char *asn1_rdn_name,
460
          int indx, void *_oid, size_t *sizeof_oid)
461
0
{
462
0
  int k2, k1, result;
463
0
  char tmpbuffer1[MAX_NAME_SIZE];
464
0
  char tmpbuffer2[MAX_NAME_SIZE];
465
0
  char tmpbuffer3[MAX_NAME_SIZE];
466
0
  char value[256];
467
0
  char oid[MAX_OID_SIZE];
468
0
  int len;
469
0
  int i = 0;
470
471
0
  k1 = 0;
472
0
  do {
473
0
    k1++;
474
    /* create a string like "tbsCertList.issuer.rdnSequence.?1"
475
     */
476
0
    if (asn1_rdn_name[0] != 0)
477
0
      snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%d",
478
0
         asn1_rdn_name, k1);
479
0
    else
480
0
      snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%d", k1);
481
482
0
    len = sizeof(value) - 1;
483
0
    result = asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
484
485
0
    if (result == ASN1_ELEMENT_NOT_FOUND) {
486
0
      gnutls_assert();
487
0
      break;
488
0
    }
489
490
0
    if (result != ASN1_VALUE_NOT_FOUND) {
491
0
      gnutls_assert();
492
0
      result = _gnutls_asn2err(result);
493
0
      goto cleanup;
494
0
    }
495
496
0
    k2 = 0;
497
498
0
    do { /* Move to the attribute type and values
499
         */
500
0
      k2++;
501
502
0
      if (tmpbuffer1[0] != 0)
503
0
        snprintf(tmpbuffer2, sizeof(tmpbuffer2),
504
0
           "%s.?%d", tmpbuffer1, k2);
505
0
      else
506
0
        snprintf(tmpbuffer2, sizeof(tmpbuffer2), "?%d",
507
0
           k2);
508
509
      /* Try to read the RelativeDistinguishedName attributes.
510
       */
511
512
0
      len = sizeof(value) - 1;
513
0
      result = asn1_read_value(asn1_struct, tmpbuffer2, value,
514
0
             &len);
515
516
0
      if (result == ASN1_ELEMENT_NOT_FOUND) {
517
0
        break;
518
0
      }
519
0
      if (result != ASN1_VALUE_NOT_FOUND) {
520
0
        gnutls_assert();
521
0
        result = _gnutls_asn2err(result);
522
0
        goto cleanup;
523
0
      }
524
525
      /* Read the OID 
526
       */
527
0
      _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
528
0
          tmpbuffer2);
529
0
      _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
530
0
          ".type");
531
532
0
      len = sizeof(oid) - 1;
533
0
      result = asn1_read_value(asn1_struct, tmpbuffer3, oid,
534
0
             &len);
535
536
0
      if (result == ASN1_ELEMENT_NOT_FOUND)
537
0
        break;
538
0
      else if (result != ASN1_SUCCESS) {
539
0
        gnutls_assert();
540
0
        result = _gnutls_asn2err(result);
541
0
        goto cleanup;
542
0
      }
543
544
0
      if (indx == i++) { /* Found the OID */
545
546
0
        len = strlen(oid) + 1;
547
548
0
        if (*sizeof_oid < (unsigned)len) {
549
0
          *sizeof_oid = len;
550
0
          gnutls_assert();
551
0
          return GNUTLS_E_SHORT_MEMORY_BUFFER;
552
0
        }
553
554
0
        memcpy(_oid, oid, len);
555
0
        *sizeof_oid = len - 1;
556
557
0
        return 0;
558
0
      }
559
0
    } while (1);
560
561
0
  } while (1);
562
563
0
  gnutls_assert();
564
565
0
  result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
566
567
0
cleanup:
568
0
  return result;
569
0
}
570
571
/* This will write the AttributeTypeAndValue field. The data must be already DER encoded.
572
 * 'multi' must be (0) if writing an AttributeTypeAndValue, and 1 if Attribute.
573
 * In all cases only one value is written.
574
 */
575
static int _gnutls_x509_write_attribute(const char *given_oid,
576
          asn1_node asn1_struct,
577
          const char *where, const void *_data,
578
          int sizeof_data)
579
0
{
580
0
  char tmp[128];
581
0
  int result;
582
583
  /* write the data (value)
584
   */
585
586
0
  _gnutls_str_cpy(tmp, sizeof(tmp), where);
587
0
  _gnutls_str_cat(tmp, sizeof(tmp), ".value");
588
589
0
  result = asn1_write_value(asn1_struct, tmp, _data, sizeof_data);
590
0
  if (result < 0) {
591
0
    gnutls_assert();
592
0
    return _gnutls_asn2err(result);
593
0
  }
594
595
  /* write the type
596
   */
597
0
  _gnutls_str_cpy(tmp, sizeof(tmp), where);
598
0
  _gnutls_str_cat(tmp, sizeof(tmp), ".type");
599
600
0
  result = asn1_write_value(asn1_struct, tmp, given_oid, 1);
601
0
  if (result != ASN1_SUCCESS) {
602
0
    gnutls_assert();
603
0
    return _gnutls_asn2err(result);
604
0
  }
605
606
0
  return 0;
607
0
}
608
609
/* Decodes an X.509 Attribute (if multi==1) or an AttributeTypeAndValue
610
 * otherwise.
611
 *
612
 * octet_string should be non-zero if we are to decode octet strings after
613
 * decoding.
614
 *
615
 * The output is allocated and stored in value.
616
 */
617
int _gnutls_x509_decode_and_read_attribute(asn1_node asn1_struct,
618
             const char *where, char *oid,
619
             int oid_size, gnutls_datum_t *value,
620
             int multi, int octet_string)
621
14.3k
{
622
14.3k
  char tmpbuffer[128];
623
14.3k
  int len, result;
624
625
  /* Read the OID 
626
   */
627
14.3k
  _gnutls_str_cpy(tmpbuffer, sizeof(tmpbuffer), where);
628
14.3k
  _gnutls_str_cat(tmpbuffer, sizeof(tmpbuffer), ".type");
629
630
14.3k
  len = oid_size - 1;
631
14.3k
  result = asn1_read_value(asn1_struct, tmpbuffer, oid, &len);
632
633
14.3k
  if (result != ASN1_SUCCESS) {
634
27
    gnutls_assert();
635
27
    result = _gnutls_asn2err(result);
636
27
    return result;
637
27
  }
638
639
  /* Read the Value 
640
   */
641
642
14.3k
  _gnutls_str_cpy(tmpbuffer, sizeof(tmpbuffer), where);
643
14.3k
  _gnutls_str_cat(tmpbuffer, sizeof(tmpbuffer), ".value");
644
645
14.3k
  if (multi)
646
14.3k
    _gnutls_str_cat(tmpbuffer, sizeof(tmpbuffer),
647
14.3k
        "s.?1"); /* .values.?1 */
648
649
14.3k
  if (octet_string)
650
0
    result = _gnutls_x509_read_string(asn1_struct, tmpbuffer, value,
651
0
              ASN1_ETYPE_OCTET_STRING, 0);
652
14.3k
  else
653
14.3k
    result = _gnutls_x509_read_value(asn1_struct, tmpbuffer, value);
654
14.3k
  if (result < 0) {
655
6
    gnutls_assert();
656
6
    return result;
657
6
  }
658
659
14.3k
  return 0;
660
14.3k
}
661
662
/* Sets an X509 DN in the asn1_struct, and puts the given OID in the DN.
663
 * The input is assumed to be raw data.
664
 *
665
 * asn1_rdn_name must be a string in the form "tbsCertificate.issuer".
666
 * That is to point before the rndSequence.
667
 *
668
 */
669
int _gnutls_x509_set_dn_oid(asn1_node asn1_struct, const char *asn1_name,
670
          const char *given_oid, int raw_flag,
671
          const char *name, int sizeof_name)
672
0
{
673
0
  int result;
674
0
  char tmp[MAX_NAME_SIZE], asn1_rdn_name[MAX_NAME_SIZE];
675
676
0
  if (sizeof_name == 0 || name == NULL) {
677
0
    gnutls_assert();
678
0
    return GNUTLS_E_INVALID_REQUEST;
679
0
  }
680
681
  /* create the rdnSequence
682
   */
683
0
  result = asn1_write_value(asn1_struct, asn1_name, "rdnSequence", 1);
684
0
  if (result != ASN1_SUCCESS) {
685
0
    gnutls_assert();
686
0
    return _gnutls_asn2err(result);
687
0
  }
688
689
0
  if (asn1_name[0] != 0) {
690
0
    _gnutls_str_cpy(asn1_rdn_name, sizeof(asn1_rdn_name),
691
0
        asn1_name);
692
0
    _gnutls_str_cat(asn1_rdn_name, sizeof(asn1_rdn_name),
693
0
        ".rdnSequence");
694
0
  } else {
695
0
    _gnutls_str_cpy(asn1_rdn_name, sizeof(asn1_rdn_name),
696
0
        "rdnSequence");
697
0
  }
698
699
  /* create a new element 
700
   */
701
0
  result = asn1_write_value(asn1_struct, asn1_rdn_name, "NEW", 1);
702
0
  if (result != ASN1_SUCCESS) {
703
0
    gnutls_assert();
704
0
    return _gnutls_asn2err(result);
705
0
  }
706
707
0
  _gnutls_str_cpy(tmp, sizeof(tmp), asn1_rdn_name);
708
0
  _gnutls_str_cat(tmp, sizeof(tmp), ".?LAST");
709
710
  /* create the set with only one element
711
   */
712
0
  result = asn1_write_value(asn1_struct, tmp, "NEW", 1);
713
0
  if (result != ASN1_SUCCESS) {
714
0
    gnutls_assert();
715
0
    return _gnutls_asn2err(result);
716
0
  }
717
718
  /* Encode and write the data
719
   */
720
0
  _gnutls_str_cpy(tmp, sizeof(tmp), asn1_rdn_name);
721
0
  _gnutls_str_cat(tmp, sizeof(tmp), ".?LAST.?LAST");
722
723
0
  if (!raw_flag) {
724
0
    result = _gnutls_x509_encode_and_write_attribute(
725
0
      given_oid, asn1_struct, tmp, name, sizeof_name, 0);
726
0
  } else {
727
0
    result = _gnutls_x509_write_attribute(given_oid, asn1_struct,
728
0
                  tmp, name, sizeof_name);
729
0
  }
730
731
0
  if (result < 0) {
732
0
    gnutls_assert();
733
0
    return result;
734
0
  }
735
736
0
  return 0;
737
0
}
738
739
/**
740
 * gnutls_x509_rdn_get:
741
 * @idn: should contain a DER encoded RDN sequence
742
 * @buf: a pointer to a structure to hold the peer's name
743
 * @buf_size: holds the size of @buf
744
 *
745
 * This function will return the name of the given RDN sequence.  The
746
 * name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in
747
 * RFC4514.
748
 *
749
 * This function does not output a fully RFC4514 compliant string, if
750
 * that is required see gnutls_x509_rdn_get2().
751
 *
752
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
753
 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
754
 * updated if the provided buffer is not long enough, otherwise a
755
 * negative error value.
756
 **/
757
int gnutls_x509_rdn_get(const gnutls_datum_t *idn, char *buf, size_t *buf_size)
758
0
{
759
0
  int ret;
760
0
  gnutls_datum_t out;
761
762
0
  ret = gnutls_x509_rdn_get2(idn, &out, GNUTLS_X509_DN_FLAG_COMPAT);
763
0
  if (ret < 0)
764
0
    return gnutls_assert_val(ret);
765
766
0
  ret = _gnutls_copy_string(&out, (void *)buf, buf_size);
767
0
  gnutls_free(out.data);
768
0
  if (ret < 0) {
769
0
    gnutls_assert();
770
0
  }
771
772
0
  return ret;
773
0
}
774
775
/**
776
 * gnutls_x509_rdn_get2:
777
 * @idn: should contain a DER encoded RDN sequence
778
 * @str: a datum that will hold the name
779
 * @flags: zero of %GNUTLS_X509_DN_FLAG_COMPAT
780
 *
781
 * This function will return the name of the given RDN sequence.  The
782
 * name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in
783
 * RFC4514.
784
 *
785
 * When the flag %GNUTLS_X509_DN_FLAG_COMPAT is specified, the output
786
 * format will match the format output by previous to 3.5.6 versions of GnuTLS
787
 * which was not not fully RFC4514-compliant.
788
 *
789
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
790
 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
791
 * updated if the provided buffer is not long enough, otherwise a
792
 * negative error value.
793
 **/
794
int gnutls_x509_rdn_get2(const gnutls_datum_t *idn, gnutls_datum_t *str,
795
       unsigned flags)
796
29.0k
{
797
29.0k
  int ret;
798
29.0k
  gnutls_x509_dn_t dn;
799
800
29.0k
  ret = gnutls_x509_dn_init(&dn);
801
29.0k
  if (ret < 0)
802
0
    return gnutls_assert_val(ret);
803
804
29.0k
  ret = gnutls_x509_dn_import(dn, idn);
805
29.0k
  if (ret < 0) {
806
0
    gnutls_assert();
807
0
    goto cleanup;
808
0
  }
809
810
29.0k
  ret = gnutls_x509_dn_get_str2(dn, str, flags);
811
29.0k
  if (ret < 0) {
812
847
    gnutls_assert();
813
847
    goto cleanup;
814
847
  }
815
816
28.1k
  ret = 0;
817
29.0k
cleanup:
818
29.0k
  gnutls_x509_dn_deinit(dn);
819
29.0k
  return ret;
820
28.1k
}
821
822
/**
823
 * gnutls_x509_rdn_get_by_oid:
824
 * @idn: should contain a DER encoded RDN sequence
825
 * @oid: an Object Identifier
826
 * @indx: In case multiple same OIDs exist in the RDN indicates which
827
 *   to send. Use 0 for the first one.
828
 * @raw_flag: If non-zero then the raw DER data are returned.
829
 * @buf: a pointer to a structure to hold the peer's name
830
 * @buf_size: holds the size of @buf
831
 *
832
 * This function will return the name of the given Object identifier,
833
 * of the RDN sequence.  The name will be encoded using the rules
834
 * from RFC4514.
835
 *
836
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
837
 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
838
 * updated if the provided buffer is not long enough, otherwise a
839
 * negative error value.
840
 **/
841
int gnutls_x509_rdn_get_by_oid(const gnutls_datum_t *idn, const char *oid,
842
             unsigned indx, unsigned int raw_flag, void *buf,
843
             size_t *buf_size)
844
0
{
845
0
  int result;
846
0
  asn1_node dn = NULL;
847
0
  gnutls_datum_t td;
848
849
0
  if (buf_size == 0) {
850
0
    return GNUTLS_E_INVALID_REQUEST;
851
0
  }
852
853
0
  if ((result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.Name",
854
0
            &dn)) != ASN1_SUCCESS) {
855
0
    gnutls_assert();
856
0
    return _gnutls_asn2err(result);
857
0
  }
858
859
0
  result = _asn1_strict_der_decode(&dn, idn->data, idn->size, NULL);
860
0
  if (result != ASN1_SUCCESS) {
861
    /* couldn't decode DER */
862
0
    gnutls_assert();
863
0
    asn1_delete_structure(&dn);
864
0
    return _gnutls_asn2err(result);
865
0
  }
866
867
0
  result = _gnutls_x509_parse_dn_oid(dn, "rdnSequence", oid, indx,
868
0
             raw_flag, &td);
869
870
0
  asn1_delete_structure(&dn);
871
0
  if (result < 0)
872
0
    return gnutls_assert_val(result);
873
874
0
  return _gnutls_strdatum_to_buf(&td, buf, buf_size);
875
0
}
876
877
/**
878
 * gnutls_x509_rdn_get_oid:
879
 * @idn: should contain a DER encoded RDN sequence
880
 * @indx: Indicates which OID to return. Use 0 for the first one.
881
 * @buf: a pointer to a structure to hold the peer's name OID
882
 * @buf_size: holds the size of @buf
883
 *
884
 * This function will return the specified Object identifier, of the
885
 * RDN sequence.
886
 *
887
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
888
 * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
889
 * updated if the provided buffer is not long enough, otherwise a
890
 * negative error value.
891
 *
892
 * Since: 2.4.0
893
 **/
894
int gnutls_x509_rdn_get_oid(const gnutls_datum_t *idn, unsigned indx, void *buf,
895
          size_t *buf_size)
896
0
{
897
0
  int result;
898
0
  asn1_node dn = NULL;
899
900
0
  if (buf_size == 0) {
901
0
    return GNUTLS_E_INVALID_REQUEST;
902
0
  }
903
904
0
  if ((result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.Name",
905
0
            &dn)) != ASN1_SUCCESS) {
906
0
    gnutls_assert();
907
0
    return _gnutls_asn2err(result);
908
0
  }
909
910
0
  result = _asn1_strict_der_decode(&dn, idn->data, idn->size, NULL);
911
0
  if (result != ASN1_SUCCESS) {
912
    /* couldn't decode DER */
913
0
    gnutls_assert();
914
0
    asn1_delete_structure(&dn);
915
0
    return _gnutls_asn2err(result);
916
0
  }
917
918
0
  result =
919
0
    _gnutls_x509_get_dn_oid(dn, "rdnSequence", indx, buf, buf_size);
920
921
0
  asn1_delete_structure(&dn);
922
0
  return result;
923
0
}
924
925
/*
926
 * Compares the DER encoded part of a DN.
927
 *
928
 * Returns 1 if the DN's match and (0) if they don't match. Otherwise
929
 * a negative error code is returned to indicate error.
930
 */
931
int _gnutls_x509_compare_raw_dn(const gnutls_datum_t *dn1,
932
        const gnutls_datum_t *dn2)
933
121k
{
934
121k
  int ret;
935
121k
  gnutls_datum_t str1, str2;
936
937
  /* Simple case of completely identical? */
938
939
121k
  if (dn1->size == dn2->size) {
940
115k
    if (memcmp(dn1->data, dn2->data, dn2->size) == 0) {
941
106k
      return 1;
942
106k
    }
943
115k
  }
944
945
  /* RFC5280 (https://tools.ietf.org/html/rfc5280#section-7.1)
946
   * requires that the LDAP StringPrep profile and caseIgnoreMatch
947
   * must be used for this comparison. We do not use that but
948
   * instead we do a simpler comparison that ignores the tags used
949
   * such as `UTF8String` and `PrintableString`. */
950
951
14.7k
  if ((dn1->size == 0) || (dn2->size == 0)) {
952
0
    gnutls_assert();
953
0
    return 0;
954
0
  }
955
956
14.7k
  ret = gnutls_x509_rdn_get2(dn1, &str1, 0);
957
14.7k
  if (ret < 0) {
958
434
    gnutls_assert();
959
434
    return 0;
960
434
  }
961
962
14.2k
  ret = gnutls_x509_rdn_get2(dn2, &str2, 0);
963
14.2k
  if (ret < 0) {
964
413
    gnutls_assert();
965
413
    _gnutls_free_datum(&str1);
966
413
    return 0;
967
413
  }
968
969
13.8k
  if (str1.size != str2.size) {
970
6.55k
    ret = 0;
971
6.55k
    goto cleanup;
972
6.55k
  }
973
7.33k
  if (memcmp(str1.data, str2.data, str2.size) != 0) {
974
1.57k
    gnutls_assert();
975
1.57k
    ret = 0;
976
1.57k
    goto cleanup;
977
1.57k
  }
978
979
5.75k
  ret = 1; /* they match */
980
981
13.8k
cleanup:
982
13.8k
  _gnutls_free_datum(&str1);
983
13.8k
  _gnutls_free_datum(&str2);
984
985
13.8k
  return ret;
986
5.75k
}