Coverage Report

Created: 2023-03-26 08:33

/src/gnutls/lib/pcert.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 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 "errors.h"
25
#include <auth/cert.h>
26
#include <x509/common.h>
27
#include <x509.h>
28
#include "x509/x509_int.h"
29
#include <gnutls/x509.h>
30
#include "x509_b64.h"
31
32
/**
33
 * gnutls_pcert_import_x509:
34
 * @pcert: The pcert structure
35
 * @crt: The certificate to be imported
36
 * @flags: zero for now
37
 *
38
 * This convenience function will import the given certificate to a
39
 * #gnutls_pcert_st structure. The structure must be deinitialized
40
 * afterwards using gnutls_pcert_deinit();
41
 *
42
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
43
 *   negative error value.
44
 *
45
 * Since: 3.0
46
 **/
47
int gnutls_pcert_import_x509(gnutls_pcert_st * pcert,
48
           gnutls_x509_crt_t crt, unsigned int flags)
49
0
{
50
0
  int ret;
51
52
0
  memset(pcert, 0, sizeof(*pcert));
53
54
0
  pcert->type = GNUTLS_CRT_X509;
55
0
  pcert->cert.data = NULL;
56
57
0
  ret = gnutls_x509_crt_export2(crt, GNUTLS_X509_FMT_DER, &pcert->cert);
58
0
  if (ret < 0) {
59
0
    ret = gnutls_assert_val(ret);
60
0
    goto cleanup;
61
0
  }
62
63
0
  ret = gnutls_pubkey_init(&pcert->pubkey);
64
0
  if (ret < 0) {
65
0
    ret = gnutls_assert_val(ret);
66
0
    goto cleanup;
67
0
  }
68
69
0
  ret = gnutls_pubkey_import_x509(pcert->pubkey, crt, 0);
70
0
  if (ret < 0) {
71
0
    gnutls_pubkey_deinit(pcert->pubkey);
72
0
    pcert->pubkey = NULL;
73
0
    ret = gnutls_assert_val(ret);
74
0
    goto cleanup;
75
0
  }
76
77
0
  return 0;
78
79
0
 cleanup:
80
0
  _gnutls_free_datum(&pcert->cert);
81
82
0
  return ret;
83
0
}
84
85
/**
86
 * gnutls_pcert_import_x509_list:
87
 * @pcert_list: The structures to store the certificates; must not contain initialized #gnutls_pcert_st structures.
88
 * @crt: The certificates to be imported
89
 * @ncrt: The number of certificates in @crt; will be updated if necessary
90
 * @flags: zero or %GNUTLS_X509_CRT_LIST_SORT
91
 *
92
 * This convenience function will import the given certificates to an
93
 * already allocated set of #gnutls_pcert_st structures. The structures must
94
 * be deinitialized afterwards using gnutls_pcert_deinit(). @pcert_list
95
 * should contain space for at least @ncrt elements.
96
 *
97
 * In the case %GNUTLS_X509_CRT_LIST_SORT is specified and that
98
 * function cannot sort the list, %GNUTLS_E_CERTIFICATE_LIST_UNSORTED
99
 * will be returned. Currently sorting can fail if the list size
100
 * exceeds an internal constraint (16).
101
 *
102
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
103
 *   negative error value.
104
 *
105
 * Since: 3.4.0
106
 **/
107
int gnutls_pcert_import_x509_list(gnutls_pcert_st * pcert_list,
108
          gnutls_x509_crt_t * crt, unsigned *ncrt,
109
          unsigned int flags)
110
0
{
111
0
  int ret;
112
0
  unsigned i;
113
0
  unsigned current = 0;
114
0
  gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH];
115
0
  gnutls_x509_crt_t *s;
116
117
0
  s = crt;
118
119
0
  if (flags & GNUTLS_X509_CRT_LIST_SORT && *ncrt > 1) {
120
0
    if (*ncrt > DEFAULT_MAX_VERIFY_DEPTH) {
121
0
      ret = _gnutls_check_if_sorted(s, *ncrt);
122
0
      if (ret < 0) {
123
0
        gnutls_assert();
124
0
        return GNUTLS_E_CERTIFICATE_LIST_UNSORTED;
125
0
      }
126
0
    } else {
127
0
      for (i = 0; i < *ncrt; i++) {
128
0
        sorted[i] = s[i];
129
0
      }
130
0
      s = sorted;
131
0
      *ncrt = _gnutls_sort_clist(s, *ncrt);
132
0
    }
133
0
  }
134
135
0
  for (i = 0; i < *ncrt; i++) {
136
0
    ret = gnutls_pcert_import_x509(&pcert_list[i], s[i], 0);
137
0
    if (ret < 0) {
138
0
      current = i;
139
0
      goto cleanup;
140
0
    }
141
0
  }
142
143
0
  return 0;
144
145
0
 cleanup:
146
0
  for (i = 0; i < current; i++) {
147
0
    gnutls_pcert_deinit(&pcert_list[i]);
148
0
  }
149
0
  return ret;
150
151
0
}
152
153
/**
154
 * gnutls_pcert_list_import_x509_raw:
155
 * @pcert_list: The structures to store the certificates; must not contain initialized #gnutls_pcert_st structures.
156
 * @pcert_list_size: Initially must hold the maximum number of certs. It will be updated with the number of certs available.
157
 * @data: The certificates.
158
 * @format: One of DER or PEM.
159
 * @flags: must be (0) or an OR'd sequence of gnutls_certificate_import_flags.
160
 *
161
 * This function will import the provided DER or PEM encoded certificates to an
162
 * already allocated set of #gnutls_pcert_st structures. The structures must
163
 * be deinitialized afterwards using gnutls_pcert_deinit(). @pcert_list
164
 * should contain space for at least @pcert_list_size elements.
165
 *
166
 * If the Certificate is PEM encoded it should have a header of "X509
167
 * CERTIFICATE", or "CERTIFICATE".
168
 *
169
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
170
 *   negative error value; if the @pcert list doesn't have enough space
171
 *   %GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
172
 *
173
 * Since: 3.0
174
 **/
175
int
176
gnutls_pcert_list_import_x509_raw(gnutls_pcert_st * pcert_list,
177
          unsigned int *pcert_list_size,
178
          const gnutls_datum_t * data,
179
          gnutls_x509_crt_fmt_t format,
180
          unsigned int flags)
181
0
{
182
0
  int ret;
183
0
  unsigned int i = 0, j;
184
0
  gnutls_x509_crt_t *crt;
185
186
0
  crt = _gnutls_reallocarray(NULL, *pcert_list_size,
187
0
           sizeof(gnutls_x509_crt_t));
188
189
0
  if (crt == NULL)
190
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
191
192
0
  ret =
193
0
      gnutls_x509_crt_list_import(crt, pcert_list_size, data, format,
194
0
          flags);
195
0
  if (ret < 0) {
196
0
    ret = gnutls_assert_val(ret);
197
0
    goto cleanup_crt;
198
0
  }
199
200
0
  for (i = 0; i < *pcert_list_size; i++) {
201
0
    ret = gnutls_pcert_import_x509(&pcert_list[i], crt[i], flags);
202
0
    if (ret < 0) {
203
0
      ret = gnutls_assert_val(ret);
204
0
      goto cleanup_pcert;
205
0
    }
206
0
  }
207
208
0
  ret = 0;
209
0
  goto cleanup;
210
211
0
 cleanup_pcert:
212
0
  for (j = 0; j < i; j++)
213
0
    gnutls_pcert_deinit(&pcert_list[j]);
214
215
0
 cleanup:
216
0
  for (i = 0; i < *pcert_list_size; i++)
217
0
    gnutls_x509_crt_deinit(crt[i]);
218
219
0
 cleanup_crt:
220
0
  gnutls_free(crt);
221
0
  return ret;
222
223
0
}
224
225
/**
226
 * gnutls_pcert_list_import_x509_url:
227
 * @pcert_list: The structures to store the certificates; must not contain initialized #gnutls_pcert_st structures.
228
 * @pcert_list_size: Initially must hold the maximum number of certs. It will be updated with the number of certs available.
229
 * @file: A file or supported URI with the certificates to load
230
 * @format: %GNUTLS_X509_FMT_DER or %GNUTLS_X509_FMT_PEM if a file is given
231
 * @pin_fn: a PIN callback if not globally set
232
 * @pin_fn_userdata: parameter for the PIN callback
233
 * @flags: zero or flags from %gnutls_certificate_import_flags
234
 *
235
 * This convenience function will import a certificate chain from the given
236
 * file or supported URI to #gnutls_pcert_st structures. The structures
237
 * must be deinitialized afterwards using gnutls_pcert_deinit().
238
 *
239
 * This function will always return a sorted certificate chain.
240
 *
241
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
242
 *   negative error value; if the @pcert list doesn't have enough space
243
 *   %GNUTLS_E_SHORT_MEMORY_BUFFER will be returned.
244
 *
245
 * Since: 3.6.3
246
 **/
247
int gnutls_pcert_list_import_x509_file(gnutls_pcert_st * pcert_list,
248
               unsigned *pcert_list_size,
249
               const char *file,
250
               gnutls_x509_crt_fmt_t format,
251
               gnutls_pin_callback_t pin_fn,
252
               void *pin_fn_userdata,
253
               unsigned int flags)
254
0
{
255
0
  int ret, ret2;
256
0
  unsigned i;
257
0
  gnutls_x509_crt_t *crts = NULL;
258
0
  unsigned crts_size = 0;
259
0
  gnutls_datum_t data = { NULL, 0 };
260
261
0
  if (gnutls_url_is_supported(file) != 0) {
262
0
    ret =
263
0
        gnutls_x509_crt_list_import_url(&crts, &crts_size, file,
264
0
                pin_fn, pin_fn_userdata, 0);
265
0
    if (ret < 0) {
266
0
      ret2 =
267
0
          gnutls_x509_crt_list_import_url(&crts, &crts_size,
268
0
                  file, pin_fn,
269
0
                  pin_fn_userdata,
270
0
                  GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
271
0
      if (ret2 >= 0)
272
0
        ret = ret2;
273
0
    }
274
275
0
    if (ret < 0) {
276
0
      gnutls_assert();
277
0
      goto cleanup;
278
0
    }
279
280
0
  } else {   /* file */
281
0
    ret = gnutls_load_file(file, &data);
282
0
    if (ret < 0)
283
0
      return gnutls_assert_val(ret);
284
285
0
    ret =
286
0
        gnutls_x509_crt_list_import2(&crts, &crts_size, &data,
287
0
             format,
288
0
             flags |
289
0
             GNUTLS_X509_CRT_LIST_SORT);
290
0
    if (ret < 0) {
291
0
      gnutls_assert();
292
0
      goto cleanup;
293
0
    }
294
0
  }
295
296
0
  if (crts_size > *pcert_list_size) {
297
0
    gnutls_assert();
298
0
    ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
299
0
    goto cleanup;
300
0
  }
301
302
0
  ret =
303
0
      gnutls_pcert_import_x509_list(pcert_list, crts, &crts_size, flags);
304
0
  if (ret < 0) {
305
0
    gnutls_assert();
306
0
    goto cleanup;
307
0
  }
308
0
  *pcert_list_size = crts_size;
309
310
0
  ret = 0;
311
0
 cleanup:
312
0
  for (i = 0; i < crts_size; i++)
313
0
    gnutls_x509_crt_deinit(crts[i]);
314
0
  gnutls_free(crts);
315
0
  gnutls_free(data.data);
316
0
  return ret;
317
0
}
318
319
/**
320
 * gnutls_pcert_import_x509_raw:
321
 * @pcert: The pcert structure
322
 * @cert: The raw certificate to be imported
323
 * @format: The format of the certificate
324
 * @flags: zero for now
325
 *
326
 * This convenience function will import the given certificate to a
327
 * #gnutls_pcert_st structure. The structure must be deinitialized
328
 * afterwards using gnutls_pcert_deinit();
329
 *
330
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
331
 *   negative error value.
332
 *
333
 * Since: 3.0
334
 **/
335
int gnutls_pcert_import_x509_raw(gnutls_pcert_st * pcert,
336
         const gnutls_datum_t * cert,
337
         gnutls_x509_crt_fmt_t format,
338
         unsigned int flags)
339
0
{
340
0
  int ret;
341
0
  gnutls_x509_crt_t crt;
342
343
0
  memset(pcert, 0, sizeof(*pcert));
344
345
0
  ret = gnutls_x509_crt_init(&crt);
346
0
  if (ret < 0)
347
0
    return gnutls_assert_val(ret);
348
349
0
  ret = gnutls_x509_crt_import(crt, cert, format);
350
0
  if (ret < 0) {
351
0
    ret = gnutls_assert_val(ret);
352
0
    goto cleanup;
353
0
  }
354
355
0
  ret = gnutls_pcert_import_x509(pcert, crt, flags);
356
0
  if (ret < 0) {
357
0
    ret = gnutls_assert_val(ret);
358
0
    goto cleanup;
359
0
  }
360
361
0
  ret = 0;
362
363
0
 cleanup:
364
0
  gnutls_x509_crt_deinit(crt);
365
366
0
  return ret;
367
0
}
368
369
/**
370
 * gnutls_pcert_import_rawpk:
371
 * @pcert: The pcert structure to import the data into.
372
 * @pubkey: The raw public-key in #gnutls_pubkey_t format to be imported
373
 * @flags: zero for now
374
 *
375
 * This convenience function will import (i.e. convert) the given raw
376
 * public key @pubkey into a #gnutls_pcert_st structure. The structure
377
 * must be deinitialized afterwards using gnutls_pcert_deinit(). The
378
 * given @pubkey must not be deinitialized because it will be associated
379
 * with the given @pcert structure and will be deinitialized with it.
380
 *
381
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
382
 *   negative error value.
383
 *
384
 * Since: 3.6.6
385
 **/
386
int gnutls_pcert_import_rawpk(gnutls_pcert_st * pcert,
387
            gnutls_pubkey_t pubkey, unsigned int flags)
388
0
{
389
0
  int ret;
390
391
0
  if (pubkey == NULL) {
392
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
393
0
  }
394
395
0
  memset(pcert, 0, sizeof(*pcert));
396
397
  /* A pcert struct holds a raw copy of the certificate data.
398
   * Therefore we convert our gnutls_pubkey_t to its raw DER
399
   * representation and copy it into our pcert. It is this raw data
400
   * that will be transferred to the peer via a Certificate msg.
401
   * According to the spec (RFC7250) a DER representation must be used.
402
   */
403
0
  ret = gnutls_pubkey_export2(pubkey, GNUTLS_X509_FMT_DER, &pcert->cert);
404
0
  if (ret < 0) {
405
0
    return gnutls_assert_val(ret);
406
0
  }
407
408
0
  pcert->pubkey = pubkey;
409
410
0
  pcert->type = GNUTLS_CRT_RAWPK;
411
412
0
  return GNUTLS_E_SUCCESS;
413
0
}
414
415
/**
416
 * gnutls_pcert_import_rawpk_raw:
417
 * @pcert: The pcert structure to import the data into.
418
 * @rawpubkey: The raw public-key in #gnutls_datum_t format to be imported.
419
 * @format: The format of the raw public-key. DER or PEM.
420
 * @key_usage: An ORed sequence of %GNUTLS_KEY_* flags.
421
 * @flags: zero for now
422
 *
423
 * This convenience function will import (i.e. convert) the given raw
424
 * public key @rawpubkey into a #gnutls_pcert_st structure. The structure
425
 * must be deinitialized afterwards using gnutls_pcert_deinit().
426
 * Note that the caller is responsible for freeing @rawpubkey. All necessary
427
 * values will be copied into @pcert.
428
 *
429
 * Key usage (as defined by X.509 extension (2.5.29.15)) can be explicitly
430
 * set because there is no certificate structure around the key to define
431
 * this value. See for more info gnutls_x509_crt_get_key_usage().
432
 *
433
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
434
 *   negative error value.
435
 *
436
 * Since: 3.6.6
437
 **/
438
int gnutls_pcert_import_rawpk_raw(gnutls_pcert_st * pcert,
439
          const gnutls_datum_t * rawpubkey,
440
          gnutls_x509_crt_fmt_t format,
441
          unsigned int key_usage, unsigned int flags)
442
0
{
443
0
  int ret;
444
445
0
  if (rawpubkey == NULL) {
446
0
    return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
447
0
  }
448
449
0
  memset(pcert, 0, sizeof(*pcert));
450
451
0
  ret = gnutls_pubkey_init(&pcert->pubkey);
452
0
  if (ret < 0) {
453
0
    return gnutls_assert_val(ret);
454
0
  }
455
  // Convert our raw public-key to a gnutls_pubkey_t structure
456
0
  ret = gnutls_pubkey_import(pcert->pubkey, rawpubkey, format);
457
0
  if (ret < 0) {
458
0
    return gnutls_assert_val(ret);
459
0
  }
460
461
0
  pcert->pubkey->key_usage = key_usage;
462
463
  /* A pcert struct holds a raw copy of the certificate data.
464
   * It is this raw data that will be transferred to the peer via a
465
   * Certificate message. According to the spec (RFC7250) a DER
466
   * representation must be used. Therefore we check the format and
467
   * convert if necessary.
468
   */
469
0
  if (format == GNUTLS_X509_FMT_PEM) {
470
0
    ret = _gnutls_fbase64_decode(PEM_PK,
471
0
               rawpubkey->data, rawpubkey->size,
472
0
               &pcert->cert);
473
474
0
    if (ret < 0) {
475
0
      gnutls_pubkey_deinit(pcert->pubkey);
476
477
0
      return gnutls_assert_val(ret);
478
0
    }
479
0
  } else {
480
    // Directly copy the raw DER data to our pcert
481
0
    ret =
482
0
        _gnutls_set_datum(&pcert->cert, rawpubkey->data,
483
0
              rawpubkey->size);
484
485
0
    if (ret < 0) {
486
0
      gnutls_pubkey_deinit(pcert->pubkey);
487
488
0
      return gnutls_assert_val(ret);
489
0
    }
490
0
  }
491
492
0
  pcert->type = GNUTLS_CRT_RAWPK;
493
494
0
  return GNUTLS_E_SUCCESS;
495
0
}
496
497
/**
498
 * gnutls_pcert_export_x509:
499
 * @pcert: The pcert structure.
500
 * @crt: An initialized #gnutls_x509_crt_t.
501
 *
502
 * Converts the given #gnutls_pcert_t type into a #gnutls_x509_crt_t.
503
 * This function only works if the type of @pcert is %GNUTLS_CRT_X509.
504
 * When successful, the value written to @crt must be freed with
505
 * gnutls_x509_crt_deinit() when no longer needed.
506
 *
507
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
508
 * negative error value.
509
 *
510
 * Since: 3.4.0
511
 */
512
int gnutls_pcert_export_x509(gnutls_pcert_st * pcert, gnutls_x509_crt_t * crt)
513
0
{
514
0
  int ret;
515
516
0
  if (pcert->type != GNUTLS_CRT_X509) {
517
0
    gnutls_assert();
518
0
    return GNUTLS_E_INVALID_REQUEST;
519
0
  }
520
521
0
  ret = gnutls_x509_crt_init(crt);
522
0
  if (ret < 0)
523
0
    return gnutls_assert_val(ret);
524
525
0
  ret = gnutls_x509_crt_import(*crt, &pcert->cert, GNUTLS_X509_FMT_DER);
526
0
  if (ret < 0) {
527
0
    gnutls_x509_crt_deinit(*crt);
528
0
    *crt = NULL;
529
530
0
    return gnutls_assert_val(ret);
531
0
  }
532
533
0
  return 0;
534
0
}
535
536
/**
537
 * gnutls_pcert_deinit:
538
 * @pcert: The structure to be deinitialized
539
 *
540
 * This function will deinitialize a pcert structure.
541
 *
542
 * Since: 3.0
543
 **/
544
void gnutls_pcert_deinit(gnutls_pcert_st * pcert)
545
0
{
546
0
  if (pcert->pubkey)
547
0
    gnutls_pubkey_deinit(pcert->pubkey);
548
0
  pcert->pubkey = NULL;
549
0
  _gnutls_free_datum(&pcert->cert);
550
0
}
551
552
/* Converts the first certificate for the cert_auth_info structure
553
 * to a pcert.
554
 */
555
int
556
_gnutls_get_auth_info_pcert(gnutls_pcert_st * pcert,
557
          gnutls_certificate_type_t type,
558
          cert_auth_info_t info)
559
0
{
560
0
  switch (type) {
561
0
  case GNUTLS_CRT_X509:
562
0
    return gnutls_pcert_import_x509_raw(pcert,
563
0
                &info->raw_certificate_list
564
0
                [0], GNUTLS_X509_FMT_DER,
565
0
                0);
566
0
  case GNUTLS_CRT_RAWPK:
567
0
    return gnutls_pcert_import_rawpk_raw(pcert,
568
0
                 &info->raw_certificate_list
569
0
                 [0], GNUTLS_X509_FMT_DER,
570
0
                 0, 0);
571
0
  default:
572
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
573
0
  }
574
0
}