blob: 783aaa2887bf3752260573edc0c4f570150600e6 [file] [log] [blame]
Nick Child5d881c32022-02-28 10:09:16 -06001/*
2 * Copyright The Mbed TLS Contributors
3 * SPDX-License-Identifier: Apache-2.0
Nayna Jainc9deb182020-11-16 19:03:12 +00004 *
Nick Child5d881c32022-02-28 10:09:16 -06005 * 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
Nayna Jainc9deb182020-11-16 19:03:12 +00008 *
Nick Child5d881c32022-02-28 10:09:16 -06009 * http://www.apache.org/licenses/LICENSE-2.0
Nayna Jainc9deb182020-11-16 19:03:12 +000010 *
Nick Child5d881c32022-02-28 10:09:16 -060011 * 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.
Nayna Jainc9deb182020-11-16 19:03:12 +000016 */
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"
Nick Child9f4fb3e2022-09-12 16:21:02 -050027#include "mbedtls/error.h"
Nayna Jainc9deb182020-11-16 19:03:12 +000028
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
Nayna Jainc9deb182020-11-16 19:03:12 +000037#include "mbedtls/platform.h"
38#include "mbedtls/platform_util.h"
Nayna Jainc9deb182020-11-16 19:03:12 +000039
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 */
50void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 )
51{
Nick Child8ce1b1a2022-09-14 14:51:23 -050052 memset( pkcs7, 0, sizeof( *pkcs7 ) );
Nayna Jainc9deb182020-11-16 19:03:12 +000053}
54
55static int pkcs7_get_next_content_len( unsigned char **p, unsigned char *end,
56 size_t *len )
57{
Nick Child9f4fb3e2022-09-12 16:21:02 -050058 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +000059
Nick Child9f4fb3e2022-09-12 16:21:02 -050060 ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_CONSTRUCTED
61 | MBEDTLS_ASN1_CONTEXT_SPECIFIC );
62 if( ret != 0 )
Nayna Jainc9deb182020-11-16 19:03:12 +000063 {
Nick Child9f4fb3e2022-09-12 16:21:02 -050064 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret );
Nayna Jainc9deb182020-11-16 19:03:12 +000065 }
66
Nick Child9f4fb3e2022-09-12 16:21:02 -050067 return( ret );
Nayna Jainc9deb182020-11-16 19:03:12 +000068}
69
70/**
71 * version Version
72 * Version ::= INTEGER
73 **/
74static int pkcs7_get_version( unsigned char **p, unsigned char *end, int *ver )
75{
Nick Child9f4fb3e2022-09-12 16:21:02 -050076 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +000077
Nick Child9f4fb3e2022-09-12 16:21:02 -050078 ret = mbedtls_asn1_get_int( p, end, ver );
79 if( ret != 0 )
80 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_VERSION, ret );
Nayna Jainc9deb182020-11-16 19:03:12 +000081
82 /* If version != 1, return invalid version */
83 if( *ver != MBEDTLS_PKCS7_SUPPORTED_VERSION )
Nick Child9f4fb3e2022-09-12 16:21:02 -050084 ret = MBEDTLS_ERR_PKCS7_INVALID_VERSION;
Nayna Jainc9deb182020-11-16 19:03:12 +000085
Nick Child9f4fb3e2022-09-12 16:21:02 -050086 return( ret );
Nayna Jainc9deb182020-11-16 19:03:12 +000087}
88
89/**
90 * ContentInfo ::= SEQUENCE {
91 * contentType ContentType,
92 * content
93 * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
94 **/
95static int pkcs7_get_content_info_type( unsigned char **p, unsigned char *end,
96 mbedtls_pkcs7_buf *pkcs7 )
97{
98 size_t len = 0;
Nick Child9f4fb3e2022-09-12 16:21:02 -050099 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jain673a2262020-12-14 22:44:49 +0000100 unsigned char *start = *p;
Nayna Jainc9deb182020-11-16 19:03:12 +0000101
102 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
103 | MBEDTLS_ASN1_SEQUENCE );
Nick Childc448c942021-07-01 15:29:50 -0400104 if( ret != 0 ) {
105 *p = start;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500106 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret );
107 goto out;
Nick Childc448c942021-07-01 15:29:50 -0400108 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000109
110 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID );
Nayna Jain673a2262020-12-14 22:44:49 +0000111 if( ret != 0 ) {
112 *p = start;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500113 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret );
114 goto out;
Nayna Jain673a2262020-12-14 22:44:49 +0000115 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000116
117 pkcs7->tag = MBEDTLS_ASN1_OID;
118 pkcs7->len = len;
119 pkcs7->p = *p;
Nick Childbb82ab72022-10-28 12:28:54 -0500120 *p += len;
Nayna Jainc9deb182020-11-16 19:03:12 +0000121
Nick Child9f4fb3e2022-09-12 16:21:02 -0500122out:
Nayna Jainc9deb182020-11-16 19:03:12 +0000123 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{
Nick Child9f4fb3e2022-09-12 16:21:02 -0500134 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +0000135
136 if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500137 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret );
Nayna Jainc9deb182020-11-16 19:03:12 +0000138
Nick Child9f4fb3e2022-09-12 16:21:02 -0500139 return( ret );
Nayna Jainc9deb182020-11-16 19:03:12 +0000140}
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;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500150 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +0000151
152 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
153 | MBEDTLS_ASN1_SET );
154 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500155 {
156 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret );
157 goto out;
158 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000159
160 end = *p + len;
161
Nayna Jainc9deb182020-11-16 19:03:12 +0000162 ret = mbedtls_asn1_get_alg_null( p, end, alg );
163 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500164 {
165 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret );
166 goto out;
167 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000168
Nick Child34d5e932022-09-14 14:44:03 -0500169 /** For now, it assumes there is only one digest algorithm specified **/
Nayna Jainc9deb182020-11-16 19:03:12 +0000170 if ( *p != end )
Nick Child34d5e932022-09-14 14:44:03 -0500171 ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
Nayna Jainc9deb182020-11-16 19:03:12 +0000172
Nick Child9f4fb3e2022-09-12 16:21:02 -0500173out:
174 return( ret );
Nayna Jainc9deb182020-11-16 19:03:12 +0000175}
176
177/**
178 * certificates :: SET OF ExtendedCertificateOrCertificate,
179 * ExtendedCertificateOrCertificate ::= CHOICE {
180 * certificate Certificate -- x509,
181 * extendedCertificate[0] IMPLICIT ExtendedCertificate }
182 * Return number of certificates added to the signed data,
183 * 0 or higher is valid.
184 * Return negative error code for failure.
185 **/
186static int pkcs7_get_certificates( unsigned char **p, unsigned char *end,
187 mbedtls_x509_crt *certs )
188{
Nick Child9f4fb3e2022-09-12 16:21:02 -0500189 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +0000190 size_t len1 = 0;
191 size_t len2 = 0;
Nick Childbb82ab72022-10-28 12:28:54 -0500192 unsigned char *end_set, *end_cert, *start;
Nayna Jainc9deb182020-11-16 19:03:12 +0000193
194 if( ( ret = mbedtls_asn1_get_tag( p, end, &len1, MBEDTLS_ASN1_CONSTRUCTED
195 | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
196 {
197 if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500198 ret = 0;
199 else
200 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret );
201 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000202 }
203 start = *p;
204 end_set = *p + len1;
205
206 ret = mbedtls_asn1_get_tag( p, end_set, &len2, MBEDTLS_ASN1_CONSTRUCTED
207 | MBEDTLS_ASN1_SEQUENCE );
208 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500209 {
210 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CERT, ret );
211 goto out;
212 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000213
214 end_cert = *p + len2;
215
216 /*
217 * This is to verify that there is only one signer certificate. It seems it is
218 * not easy to differentiate between the chain vs different signer's certificate.
219 * So, we support only the root certificate and the single signer.
220 * The behaviour would be improved with addition of multiple signer support.
221 */
Nick Child8ce1b1a2022-09-14 14:51:23 -0500222 if ( end_cert != end_set )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500223 {
Nick Child34d5e932022-09-14 14:44:03 -0500224 ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500225 goto out;
226 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000227
228 *p = start;
Nick Childbb82ab72022-10-28 12:28:54 -0500229 if( ( ret = mbedtls_x509_crt_parse_der( certs, *p, len1 ) ) < 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500230 {
231 ret = MBEDTLS_ERR_PKCS7_INVALID_CERT;
232 goto out;
233 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000234
235 *p = *p + len1;
236
Nick Child5f9456f2022-09-19 10:01:25 -0500237 /*
Nick Child9f4fb3e2022-09-12 16:21:02 -0500238 * Since in this version we strictly support single certificate, and reaching
Nick Child5f9456f2022-09-19 10:01:25 -0500239 * here implies we have parsed successfully, we return 1.
Nick Child9f4fb3e2022-09-12 16:21:02 -0500240 */
241 ret = 1;
Nayna Jainc9deb182020-11-16 19:03:12 +0000242
Nick Child9f4fb3e2022-09-12 16:21:02 -0500243out:
244 return( ret );
Nayna Jainc9deb182020-11-16 19:03:12 +0000245}
246
247/**
248 * EncryptedDigest ::= OCTET STRING
249 **/
250static int pkcs7_get_signature( unsigned char **p, unsigned char *end,
251 mbedtls_pkcs7_buf *signature )
252{
Nick Child9f4fb3e2022-09-12 16:21:02 -0500253 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +0000254 size_t len = 0;
255
256 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OCTET_STRING );
257 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500258 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000259
260 signature->tag = MBEDTLS_ASN1_OCTET_STRING;
261 signature->len = len;
262 signature->p = *p;
263
264 *p = *p + len;
265
Nick Child9f4fb3e2022-09-12 16:21:02 -0500266out:
267 return( ret );
Nayna Jainc9deb182020-11-16 19:03:12 +0000268}
269
270/**
Nayna Jainc9deb182020-11-16 19:03:12 +0000271 * SignerInfo ::= SEQUENCE {
272 * version Version;
273 * issuerAndSerialNumber IssuerAndSerialNumber,
274 * digestAlgorithm DigestAlgorithmIdentifier,
275 * authenticatedAttributes
276 * [0] IMPLICIT Attributes OPTIONAL,
277 * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
278 * encryptedDigest EncryptedDigest,
279 * unauthenticatedAttributes
280 * [1] IMPLICIT Attributes OPTIONAL,
Daniel Axtens35384792020-09-02 14:48:45 +1000281 * Returns 0 if the signerInfo is valid.
282 * Return negative error code for failure.
Nick Childbb82ab72022-10-28 12:28:54 -0500283 * Structure must not contain vales for authenticatedAttributes
284 * and unauthenticatedAttributes.
Daniel Axtens35384792020-09-02 14:48:45 +1000285 **/
286static int pkcs7_get_signer_info( unsigned char **p, unsigned char *end,
287 mbedtls_pkcs7_signer_info *signer )
288{
289 unsigned char *end_signer;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500290 int asn1_ret = 0, ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Daniel Axtens35384792020-09-02 14:48:45 +1000291 size_t len = 0;
292
Nick Child9f4fb3e2022-09-12 16:21:02 -0500293 asn1_ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
Daniel Axtens35384792020-09-02 14:48:45 +1000294 | MBEDTLS_ASN1_SEQUENCE );
Nick Child9f4fb3e2022-09-12 16:21:02 -0500295 if( asn1_ret != 0 )
296 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000297
298 end_signer = *p + len;
299
300 ret = pkcs7_get_version( p, end_signer, &signer->version );
301 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500302 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000303
Nick Child9f4fb3e2022-09-12 16:21:02 -0500304 asn1_ret = mbedtls_asn1_get_tag( p, end_signer, &len,
305 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
306 if( asn1_ret != 0 )
307 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000308
309 /* Parsing IssuerAndSerialNumber */
310 signer->issuer_raw.p = *p;
311
Nick Child9f4fb3e2022-09-12 16:21:02 -0500312 asn1_ret = mbedtls_asn1_get_tag( p, end_signer, &len,
313 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
314 if( asn1_ret != 0 )
315 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000316
317 ret = mbedtls_x509_get_name( p, *p + len, &signer->issuer );
318 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500319 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000320
321 signer->issuer_raw.len = *p - signer->issuer_raw.p;
322
323 ret = mbedtls_x509_get_serial( p, end_signer, &signer->serial );
324 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500325 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000326
327 ret = pkcs7_get_digest_algorithm( p, end_signer, &signer->alg_identifier );
328 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500329 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000330
Nick Childbb82ab72022-10-28 12:28:54 -0500331 /* Asssume authenticatedAttributes is nonexistent */
332
Daniel Axtens35384792020-09-02 14:48:45 +1000333 ret = pkcs7_get_digest_algorithm( p, end_signer, &signer->sig_alg_identifier );
334 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500335 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000336
337 ret = pkcs7_get_signature( p, end_signer, &signer->sig );
338 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500339 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000340
341 /* Do not permit any unauthenticated attributes */
342 if( *p != end_signer )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500343 ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
Daniel Axtens35384792020-09-02 14:48:45 +1000344
Nick Child9f4fb3e2022-09-12 16:21:02 -0500345out:
346 if( asn1_ret != 0 )
347 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO,
348 asn1_ret );
349 else if( ret != 0 )
350 ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
351
352 return( ret );
Daniel Axtens35384792020-09-02 14:48:45 +1000353}
354
355static void pkcs7_free_signer_info( mbedtls_pkcs7_signer_info *signer )
356{
357 mbedtls_x509_name *name_cur;
358 mbedtls_x509_name *name_prv;
359
360 if( signer == NULL )
361 return;
362
363 name_cur = signer->issuer.next;
364 while( name_cur != NULL )
365 {
366 name_prv = name_cur;
367 name_cur = name_cur->next;
368 mbedtls_free( name_prv );
369 }
370}
371
372/**
373 * SignerInfos ::= SET of SignerInfo
Nayna Jainc9deb182020-11-16 19:03:12 +0000374 * Return number of signers added to the signed data,
375 * 0 or higher is valid.
376 * Return negative error code for failure.
377 **/
378static int pkcs7_get_signers_info_set( unsigned char **p, unsigned char *end,
379 mbedtls_pkcs7_signer_info *signers_set )
380{
Daniel Axtens35384792020-09-02 14:48:45 +1000381 unsigned char *end_set;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500382 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Daniel Axtens35384792020-09-02 14:48:45 +1000383 int count = 0;
Nayna Jainc9deb182020-11-16 19:03:12 +0000384 size_t len = 0;
Daniel Axtens35384792020-09-02 14:48:45 +1000385 mbedtls_pkcs7_signer_info *signer, *prev;
Nayna Jainc9deb182020-11-16 19:03:12 +0000386
387 ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
388 | MBEDTLS_ASN1_SET );
389 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500390 {
391 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO, ret );
392 goto out;
393 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000394
Daniel Axtens35384792020-09-02 14:48:45 +1000395 /* Detect zero signers */
396 if( len == 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500397 {
398 ret = 0;
399 goto out;
400 }
Daniel Axtens35384792020-09-02 14:48:45 +1000401
Nayna Jainc9deb182020-11-16 19:03:12 +0000402 end_set = *p + len;
403
Daniel Axtens35384792020-09-02 14:48:45 +1000404 ret = pkcs7_get_signer_info( p, end_set, signers_set );
Nayna Jainc9deb182020-11-16 19:03:12 +0000405 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500406 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000407 count++;
Nayna Jainc9deb182020-11-16 19:03:12 +0000408
Daniel Axtens35384792020-09-02 14:48:45 +1000409 prev = signers_set;
410 while( *p != end_set )
411 {
412 signer = mbedtls_calloc( 1, sizeof( mbedtls_pkcs7_signer_info ) );
413 if( !signer )
414 {
415 ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
416 goto cleanup;
417 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000418
Daniel Axtens35384792020-09-02 14:48:45 +1000419 ret = pkcs7_get_signer_info( p, end_set, signer );
420 if( ret != 0 ) {
421 mbedtls_free( signer );
422 goto cleanup;
423 }
424 prev->next = signer;
425 prev = signer;
426 count++;
427 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000428
Nick Child9f4fb3e2022-09-12 16:21:02 -0500429 ret = count;
430 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000431
Daniel Axtens35384792020-09-02 14:48:45 +1000432cleanup:
Daniel Axtens35384792020-09-02 14:48:45 +1000433 pkcs7_free_signer_info( signers_set );
Gilles Peskine290f01b2022-11-27 21:28:31 +0100434 signer = signers_set->next;
435 while( signer != NULL )
Daniel Axtens35384792020-09-02 14:48:45 +1000436 {
437 prev = signer;
438 signer = signer->next;
439 pkcs7_free_signer_info( prev );
440 mbedtls_free( prev );
441 }
Gilles Peskine290f01b2022-11-27 21:28:31 +0100442 signers_set->next = NULL;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500443
444out:
Daniel Axtens35384792020-09-02 14:48:45 +1000445 return( ret );
Nayna Jainc9deb182020-11-16 19:03:12 +0000446}
447
448/**
449 * SignedData ::= SEQUENCE {
450 * version Version,
451 * digestAlgorithms DigestAlgorithmIdentifiers,
452 * contentInfo ContentInfo,
453 * certificates
454 * [0] IMPLICIT ExtendedCertificatesAndCertificates
455 * OPTIONAL,
456 * crls
457 * [0] IMPLICIT CertificateRevocationLists OPTIONAL,
458 * signerInfos SignerInfos }
459 */
460static int pkcs7_get_signed_data( unsigned char *buf, size_t buflen,
461 mbedtls_pkcs7_signed_data *signed_data )
462{
463 unsigned char *p = buf;
464 unsigned char *end = buf + buflen;
465 unsigned char *end_set;
466 size_t len = 0;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500467 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +0000468 mbedtls_md_type_t md_alg;
469
470 ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
471 | MBEDTLS_ASN1_SEQUENCE );
472 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500473 {
474 ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret );
475 goto out;
476 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000477
478 end_set = p + len;
479
480 /* Get version of signed data */
481 ret = pkcs7_get_version( &p, end_set, &signed_data->version );
482 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500483 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000484
485 /* Get digest algorithm */
486 ret = pkcs7_get_digest_algorithm_set( &p, end_set,
487 &signed_data->digest_alg_identifiers );
488 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500489 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000490
491 ret = mbedtls_oid_get_md_alg( &signed_data->digest_alg_identifiers, &md_alg );
492 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500493 {
494 ret = MBEDTLS_ERR_PKCS7_INVALID_ALG;
495 goto out;
496 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000497
498 /* Do not expect any content */
499 ret = pkcs7_get_content_info_type( &p, end_set, &signed_data->content.oid );
500 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500501 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000502
503 if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &signed_data->content.oid ) )
504 {
Nick Child9f4fb3e2022-09-12 16:21:02 -0500505 ret = MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO;
506 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000507 }
508
Nayna Jainc9deb182020-11-16 19:03:12 +0000509 /* Look for certificates, there may or may not be any */
510 mbedtls_x509_crt_init( &signed_data->certs );
511 ret = pkcs7_get_certificates( &p, end_set, &signed_data->certs );
512 if( ret < 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500513 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000514
515 signed_data->no_of_certs = ret;
516
517 /*
518 * Currently CRLs are not supported. If CRL exist, the parsing will fail
519 * at next step of getting signers info and return error as invalid
520 * signer info.
521 */
522
523 signed_data->no_of_crls = 0;
524
525 /* Get signers info */
526 ret = pkcs7_get_signers_info_set( &p, end_set, &signed_data->signers );
527 if( ret < 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500528 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000529
530 signed_data->no_of_signers = ret;
531
Daniel Axtens35384792020-09-02 14:48:45 +1000532 /* Don't permit trailing data */
Nayna Jainc9deb182020-11-16 19:03:12 +0000533 if ( p != end )
534 ret = MBEDTLS_ERR_PKCS7_INVALID_FORMAT;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500535 else
536 ret = 0;
Nayna Jainc9deb182020-11-16 19:03:12 +0000537
Nick Child9f4fb3e2022-09-12 16:21:02 -0500538out:
Nayna Jainc9deb182020-11-16 19:03:12 +0000539 return( ret );
540}
541
542int mbedtls_pkcs7_parse_der( mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
543 const size_t buflen )
544{
Nick Childbb82ab72022-10-28 12:28:54 -0500545 unsigned char *p;
Nayna Jainc9deb182020-11-16 19:03:12 +0000546 unsigned char *end;
547 size_t len = 0;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500548 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jain673a2262020-12-14 22:44:49 +0000549 int isoidset = 0;
Nayna Jainc9deb182020-11-16 19:03:12 +0000550
551 if( !pkcs7 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500552 {
553 ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
554 goto out;
555 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000556
557 /* make an internal copy of the buffer for parsing */
Nick Childbb82ab72022-10-28 12:28:54 -0500558 pkcs7->raw.p = p = mbedtls_calloc( 1, buflen );
Nayna Jainc9deb182020-11-16 19:03:12 +0000559 if( pkcs7->raw.p == NULL )
560 {
Nick Child9f4fb3e2022-09-12 16:21:02 -0500561 ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
562 goto out;
Nayna Jainc9deb182020-11-16 19:03:12 +0000563 }
Nick Childbb82ab72022-10-28 12:28:54 -0500564 memcpy( p, buf, buflen );
Nayna Jainc9deb182020-11-16 19:03:12 +0000565 pkcs7->raw.len = buflen;
Nick Childbb82ab72022-10-28 12:28:54 -0500566 end = p + buflen;
Nayna Jainc9deb182020-11-16 19:03:12 +0000567
Nick Childbb82ab72022-10-28 12:28:54 -0500568 ret = pkcs7_get_content_info_type( &p, end, &pkcs7->content_type_oid );
Nayna Jainc9deb182020-11-16 19:03:12 +0000569 if( ret != 0 )
Nayna Jain673a2262020-12-14 22:44:49 +0000570 {
571 len = buflen;
572 goto try_data;
573 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000574
575 if( ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &pkcs7->content_type_oid )
576 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid )
577 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENVELOPED_DATA, &pkcs7->content_type_oid )
578 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, &pkcs7->content_type_oid )
579 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DIGESTED_DATA, &pkcs7->content_type_oid )
580 || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid ) )
581 {
582 ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
583 goto out;
584 }
585
586 if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_DATA, &pkcs7->content_type_oid ) )
587 {
588 ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
589 goto out;
590 }
591
Nayna Jain673a2262020-12-14 22:44:49 +0000592 isoidset = 1;
Nayna Jainc9deb182020-11-16 19:03:12 +0000593
Nick Childbb82ab72022-10-28 12:28:54 -0500594 ret = pkcs7_get_next_content_len( &p, end, &len );
Nayna Jainc9deb182020-11-16 19:03:12 +0000595 if( ret != 0 )
596 goto out;
597
Nayna Jain673a2262020-12-14 22:44:49 +0000598try_data:
Nick Childbb82ab72022-10-28 12:28:54 -0500599 ret = pkcs7_get_signed_data( p, len, &pkcs7->signed_data );
Nayna Jain673a2262020-12-14 22:44:49 +0000600 if ( ret != 0 )
601 goto out;
602
603 if ( !isoidset )
604 {
605 pkcs7->content_type_oid.tag = MBEDTLS_ASN1_OID;
606 pkcs7->content_type_oid.len = MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS7_SIGNED_DATA );
607 pkcs7->content_type_oid.p = (unsigned char *)MBEDTLS_OID_PKCS7_SIGNED_DATA;
608 }
609
610 ret = MBEDTLS_PKCS7_SIGNED_DATA;
Nayna Jainc9deb182020-11-16 19:03:12 +0000611
612out:
Nayna Jain673a2262020-12-14 22:44:49 +0000613 if ( ret < 0 )
Nayna Jainc9deb182020-11-16 19:03:12 +0000614 mbedtls_pkcs7_free( pkcs7 );
Nayna Jain673a2262020-12-14 22:44:49 +0000615
Nayna Jainc9deb182020-11-16 19:03:12 +0000616 return( ret );
617}
618
Nick Child73621ef2022-10-28 11:23:15 -0500619static int mbedtls_pkcs7_data_or_hash_verify( mbedtls_pkcs7 *pkcs7,
620 const mbedtls_x509_crt *cert,
621 const unsigned char *data,
622 size_t datalen,
623 const int is_data_hash )
Nayna Jainc9deb182020-11-16 19:03:12 +0000624{
Nick Child9f4fb3e2022-09-12 16:21:02 -0500625 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Nayna Jainc9deb182020-11-16 19:03:12 +0000626 unsigned char *hash;
627 mbedtls_pk_context pk_cxt = cert->pk;
628 const mbedtls_md_info_t *md_info;
629 mbedtls_md_type_t md_alg;
Daniel Axtens35384792020-09-02 14:48:45 +1000630 mbedtls_pkcs7_signer_info *signer;
Nayna Jainc9deb182020-11-16 19:03:12 +0000631
Daniel Axtens35384792020-09-02 14:48:45 +1000632 if( pkcs7->signed_data.no_of_signers == 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500633 {
Nick Child3951a4f2022-10-31 09:17:15 -0500634 ret = MBEDTLS_ERR_PKCS7_INVALID_CERT;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500635 goto out;
636 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000637
Nick Child73621ef2022-10-28 11:23:15 -0500638 if( mbedtls_x509_time_is_past( &cert->valid_to ) ||
639 mbedtls_x509_time_is_future( &cert->valid_from ))
640 {
Nick Child3951a4f2022-10-31 09:17:15 -0500641 ret = MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID;
Nick Child73621ef2022-10-28 11:23:15 -0500642 goto out;
643 }
644
Daniel Axtens35384792020-09-02 14:48:45 +1000645 /*
646 * Potential TODOs
647 * Currently we iterate over all signers and return success if any of them
648 * verify.
649 *
650 * However, we could make this better by checking against the certificate's
651 * identification and SignerIdentifier fields first. That would also allow
652 * us to distinguish between 'no signature for key' and 'signature for key
653 * failed to validate'.
654 *
655 * We could also cache hashes by md, so if there are several sigs all using
656 * the same algo we don't recalculate the hash each time.
657 */
Nick Child7089ce82022-09-14 14:10:00 -0500658 for( signer = &pkcs7->signed_data.signers; signer; signer = signer->next )
Nick Child66718412022-02-22 17:19:59 -0600659 {
Daniel Axtens35384792020-09-02 14:48:45 +1000660 ret = mbedtls_oid_get_md_alg( &signer->alg_identifier, &md_alg );
661 if( ret != 0 )
Nick Child9f4fb3e2022-09-12 16:21:02 -0500662 {
663 ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
Nick Child7089ce82022-09-14 14:10:00 -0500664 continue;
Nick Child9f4fb3e2022-09-12 16:21:02 -0500665 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000666
Daniel Axtens35384792020-09-02 14:48:45 +1000667 md_info = mbedtls_md_info_from_type( md_alg );
Nick Child7089ce82022-09-14 14:10:00 -0500668 if( md_info == NULL )
669 {
670 ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
671 continue;
672 }
Daniel Axtens35384792020-09-02 14:48:45 +1000673
674 hash = mbedtls_calloc( mbedtls_md_get_size( md_info ), 1 );
675 if( hash == NULL ) {
Nick Child9f4fb3e2022-09-12 16:21:02 -0500676 ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
677 goto out;
Daniel Axtens35384792020-09-02 14:48:45 +1000678 }
Nick Child73621ef2022-10-28 11:23:15 -0500679 if( is_data_hash )
680 {
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 {
688 ret = mbedtls_md( md_info, data, datalen, hash );
689 }
Daniel Axtens35384792020-09-02 14:48:45 +1000690 if( ret != 0 )
691 {
Nick Child7089ce82022-09-14 14:10:00 -0500692 ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
Daniel Axtens35384792020-09-02 14:48:45 +1000693 mbedtls_free( hash );
Nick Child7089ce82022-09-14 14:10:00 -0500694 continue;
Daniel Axtens35384792020-09-02 14:48:45 +1000695 }
696
697 ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash,
698 mbedtls_md_get_size( md_info ),
699 signer->sig.p, signer->sig.len );
Daniel Axtens35384792020-09-02 14:48:45 +1000700 mbedtls_free( hash );
701
702 if( ret == 0 )
703 break;
Daniel Axtens35384792020-09-02 14:48:45 +1000704 }
Nayna Jainc9deb182020-11-16 19:03:12 +0000705
Nick Child9f4fb3e2022-09-12 16:21:02 -0500706out:
Nayna Jainc9deb182020-11-16 19:03:12 +0000707 return( ret );
708}
Nick Child73621ef2022-10-28 11:23:15 -0500709int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
710 const mbedtls_x509_crt *cert,
711 const unsigned char *data,
712 size_t datalen )
713{
714 return( mbedtls_pkcs7_data_or_hash_verify( pkcs7, cert, data, datalen, 0 ) );
715}
Nayna Jainc9deb182020-11-16 19:03:12 +0000716
717int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
718 const mbedtls_x509_crt *cert,
Nick Child5f9456f2022-09-19 10:01:25 -0500719 const unsigned char *hash,
Nick Child8ce1b1a2022-09-14 14:51:23 -0500720 size_t hashlen )
Nayna Jainc9deb182020-11-16 19:03:12 +0000721{
Nick Child73621ef2022-10-28 11:23:15 -0500722 return( mbedtls_pkcs7_data_or_hash_verify( pkcs7, cert, hash, hashlen, 1 ) );
Nayna Jainc9deb182020-11-16 19:03:12 +0000723}
724
725/*
726 * Unallocate all pkcs7 data
727 */
728void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 )
729{
Daniel Axtens35384792020-09-02 14:48:45 +1000730 mbedtls_pkcs7_signer_info *signer_cur;
731 mbedtls_pkcs7_signer_info *signer_prev;
Nayna Jainc9deb182020-11-16 19:03:12 +0000732
733 if( pkcs7 == NULL || pkcs7->raw.p == NULL )
734 return;
735
736 mbedtls_free( pkcs7->raw.p );
737
738 mbedtls_x509_crt_free( &pkcs7->signed_data.certs );
739 mbedtls_x509_crl_free( &pkcs7->signed_data.crl );
740
Daniel Axtens35384792020-09-02 14:48:45 +1000741 signer_cur = pkcs7->signed_data.signers.next;
742 pkcs7_free_signer_info( &pkcs7->signed_data.signers );
743 while( signer_cur != NULL )
Nayna Jainc9deb182020-11-16 19:03:12 +0000744 {
Daniel Axtens35384792020-09-02 14:48:45 +1000745 signer_prev = signer_cur;
746 signer_cur = signer_prev->next;
747 pkcs7_free_signer_info( signer_prev );
748 mbedtls_free( signer_prev );
Nayna Jainc9deb182020-11-16 19:03:12 +0000749 }
750
751 pkcs7->raw.p = NULL;
752}
753
754#endif