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