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