blob: 5563f330ee5d0d9fa9106c359bdd444f35254ff6 [file] [log] [blame]
Nayna Jainc9deb182020-11-16 19:03:12 +00001/* Copyright 2019 IBM Corp.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 * implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "common.h"
17
18#include "mbedtls/build_info.h"
19#if defined(MBEDTLS_PKCS7_C)
20#include "mbedtls/pkcs7.h"
21#include "mbedtls/x509.h"
22#include "mbedtls/asn1.h"
23#include "mbedtls/x509_crt.h"
24#include "mbedtls/x509_crl.h"
25#include "mbedtls/oid.h"
26
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#if defined(MBEDTLS_FS_IO)
31#include <sys/types.h>
32#include <sys/stat.h>
33#endif
34
35#if defined(MBEDTLS_PLATFORM_C)
36#include "mbedtls/platform.h"
37#include "mbedtls/platform_util.h"
38#else
39#include <stdio.h>
40#include <stdlib.h>
41#define mbedtls_free free
42#define mbedtls_calloc calloc
43#define mbedtls_printf printf
44#define mbedtls_snprintf snprintf
45#endif
46
47#if defined(MBEDTLS_HAVE_TIME)
48#include "mbedtls/platform_time.h"
49#endif
50#if defined(MBEDTLS_HAVE_TIME_DATE)
51#include <time.h>
52#endif
53
54/**
55 * Initializes the pkcs7 structure.
56 */
57void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 )
58{
59 memset( pkcs7, 0, sizeof( mbedtls_pkcs7 ) );
60 pkcs7->raw.p = NULL;
61}
62
63static int pkcs7_get_next_content_len( unsigned char **p, unsigned char *end,
64 size_t *len )
65{
66 int ret;
67
68 if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_CONSTRUCTED
69 | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
70 {
71 return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
72 }
73
74 return( 0 );
75}
76
77/**
78 * version Version
79 * Version ::= INTEGER
80 **/
81static int pkcs7_get_version( unsigned char **p, unsigned char *end, int *ver )
82{
83 int ret;
84
85 if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 )
86 return( MBEDTLS_ERR_PKCS7_INVALID_VERSION + ret );
87
88 /* If version != 1, return invalid version */
89 if( *ver != MBEDTLS_PKCS7_SUPPORTED_VERSION )
90 return( MBEDTLS_ERR_PKCS7_INVALID_VERSION );
91
92 return( 0 );
93}
94
95/**
96 * ContentInfo ::= SEQUENCE {
97 * contentType ContentType,
98 * content
99 * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
100 **/
101static int pkcs7_get_content_info_type( unsigned char **p, unsigned char *end,
102 mbedtls_pkcs7_buf *pkcs7 )
103{
104 size_t len = 0;
105 int ret;
Nayna Jain673a2262020-12-14 22:44:49 +0000106 unsigned char *start = *p;
Nayna Jainc9deb182020-11-16 19:03:12 +0000107
108 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
109 | MBEDTLS_ASN1_SEQUENCE );
110 if( ret != 0 )
111 return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret );
112
113 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID );
Nayna Jain673a2262020-12-14 22:44:49 +0000114 if( ret != 0 ) {
115 *p = start;
Nayna Jainc9deb182020-11-16 19:03:12 +0000116 return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret );
Nayna Jain673a2262020-12-14 22:44:49 +0000117 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000118
119 pkcs7->tag = MBEDTLS_ASN1_OID;
120 pkcs7->len = len;
121 pkcs7->p = *p;
122
123 return( ret );
124}
125
126/**
127 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
128 *
129 * This is from x509.h
130 **/
131static int pkcs7_get_digest_algorithm( unsigned char **p, unsigned char *end,
132 mbedtls_x509_buf *alg )
133{
134 int ret;
135
136 if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 )
137 return( MBEDTLS_ERR_PKCS7_INVALID_ALG );
138
139 return( 0 );
140}
141
142/**
143 * DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier
144 **/
145static int pkcs7_get_digest_algorithm_set( unsigned char **p,
146 unsigned char *end,
147 mbedtls_x509_buf *alg )
148{
149 size_t len = 0;
150 int ret;
151
152 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
153 | MBEDTLS_ASN1_SET );
154 if( ret != 0 )
155 return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
156
157 end = *p + len;
158
159 /** For now, it assumes there is only one digest algorithm specified **/
160 ret = mbedtls_asn1_get_alg_null( p, end, alg );
161 if( ret != 0 )
162 return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
163
164 if ( *p != end )
165 return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT );
166
167 return( 0 );
168}
169
170/**
171 * certificates :: SET OF ExtendedCertificateOrCertificate,
172 * ExtendedCertificateOrCertificate ::= CHOICE {
173 * certificate Certificate -- x509,
174 * extendedCertificate[0] IMPLICIT ExtendedCertificate }
175 * Return number of certificates added to the signed data,
176 * 0 or higher is valid.
177 * Return negative error code for failure.
178 **/
179static int pkcs7_get_certificates( unsigned char **p, unsigned char *end,
180 mbedtls_x509_crt *certs )
181{
182 int ret;
183 size_t len1 = 0;
184 size_t len2 = 0;
185 unsigned char *end_set, *end_cert;
186 unsigned char *start = *p;
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
194 return( 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 return( MBEDTLS_ERR_PKCS7_INVALID_CERT + ret );
203
204 end_cert = *p + len2;
205
206 /*
207 * This is to verify that there is only one signer certificate. It seems it is
208 * not easy to differentiate between the chain vs different signer's certificate.
209 * So, we support only the root certificate and the single signer.
210 * The behaviour would be improved with addition of multiple signer support.
211 */
212 if (end_cert != end_set)
213 return ( MBEDTLS_ERR_PKCS7_INVALID_CERT );
214
215 *p = start;
216 if( ( ret = mbedtls_x509_crt_parse( certs, *p, len1 ) ) < 0 )
217 return( MBEDTLS_ERR_PKCS7_INVALID_CERT );
218
219 *p = *p + len1;
220
221 /* Since in this version we strictly support single certificate, and reaching
222 * here implies we have parsed successfully, we return 1. */
223
224 return( 1 );
225}
226
227/**
228 * EncryptedDigest ::= OCTET STRING
229 **/
230static int pkcs7_get_signature( unsigned char **p, unsigned char *end,
231 mbedtls_pkcs7_buf *signature )
232{
233 int ret;
234 size_t len = 0;
235
236 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OCTET_STRING );
237 if( ret != 0 )
238 return( ret );
239
240 signature->tag = MBEDTLS_ASN1_OCTET_STRING;
241 signature->len = len;
242 signature->p = *p;
243
244 *p = *p + len;
245
246 return( 0 );
247}
248
249/**
250 * SignerInfos ::= SET of SignerInfo
251 * SignerInfo ::= SEQUENCE {
252 * version Version;
253 * issuerAndSerialNumber IssuerAndSerialNumber,
254 * digestAlgorithm DigestAlgorithmIdentifier,
255 * authenticatedAttributes
256 * [0] IMPLICIT Attributes OPTIONAL,
257 * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
258 * encryptedDigest EncryptedDigest,
259 * unauthenticatedAttributes
260 * [1] IMPLICIT Attributes OPTIONAL,
261 * Return number of signers added to the signed data,
262 * 0 or higher is valid.
263 * Return negative error code for failure.
264 **/
265static int pkcs7_get_signers_info_set( unsigned char **p, unsigned char *end,
266 mbedtls_pkcs7_signer_info *signers_set )
267{
268 unsigned char *end_set, *end_set_signer;
269 int ret;
270 size_t len = 0;
271
272 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
273 | MBEDTLS_ASN1_SET );
274 if( ret != 0 )
275 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
276
277 end_set = *p + len;
278
279 ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
280 | MBEDTLS_ASN1_SEQUENCE );
281 if( ret != 0 )
282 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
283
284 end_set_signer = *p + len;
285 if (end_set_signer != end_set)
286 return ( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
287
288 end_set = end_set_signer;
289
290 ret = mbedtls_asn1_get_int( p, end_set, &signers_set->version );
291 if( ret != 0 )
292 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
293
294 ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
295 | MBEDTLS_ASN1_SEQUENCE );
296 if( ret != 0 )
297 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
298
299 /* Parsing IssuerAndSerialNumber */
300 signers_set->issuer_raw.p = *p;
301
302 ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
303 | MBEDTLS_ASN1_SEQUENCE );
304 if( ret != 0 )
305 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
306
307 ret = mbedtls_x509_get_name( p, *p + len, &signers_set->issuer );
308 if( ret != 0 )
309 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
310
311 signers_set->issuer_raw.len = *p - signers_set->issuer_raw.p;
312
313 ret = mbedtls_x509_get_serial( p, end_set, &signers_set->serial );
314 if( ret != 0 )
315 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
316
317 ret = pkcs7_get_digest_algorithm( p, end_set, &signers_set->alg_identifier );
318 if( ret != 0 )
319 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
320
321 ret = pkcs7_get_digest_algorithm( p, end_set, &signers_set->sig_alg_identifier );
322 if( ret != 0 )
323 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
324
325 ret = pkcs7_get_signature( p, end_set, &signers_set->sig );
326 if( ret != 0 )
327 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
328
329 signers_set->next = NULL;
330
331 if (*p != end_set)
332 return ( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
333
334 /* Since in this version we strictly support single signer, and reaching
335 * here implies we have parsed successfully, we return 1. */
336
337 return( 1 );
338}
339
340/**
341 * SignedData ::= SEQUENCE {
342 * version Version,
343 * digestAlgorithms DigestAlgorithmIdentifiers,
344 * contentInfo ContentInfo,
345 * certificates
346 * [0] IMPLICIT ExtendedCertificatesAndCertificates
347 * OPTIONAL,
348 * crls
349 * [0] IMPLICIT CertificateRevocationLists OPTIONAL,
350 * signerInfos SignerInfos }
351 */
352static int pkcs7_get_signed_data( unsigned char *buf, size_t buflen,
353 mbedtls_pkcs7_signed_data *signed_data )
354{
355 unsigned char *p = buf;
356 unsigned char *end = buf + buflen;
357 unsigned char *end_set;
358 size_t len = 0;
359 int ret;
360 mbedtls_md_type_t md_alg;
361
362 ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
363 | MBEDTLS_ASN1_SEQUENCE );
364 if( ret != 0 )
365 return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
366
367 end_set = p + len;
368
369 /* Get version of signed data */
370 ret = pkcs7_get_version( &p, end_set, &signed_data->version );
371 if( ret != 0 )
372 return( ret );
373
374 /* Get digest algorithm */
375 ret = pkcs7_get_digest_algorithm_set( &p, end_set,
376 &signed_data->digest_alg_identifiers );
377 if( ret != 0 )
378 return( ret );
379
380 ret = mbedtls_oid_get_md_alg( &signed_data->digest_alg_identifiers, &md_alg );
381 if( ret != 0 )
382 return( MBEDTLS_ERR_PKCS7_INVALID_ALG );
383
384 /* Do not expect any content */
385 ret = pkcs7_get_content_info_type( &p, end_set, &signed_data->content.oid );
386 if( ret != 0 )
387 return( ret );
388
389 if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &signed_data->content.oid ) )
390 {
391 return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO ) ;
392 }
393
394 p = p + signed_data->content.oid.len;
395
396 /* Look for certificates, there may or may not be any */
397 mbedtls_x509_crt_init( &signed_data->certs );
398 ret = pkcs7_get_certificates( &p, end_set, &signed_data->certs );
399 if( ret < 0 )
400 return( ret ) ;
401
402 signed_data->no_of_certs = ret;
403
404 /*
405 * Currently CRLs are not supported. If CRL exist, the parsing will fail
406 * at next step of getting signers info and return error as invalid
407 * signer info.
408 */
409
410 signed_data->no_of_crls = 0;
411
412 /* Get signers info */
413 ret = pkcs7_get_signers_info_set( &p, end_set, &signed_data->signers );
414 if( ret < 0 )
415 return( ret );
416
417 signed_data->no_of_signers = ret;
418
419 /* Support single signer */
420 if ( p != end )
421 ret = MBEDTLS_ERR_PKCS7_INVALID_FORMAT;
422
423 ret = 0;
424 return( ret );
425}
426
427int mbedtls_pkcs7_parse_der( mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
428 const size_t buflen )
429{
430 unsigned char *start;
431 unsigned char *end;
432 size_t len = 0;
433 int ret;
Nayna Jain673a2262020-12-14 22:44:49 +0000434 int isoidset = 0;
Nayna Jainc9deb182020-11-16 19:03:12 +0000435
436 if( !pkcs7 )
437 return( MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA );
438
439 /* make an internal copy of the buffer for parsing */
440 pkcs7->raw.p = start = mbedtls_calloc( 1, buflen );
441 if( pkcs7->raw.p == NULL )
442 {
443 return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED );
444 }
445 memcpy( start, buf, buflen );
446 pkcs7->raw.len = buflen;
447 end = start + buflen;
448
449 ret = pkcs7_get_content_info_type( &start, end, &pkcs7->content_type_oid );
450 if( ret != 0 )
Nayna Jain673a2262020-12-14 22:44:49 +0000451 {
452 len = buflen;
453 goto try_data;
454 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000455
456 if( ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &pkcs7->content_type_oid )
457 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid )
458 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENVELOPED_DATA, &pkcs7->content_type_oid )
459 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, &pkcs7->content_type_oid )
460 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DIGESTED_DATA, &pkcs7->content_type_oid )
461 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid ) )
462 {
463 ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
464 goto out;
465 }
466
467 if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_DATA, &pkcs7->content_type_oid ) )
468 {
469 ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
470 goto out;
471 }
472
Nayna Jain673a2262020-12-14 22:44:49 +0000473 isoidset = 1;
Nayna Jainc9deb182020-11-16 19:03:12 +0000474 start = start + pkcs7->content_type_oid.len;
475
476 ret = pkcs7_get_next_content_len( &start, end, &len );
477 if( ret != 0 )
478 goto out;
479
Nayna Jain673a2262020-12-14 22:44:49 +0000480try_data:
Nayna Jainc9deb182020-11-16 19:03:12 +0000481 ret = pkcs7_get_signed_data( start, len, &pkcs7->signed_data );
Nayna Jain673a2262020-12-14 22:44:49 +0000482 if ( ret != 0 )
483 goto out;
484
485 if ( !isoidset )
486 {
487 pkcs7->content_type_oid.tag = MBEDTLS_ASN1_OID;
488 pkcs7->content_type_oid.len = MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS7_SIGNED_DATA );
489 pkcs7->content_type_oid.p = (unsigned char *)MBEDTLS_OID_PKCS7_SIGNED_DATA;
490 }
491
492 ret = MBEDTLS_PKCS7_SIGNED_DATA;
Nayna Jainc9deb182020-11-16 19:03:12 +0000493
494out:
Nayna Jain673a2262020-12-14 22:44:49 +0000495 if ( ret < 0 )
Nayna Jainc9deb182020-11-16 19:03:12 +0000496 mbedtls_pkcs7_free( pkcs7 );
Nayna Jain673a2262020-12-14 22:44:49 +0000497
Nayna Jainc9deb182020-11-16 19:03:12 +0000498 return( ret );
499}
500
501int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
502 const mbedtls_x509_crt *cert,
503 const unsigned char *data,
504 size_t datalen )
505{
506
507 int ret;
508 unsigned char *hash;
509 mbedtls_pk_context pk_cxt = cert->pk;
510 const mbedtls_md_info_t *md_info;
511 mbedtls_md_type_t md_alg;
512
513 ret = mbedtls_oid_get_md_alg( &pkcs7->signed_data.digest_alg_identifiers, &md_alg );
514 if( ret != 0 )
515 return( MBEDTLS_ERR_PKCS7_VERIFY_FAIL );
516
517 md_info = mbedtls_md_info_from_type( md_alg );
518
519 hash = mbedtls_calloc( mbedtls_md_get_size( md_info ), 1 );
520 if( hash == NULL ) {
521 return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED );
522 }
523
524 mbedtls_md( md_info, data, datalen, hash );
525
526 ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, 0,
527 pkcs7->signed_data.signers.sig.p,
528 pkcs7->signed_data.signers.sig.len );
529
530 mbedtls_free( hash );
531
532 return( ret );
533}
534
535int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
536 const mbedtls_x509_crt *cert,
537 const unsigned char *hash, size_t hashlen)
538{
539 int ret;
540 mbedtls_md_type_t md_alg;
541 mbedtls_pk_context pk_cxt;
542
543 ret = mbedtls_oid_get_md_alg( &pkcs7->signed_data.digest_alg_identifiers, &md_alg );
544 if( ret != 0 )
545 return( MBEDTLS_ERR_PKCS7_VERIFY_FAIL );
546
547 pk_cxt = cert->pk;
548 ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, hashlen,
549 pkcs7->signed_data.signers.sig.p,
550 pkcs7->signed_data.signers.sig.len );
551
552 return ( ret );
553}
554
555/*
556 * Unallocate all pkcs7 data
557 */
558void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 )
559{
560 mbedtls_x509_name *name_cur;
561 mbedtls_x509_name *name_prv;
562
563 if( pkcs7 == NULL || pkcs7->raw.p == NULL )
564 return;
565
566 mbedtls_free( pkcs7->raw.p );
567
568 mbedtls_x509_crt_free( &pkcs7->signed_data.certs );
569 mbedtls_x509_crl_free( &pkcs7->signed_data.crl );
570
571 name_cur = pkcs7->signed_data.signers.issuer.next;
572 while( name_cur != NULL )
573 {
574 name_prv = name_cur;
575 name_cur = name_cur->next;
576 mbedtls_free( name_prv );
577 }
578
579 pkcs7->raw.p = NULL;
580}
581
582#endif