xref: /third_party/mbedtls/library/x509_crl.c (revision a8e1175b)
1/*
2 *  X.509 Certificate Revocation List (CRL) parsing
3 *
4 *  Copyright The Mbed TLS Contributors
5 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7/*
8 *  The ITU-T X.509 standard defines a certificate format for PKI.
9 *
10 *  http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs)
11 *  http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs)
12 *  http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10)
13 *
14 *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
15 *  http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
16 */
17
18#include "common.h"
19
20#if defined(MBEDTLS_X509_CRL_PARSE_C)
21
22#include "mbedtls/x509_crl.h"
23#include "x509_internal.h"
24#include "mbedtls/error.h"
25#include "mbedtls/oid.h"
26#include "mbedtls/platform_util.h"
27
28#include <string.h>
29
30#if defined(MBEDTLS_PEM_PARSE_C)
31#include "mbedtls/pem.h"
32#endif
33
34#include "mbedtls/platform.h"
35
36#if defined(MBEDTLS_HAVE_TIME)
37#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
38#include <windows.h>
39#else
40#include <time.h>
41#endif
42#endif
43
44#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32)
45#include <stdio.h>
46#endif
47
48/*
49 *  Version  ::=  INTEGER  {  v1(0), v2(1)  }
50 */
51static int x509_crl_get_version(unsigned char **p,
52                                const unsigned char *end,
53                                int *ver)
54{
55    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
56
57    if ((ret = mbedtls_asn1_get_int(p, end, ver)) != 0) {
58        if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
59            *ver = 0;
60            return 0;
61        }
62
63        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_VERSION, ret);
64    }
65
66    return 0;
67}
68
69/*
70 * X.509 CRL v2 extensions
71 *
72 * We currently don't parse any extension's content, but we do check that the
73 * list of extensions is well-formed and abort on critical extensions (that
74 * are unsupported as we don't support any extension so far)
75 */
76static int x509_get_crl_ext(unsigned char **p,
77                            const unsigned char *end,
78                            mbedtls_x509_buf *ext)
79{
80    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
81
82    if (*p == end) {
83        return 0;
84    }
85
86    /*
87     * crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
88     *                              -- if present, version MUST be v2
89     */
90    if ((ret = mbedtls_x509_get_ext(p, end, ext, 0)) != 0) {
91        return ret;
92    }
93
94    end = ext->p + ext->len;
95
96    while (*p < end) {
97        /*
98         * Extension  ::=  SEQUENCE  {
99         *      extnID      OBJECT IDENTIFIER,
100         *      critical    BOOLEAN DEFAULT FALSE,
101         *      extnValue   OCTET STRING  }
102         */
103        int is_critical = 0;
104        const unsigned char *end_ext_data;
105        size_t len;
106
107        /* Get enclosing sequence tag */
108        if ((ret = mbedtls_asn1_get_tag(p, end, &len,
109                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
110            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
111        }
112
113        end_ext_data = *p + len;
114
115        /* Get OID (currently ignored) */
116        if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len,
117                                        MBEDTLS_ASN1_OID)) != 0) {
118            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
119        }
120        *p += len;
121
122        /* Get optional critical */
123        if ((ret = mbedtls_asn1_get_bool(p, end_ext_data,
124                                         &is_critical)) != 0 &&
125            (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) {
126            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
127        }
128
129        /* Data should be octet string type */
130        if ((ret = mbedtls_asn1_get_tag(p, end_ext_data, &len,
131                                        MBEDTLS_ASN1_OCTET_STRING)) != 0) {
132            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
133        }
134
135        /* Ignore data so far and just check its length */
136        *p += len;
137        if (*p != end_ext_data) {
138            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
139                                     MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
140        }
141
142        /* Abort on (unsupported) critical extensions */
143        if (is_critical) {
144            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
145                                     MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
146        }
147    }
148
149    if (*p != end) {
150        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
151                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
152    }
153
154    return 0;
155}
156
157/*
158 * X.509 CRL v2 entry extensions (no extensions parsed yet.)
159 */
160static int x509_get_crl_entry_ext(unsigned char **p,
161                                  const unsigned char *end,
162                                  mbedtls_x509_buf *ext)
163{
164    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
165    size_t len = 0;
166
167    /* OPTIONAL */
168    if (end <= *p) {
169        return 0;
170    }
171
172    ext->tag = **p;
173    ext->p = *p;
174
175    /*
176     * Get CRL-entry extension sequence header
177     * crlEntryExtensions      Extensions OPTIONAL  -- if present, MUST be v2
178     */
179    if ((ret = mbedtls_asn1_get_tag(p, end, &ext->len,
180                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
181        if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
182            ext->p = NULL;
183            return 0;
184        }
185        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
186    }
187
188    end = *p + ext->len;
189
190    if (end != *p + ext->len) {
191        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
192                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
193    }
194
195    while (*p < end) {
196        if ((ret = mbedtls_asn1_get_tag(p, end, &len,
197                                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
198            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
199        }
200
201        *p += len;
202    }
203
204    if (*p != end) {
205        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
206                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
207    }
208
209    return 0;
210}
211
212/*
213 * X.509 CRL Entries
214 */
215static int x509_get_entries(unsigned char **p,
216                            const unsigned char *end,
217                            mbedtls_x509_crl_entry *entry)
218{
219    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
220    size_t entry_len;
221    mbedtls_x509_crl_entry *cur_entry = entry;
222
223    if (*p == end) {
224        return 0;
225    }
226
227    if ((ret = mbedtls_asn1_get_tag(p, end, &entry_len,
228                                    MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED)) != 0) {
229        if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
230            return 0;
231        }
232
233        return ret;
234    }
235
236    end = *p + entry_len;
237
238    while (*p < end) {
239        size_t len2;
240        const unsigned char *end2;
241
242        cur_entry->raw.tag = **p;
243        if ((ret = mbedtls_asn1_get_tag(p, end, &len2,
244                                        MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED)) != 0) {
245            return ret;
246        }
247
248        cur_entry->raw.p = *p;
249        cur_entry->raw.len = len2;
250        end2 = *p + len2;
251
252        if ((ret = mbedtls_x509_get_serial(p, end2, &cur_entry->serial)) != 0) {
253            return ret;
254        }
255
256        if ((ret = mbedtls_x509_get_time(p, end2,
257                                         &cur_entry->revocation_date)) != 0) {
258            return ret;
259        }
260
261        if ((ret = x509_get_crl_entry_ext(p, end2,
262                                          &cur_entry->entry_ext)) != 0) {
263            return ret;
264        }
265
266        if (*p < end) {
267            cur_entry->next = mbedtls_calloc(1, sizeof(mbedtls_x509_crl_entry));
268
269            if (cur_entry->next == NULL) {
270                return MBEDTLS_ERR_X509_ALLOC_FAILED;
271            }
272
273            cur_entry = cur_entry->next;
274        }
275    }
276
277    return 0;
278}
279
280/*
281 * Parse one  CRLs in DER format and append it to the chained list
282 */
283int mbedtls_x509_crl_parse_der(mbedtls_x509_crl *chain,
284                               const unsigned char *buf, size_t buflen)
285{
286    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
287    size_t len;
288    unsigned char *p = NULL, *end = NULL;
289    mbedtls_x509_buf sig_params1, sig_params2, sig_oid2;
290    mbedtls_x509_crl *crl = chain;
291
292    /*
293     * Check for valid input
294     */
295    if (crl == NULL || buf == NULL) {
296        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
297    }
298
299    memset(&sig_params1, 0, sizeof(mbedtls_x509_buf));
300    memset(&sig_params2, 0, sizeof(mbedtls_x509_buf));
301    memset(&sig_oid2, 0, sizeof(mbedtls_x509_buf));
302
303    /*
304     * Add new CRL on the end of the chain if needed.
305     */
306    while (crl->version != 0 && crl->next != NULL) {
307        crl = crl->next;
308    }
309
310    if (crl->version != 0 && crl->next == NULL) {
311        crl->next = mbedtls_calloc(1, sizeof(mbedtls_x509_crl));
312
313        if (crl->next == NULL) {
314            mbedtls_x509_crl_free(crl);
315            return MBEDTLS_ERR_X509_ALLOC_FAILED;
316        }
317
318        mbedtls_x509_crl_init(crl->next);
319        crl = crl->next;
320    }
321
322    /*
323     * Copy raw DER-encoded CRL
324     */
325    if (buflen == 0) {
326        return MBEDTLS_ERR_X509_INVALID_FORMAT;
327    }
328
329    p = mbedtls_calloc(1, buflen);
330    if (p == NULL) {
331        return MBEDTLS_ERR_X509_ALLOC_FAILED;
332    }
333
334    memcpy(p, buf, buflen);
335
336    crl->raw.p = p;
337    crl->raw.len = buflen;
338
339    end = p + buflen;
340
341    /*
342     * CertificateList  ::=  SEQUENCE  {
343     *      tbsCertList          TBSCertList,
344     *      signatureAlgorithm   AlgorithmIdentifier,
345     *      signatureValue       BIT STRING  }
346     */
347    if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
348                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
349        mbedtls_x509_crl_free(crl);
350        return MBEDTLS_ERR_X509_INVALID_FORMAT;
351    }
352
353    if (len != (size_t) (end - p)) {
354        mbedtls_x509_crl_free(crl);
355        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
356                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
357    }
358
359    /*
360     * TBSCertList  ::=  SEQUENCE  {
361     */
362    crl->tbs.p = p;
363
364    if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
365                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
366        mbedtls_x509_crl_free(crl);
367        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
368    }
369
370    end = p + len;
371    crl->tbs.len = (size_t) (end - crl->tbs.p);
372
373    /*
374     * Version  ::=  INTEGER  OPTIONAL {  v1(0), v2(1)  }
375     *               -- if present, MUST be v2
376     *
377     * signature            AlgorithmIdentifier
378     */
379    if ((ret = x509_crl_get_version(&p, end, &crl->version)) != 0 ||
380        (ret = mbedtls_x509_get_alg(&p, end, &crl->sig_oid, &sig_params1)) != 0) {
381        mbedtls_x509_crl_free(crl);
382        return ret;
383    }
384
385    if (crl->version < 0 || crl->version > 1) {
386        mbedtls_x509_crl_free(crl);
387        return MBEDTLS_ERR_X509_UNKNOWN_VERSION;
388    }
389
390    crl->version++;
391
392    if ((ret = mbedtls_x509_get_sig_alg(&crl->sig_oid, &sig_params1,
393                                        &crl->sig_md, &crl->sig_pk,
394                                        &crl->sig_opts)) != 0) {
395        mbedtls_x509_crl_free(crl);
396        return MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG;
397    }
398
399    /*
400     * issuer               Name
401     */
402    crl->issuer_raw.p = p;
403
404    if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
405                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
406        mbedtls_x509_crl_free(crl);
407        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
408    }
409
410    if ((ret = mbedtls_x509_get_name(&p, p + len, &crl->issuer)) != 0) {
411        mbedtls_x509_crl_free(crl);
412        return ret;
413    }
414
415    crl->issuer_raw.len = (size_t) (p - crl->issuer_raw.p);
416
417    /*
418     * thisUpdate          Time
419     * nextUpdate          Time OPTIONAL
420     */
421    if ((ret = mbedtls_x509_get_time(&p, end, &crl->this_update)) != 0) {
422        mbedtls_x509_crl_free(crl);
423        return ret;
424    }
425
426    if ((ret = mbedtls_x509_get_time(&p, end, &crl->next_update)) != 0) {
427        if (ret != (MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE,
428                                      MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) &&
429            ret != (MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE,
430                                      MBEDTLS_ERR_ASN1_OUT_OF_DATA))) {
431            mbedtls_x509_crl_free(crl);
432            return ret;
433        }
434    }
435
436    /*
437     * revokedCertificates    SEQUENCE OF SEQUENCE   {
438     *      userCertificate        CertificateSerialNumber,
439     *      revocationDate         Time,
440     *      crlEntryExtensions     Extensions OPTIONAL
441     *                                   -- if present, MUST be v2
442     *                        } OPTIONAL
443     */
444    if ((ret = x509_get_entries(&p, end, &crl->entry)) != 0) {
445        mbedtls_x509_crl_free(crl);
446        return ret;
447    }
448
449    /*
450     * crlExtensions          EXPLICIT Extensions OPTIONAL
451     *                              -- if present, MUST be v2
452     */
453    if (crl->version == 2) {
454        ret = x509_get_crl_ext(&p, end, &crl->crl_ext);
455
456        if (ret != 0) {
457            mbedtls_x509_crl_free(crl);
458            return ret;
459        }
460    }
461
462    if (p != end) {
463        mbedtls_x509_crl_free(crl);
464        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
465                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
466    }
467
468    end = crl->raw.p + crl->raw.len;
469
470    /*
471     *  signatureAlgorithm   AlgorithmIdentifier,
472     *  signatureValue       BIT STRING
473     */
474    if ((ret = mbedtls_x509_get_alg(&p, end, &sig_oid2, &sig_params2)) != 0) {
475        mbedtls_x509_crl_free(crl);
476        return ret;
477    }
478
479    if (crl->sig_oid.len != sig_oid2.len ||
480        memcmp(crl->sig_oid.p, sig_oid2.p, crl->sig_oid.len) != 0 ||
481        sig_params1.len != sig_params2.len ||
482        (sig_params1.len != 0 &&
483         memcmp(sig_params1.p, sig_params2.p, sig_params1.len) != 0)) {
484        mbedtls_x509_crl_free(crl);
485        return MBEDTLS_ERR_X509_SIG_MISMATCH;
486    }
487
488    if ((ret = mbedtls_x509_get_sig(&p, end, &crl->sig)) != 0) {
489        mbedtls_x509_crl_free(crl);
490        return ret;
491    }
492
493    if (p != end) {
494        mbedtls_x509_crl_free(crl);
495        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT,
496                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
497    }
498
499    return 0;
500}
501
502/*
503 * Parse one or more CRLs and add them to the chained list
504 */
505int mbedtls_x509_crl_parse(mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen)
506{
507#if defined(MBEDTLS_PEM_PARSE_C)
508    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
509    size_t use_len = 0;
510    mbedtls_pem_context pem;
511    int is_pem = 0;
512
513    if (chain == NULL || buf == NULL) {
514        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
515    }
516
517    do {
518        mbedtls_pem_init(&pem);
519
520        // Avoid calling mbedtls_pem_read_buffer() on non-null-terminated
521        // string
522        if (buflen == 0 || buf[buflen - 1] != '\0') {
523            ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
524        } else {
525            ret = mbedtls_pem_read_buffer(&pem,
526                                          "-----BEGIN X509 CRL-----",
527                                          "-----END X509 CRL-----",
528                                          buf, NULL, 0, &use_len);
529        }
530
531        if (ret == 0) {
532            /*
533             * Was PEM encoded
534             */
535            is_pem = 1;
536
537            buflen -= use_len;
538            buf += use_len;
539
540            if ((ret = mbedtls_x509_crl_parse_der(chain,
541                                                  pem.buf, pem.buflen)) != 0) {
542                mbedtls_pem_free(&pem);
543                return ret;
544            }
545        } else if (is_pem) {
546            mbedtls_pem_free(&pem);
547            return ret;
548        }
549
550        mbedtls_pem_free(&pem);
551    }
552    /* In the PEM case, buflen is 1 at the end, for the terminated NULL byte.
553     * And a valid CRL cannot be less than 1 byte anyway. */
554    while (is_pem && buflen > 1);
555
556    if (is_pem) {
557        return 0;
558    } else
559#endif /* MBEDTLS_PEM_PARSE_C */
560    return mbedtls_x509_crl_parse_der(chain, buf, buflen);
561}
562
563#if defined(MBEDTLS_FS_IO)
564/*
565 * Load one or more CRLs and add them to the chained list
566 */
567int mbedtls_x509_crl_parse_file(mbedtls_x509_crl *chain, const char *path)
568{
569    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
570    size_t n;
571    unsigned char *buf;
572
573    if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
574        return ret;
575    }
576
577    ret = mbedtls_x509_crl_parse(chain, buf, n);
578
579    mbedtls_zeroize_and_free(buf, n);
580
581    return ret;
582}
583#endif /* MBEDTLS_FS_IO */
584
585#if !defined(MBEDTLS_X509_REMOVE_INFO)
586/*
587 * Return an informational string about the certificate.
588 */
589#define BEFORE_COLON    14
590#define BC              "14"
591/*
592 * Return an informational string about the CRL.
593 */
594int mbedtls_x509_crl_info(char *buf, size_t size, const char *prefix,
595                          const mbedtls_x509_crl *crl)
596{
597    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
598    size_t n;
599    char *p;
600    const mbedtls_x509_crl_entry *entry;
601
602    p = buf;
603    n = size;
604
605    ret = mbedtls_snprintf(p, n, "%sCRL version   : %d",
606                           prefix, crl->version);
607    MBEDTLS_X509_SAFE_SNPRINTF;
608
609    ret = mbedtls_snprintf(p, n, "\n%sissuer name   : ", prefix);
610    MBEDTLS_X509_SAFE_SNPRINTF;
611    ret = mbedtls_x509_dn_gets(p, n, &crl->issuer);
612    MBEDTLS_X509_SAFE_SNPRINTF;
613
614    ret = mbedtls_snprintf(p, n, "\n%sthis update   : " \
615                                 "%04d-%02d-%02d %02d:%02d:%02d", prefix,
616                           crl->this_update.year, crl->this_update.mon,
617                           crl->this_update.day,  crl->this_update.hour,
618                           crl->this_update.min,  crl->this_update.sec);
619    MBEDTLS_X509_SAFE_SNPRINTF;
620
621    ret = mbedtls_snprintf(p, n, "\n%snext update   : " \
622                                 "%04d-%02d-%02d %02d:%02d:%02d", prefix,
623                           crl->next_update.year, crl->next_update.mon,
624                           crl->next_update.day,  crl->next_update.hour,
625                           crl->next_update.min,  crl->next_update.sec);
626    MBEDTLS_X509_SAFE_SNPRINTF;
627
628    entry = &crl->entry;
629
630    ret = mbedtls_snprintf(p, n, "\n%sRevoked certificates:",
631                           prefix);
632    MBEDTLS_X509_SAFE_SNPRINTF;
633
634    while (entry != NULL && entry->raw.len != 0) {
635        ret = mbedtls_snprintf(p, n, "\n%sserial number: ",
636                               prefix);
637        MBEDTLS_X509_SAFE_SNPRINTF;
638
639        ret = mbedtls_x509_serial_gets(p, n, &entry->serial);
640        MBEDTLS_X509_SAFE_SNPRINTF;
641
642        ret = mbedtls_snprintf(p, n, " revocation date: " \
643                                     "%04d-%02d-%02d %02d:%02d:%02d",
644                               entry->revocation_date.year, entry->revocation_date.mon,
645                               entry->revocation_date.day,  entry->revocation_date.hour,
646                               entry->revocation_date.min,  entry->revocation_date.sec);
647        MBEDTLS_X509_SAFE_SNPRINTF;
648
649        entry = entry->next;
650    }
651
652    ret = mbedtls_snprintf(p, n, "\n%ssigned using  : ", prefix);
653    MBEDTLS_X509_SAFE_SNPRINTF;
654
655    ret = mbedtls_x509_sig_alg_gets(p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md,
656                                    crl->sig_opts);
657    MBEDTLS_X509_SAFE_SNPRINTF;
658
659    ret = mbedtls_snprintf(p, n, "\n");
660    MBEDTLS_X509_SAFE_SNPRINTF;
661
662    return (int) (size - n);
663}
664#endif /* MBEDTLS_X509_REMOVE_INFO */
665
666/*
667 * Initialize a CRL chain
668 */
669void mbedtls_x509_crl_init(mbedtls_x509_crl *crl)
670{
671    memset(crl, 0, sizeof(mbedtls_x509_crl));
672}
673
674/*
675 * Unallocate all CRL data
676 */
677void mbedtls_x509_crl_free(mbedtls_x509_crl *crl)
678{
679    mbedtls_x509_crl *crl_cur = crl;
680    mbedtls_x509_crl *crl_prv;
681    mbedtls_x509_crl_entry *entry_cur;
682    mbedtls_x509_crl_entry *entry_prv;
683
684    while (crl_cur != NULL) {
685#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
686        mbedtls_free(crl_cur->sig_opts);
687#endif
688
689        mbedtls_asn1_free_named_data_list_shallow(crl_cur->issuer.next);
690
691        entry_cur = crl_cur->entry.next;
692        while (entry_cur != NULL) {
693            entry_prv = entry_cur;
694            entry_cur = entry_cur->next;
695            mbedtls_zeroize_and_free(entry_prv,
696                                     sizeof(mbedtls_x509_crl_entry));
697        }
698
699        if (crl_cur->raw.p != NULL) {
700            mbedtls_zeroize_and_free(crl_cur->raw.p, crl_cur->raw.len);
701        }
702
703        crl_prv = crl_cur;
704        crl_cur = crl_cur->next;
705
706        mbedtls_platform_zeroize(crl_prv, sizeof(mbedtls_x509_crl));
707        if (crl_prv != crl) {
708            mbedtls_free(crl_prv);
709        }
710    }
711}
712
713#endif /* MBEDTLS_X509_CRL_PARSE_C */
714