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