xref: /third_party/mbedtls/library/pkcs7.c (revision a8e1175b)
1/*
2 *  Copyright The Mbed TLS Contributors
3 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
4 */
5#include "common.h"
6
7#include "mbedtls/build_info.h"
8#if defined(MBEDTLS_PKCS7_C)
9#include "mbedtls/pkcs7.h"
10#include "x509_internal.h"
11#include "mbedtls/asn1.h"
12#include "mbedtls/x509_crt.h"
13#include "mbedtls/x509_crl.h"
14#include "mbedtls/oid.h"
15#include "mbedtls/error.h"
16
17#if defined(MBEDTLS_FS_IO)
18#include <sys/types.h>
19#include <sys/stat.h>
20#endif
21
22#include "mbedtls/platform.h"
23#include "mbedtls/platform_util.h"
24
25#if defined(MBEDTLS_HAVE_TIME)
26#include "mbedtls/platform_time.h"
27#endif
28#if defined(MBEDTLS_HAVE_TIME_DATE)
29#include <time.h>
30#endif
31
32/**
33 * Initializes the mbedtls_pkcs7 structure.
34 */
35void mbedtls_pkcs7_init(mbedtls_pkcs7 *pkcs7)
36{
37    memset(pkcs7, 0, sizeof(*pkcs7));
38}
39
40static int pkcs7_get_next_content_len(unsigned char **p, unsigned char *end,
41                                      size_t *len)
42{
43    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
44
45    ret = mbedtls_asn1_get_tag(p, end, len, MBEDTLS_ASN1_CONSTRUCTED
46                               | MBEDTLS_ASN1_CONTEXT_SPECIFIC);
47    if (ret != 0) {
48        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret);
49    } else if ((size_t) (end - *p) != *len) {
50        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO,
51                                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
52    }
53
54    return ret;
55}
56
57/**
58 * version Version
59 * Version ::= INTEGER
60 **/
61static int pkcs7_get_version(unsigned char **p, unsigned char *end, int *ver)
62{
63    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
64
65    ret = mbedtls_asn1_get_int(p, end, ver);
66    if (ret != 0) {
67        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_VERSION, ret);
68    }
69
70    /* If version != 1, return invalid version */
71    if (*ver != MBEDTLS_PKCS7_SUPPORTED_VERSION) {
72        ret = MBEDTLS_ERR_PKCS7_INVALID_VERSION;
73    }
74
75    return ret;
76}
77
78/**
79 * ContentInfo ::= SEQUENCE {
80 *      contentType ContentType,
81 *      content
82 *              [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
83 **/
84static int pkcs7_get_content_info_type(unsigned char **p, unsigned char *end,
85                                       unsigned char **seq_end,
86                                       mbedtls_pkcs7_buf *pkcs7)
87{
88    size_t len = 0;
89    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
90    unsigned char *start = *p;
91
92    ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
93                               | MBEDTLS_ASN1_SEQUENCE);
94    if (ret != 0) {
95        *p = start;
96        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret);
97    }
98    *seq_end = *p + len;
99    ret = mbedtls_asn1_get_tag(p, *seq_end, &len, MBEDTLS_ASN1_OID);
100    if (ret != 0) {
101        *p = start;
102        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret);
103    }
104
105    pkcs7->tag = MBEDTLS_ASN1_OID;
106    pkcs7->len = len;
107    pkcs7->p = *p;
108    *p += len;
109
110    return ret;
111}
112
113/**
114 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
115 *
116 * This is from x509.h
117 **/
118static int pkcs7_get_digest_algorithm(unsigned char **p, unsigned char *end,
119                                      mbedtls_x509_buf *alg)
120{
121    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
122
123    if ((ret = mbedtls_asn1_get_alg_null(p, end, alg)) != 0) {
124        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_ALG, ret);
125    }
126
127    return ret;
128}
129
130/**
131 * DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier
132 **/
133static int pkcs7_get_digest_algorithm_set(unsigned char **p,
134                                          unsigned char *end,
135                                          mbedtls_x509_buf *alg)
136{
137    size_t len = 0;
138    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
139
140    ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
141                               | MBEDTLS_ASN1_SET);
142    if (ret != 0) {
143        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_ALG, ret);
144    }
145
146    end = *p + len;
147
148    ret = mbedtls_asn1_get_alg_null(p, end, alg);
149    if (ret != 0) {
150        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_ALG, ret);
151    }
152
153    /** For now, it assumes there is only one digest algorithm specified **/
154    if (*p != end) {
155        return MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
156    }
157
158    return 0;
159}
160
161/**
162 * certificates :: SET OF ExtendedCertificateOrCertificate,
163 * ExtendedCertificateOrCertificate ::= CHOICE {
164 *      certificate Certificate -- x509,
165 *      extendedCertificate[0] IMPLICIT ExtendedCertificate }
166 * Return number of certificates added to the signed data,
167 * 0 or higher is valid.
168 * Return negative error code for failure.
169 **/
170static int pkcs7_get_certificates(unsigned char **p, unsigned char *end,
171                                  mbedtls_x509_crt *certs)
172{
173    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
174    size_t len1 = 0;
175    size_t len2 = 0;
176    unsigned char *end_set, *end_cert, *start;
177
178    ret = mbedtls_asn1_get_tag(p, end, &len1, MBEDTLS_ASN1_CONSTRUCTED
179                               | MBEDTLS_ASN1_CONTEXT_SPECIFIC);
180    if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
181        return 0;
182    }
183    if (ret != 0) {
184        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret);
185    }
186    start = *p;
187    end_set = *p + len1;
188
189    ret = mbedtls_asn1_get_tag(p, end_set, &len2, MBEDTLS_ASN1_CONSTRUCTED
190                               | MBEDTLS_ASN1_SEQUENCE);
191    if (ret != 0) {
192        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_CERT, ret);
193    }
194
195    end_cert = *p + len2;
196
197    /*
198     * This is to verify that there is only one signer certificate. It seems it is
199     * not easy to differentiate between the chain vs different signer's certificate.
200     * So, we support only the root certificate and the single signer.
201     * The behaviour would be improved with addition of multiple signer support.
202     */
203    if (end_cert != end_set) {
204        return MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
205    }
206
207    if ((ret = mbedtls_x509_crt_parse_der(certs, start, len1)) < 0) {
208        return MBEDTLS_ERR_PKCS7_INVALID_CERT;
209    }
210
211    *p = end_cert;
212
213    /*
214     * Since in this version we strictly support single certificate, and reaching
215     * here implies we have parsed successfully, we return 1.
216     */
217    return 1;
218}
219
220/**
221 * EncryptedDigest ::= OCTET STRING
222 **/
223static int pkcs7_get_signature(unsigned char **p, unsigned char *end,
224                               mbedtls_pkcs7_buf *signature)
225{
226    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
227    size_t len = 0;
228
229    ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING);
230    if (ret != 0) {
231        return ret;
232    }
233
234    signature->tag = MBEDTLS_ASN1_OCTET_STRING;
235    signature->len = len;
236    signature->p = *p;
237
238    *p = *p + len;
239
240    return 0;
241}
242
243static void pkcs7_free_signer_info(mbedtls_pkcs7_signer_info *signer)
244{
245    mbedtls_x509_name *name_cur;
246    mbedtls_x509_name *name_prv;
247
248    if (signer == NULL) {
249        return;
250    }
251
252    name_cur = signer->issuer.next;
253    while (name_cur != NULL) {
254        name_prv = name_cur;
255        name_cur = name_cur->next;
256        mbedtls_free(name_prv);
257    }
258    signer->issuer.next = NULL;
259}
260
261/**
262 * SignerInfo ::= SEQUENCE {
263 *      version Version;
264 *      issuerAndSerialNumber   IssuerAndSerialNumber,
265 *      digestAlgorithm DigestAlgorithmIdentifier,
266 *      authenticatedAttributes
267 *              [0] IMPLICIT Attributes OPTIONAL,
268 *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
269 *      encryptedDigest EncryptedDigest,
270 *      unauthenticatedAttributes
271 *              [1] IMPLICIT Attributes OPTIONAL,
272 * Returns 0 if the signerInfo is valid.
273 * Return negative error code for failure.
274 * Structure must not contain vales for authenticatedAttributes
275 * and unauthenticatedAttributes.
276 **/
277static int pkcs7_get_signer_info(unsigned char **p, unsigned char *end,
278                                 mbedtls_pkcs7_signer_info *signer,
279                                 mbedtls_x509_buf *alg)
280{
281    unsigned char *end_signer, *end_issuer_and_sn;
282    int asn1_ret = 0, ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
283    size_t len = 0;
284
285    asn1_ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
286                                    | MBEDTLS_ASN1_SEQUENCE);
287    if (asn1_ret != 0) {
288        goto out;
289    }
290
291    end_signer = *p + len;
292
293    ret = pkcs7_get_version(p, end_signer, &signer->version);
294    if (ret != 0) {
295        goto out;
296    }
297
298    asn1_ret = mbedtls_asn1_get_tag(p, end_signer, &len,
299                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
300    if (asn1_ret != 0) {
301        goto out;
302    }
303
304    end_issuer_and_sn = *p + len;
305    /* Parsing IssuerAndSerialNumber */
306    signer->issuer_raw.p = *p;
307
308    asn1_ret = mbedtls_asn1_get_tag(p, end_issuer_and_sn, &len,
309                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
310    if (asn1_ret != 0) {
311        goto out;
312    }
313
314    ret  = mbedtls_x509_get_name(p, *p + len, &signer->issuer);
315    if (ret != 0) {
316        goto out;
317    }
318
319    signer->issuer_raw.len =  (size_t) (*p - signer->issuer_raw.p);
320
321    ret = mbedtls_x509_get_serial(p, end_issuer_and_sn, &signer->serial);
322    if (ret != 0) {
323        goto out;
324    }
325
326    /* ensure no extra or missing bytes */
327    if (*p != end_issuer_and_sn) {
328        ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
329        goto out;
330    }
331
332    ret = pkcs7_get_digest_algorithm(p, end_signer, &signer->alg_identifier);
333    if (ret != 0) {
334        goto out;
335    }
336
337    /* Check that the digest algorithm used matches the one provided earlier */
338    if (signer->alg_identifier.tag != alg->tag ||
339        signer->alg_identifier.len != alg->len ||
340        memcmp(signer->alg_identifier.p, alg->p, alg->len) != 0) {
341        ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
342        goto out;
343    }
344
345    /* Assume authenticatedAttributes is nonexistent */
346    ret = pkcs7_get_digest_algorithm(p, end_signer, &signer->sig_alg_identifier);
347    if (ret != 0) {
348        goto out;
349    }
350
351    ret = pkcs7_get_signature(p, end_signer, &signer->sig);
352    if (ret != 0) {
353        goto out;
354    }
355
356    /* Do not permit any unauthenticated attributes */
357    if (*p != end_signer) {
358        ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
359    }
360
361out:
362    if (asn1_ret != 0 || ret != 0) {
363        pkcs7_free_signer_info(signer);
364        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO,
365                                asn1_ret);
366    }
367
368    return ret;
369}
370
371/**
372 * SignerInfos ::= SET of SignerInfo
373 * Return number of signers added to the signed data,
374 * 0 or higher is valid.
375 * Return negative error code for failure.
376 **/
377static int pkcs7_get_signers_info_set(unsigned char **p, unsigned char *end,
378                                      mbedtls_pkcs7_signer_info *signers_set,
379                                      mbedtls_x509_buf *digest_alg)
380{
381    unsigned char *end_set;
382    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
383    int count = 0;
384    size_t len = 0;
385
386    ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
387                               | MBEDTLS_ASN1_SET);
388    if (ret != 0) {
389        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO, ret);
390    }
391
392    /* Detect zero signers */
393    if (len == 0) {
394        return 0;
395    }
396
397    end_set = *p + len;
398
399    ret = pkcs7_get_signer_info(p, end_set, signers_set, digest_alg);
400    if (ret != 0) {
401        return ret;
402    }
403    count++;
404
405    mbedtls_pkcs7_signer_info *prev = signers_set;
406    while (*p != end_set) {
407        mbedtls_pkcs7_signer_info *signer =
408            mbedtls_calloc(1, sizeof(mbedtls_pkcs7_signer_info));
409        if (!signer) {
410            ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
411            goto cleanup;
412        }
413
414        ret = pkcs7_get_signer_info(p, end_set, signer, digest_alg);
415        if (ret != 0) {
416            mbedtls_free(signer);
417            goto cleanup;
418        }
419        prev->next = signer;
420        prev = signer;
421        count++;
422    }
423
424    return count;
425
426cleanup:
427    pkcs7_free_signer_info(signers_set);
428    mbedtls_pkcs7_signer_info *signer = signers_set->next;
429    while (signer != NULL) {
430        prev = signer;
431        signer = signer->next;
432        pkcs7_free_signer_info(prev);
433        mbedtls_free(prev);
434    }
435    signers_set->next = NULL;
436    return ret;
437}
438
439/**
440 * SignedData ::= SEQUENCE {
441 *      version Version,
442 *      digestAlgorithms DigestAlgorithmIdentifiers,
443 *      contentInfo ContentInfo,
444 *      certificates
445 *              [0] IMPLICIT ExtendedCertificatesAndCertificates
446 *                  OPTIONAL,
447 *      crls
448 *              [0] IMPLICIT CertificateRevocationLists OPTIONAL,
449 *      signerInfos SignerInfos }
450 */
451static int pkcs7_get_signed_data(unsigned char *buf, size_t buflen,
452                                 mbedtls_pkcs7_signed_data *signed_data)
453{
454    unsigned char *p = buf;
455    unsigned char *end = buf + buflen;
456    unsigned char *end_content_info = NULL;
457    size_t len = 0;
458    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
459    mbedtls_md_type_t md_alg;
460
461    ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
462                               | MBEDTLS_ASN1_SEQUENCE);
463    if (ret != 0) {
464        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret);
465    }
466
467    if (p + len != end) {
468        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_FORMAT,
469                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
470    }
471
472    /* Get version of signed data */
473    ret = pkcs7_get_version(&p, end, &signed_data->version);
474    if (ret != 0) {
475        return ret;
476    }
477
478    /* Get digest algorithm */
479    ret = pkcs7_get_digest_algorithm_set(&p, end,
480                                         &signed_data->digest_alg_identifiers);
481    if (ret != 0) {
482        return ret;
483    }
484
485    ret = mbedtls_oid_get_md_alg(&signed_data->digest_alg_identifiers, &md_alg);
486    if (ret != 0) {
487        return MBEDTLS_ERR_PKCS7_INVALID_ALG;
488    }
489
490    mbedtls_pkcs7_buf content_type;
491    memset(&content_type, 0, sizeof(content_type));
492    ret = pkcs7_get_content_info_type(&p, end, &end_content_info, &content_type);
493    if (ret != 0) {
494        return ret;
495    }
496    if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS7_DATA, &content_type)) {
497        return MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO;
498    }
499
500    if (p != end_content_info) {
501        /* Determine if valid content is present */
502        ret = mbedtls_asn1_get_tag(&p,
503                                   end_content_info,
504                                   &len,
505                                   MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC);
506        if (ret != 0) {
507            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret);
508        }
509        p += len;
510        if (p != end_content_info) {
511            return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret);
512        }
513        /* Valid content is present - this is not supported */
514        return MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
515    }
516
517    /* Look for certificates, there may or may not be any */
518    mbedtls_x509_crt_init(&signed_data->certs);
519    ret = pkcs7_get_certificates(&p, end, &signed_data->certs);
520    if (ret < 0) {
521        return ret;
522    }
523
524    signed_data->no_of_certs = ret;
525
526    /*
527     * Currently CRLs are not supported. If CRL exist, the parsing will fail
528     * at next step of getting signers info and return error as invalid
529     * signer info.
530     */
531
532    signed_data->no_of_crls = 0;
533
534    /* Get signers info */
535    ret = pkcs7_get_signers_info_set(&p,
536                                     end,
537                                     &signed_data->signers,
538                                     &signed_data->digest_alg_identifiers);
539    if (ret < 0) {
540        return ret;
541    }
542
543    signed_data->no_of_signers = ret;
544
545    /* Don't permit trailing data */
546    if (p != end) {
547        return MBEDTLS_ERR_PKCS7_INVALID_FORMAT;
548    }
549
550    return 0;
551}
552
553int mbedtls_pkcs7_parse_der(mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
554                            const size_t buflen)
555{
556    unsigned char *p;
557    unsigned char *end;
558    size_t len = 0;
559    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
560
561    if (pkcs7 == NULL) {
562        return MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
563    }
564
565    /* make an internal copy of the buffer for parsing */
566    pkcs7->raw.p = p = mbedtls_calloc(1, buflen);
567    if (pkcs7->raw.p == NULL) {
568        ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
569        goto out;
570    }
571    memcpy(p, buf, buflen);
572    pkcs7->raw.len = buflen;
573    end = p + buflen;
574
575    ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
576                               | MBEDTLS_ASN1_SEQUENCE);
577    if (ret != 0) {
578        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret);
579        goto out;
580    }
581
582    if ((size_t) (end - p) != len) {
583        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_FORMAT,
584                                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
585        goto out;
586    }
587
588    if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID)) != 0) {
589        if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
590            goto out;
591        }
592        p = pkcs7->raw.p;
593        len = buflen;
594        goto try_data;
595    }
596
597    if (MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS7_SIGNED_DATA, p, len)) {
598        /* OID is not MBEDTLS_OID_PKCS7_SIGNED_DATA, which is the only supported feature */
599        if (!MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS7_DATA, p, len)
600            || !MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, p, len)
601            || !MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS7_ENVELOPED_DATA, p, len)
602            || !MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, p, len)
603            || !MBEDTLS_OID_CMP_RAW(MBEDTLS_OID_PKCS7_DIGESTED_DATA, p, len)) {
604            /* OID is valid according to the spec, but unsupported */
605            ret =  MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
606        } else {
607            /* OID is invalid according to the spec */
608            ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
609        }
610        goto out;
611    }
612
613    p += len;
614
615    ret = pkcs7_get_next_content_len(&p, end, &len);
616    if (ret != 0) {
617        goto out;
618    }
619
620    /* ensure no extra/missing data */
621    if (p + len != end) {
622        ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
623        goto out;
624    }
625
626try_data:
627    ret = pkcs7_get_signed_data(p, len, &pkcs7->signed_data);
628    if (ret != 0) {
629        goto out;
630    }
631
632    ret = MBEDTLS_PKCS7_SIGNED_DATA;
633
634out:
635    if (ret < 0) {
636        mbedtls_pkcs7_free(pkcs7);
637    }
638
639    return ret;
640}
641
642static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7,
643                                             const mbedtls_x509_crt *cert,
644                                             const unsigned char *data,
645                                             size_t datalen,
646                                             const int is_data_hash)
647{
648    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
649    unsigned char *hash;
650    mbedtls_pk_context pk_cxt = cert->pk;
651    const mbedtls_md_info_t *md_info;
652    mbedtls_md_type_t md_alg;
653    mbedtls_pkcs7_signer_info *signer;
654
655    if (pkcs7->signed_data.no_of_signers == 0) {
656        return MBEDTLS_ERR_PKCS7_INVALID_CERT;
657    }
658
659    if (mbedtls_x509_time_is_past(&cert->valid_to) ||
660        mbedtls_x509_time_is_future(&cert->valid_from)) {
661        return MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID;
662    }
663
664    ret = mbedtls_oid_get_md_alg(&pkcs7->signed_data.digest_alg_identifiers, &md_alg);
665    if (ret != 0) {
666        return ret;
667    }
668
669    md_info = mbedtls_md_info_from_type(md_alg);
670    if (md_info == NULL) {
671        return MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
672    }
673
674    hash = mbedtls_calloc(mbedtls_md_get_size(md_info), 1);
675    if (hash == NULL) {
676        return MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
677    }
678
679    /* BEGIN must free hash before jumping out */
680    if (is_data_hash) {
681        if (datalen != mbedtls_md_get_size(md_info)) {
682            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
683        } else {
684            memcpy(hash, data, datalen);
685        }
686    } else {
687        ret = mbedtls_md(md_info, data, datalen, hash);
688    }
689    if (ret != 0) {
690        mbedtls_free(hash);
691        return MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
692    }
693
694    /* assume failure */
695    ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
696
697    /*
698     * Potential TODOs
699     * Currently we iterate over all signers and return success if any of them
700     * verify.
701     *
702     * However, we could make this better by checking against the certificate's
703     * identification and SignerIdentifier fields first. That would also allow
704     * us to distinguish between 'no signature for key' and 'signature for key
705     * failed to validate'.
706     */
707    for (signer = &pkcs7->signed_data.signers; signer; signer = signer->next) {
708        ret = mbedtls_pk_verify(&pk_cxt, md_alg, hash,
709                                mbedtls_md_get_size(md_info),
710                                signer->sig.p, signer->sig.len);
711
712        if (ret == 0) {
713            break;
714        }
715    }
716
717    mbedtls_free(hash);
718    /* END must free hash before jumping out */
719    return ret;
720}
721
722int mbedtls_pkcs7_signed_data_verify(mbedtls_pkcs7 *pkcs7,
723                                     const mbedtls_x509_crt *cert,
724                                     const unsigned char *data,
725                                     size_t datalen)
726{
727    if (data == NULL) {
728        return MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
729    }
730    return mbedtls_pkcs7_data_or_hash_verify(pkcs7, cert, data, datalen, 0);
731}
732
733int mbedtls_pkcs7_signed_hash_verify(mbedtls_pkcs7 *pkcs7,
734                                     const mbedtls_x509_crt *cert,
735                                     const unsigned char *hash,
736                                     size_t hashlen)
737{
738    if (hash == NULL) {
739        return MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
740    }
741    return mbedtls_pkcs7_data_or_hash_verify(pkcs7, cert, hash, hashlen, 1);
742}
743
744/*
745 * Unallocate all pkcs7 data
746 */
747void mbedtls_pkcs7_free(mbedtls_pkcs7 *pkcs7)
748{
749    mbedtls_pkcs7_signer_info *signer_cur;
750    mbedtls_pkcs7_signer_info *signer_prev;
751
752    if (pkcs7 == NULL || pkcs7->raw.p == NULL) {
753        return;
754    }
755
756    mbedtls_free(pkcs7->raw.p);
757
758    mbedtls_x509_crt_free(&pkcs7->signed_data.certs);
759    mbedtls_x509_crl_free(&pkcs7->signed_data.crl);
760
761    signer_cur = pkcs7->signed_data.signers.next;
762    pkcs7_free_signer_info(&pkcs7->signed_data.signers);
763    while (signer_cur != NULL) {
764        signer_prev = signer_cur;
765        signer_cur = signer_prev->next;
766        pkcs7_free_signer_info(signer_prev);
767        mbedtls_free(signer_prev);
768    }
769
770    pkcs7->raw.p = NULL;
771}
772
773#endif
774