blob: 8c2a3ecaf3cfa7c272dabcfc6dccd659bdafa014 [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 );
Nick Childc448c942021-07-01 15:29:50 -0400110 if( ret != 0 ) {
111 *p = start;
Nayna Jainc9deb182020-11-16 19:03:12 +0000112 return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret );
Nick Childc448c942021-07-01 15:29:50 -0400113 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000114
115 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID );
Nayna Jain673a2262020-12-14 22:44:49 +0000116 if( ret != 0 ) {
117 *p = start;
Nayna Jainc9deb182020-11-16 19:03:12 +0000118 return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret );
Nayna Jain673a2262020-12-14 22:44:49 +0000119 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000120
121 pkcs7->tag = MBEDTLS_ASN1_OID;
122 pkcs7->len = len;
123 pkcs7->p = *p;
124
125 return( ret );
126}
127
128/**
129 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
130 *
131 * This is from x509.h
132 **/
133static int pkcs7_get_digest_algorithm( unsigned char **p, unsigned char *end,
134 mbedtls_x509_buf *alg )
135{
136 int ret;
137
138 if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 )
139 return( MBEDTLS_ERR_PKCS7_INVALID_ALG );
140
141 return( 0 );
142}
143
144/**
145 * DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier
146 **/
147static int pkcs7_get_digest_algorithm_set( unsigned char **p,
148 unsigned char *end,
149 mbedtls_x509_buf *alg )
150{
151 size_t len = 0;
152 int ret;
153
154 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
155 | MBEDTLS_ASN1_SET );
156 if( ret != 0 )
157 return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
158
159 end = *p + len;
160
161 /** For now, it assumes there is only one digest algorithm specified **/
162 ret = mbedtls_asn1_get_alg_null( p, end, alg );
163 if( ret != 0 )
164 return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
165
166 if ( *p != end )
167 return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT );
168
169 return( 0 );
170}
171
172/**
173 * certificates :: SET OF ExtendedCertificateOrCertificate,
174 * ExtendedCertificateOrCertificate ::= CHOICE {
175 * certificate Certificate -- x509,
176 * extendedCertificate[0] IMPLICIT ExtendedCertificate }
177 * Return number of certificates added to the signed data,
178 * 0 or higher is valid.
179 * Return negative error code for failure.
180 **/
181static int pkcs7_get_certificates( unsigned char **p, unsigned char *end,
182 mbedtls_x509_crt *certs )
183{
184 int ret;
185 size_t len1 = 0;
186 size_t len2 = 0;
187 unsigned char *end_set, *end_cert;
188 unsigned char *start = *p;
189
190 if( ( ret = mbedtls_asn1_get_tag( p, end, &len1, MBEDTLS_ASN1_CONSTRUCTED
191 | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
192 {
193 if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
194 return( 0 );
195
196 return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
197 }
198 start = *p;
199 end_set = *p + len1;
200
201 ret = mbedtls_asn1_get_tag( p, end_set, &len2, MBEDTLS_ASN1_CONSTRUCTED
202 | MBEDTLS_ASN1_SEQUENCE );
203 if( ret != 0 )
204 return( MBEDTLS_ERR_PKCS7_INVALID_CERT + ret );
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 return ( MBEDTLS_ERR_PKCS7_INVALID_CERT );
216
217 *p = start;
218 if( ( ret = mbedtls_x509_crt_parse( certs, *p, len1 ) ) < 0 )
219 return( MBEDTLS_ERR_PKCS7_INVALID_CERT );
220
221 *p = *p + len1;
222
223 /* Since in this version we strictly support single certificate, and reaching
224 * here implies we have parsed successfully, we return 1. */
225
226 return( 1 );
227}
228
229/**
230 * EncryptedDigest ::= OCTET STRING
231 **/
232static int pkcs7_get_signature( unsigned char **p, unsigned char *end,
233 mbedtls_pkcs7_buf *signature )
234{
235 int ret;
236 size_t len = 0;
237
238 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OCTET_STRING );
239 if( ret != 0 )
240 return( ret );
241
242 signature->tag = MBEDTLS_ASN1_OCTET_STRING;
243 signature->len = len;
244 signature->p = *p;
245
246 *p = *p + len;
247
248 return( 0 );
249}
250
251/**
252 * SignerInfos ::= SET of SignerInfo
253 * SignerInfo ::= SEQUENCE {
254 * version Version;
255 * issuerAndSerialNumber IssuerAndSerialNumber,
256 * digestAlgorithm DigestAlgorithmIdentifier,
257 * authenticatedAttributes
258 * [0] IMPLICIT Attributes OPTIONAL,
259 * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
260 * encryptedDigest EncryptedDigest,
261 * unauthenticatedAttributes
262 * [1] IMPLICIT Attributes OPTIONAL,
263 * Return number of signers added to the signed data,
264 * 0 or higher is valid.
265 * Return negative error code for failure.
266 **/
267static int pkcs7_get_signers_info_set( unsigned char **p, unsigned char *end,
268 mbedtls_pkcs7_signer_info *signers_set )
269{
270 unsigned char *end_set, *end_set_signer;
271 int ret;
272 size_t len = 0;
273
274 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
275 | MBEDTLS_ASN1_SET );
276 if( ret != 0 )
277 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
278
279 end_set = *p + len;
280
281 ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
282 | MBEDTLS_ASN1_SEQUENCE );
283 if( ret != 0 )
284 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
285
286 end_set_signer = *p + len;
287 if (end_set_signer != end_set)
288 return ( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
289
290 end_set = end_set_signer;
291
292 ret = mbedtls_asn1_get_int( p, end_set, &signers_set->version );
293 if( ret != 0 )
294 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
295
296 ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
297 | MBEDTLS_ASN1_SEQUENCE );
298 if( ret != 0 )
299 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
300
301 /* Parsing IssuerAndSerialNumber */
302 signers_set->issuer_raw.p = *p;
303
304 ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
305 | MBEDTLS_ASN1_SEQUENCE );
306 if( ret != 0 )
307 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
308
309 ret = mbedtls_x509_get_name( p, *p + len, &signers_set->issuer );
310 if( ret != 0 )
311 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
312
313 signers_set->issuer_raw.len = *p - signers_set->issuer_raw.p;
314
315 ret = mbedtls_x509_get_serial( p, end_set, &signers_set->serial );
316 if( ret != 0 )
317 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
318
319 ret = pkcs7_get_digest_algorithm( p, end_set, &signers_set->alg_identifier );
320 if( ret != 0 )
321 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
322
323 ret = pkcs7_get_digest_algorithm( p, end_set, &signers_set->sig_alg_identifier );
324 if( ret != 0 )
325 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
326
327 ret = pkcs7_get_signature( p, end_set, &signers_set->sig );
328 if( ret != 0 )
329 return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
330
331 signers_set->next = NULL;
332
333 if (*p != end_set)
334 return ( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
335
336 /* Since in this version we strictly support single signer, and reaching
337 * here implies we have parsed successfully, we return 1. */
338
339 return( 1 );
340}
341
342/**
343 * SignedData ::= SEQUENCE {
344 * version Version,
345 * digestAlgorithms DigestAlgorithmIdentifiers,
346 * contentInfo ContentInfo,
347 * certificates
348 * [0] IMPLICIT ExtendedCertificatesAndCertificates
349 * OPTIONAL,
350 * crls
351 * [0] IMPLICIT CertificateRevocationLists OPTIONAL,
352 * signerInfos SignerInfos }
353 */
354static int pkcs7_get_signed_data( unsigned char *buf, size_t buflen,
355 mbedtls_pkcs7_signed_data *signed_data )
356{
357 unsigned char *p = buf;
358 unsigned char *end = buf + buflen;
359 unsigned char *end_set;
360 size_t len = 0;
361 int ret;
362 mbedtls_md_type_t md_alg;
363
364 ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
365 | MBEDTLS_ASN1_SEQUENCE );
366 if( ret != 0 )
367 return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
368
369 end_set = p + len;
370
371 /* Get version of signed data */
372 ret = pkcs7_get_version( &p, end_set, &signed_data->version );
373 if( ret != 0 )
374 return( ret );
375
376 /* Get digest algorithm */
377 ret = pkcs7_get_digest_algorithm_set( &p, end_set,
378 &signed_data->digest_alg_identifiers );
379 if( ret != 0 )
380 return( ret );
381
382 ret = mbedtls_oid_get_md_alg( &signed_data->digest_alg_identifiers, &md_alg );
383 if( ret != 0 )
384 return( MBEDTLS_ERR_PKCS7_INVALID_ALG );
385
386 /* Do not expect any content */
387 ret = pkcs7_get_content_info_type( &p, end_set, &signed_data->content.oid );
388 if( ret != 0 )
389 return( ret );
390
391 if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &signed_data->content.oid ) )
392 {
393 return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO ) ;
394 }
395
396 p = p + signed_data->content.oid.len;
397
398 /* Look for certificates, there may or may not be any */
399 mbedtls_x509_crt_init( &signed_data->certs );
400 ret = pkcs7_get_certificates( &p, end_set, &signed_data->certs );
401 if( ret < 0 )
402 return( ret ) ;
403
404 signed_data->no_of_certs = ret;
405
406 /*
407 * Currently CRLs are not supported. If CRL exist, the parsing will fail
408 * at next step of getting signers info and return error as invalid
409 * signer info.
410 */
411
412 signed_data->no_of_crls = 0;
413
414 /* Get signers info */
415 ret = pkcs7_get_signers_info_set( &p, end_set, &signed_data->signers );
416 if( ret < 0 )
417 return( ret );
418
419 signed_data->no_of_signers = ret;
420
421 /* Support single signer */
422 if ( p != end )
423 ret = MBEDTLS_ERR_PKCS7_INVALID_FORMAT;
424
425 ret = 0;
426 return( ret );
427}
428
429int mbedtls_pkcs7_parse_der( mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
430 const size_t buflen )
431{
432 unsigned char *start;
433 unsigned char *end;
434 size_t len = 0;
435 int ret;
Nayna Jain673a2262020-12-14 22:44:49 +0000436 int isoidset = 0;
Nayna Jainc9deb182020-11-16 19:03:12 +0000437
438 if( !pkcs7 )
439 return( MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA );
440
441 /* make an internal copy of the buffer for parsing */
442 pkcs7->raw.p = start = mbedtls_calloc( 1, buflen );
443 if( pkcs7->raw.p == NULL )
444 {
445 return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED );
446 }
447 memcpy( start, buf, buflen );
448 pkcs7->raw.len = buflen;
449 end = start + buflen;
450
451 ret = pkcs7_get_content_info_type( &start, end, &pkcs7->content_type_oid );
452 if( ret != 0 )
Nayna Jain673a2262020-12-14 22:44:49 +0000453 {
454 len = buflen;
455 goto try_data;
456 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000457
458 if( ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &pkcs7->content_type_oid )
459 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid )
460 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENVELOPED_DATA, &pkcs7->content_type_oid )
461 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, &pkcs7->content_type_oid )
462 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DIGESTED_DATA, &pkcs7->content_type_oid )
463 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid ) )
464 {
465 ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
466 goto out;
467 }
468
469 if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_DATA, &pkcs7->content_type_oid ) )
470 {
471 ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
472 goto out;
473 }
474
Nayna Jain673a2262020-12-14 22:44:49 +0000475 isoidset = 1;
Nayna Jainc9deb182020-11-16 19:03:12 +0000476 start = start + pkcs7->content_type_oid.len;
477
478 ret = pkcs7_get_next_content_len( &start, end, &len );
479 if( ret != 0 )
480 goto out;
481
Nayna Jain673a2262020-12-14 22:44:49 +0000482try_data:
Nayna Jainc9deb182020-11-16 19:03:12 +0000483 ret = pkcs7_get_signed_data( start, len, &pkcs7->signed_data );
Nayna Jain673a2262020-12-14 22:44:49 +0000484 if ( ret != 0 )
485 goto out;
486
487 if ( !isoidset )
488 {
489 pkcs7->content_type_oid.tag = MBEDTLS_ASN1_OID;
490 pkcs7->content_type_oid.len = MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS7_SIGNED_DATA );
491 pkcs7->content_type_oid.p = (unsigned char *)MBEDTLS_OID_PKCS7_SIGNED_DATA;
492 }
493
494 ret = MBEDTLS_PKCS7_SIGNED_DATA;
Nayna Jainc9deb182020-11-16 19:03:12 +0000495
496out:
Nayna Jain673a2262020-12-14 22:44:49 +0000497 if ( ret < 0 )
Nayna Jainc9deb182020-11-16 19:03:12 +0000498 mbedtls_pkcs7_free( pkcs7 );
Nayna Jain673a2262020-12-14 22:44:49 +0000499
Nayna Jainc9deb182020-11-16 19:03:12 +0000500 return( ret );
501}
502
503int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
504 const mbedtls_x509_crt *cert,
505 const unsigned char *data,
506 size_t datalen )
507{
508
509 int ret;
510 unsigned char *hash;
511 mbedtls_pk_context pk_cxt = cert->pk;
512 const mbedtls_md_info_t *md_info;
513 mbedtls_md_type_t md_alg;
514
515 ret = mbedtls_oid_get_md_alg( &pkcs7->signed_data.digest_alg_identifiers, &md_alg );
516 if( ret != 0 )
517 return( MBEDTLS_ERR_PKCS7_VERIFY_FAIL );
518
519 md_info = mbedtls_md_info_from_type( md_alg );
520
521 hash = mbedtls_calloc( mbedtls_md_get_size( md_info ), 1 );
522 if( hash == NULL ) {
523 return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED );
524 }
525
526 mbedtls_md( md_info, data, datalen, hash );
527
528 ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, 0,
529 pkcs7->signed_data.signers.sig.p,
530 pkcs7->signed_data.signers.sig.len );
531
532 mbedtls_free( hash );
533
534 return( ret );
535}
536
537int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
538 const mbedtls_x509_crt *cert,
539 const unsigned char *hash, size_t hashlen)
540{
541 int ret;
542 mbedtls_md_type_t md_alg;
543 mbedtls_pk_context pk_cxt;
544
545 ret = mbedtls_oid_get_md_alg( &pkcs7->signed_data.digest_alg_identifiers, &md_alg );
546 if( ret != 0 )
547 return( MBEDTLS_ERR_PKCS7_VERIFY_FAIL );
548
549 pk_cxt = cert->pk;
550 ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, hashlen,
551 pkcs7->signed_data.signers.sig.p,
552 pkcs7->signed_data.signers.sig.len );
553
554 return ( ret );
555}
556
557/*
558 * Unallocate all pkcs7 data
559 */
560void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 )
561{
562 mbedtls_x509_name *name_cur;
563 mbedtls_x509_name *name_prv;
564
565 if( pkcs7 == NULL || pkcs7->raw.p == NULL )
566 return;
567
568 mbedtls_free( pkcs7->raw.p );
569
570 mbedtls_x509_crt_free( &pkcs7->signed_data.certs );
571 mbedtls_x509_crl_free( &pkcs7->signed_data.crl );
572
573 name_cur = pkcs7->signed_data.signers.issuer.next;
574 while( name_cur != NULL )
575 {
576 name_prv = name_cur;
577 name_cur = name_cur->next;
578 mbedtls_free( name_prv );
579 }
580
581 pkcs7->raw.p = NULL;
582}
583
584#endif