Merge remote-tracking branch 'origin/development' into pr3431
diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h
index 8b66ee2..5e3f387 100644
--- a/include/mbedtls/asn1.h
+++ b/include/mbedtls/asn1.h
@@ -39,8 +39,9 @@
 
 /**
  * \name ASN1 Error codes
- * These error codes are OR'ed to X509 error codes for
+ * These error codes are combined with other error codes for
  * higher error granularity.
+ * e.g. X.509 and PKCS #7 error codes
  * ASN1 is a standard to specify data structures.
  * \{
  */
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index d36db4a..701bded 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -1062,6 +1062,14 @@
 #error "MBEDTLS_SSL_TRUNCATED_HMAC was removed in Mbed TLS 3.0. See https://github.com/Mbed-TLS/mbedtls/issues/4341"
 #endif
 
+#if defined(MBEDTLS_PKCS7_C) && ( ( !defined(MBEDTLS_ASN1_PARSE_C) ) || \
+    ( !defined(MBEDTLS_OID_C) ) || ( !defined(MBEDTLS_PK_PARSE_C) ) || \
+    ( !defined(MBEDTLS_X509_CRT_PARSE_C) ) ||\
+    ( !defined(MBEDTLS_X509_CRL_PARSE_C) ) || ( !defined(MBEDTLS_BIGNUM_C) ) \
+    ( !defined(MBEDTLS_MD_C) ) )
+#error  "MBEDTLS_PKCS7_C is defined, but not all prerequisites"
+#endif
+
 /*
  * Avoid warning from -pedantic. This is a convenient place for this
  * workaround since this is included by every single file before the
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index eb83913..841b75b 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -96,6 +96,7 @@
  * ECP       4   10 (Started from top)
  * MD        5   5
  * HKDF      5   1 (Started from top)
+ * PKCS7     5   12 (Started from 0x5300)
  * SSL       5   2 (Started from 0x5F00)
  * CIPHER    6   8 (Started from 0x6080)
  * SSL       6   22 (Started from top, plus 0x6000)
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index b4c8635..6a4f584 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -2781,6 +2781,22 @@
 #define MBEDTLS_PKCS5_C
 
 /**
+ * \def MBEDTLS_PKCS7_C
+ *
+ * Enable PKCS7 core for using PKCS7 formatted signatures.
+ * RFC Link - https://tools.ietf.org/html/rfc2315
+ *
+ * Module:  library/pkcs7.c
+ *
+ * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_OID_C, MBEDTLS_PK_PARSE_C,
+ *           MBEDTLS_X509_CRT_PARSE_C MBEDTLS_X509_CRL_PARSE_C,
+ *           MBEDTLS_BIGNUM_C, MBEDTLS_MD_C
+ *
+ * This module is required for the PKCS7 parsing modules.
+ */
+#define MBEDTLS_PKCS7_C
+
+/**
  * \def MBEDTLS_PKCS12_C
  *
  * Enable PKCS#12 PBE functions.
diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h
index 4ee3f93..e5c4b92 100644
--- a/include/mbedtls/oid.h
+++ b/include/mbedtls/oid.h
@@ -220,6 +220,7 @@
 #define MBEDTLS_OID_PKCS                MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */
 #define MBEDTLS_OID_PKCS1               MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */
 #define MBEDTLS_OID_PKCS5               MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */
+#define MBEDTLS_OID_PKCS7               MBEDTLS_OID_PKCS "\x07" /**< pkcs-7 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } */
 #define MBEDTLS_OID_PKCS9               MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */
 #define MBEDTLS_OID_PKCS12              MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */
 
@@ -301,6 +302,16 @@
 #define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC      MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */
 
 /*
+ * PKCS#7 OIDs
+ */
+#define MBEDTLS_OID_PKCS7_DATA                        MBEDTLS_OID_PKCS7 "\x01" /**< Content type is Data OBJECT IDENTIFIER ::= {pkcs-7 1} */
+#define MBEDTLS_OID_PKCS7_SIGNED_DATA                 MBEDTLS_OID_PKCS7 "\x02" /**< Content type is Signed Data OBJECT IDENTIFIER ::= {pkcs-7 2} */
+#define MBEDTLS_OID_PKCS7_ENVELOPED_DATA              MBEDTLS_OID_PKCS7 "\x03" /**< Content type is Enveloped Data OBJECT IDENTIFIER ::= {pkcs-7 3} */
+#define MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA   MBEDTLS_OID_PKCS7 "\x04" /**< Content type is Signed and Enveloped Data OBJECT IDENTIFIER ::= {pkcs-7 4} */
+#define MBEDTLS_OID_PKCS7_DIGESTED_DATA               MBEDTLS_OID_PKCS7 "\x05" /**< Content type is Digested Data OBJECT IDENTIFIER ::= {pkcs-7 5} */
+#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA              MBEDTLS_OID_PKCS7 "\x06" /**< Content type is Encrypted Data OBJECT IDENTIFIER ::= {pkcs-7 6} */
+
+/*
  * PKCS#8 OIDs
  */
 #define MBEDTLS_OID_PKCS9_CSR_EXT_REQ           MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */
diff --git a/include/mbedtls/pkcs7.h b/include/mbedtls/pkcs7.h
new file mode 100644
index 0000000..52895ac
--- /dev/null
+++ b/include/mbedtls/pkcs7.h
@@ -0,0 +1,241 @@
+/**
+ * \file pkcs7.h
+ *
+ * \brief PKCS7 generic defines and structures
+ *  https://tools.ietf.org/html/rfc2315
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * Note: For the time being, this implementation of the PKCS7 cryptographic
+ * message syntax is a partial implementation of RFC 2315.
+ * Differences include:
+ *  - The RFC specifies 6 different content types. The only type currently
+ *    supported in Mbed TLS is the signed data content type.
+ *  - The only supported PKCS7 Signed Data syntax version is version 1
+ *  - The RFC specifies support for BER. This implementation is limited to
+ *    DER only.
+ *  - The RFC specifies that multiple digest algorithms can be specified
+ *    in the Signed Data type. Only one digest algorithm is supported in Mbed TLS.
+ *  - The RFC specifies the Signed Data type can contain multiple X509 or PKCS6
+ *    certificates. In Mbed TLS, this list can only contain 0 or 1 certificates
+ *    and they must be in X509 format.
+ *  - The RFC specifies the Signed Data type can contain
+ *    certificate-revocation lists (crls). This implementation has no support
+ *    for crls so it is assumed to be an empty list.
+ *  - The RFC allows for SignerInfo structure to optionally contain
+ *    unauthenticatedAttributes and authenticatedAttributes. In Mbed TLS it is
+ *    assumed these fields are empty.
+ */
+
+#ifndef MBEDTLS_PKCS7_H
+#define MBEDTLS_PKCS7_H
+
+#include "mbedtls/private_access.h"
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/asn1.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crt.h"
+
+/**
+ * \name PKCS7 Module Error codes
+ * \{
+ */
+#define MBEDTLS_ERR_PKCS7_INVALID_FORMAT                   -0x5300  /**< The format is invalid, e.g. different type expected. */
+#define MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE              -0x5380  /**< Unavailable feature, e.g. anything other than signed data. */
+#define MBEDTLS_ERR_PKCS7_INVALID_VERSION                  -0x5400  /**< The PKCS7 version element is invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO             -0x5480  /**< The PKCS7 content info invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_ALG                      -0x5500  /**< The algorithm tag or value is invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_CERT                     -0x5580  /**< The certificate tag or value is invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_SIGNATURE                -0x5600  /**< Error parsing the signature */
+#define MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO              -0x5680  /**< Error parsing the signer's info */
+#define MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA                   -0x5700  /**< Input invalid. */
+#define MBEDTLS_ERR_PKCS7_ALLOC_FAILED                     -0x5780  /**< Allocation of memory failed. */
+#define MBEDTLS_ERR_PKCS7_VERIFY_FAIL                      -0x5800  /**< Verification Failed */
+#define MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID                -0x5880  /**< The PKCS7 date issued/expired dates are invalid */
+/* \} name */
+
+/**
+ * \name PKCS7 Supported Version
+ * \{
+ */
+#define MBEDTLS_PKCS7_SUPPORTED_VERSION                           0x01
+/* \} name */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Type-length-value structure that allows for ASN1 using DER.
+ */
+typedef mbedtls_asn1_buf mbedtls_pkcs7_buf;
+
+/**
+ * Container for ASN1 named information objects.
+ * It allows for Relative Distinguished Names (e.g. cn=localhost,ou=code,etc.).
+ */
+typedef mbedtls_asn1_named_data mbedtls_pkcs7_name;
+
+/**
+ * Container for a sequence of ASN.1 items
+ */
+typedef mbedtls_asn1_sequence mbedtls_pkcs7_sequence;
+
+/**
+ * PKCS7 types
+ */
+typedef enum {
+    MBEDTLS_PKCS7_NONE=0,
+    MBEDTLS_PKCS7_DATA,
+    MBEDTLS_PKCS7_SIGNED_DATA,
+    MBEDTLS_PKCS7_ENVELOPED_DATA,
+    MBEDTLS_PKCS7_SIGNED_AND_ENVELOPED_DATA,
+    MBEDTLS_PKCS7_DIGESTED_DATA,
+    MBEDTLS_PKCS7_ENCRYPTED_DATA,
+}
+mbedtls_pkcs7_type;
+
+/**
+ * Structure holding PKCS7 signer info
+ */
+typedef struct mbedtls_pkcs7_signer_info
+{
+    int MBEDTLS_PRIVATE(version);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(serial);
+    mbedtls_x509_name MBEDTLS_PRIVATE(issuer);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(issuer_raw);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(alg_identifier);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(sig_alg_identifier);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(sig);
+    struct mbedtls_pkcs7_signer_info *MBEDTLS_PRIVATE(next);
+}
+mbedtls_pkcs7_signer_info;
+
+/**
+ * Structure holding attached data as part of PKCS7 signed data format
+ */
+typedef struct mbedtls_pkcs7_data
+{
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(oid);
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(data);
+}
+mbedtls_pkcs7_data;
+
+/**
+ * Structure holding the signed data section
+ */
+typedef struct mbedtls_pkcs7_signed_data
+{
+    int MBEDTLS_PRIVATE(version);
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(digest_alg_identifiers);
+    struct mbedtls_pkcs7_data MBEDTLS_PRIVATE(content);
+    int MBEDTLS_PRIVATE(no_of_certs);
+    mbedtls_x509_crt MBEDTLS_PRIVATE(certs);
+    int MBEDTLS_PRIVATE(no_of_crls);
+    mbedtls_x509_crl MBEDTLS_PRIVATE(crl);
+    int MBEDTLS_PRIVATE(no_of_signers);
+    mbedtls_pkcs7_signer_info MBEDTLS_PRIVATE(signers);
+}
+mbedtls_pkcs7_signed_data;
+
+/**
+ * Structure holding PKCS7 structure, only signed data for now
+ */
+typedef struct mbedtls_pkcs7
+{
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(raw);
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(content_type_oid);
+    mbedtls_pkcs7_signed_data MBEDTLS_PRIVATE(signed_data);
+}
+mbedtls_pkcs7;
+
+/**
+ * \brief          Initialize pkcs7 structure.
+ *
+ * \param pkcs7    pkcs7 structure.
+ */
+void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 );
+
+/**
+ * \brief          Parse a single DER formatted pkcs7 content.
+ *
+ * \param pkcs7    The pkcs7 structure to be filled by parser for the output.
+ * \param buf      The buffer holding the DER encoded pkcs7.
+ * \param buflen   The size in Bytes of \p buf.
+ *
+ * \note           This function makes an internal copy of the PKCS7 buffer
+ *                 \p buf. In particular, \p buf may be destroyed or reused
+ *                 after this call returns.
+ *
+ * \return         The \c mbedtls_pkcs7_type of \p buf, if successful.
+ * \return         A negative error code on failure.
+ */
+int mbedtls_pkcs7_parse_der( mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
+                             const size_t buflen );
+
+/**
+ * \brief          Verification of PKCS7 signature.
+ *
+ * \param pkcs7    PKCS7 structure containing signature.
+ * \param cert     Certificate containing key to verify signature.
+ * \param data     Plain data on which signature has to be verified.
+ * \param datalen  Length of the data.
+ *
+ * \note           This function internally calculates the hash on the supplied
+ *                 plain data for signature verification.
+ *
+ * \return         A negative error code on failure.
+ */
+int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *data,
+                                      size_t datalen );
+
+/**
+ * \brief          Verification of PKCS7 signature.
+ *
+ * \param pkcs7    PKCS7 structure containing signature.
+ * \param cert     Certificate containing key to verify signature.
+ * \param hash     Hash of the plain data on which signature has to be verified.
+ * \param hashlen  Length of the hash.
+ *
+ * \note           This function is different from mbedtls_pkcs7_signed_data_verify()
+ *                 in a way that it directly recieves the hash of the data.
+ *
+ * \return         A negative error code on failure.
+ */
+int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *hash, size_t hashlen);
+
+/**
+ * \brief          Unallocate all PKCS7 data and zeroize the memory.
+ *                 It doesn't free pkcs7 itself. It should be done by the caller.
+ *
+ * \param pkcs7    PKCS7 structure to free.
+ */
+void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* pkcs7.h */
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 7c325f7..60b1cf4 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -92,6 +92,7 @@
 )
 
 set(src_x509
+    pkcs7.c
     x509.c
     x509_create.c
     x509_crl.c
diff --git a/library/Makefile b/library/Makefile
index b1cdc7f..6c3b758 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -168,6 +168,7 @@
 	   x509_csr.o \
 	   x509write_crt.o \
 	   x509write_csr.o \
+	   pkcs7.o \
 	   # This line is intentionally left blank
 
 OBJS_TLS= \
diff --git a/library/pkcs7.c b/library/pkcs7.c
new file mode 100644
index 0000000..ca0170a
--- /dev/null
+++ b/library/pkcs7.c
@@ -0,0 +1,753 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+#include "common.h"
+
+#include "mbedtls/build_info.h"
+#if defined(MBEDTLS_PKCS7_C)
+#include "mbedtls/pkcs7.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/asn1.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_crl.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/error.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if defined(MBEDTLS_FS_IO)
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#include "mbedtls/platform.h"
+#include "mbedtls/platform_util.h"
+
+#if defined(MBEDTLS_HAVE_TIME)
+#include "mbedtls/platform_time.h"
+#endif
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+#include <time.h>
+#endif
+
+/**
+ * Initializes the pkcs7 structure.
+ */
+void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 )
+{
+    memset( pkcs7, 0, sizeof( *pkcs7 ) );
+}
+
+static int pkcs7_get_next_content_len( unsigned char **p, unsigned char *end,
+                                       size_t *len )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_CONTEXT_SPECIFIC );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret );
+    }
+
+    return( ret );
+}
+
+/**
+ * version Version
+ * Version ::= INTEGER
+ **/
+static int pkcs7_get_version( unsigned char **p, unsigned char *end, int *ver )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ret = mbedtls_asn1_get_int( p, end, ver );
+    if( ret != 0 )
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_VERSION, ret );
+
+    /* If version != 1, return invalid version */
+    if( *ver != MBEDTLS_PKCS7_SUPPORTED_VERSION )
+        ret = MBEDTLS_ERR_PKCS7_INVALID_VERSION;
+
+    return( ret );
+}
+
+/**
+ * ContentInfo ::= SEQUENCE {
+ *      contentType ContentType,
+ *      content
+ *              [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ **/
+static int pkcs7_get_content_info_type( unsigned char **p, unsigned char *end,
+                                        mbedtls_pkcs7_buf *pkcs7 )
+{
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char *start = *p;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 ) {
+        *p = start;
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret );
+        goto out;
+    }
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID );
+    if( ret != 0 ) {
+        *p = start;
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret );
+        goto out;
+    }
+
+    pkcs7->tag = MBEDTLS_ASN1_OID;
+    pkcs7->len = len;
+    pkcs7->p = *p;
+    *p += len;
+
+out:
+    return( ret );
+}
+
+/**
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * This is from x509.h
+ **/
+static int pkcs7_get_digest_algorithm( unsigned char **p, unsigned char *end,
+                                       mbedtls_x509_buf *alg )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 )
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret );
+
+    return( ret );
+}
+
+/**
+ * DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier
+ **/
+static int pkcs7_get_digest_algorithm_set( unsigned char **p,
+                                           unsigned char *end,
+                                           mbedtls_x509_buf *alg )
+{
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                            | MBEDTLS_ASN1_SET );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret );
+        goto out;
+    }
+
+    end = *p + len;
+
+    ret = mbedtls_asn1_get_alg_null( p, end, alg );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret );
+        goto out;
+    }
+
+    /** For now, it assumes there is only one digest algorithm specified **/
+    if ( *p != end )
+        ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
+
+out:
+    return( ret );
+}
+
+/**
+ * certificates :: SET OF ExtendedCertificateOrCertificate,
+ * ExtendedCertificateOrCertificate ::= CHOICE {
+ *      certificate Certificate -- x509,
+ *      extendedCertificate[0] IMPLICIT ExtendedCertificate }
+ * Return number of certificates added to the signed data,
+ * 0 or higher is valid.
+ * Return negative error code for failure.
+ **/
+static int pkcs7_get_certificates( unsigned char **p, unsigned char *end,
+                                   mbedtls_x509_crt *certs )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len1 = 0;
+    size_t len2 = 0;
+    unsigned char *end_set, *end_cert, *start;
+
+    if( ( ret = mbedtls_asn1_get_tag( p, end, &len1, MBEDTLS_ASN1_CONSTRUCTED
+                    | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
+    {
+        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
+            ret = 0;
+        else
+            ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret );
+        goto out;
+    }
+    start = *p;
+    end_set = *p + len1;
+
+    ret = mbedtls_asn1_get_tag( p, end_set, &len2, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CERT, ret );
+        goto out;
+    }
+
+    end_cert = *p + len2;
+
+    /*
+     * This is to verify that there is only one signer certificate. It seems it is
+     * not easy to differentiate between the chain vs different signer's certificate.
+     * So, we support only the root certificate and the single signer.
+     * The behaviour would be improved with addition of multiple signer support.
+     */
+    if ( end_cert != end_set )
+    {
+        ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
+        goto out;
+    }
+
+    *p = start;
+    if( ( ret = mbedtls_x509_crt_parse_der( certs, *p, len1 ) ) < 0 )
+    {
+        ret = MBEDTLS_ERR_PKCS7_INVALID_CERT;
+        goto out;
+    }
+
+    *p = *p + len1;
+
+    /*
+     * Since in this version we strictly support single certificate, and reaching
+     * here implies we have parsed successfully, we return 1.
+     */
+    ret = 1;
+
+out:
+    return( ret );
+}
+
+/**
+ * EncryptedDigest ::= OCTET STRING
+ **/
+static int pkcs7_get_signature( unsigned char **p, unsigned char *end,
+                                mbedtls_pkcs7_buf *signature )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len = 0;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OCTET_STRING );
+    if( ret != 0 )
+        goto out;
+
+    signature->tag = MBEDTLS_ASN1_OCTET_STRING;
+    signature->len = len;
+    signature->p = *p;
+
+    *p = *p + len;
+
+out:
+    return( ret );
+}
+
+/**
+ * SignerInfo ::= SEQUENCE {
+ *      version Version;
+ *      issuerAndSerialNumber   IssuerAndSerialNumber,
+ *      digestAlgorithm DigestAlgorithmIdentifier,
+ *      authenticatedAttributes
+ *              [0] IMPLICIT Attributes OPTIONAL,
+ *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ *      encryptedDigest EncryptedDigest,
+ *      unauthenticatedAttributes
+ *              [1] IMPLICIT Attributes OPTIONAL,
+ * Returns 0 if the signerInfo is valid.
+ * Return negative error code for failure.
+ * Structure must not contain vales for authenticatedAttributes
+ * and unauthenticatedAttributes.
+ **/
+static int pkcs7_get_signer_info( unsigned char **p, unsigned char *end,
+                                  mbedtls_pkcs7_signer_info *signer )
+{
+    unsigned char *end_signer;
+    int asn1_ret = 0, ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len = 0;
+
+    asn1_ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                | MBEDTLS_ASN1_SEQUENCE );
+    if( asn1_ret != 0 )
+        goto out;
+
+    end_signer = *p + len;
+
+    ret = pkcs7_get_version( p, end_signer, &signer->version );
+    if( ret != 0 )
+        goto out;
+
+    asn1_ret = mbedtls_asn1_get_tag( p, end_signer, &len,
+                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
+    if( asn1_ret != 0 )
+        goto out;
+
+    /* Parsing IssuerAndSerialNumber */
+    signer->issuer_raw.p = *p;
+
+    asn1_ret = mbedtls_asn1_get_tag( p, end_signer, &len,
+                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
+    if( asn1_ret != 0 )
+        goto out;
+
+    ret  = mbedtls_x509_get_name( p, *p + len, &signer->issuer );
+    if( ret != 0 )
+        goto out;
+
+    signer->issuer_raw.len =  *p - signer->issuer_raw.p;
+
+    ret = mbedtls_x509_get_serial( p, end_signer, &signer->serial );
+    if( ret != 0 )
+        goto out;
+
+    ret = pkcs7_get_digest_algorithm( p, end_signer, &signer->alg_identifier );
+    if( ret != 0 )
+        goto out;
+
+    /* Asssume authenticatedAttributes is nonexistent */
+
+    ret = pkcs7_get_digest_algorithm( p, end_signer, &signer->sig_alg_identifier );
+    if( ret != 0 )
+        goto out;
+
+    ret = pkcs7_get_signature( p, end_signer, &signer->sig );
+    if( ret != 0 )
+        goto out;
+
+    /* Do not permit any unauthenticated attributes */
+    if( *p != end_signer )
+        ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
+
+out:
+    if( asn1_ret != 0 )
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO,
+                                    asn1_ret );
+    else if( ret != 0 )
+        ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
+
+    return( ret );
+}
+
+static void pkcs7_free_signer_info( mbedtls_pkcs7_signer_info *signer )
+{
+    mbedtls_x509_name *name_cur;
+    mbedtls_x509_name *name_prv;
+
+    if( signer == NULL )
+        return;
+
+    name_cur = signer->issuer.next;
+    while( name_cur != NULL )
+    {
+        name_prv = name_cur;
+        name_cur = name_cur->next;
+        mbedtls_free( name_prv );
+    }
+}
+
+/**
+ * SignerInfos ::= SET of SignerInfo
+ * Return number of signers added to the signed data,
+ * 0 or higher is valid.
+ * Return negative error code for failure.
+ **/
+static int pkcs7_get_signers_info_set( unsigned char **p, unsigned char *end,
+                                       mbedtls_pkcs7_signer_info *signers_set )
+{
+    unsigned char *end_set;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    int count = 0;
+    size_t len = 0;
+    mbedtls_pkcs7_signer_info *signer, *prev;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                | MBEDTLS_ASN1_SET );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO, ret );
+        goto out;
+    }
+
+    /* Detect zero signers */
+    if( len == 0 )
+    {
+        ret = 0;
+        goto out;
+    }
+
+    end_set = *p + len;
+
+    ret = pkcs7_get_signer_info( p, end_set, signers_set );
+    if( ret != 0 )
+        goto out;
+    count++;
+
+    prev = signers_set;
+    while( *p != end_set )
+    {
+        signer = mbedtls_calloc( 1, sizeof( mbedtls_pkcs7_signer_info ) );
+        if( !signer )
+        {
+            ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
+            goto cleanup;
+        }
+
+        ret = pkcs7_get_signer_info( p, end_set, signer );
+        if( ret != 0 ) {
+            mbedtls_free( signer );
+            goto cleanup;
+        }
+        prev->next = signer;
+        prev = signer;
+        count++;
+    }
+
+    ret = count;
+    goto out;
+
+cleanup:
+    signer = signers_set->next;
+    pkcs7_free_signer_info( signers_set );
+    while( signer )
+    {
+        prev = signer;
+        signer = signer->next;
+        pkcs7_free_signer_info( prev );
+        mbedtls_free( prev );
+    }
+
+out:
+    return( ret );
+}
+
+/**
+ * SignedData ::= SEQUENCE {
+ *      version Version,
+ *      digestAlgorithms DigestAlgorithmIdentifiers,
+ *      contentInfo ContentInfo,
+ *      certificates
+ *              [0] IMPLICIT ExtendedCertificatesAndCertificates
+ *                  OPTIONAL,
+ *      crls
+ *              [0] IMPLICIT CertificateRevocationLists OPTIONAL,
+ *      signerInfos SignerInfos }
+ */
+static int pkcs7_get_signed_data( unsigned char *buf, size_t buflen,
+                                  mbedtls_pkcs7_signed_data *signed_data )
+{
+    unsigned char *p = buf;
+    unsigned char *end = buf + buflen;
+    unsigned char *end_set;
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    mbedtls_md_type_t md_alg;
+
+    ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret );
+        goto out;
+    }
+
+    end_set = p + len;
+
+    /* Get version of signed data */
+    ret = pkcs7_get_version( &p, end_set, &signed_data->version );
+    if( ret != 0 )
+        goto out;
+
+    /* Get digest algorithm */
+    ret = pkcs7_get_digest_algorithm_set( &p, end_set,
+            &signed_data->digest_alg_identifiers );
+    if( ret != 0 )
+        goto out;
+
+    ret = mbedtls_oid_get_md_alg( &signed_data->digest_alg_identifiers, &md_alg );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERR_PKCS7_INVALID_ALG;
+        goto out;
+    }
+
+    /* Do not expect any content */
+    ret = pkcs7_get_content_info_type( &p, end_set, &signed_data->content.oid );
+    if( ret != 0 )
+        goto out;
+
+    if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &signed_data->content.oid ) )
+    {
+        ret = MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO;
+        goto out;
+    }
+
+    /* Look for certificates, there may or may not be any */
+    mbedtls_x509_crt_init( &signed_data->certs );
+    ret = pkcs7_get_certificates( &p, end_set, &signed_data->certs );
+    if( ret < 0 )
+        goto out;
+
+    signed_data->no_of_certs = ret;
+
+    /*
+     * Currently CRLs are not supported. If CRL exist, the parsing will fail
+     * at next step of getting signers info and return error as invalid
+     * signer info.
+     */
+
+    signed_data->no_of_crls = 0;
+
+    /* Get signers info */
+    ret = pkcs7_get_signers_info_set( &p, end_set, &signed_data->signers );
+    if( ret < 0 )
+        goto out;
+
+    signed_data->no_of_signers = ret;
+
+    /* Don't permit trailing data */
+    if ( p != end )
+        ret = MBEDTLS_ERR_PKCS7_INVALID_FORMAT;
+    else
+        ret = 0;
+
+out:
+    return( ret );
+}
+
+int mbedtls_pkcs7_parse_der( mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
+                             const size_t buflen )
+{
+    unsigned char *p;
+    unsigned char *end;
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    int isoidset = 0;
+
+    if( !pkcs7 )
+    {
+        ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
+        goto out;
+    }
+
+    /* make an internal copy of the buffer for parsing */
+    pkcs7->raw.p = p = mbedtls_calloc( 1, buflen );
+    if( pkcs7->raw.p == NULL )
+    {
+        ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
+        goto out;
+    }
+    memcpy( p, buf, buflen );
+    pkcs7->raw.len = buflen;
+    end = p + buflen;
+
+    ret = pkcs7_get_content_info_type( &p, end, &pkcs7->content_type_oid );
+    if( ret != 0 )
+    {
+        len = buflen;
+        goto try_data;
+    }
+
+    if( ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENVELOPED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DIGESTED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid ) )
+    {
+        ret =  MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
+        goto out;
+    }
+
+    if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_DATA, &pkcs7->content_type_oid ) )
+    {
+        ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
+        goto out;
+    }
+
+    isoidset = 1;
+
+    ret = pkcs7_get_next_content_len( &p, end, &len );
+    if( ret != 0 )
+        goto out;
+
+try_data:
+    ret = pkcs7_get_signed_data( p, len, &pkcs7->signed_data );
+    if ( ret != 0 )
+        goto out;
+
+    if ( !isoidset )
+    {
+        pkcs7->content_type_oid.tag = MBEDTLS_ASN1_OID;
+        pkcs7->content_type_oid.len = MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS7_SIGNED_DATA );
+        pkcs7->content_type_oid.p = (unsigned char *)MBEDTLS_OID_PKCS7_SIGNED_DATA;
+    }
+
+    ret = MBEDTLS_PKCS7_SIGNED_DATA;
+
+out:
+    if ( ret < 0 )
+        mbedtls_pkcs7_free( pkcs7 );
+
+    return( ret );
+}
+
+static int 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 )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char *hash;
+    mbedtls_pk_context pk_cxt = cert->pk;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+    mbedtls_pkcs7_signer_info *signer;
+
+    if( pkcs7->signed_data.no_of_signers == 0 )
+    {
+        ret = MBEDTLS_ERR_PKCS7_INVALID_CERT;
+        goto out;
+    }
+
+    if( mbedtls_x509_time_is_past( &cert->valid_to ) ||
+        mbedtls_x509_time_is_future( &cert->valid_from ))
+    {
+        ret = MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID;
+        goto out;
+    }
+
+    /*
+     * Potential TODOs
+     * Currently we iterate over all signers and return success if any of them
+     * verify.
+     *
+     * However, we could make this better by checking against the certificate's
+     * identification and SignerIdentifier fields first. That would also allow
+     * us to distinguish between 'no signature for key' and 'signature for key
+     * failed to validate'.
+     *
+     * We could also cache hashes by md, so if there are several sigs all using
+     * the same algo we don't recalculate the hash each time.
+     */
+    for( signer = &pkcs7->signed_data.signers; signer; signer = signer->next )
+    {
+        ret = mbedtls_oid_get_md_alg( &signer->alg_identifier, &md_alg );
+        if( ret != 0 )
+        {
+            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            continue;
+        }
+
+        md_info = mbedtls_md_info_from_type( md_alg );
+        if( md_info == NULL )
+        {
+            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            continue;
+        }
+
+        hash = mbedtls_calloc( mbedtls_md_get_size( md_info ), 1 );
+        if( hash == NULL ) {
+            ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
+            goto out;
+        }
+        if( is_data_hash )
+        {
+            if( datalen != mbedtls_md_get_size( md_info ))
+                ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            else
+                memcpy(hash, data, datalen);
+        }
+        else
+        {
+            ret = mbedtls_md( md_info, data, datalen, hash );
+        }
+        if( ret != 0 )
+        {
+            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            mbedtls_free( hash );
+            continue;
+        }
+
+        ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash,
+                                 mbedtls_md_get_size( md_info ),
+                                 signer->sig.p, signer->sig.len );
+        mbedtls_free( hash );
+
+        if( ret == 0 )
+            break;
+    }
+
+out:
+    return( ret );
+}
+int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *data,
+                                      size_t datalen )
+{
+    return( mbedtls_pkcs7_data_or_hash_verify( pkcs7, cert, data, datalen, 0 ) );
+}
+
+int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *hash,
+                                      size_t hashlen )
+{
+    return( mbedtls_pkcs7_data_or_hash_verify( pkcs7, cert, hash, hashlen, 1 ) );
+}
+
+/*
+ * Unallocate all pkcs7 data
+ */
+void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 )
+{
+    mbedtls_pkcs7_signer_info *signer_cur;
+    mbedtls_pkcs7_signer_info *signer_prev;
+
+    if( pkcs7 == NULL || pkcs7->raw.p == NULL )
+        return;
+
+    mbedtls_free( pkcs7->raw.p );
+
+    mbedtls_x509_crt_free( &pkcs7->signed_data.certs );
+    mbedtls_x509_crl_free( &pkcs7->signed_data.crl );
+
+    signer_cur = pkcs7->signed_data.signers.next;
+    pkcs7_free_signer_info( &pkcs7->signed_data.signers );
+    while( signer_cur != NULL )
+    {
+        signer_prev = signer_cur;
+        signer_cur = signer_prev->next;
+        pkcs7_free_signer_info( signer_prev );
+        mbedtls_free( signer_prev );
+    }
+
+    pkcs7->raw.p = NULL;
+}
+
+#endif
diff --git a/programs/fuzz/.gitignore b/programs/fuzz/.gitignore
index 5dc0960..34e3ed0 100644
--- a/programs/fuzz/.gitignore
+++ b/programs/fuzz/.gitignore
@@ -1,6 +1,7 @@
 fuzz_client
 fuzz_dtlsclient
 fuzz_dtlsserver
+fuzz_pkcs7
 fuzz_privkey
 fuzz_pubkey
 fuzz_server
diff --git a/programs/fuzz/CMakeLists.txt b/programs/fuzz/CMakeLists.txt
index c7fcd35..7747744 100644
--- a/programs/fuzz/CMakeLists.txt
+++ b/programs/fuzz/CMakeLists.txt
@@ -12,6 +12,7 @@
     fuzz_x509crl
     fuzz_x509crt
     fuzz_x509csr
+    fuzz_pkcs7
 )
 
 set(executables_with_common_c
diff --git a/programs/fuzz/fuzz_pkcs7.c b/programs/fuzz/fuzz_pkcs7.c
new file mode 100644
index 0000000..960007d
--- /dev/null
+++ b/programs/fuzz/fuzz_pkcs7.c
@@ -0,0 +1,19 @@
+#include <stdint.h>
+#include "mbedtls/pkcs7.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+#ifdef MBEDTLS_PKCS7_C
+    mbedtls_pkcs7 pkcs7;
+
+    mbedtls_pkcs7_init( &pkcs7 );
+
+    mbedtls_pkcs7_parse_der( &pkcs7, Data, Size );
+
+    mbedtls_pkcs7_free( &pkcs7 );
+#else
+    (void) Data;
+    (void) Size;
+#endif
+
+    return 0;
+}
diff --git a/programs/fuzz/fuzz_pkcs7.options b/programs/fuzz/fuzz_pkcs7.options
new file mode 100644
index 0000000..0824b19
--- /dev/null
+++ b/programs/fuzz/fuzz_pkcs7.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/scripts/config.py b/scripts/config.py
index 470c63d..7e58acd 100755
--- a/scripts/config.py
+++ b/scripts/config.py
@@ -311,6 +311,7 @@
     if name in [
             'MBEDTLS_DEBUG_C', # part of libmbedtls
             'MBEDTLS_NET_C', # part of libmbedtls
+            'MBEDTLS_PKCS7_C', # part of libmbedx509
     ]:
         return False
     return True
diff --git a/scripts/generate_errors.pl b/scripts/generate_errors.pl
index 41b0337..5395abf 100755
--- a/scripts/generate_errors.pl
+++ b/scripts/generate_errors.pl
@@ -52,7 +52,7 @@
                             SHA1 SHA256 SHA512 THREADING );
 my @high_level_modules = qw( CIPHER DHM ECP MD
                              PEM PK PKCS12 PKCS5
-                             RSA SSL X509 );
+                             RSA SSL X509 PKCS7 );
 
 undef $/;
 
@@ -136,6 +136,7 @@
     $define_name = "ASN1_PARSE" if ($define_name eq "ASN1");
     $define_name = "SSL_TLS" if ($define_name eq "SSL");
     $define_name = "PEM_PARSE,PEM_WRITE" if ($define_name eq "PEM");
+    $define_name = "PKCS7" if ($define_name eq "PKCS7");
 
     my $include_name = $module_name;
     $include_name =~ tr/A-Z/a-z/;
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index 09a0689..c5924ec 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -1134,6 +1134,108 @@
 all_final += ecdsa_secp521r1.crt ecdsa_secp521r1.key
 tls13_certs: ecdsa_secp521r1.crt ecdsa_secp521r1.key
 
+# PKCS7 test data
+pkcs7_test_cert_1 = pkcs7-rsa-sha256-1.crt
+pkcs7_test_cert_2 = pkcs7-rsa-sha256-2.crt
+pkcs7_test_file = pkcs7_data.bin
+
+$(pkcs7_test_file):
+	echo -e "Hello\xd" > $@
+all_final += $(pkcs7_test_file)
+
+pkcs7_data_1.bin:
+	echo -e "2\xd" > $@
+all_final += pkcs7_data_1.bin
+
+# Generate signing cert
+pkcs7-rsa-sha256-1.crt:
+	$(OPENSSL) req -x509 -subj="/C=NL/O=PKCS7/CN=PKCS7 Cert 1" -sha256 -nodes -days 365  -newkey rsa:2048 -keyout pkcs7-rsa-sha256-1.key -out pkcs7-rsa-sha256-1.crt
+	cat pkcs7-rsa-sha256-1.crt pkcs7-rsa-sha256-1.key > pkcs7-rsa-sha256-1.pem
+all_final += pkcs7-rsa-sha256-1.crt
+
+pkcs7-rsa-sha256-2.crt:
+	$(OPENSSL) req -x509 -subj="/C=NL/O=PKCS7/CN=PKCS7 Cert 2" -sha256 -nodes -days 365  -newkey rsa:2048 -keyout pkcs7-rsa-sha256-2.key -out pkcs7-rsa-sha256-2.crt
+	cat pkcs7-rsa-sha256-2.crt pkcs7-rsa-sha256-2.key > pkcs7-rsa-sha256-2.pem
+all_final += pkcs7-rsa-sha256-2.crt
+
+# Convert signing certs to DER for testing PEM-free builds
+pkcs7-rsa-sha256-1.der: $(pkcs7_test_cert_1)
+	$(OPENSSL) x509 -in pkcs7-rsa-sha256-1.crt -out $@ -outform DER
+all_final += pkcs7-rsa-sha256-1.der
+
+pkcs7-rsa-sha256-2.der: $(pkcs7_test_cert_2)
+	$(OPENSSL) x509 -in pkcs7-rsa-sha256-2.crt -out $@ -outform DER
+all_final += pkcs7-rsa-sha256-2.der
+
+# pkcs7 signature file with CERT
+pkcs7_data_cert_signed_sha256.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_cert_signed_sha256.der
+
+# pkcs7 signature file with CERT and sha1
+pkcs7_data_cert_signed_sha1.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha1 -signer pkcs7-rsa-sha256-1.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_cert_signed_sha1.der
+
+# pkcs7 signature file with CERT and sha512
+pkcs7_data_cert_signed_sha512.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha512 -signer pkcs7-rsa-sha256-1.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_cert_signed_sha512.der
+
+# pkcs7 signature file without CERT
+pkcs7_data_without_cert_signed.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -nocerts -noattr -outform DER -out $@
+all_final += pkcs7_data_without_cert_signed.der
+
+# pkcs7 signature file with multiple signers
+pkcs7_data_multiple_signed.der: $(pkcs7_test_file) $(pkcs7_test_cert_1) $(pkcs7_test_cert_2)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -signer pkcs7-rsa-sha256-2.pem -nocerts -noattr -outform DER -out $@
+all_final += pkcs7_data_multiple_signed.der
+
+# pkcs7 signature file with multiple certificates
+pkcs7_data_multiple_certs_signed.der: $(pkcs7_test_file) $(pkcs7_test_cert_1) $(pkcs7_test_cert_2)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -signer pkcs7-rsa-sha256-2.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_multiple_certs_signed.der
+
+# pkcs7 signature file with corrupted CERT
+pkcs7_data_signed_badcert.der: pkcs7_data_cert_signed_sha256.der
+	cp pkcs7_data_cert_signed_sha256.der $@
+	echo -en '\xa1' | dd of=$@ bs=1 seek=547 conv=notrunc
+all_final += pkcs7_data_signed_badcert.der
+
+# pkcs7 signature file with corrupted signer info
+pkcs7_data_signed_badsigner.der: pkcs7_data_cert_signed_sha256.der
+	cp pkcs7_data_cert_signed_sha256.der $@
+	echo -en '\xa1' | dd of=$@ bs=1 seek=918 conv=notrunc
+all_final += pkcs7_data_signed_badsigner.der
+
+# pkcs7 file with version 2
+pkcs7_data_cert_signed_v2.der: pkcs7_data_cert_signed_sha256.der
+	cp pkcs7_data_cert_signed_sha256.der $@
+	echo -en '\x02' | dd of=$@ bs=1 seek=25 conv=notrunc
+all_final += pkcs7_data_cert_signed_v2.der
+
+pkcs7_data_cert_encrypted.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -encrypt -aes256 -in pkcs7_data.bin -binary -outform DER -out $@ pkcs7-rsa-sha256-1.crt
+all_final += pkcs7_data_cert_encrypted.der
+
+## Negative tests
+# For some interesting sizes, what happens if we make them off-by-one?
+pkcs7_signerInfo_issuer_invalid_size.der: pkcs7_data_cert_signed_sha256.der
+	cp $< $@
+	echo -en '\x35' | dd of=$@ seek=919 bs=1 conv=notrunc
+all_final += pkcs7_signerInfo_issuer_invalid_size.der
+
+pkcs7_signerInfo_serial_invalid_size.der: pkcs7_data_cert_signed_sha256.der
+	cp $< $@
+	echo -en '\x15' | dd of=$@ seek=973 bs=1 conv=notrunc
+all_final += pkcs7_signerInfo_serial_invalid_size.der
+
+# pkcs7 signature file just with signed data
+pkcs7_data_cert_signeddata_sha256.der: pkcs7_data_cert_signed_sha256.der
+	dd if=pkcs7_data_cert_signed_sha256.der of=$@ skip=19 bs=1
+all_final += pkcs7_data_cert_signeddata_sha256.der
+
 ################################################################
 #### Diffie-Hellman parameters
 ################################################################
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.crt b/tests/data_files/pkcs7-rsa-sha256-1.crt
new file mode 100644
index 0000000..9e461cd
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUe97d0kRM0c3+XEGoECyJt98ubL8wDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDEwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMi2z2mJnNHw67TKZFwF5w4N
+Lv7dzGHQicvVFaOaNXm5I0O2HsdQBg+07TeHYzJADkJfHTdsfnXClzMU7fS7MMj4
+3QO5/P+VWiRdSRN61uYAVsrBlVKoZdUhhxh8wELJxJ4+OpwXpTS0U82rwMsRO09j
+9bMXS57pkCsZENEUlqJ5p0Mmrc/uEL/Z5+uvuzd76bY5WRZdE91XURccra08HTra
+xovIAR1htUz2AXi+NoOaiayRq0GePKN9a6iB0lUYxNtovKb3yDYC9pmoaxf7Hnc7
+y+dLuTpJslGuhkKLV0Dhhoux1vq54ocS6Y7DGa2Pyk1zAQxLCcS4BFiWHnzwg1MC
+AwEAAaNTMFEwHQYDVR0OBBYEFIru5ZR8xnxd1RWnbip+zTHuUv3IMB8GA1UdIwQY
+MBaAFIru5ZR8xnxd1RWnbip+zTHuUv3IMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAIIda5jNRX3r0rCBrKJ+vs1Pk6zIKEQ7Oeq/+p+k6eRUO0b8
+wx4rW0gXeQPeppaaxKLMZXBlA5DxsI1DpML5dcfti/M1bHIYOAISRRqPEd5GVTy8
+1ltCVN249mg06yHdoqjzO1geFIRVesoblO6JMd3xYDe3pxcTIakZNq/Cf/zjld51
+1fcMuLWu4F/1BwiNZa8eQ5Zs1Cy+b3+s+NrgVd2CIrFpZSFyP4EkUXhZXJha6Rf9
+SzmYdz4al7e9EAhURvQlm8wJpFSSkoLBuJtx7Vh6d14KPUU2NB9F2ulp6AbJb+/H
+EGd3bAK6IhIrkZmxTAwowESHUJBwuX890tbZcnM=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.der b/tests/data_files/pkcs7-rsa-sha256-1.der
new file mode 100644
index 0000000..0d799ea
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.der
Binary files differ
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.key b/tests/data_files/pkcs7-rsa-sha256-1.key
new file mode 100644
index 0000000..e31159d
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDIts9piZzR8Ou0
+ymRcBecODS7+3cxh0InL1RWjmjV5uSNDth7HUAYPtO03h2MyQA5CXx03bH51wpcz
+FO30uzDI+N0Dufz/lVokXUkTetbmAFbKwZVSqGXVIYcYfMBCycSePjqcF6U0tFPN
+q8DLETtPY/WzF0ue6ZArGRDRFJaieadDJq3P7hC/2efrr7s3e+m2OVkWXRPdV1EX
+HK2tPB062saLyAEdYbVM9gF4vjaDmomskatBnjyjfWuogdJVGMTbaLym98g2AvaZ
+qGsX+x53O8vnS7k6SbJRroZCi1dA4YaLsdb6ueKHEumOwxmtj8pNcwEMSwnEuARY
+lh588INTAgMBAAECggEBAIg+P1B+TurbRMQ11iX5A7wwCsSKPh/vdHneLJAfL0lu
++JcP2piko1iqEZPt3NHRVVyMP8LNbJH3Ardz74p+PkFNXIkZCLlc4hFpGR+V9KWv
+eTqsaPXwxR8FYTSoCcHMQCDCUPp/um6qMXCcs4OkMMRVMATfPT+jf28h1p52AUJL
+aAoBJfn7gP3WiB0FWq0bRZgSZzNYowE/MhGAQ+DuBGTSASSK3YJcxE94044fBVE8
+EqYKrxoY/x56li5cZ0v9kaURCrvhqCeq2+U5kIkgtvp2l6wF0Mm1du3BLxo2LQEI
+Y2j+6BFEV74Mtv48GTwrZcyit787zyo9vVGcviSD5VECgYEA/mgLc5KfF/cQLmM/
+20T4k0edvktkRIJHFUBphowt5Hb0a0wM5C1VM4z3yN3b9ikQK+ZaQXETdPATBXIe
+LntX1D1xtbMxdcAfd1FSq8QxAuaPknJZBgtzlpCsx3ZvMnNuzKZN/TU8kR1biwPE
+9HaeEG3bouUu+CI/l/DqrBbQRacCgYEAyfiqsLWGhXQ7e3pLk47PDYlMOsjDWPjs
+SGcatH1/lIMWyZue4W2IUcFMbpbjA6QWibo3VnOavIRSTn97JNUWYvgc5MmaQ7iX
+Iss4m3vJ1LIqx30iUgw3EfDoWdpufEEYssZ/VxJPs3sdmZGALgd3CaqxHJuhuS+U
+eVhWzD6LonUCgYBRCbt8GRxsedrBrAPPSO0VnR52W3WZDRavglEa9tQ3jlzVQOhq
+VrZpMWJMrb8/bl0kXsApUGeuPDsS5QMQM2IKzXfHNUlwBL8BNvpqlJg4IFFjiOEq
+t8MeFv+ymdtZ6sNElUUKf0bHwt5CLfUzGgXHnfb0sKSBjgdL0wYtwyacyQKBgQDJ
+NcyG4zEy/srLhtiIFnu8Fo40+hFzL/nlX6JBMc3KHJa1Hy43krF+ET6d5gAffndd
+moDKxbzgFksRHPuHhCobSucuHpJq6RjYdvDcJYS7OwxXVRi9+KFcZE52RaBQdWGv
+qQTvr7RrMDoa5dN3B8TVgpGT2JBTN02JXjKKo7zkiQKBgCZwKDiXl7qsGidvlFZc
+4CEtFsCgnNgdRTzsTL/Pr8q9CBK3BhjZjNzQALF1iGFDC1FdFYFOwI1E3j+MRHJB
+rQMF8zbmmlZ6SC5QtqatCSCCKUyrUjD5J+4UfJqWFjiBBdwz+5VJojHw1yijEwl4
+LrS/V2yBrDJVczQQM4psonLF
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.pem b/tests/data_files/pkcs7-rsa-sha256-1.pem
new file mode 100644
index 0000000..3795b71
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.pem
@@ -0,0 +1,48 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUe97d0kRM0c3+XEGoECyJt98ubL8wDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDEwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMi2z2mJnNHw67TKZFwF5w4N
+Lv7dzGHQicvVFaOaNXm5I0O2HsdQBg+07TeHYzJADkJfHTdsfnXClzMU7fS7MMj4
+3QO5/P+VWiRdSRN61uYAVsrBlVKoZdUhhxh8wELJxJ4+OpwXpTS0U82rwMsRO09j
+9bMXS57pkCsZENEUlqJ5p0Mmrc/uEL/Z5+uvuzd76bY5WRZdE91XURccra08HTra
+xovIAR1htUz2AXi+NoOaiayRq0GePKN9a6iB0lUYxNtovKb3yDYC9pmoaxf7Hnc7
+y+dLuTpJslGuhkKLV0Dhhoux1vq54ocS6Y7DGa2Pyk1zAQxLCcS4BFiWHnzwg1MC
+AwEAAaNTMFEwHQYDVR0OBBYEFIru5ZR8xnxd1RWnbip+zTHuUv3IMB8GA1UdIwQY
+MBaAFIru5ZR8xnxd1RWnbip+zTHuUv3IMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAIIda5jNRX3r0rCBrKJ+vs1Pk6zIKEQ7Oeq/+p+k6eRUO0b8
+wx4rW0gXeQPeppaaxKLMZXBlA5DxsI1DpML5dcfti/M1bHIYOAISRRqPEd5GVTy8
+1ltCVN249mg06yHdoqjzO1geFIRVesoblO6JMd3xYDe3pxcTIakZNq/Cf/zjld51
+1fcMuLWu4F/1BwiNZa8eQ5Zs1Cy+b3+s+NrgVd2CIrFpZSFyP4EkUXhZXJha6Rf9
+SzmYdz4al7e9EAhURvQlm8wJpFSSkoLBuJtx7Vh6d14KPUU2NB9F2ulp6AbJb+/H
+EGd3bAK6IhIrkZmxTAwowESHUJBwuX890tbZcnM=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDIts9piZzR8Ou0
+ymRcBecODS7+3cxh0InL1RWjmjV5uSNDth7HUAYPtO03h2MyQA5CXx03bH51wpcz
+FO30uzDI+N0Dufz/lVokXUkTetbmAFbKwZVSqGXVIYcYfMBCycSePjqcF6U0tFPN
+q8DLETtPY/WzF0ue6ZArGRDRFJaieadDJq3P7hC/2efrr7s3e+m2OVkWXRPdV1EX
+HK2tPB062saLyAEdYbVM9gF4vjaDmomskatBnjyjfWuogdJVGMTbaLym98g2AvaZ
+qGsX+x53O8vnS7k6SbJRroZCi1dA4YaLsdb6ueKHEumOwxmtj8pNcwEMSwnEuARY
+lh588INTAgMBAAECggEBAIg+P1B+TurbRMQ11iX5A7wwCsSKPh/vdHneLJAfL0lu
++JcP2piko1iqEZPt3NHRVVyMP8LNbJH3Ardz74p+PkFNXIkZCLlc4hFpGR+V9KWv
+eTqsaPXwxR8FYTSoCcHMQCDCUPp/um6qMXCcs4OkMMRVMATfPT+jf28h1p52AUJL
+aAoBJfn7gP3WiB0FWq0bRZgSZzNYowE/MhGAQ+DuBGTSASSK3YJcxE94044fBVE8
+EqYKrxoY/x56li5cZ0v9kaURCrvhqCeq2+U5kIkgtvp2l6wF0Mm1du3BLxo2LQEI
+Y2j+6BFEV74Mtv48GTwrZcyit787zyo9vVGcviSD5VECgYEA/mgLc5KfF/cQLmM/
+20T4k0edvktkRIJHFUBphowt5Hb0a0wM5C1VM4z3yN3b9ikQK+ZaQXETdPATBXIe
+LntX1D1xtbMxdcAfd1FSq8QxAuaPknJZBgtzlpCsx3ZvMnNuzKZN/TU8kR1biwPE
+9HaeEG3bouUu+CI/l/DqrBbQRacCgYEAyfiqsLWGhXQ7e3pLk47PDYlMOsjDWPjs
+SGcatH1/lIMWyZue4W2IUcFMbpbjA6QWibo3VnOavIRSTn97JNUWYvgc5MmaQ7iX
+Iss4m3vJ1LIqx30iUgw3EfDoWdpufEEYssZ/VxJPs3sdmZGALgd3CaqxHJuhuS+U
+eVhWzD6LonUCgYBRCbt8GRxsedrBrAPPSO0VnR52W3WZDRavglEa9tQ3jlzVQOhq
+VrZpMWJMrb8/bl0kXsApUGeuPDsS5QMQM2IKzXfHNUlwBL8BNvpqlJg4IFFjiOEq
+t8MeFv+ymdtZ6sNElUUKf0bHwt5CLfUzGgXHnfb0sKSBjgdL0wYtwyacyQKBgQDJ
+NcyG4zEy/srLhtiIFnu8Fo40+hFzL/nlX6JBMc3KHJa1Hy43krF+ET6d5gAffndd
+moDKxbzgFksRHPuHhCobSucuHpJq6RjYdvDcJYS7OwxXVRi9+KFcZE52RaBQdWGv
+qQTvr7RrMDoa5dN3B8TVgpGT2JBTN02JXjKKo7zkiQKBgCZwKDiXl7qsGidvlFZc
+4CEtFsCgnNgdRTzsTL/Pr8q9CBK3BhjZjNzQALF1iGFDC1FdFYFOwI1E3j+MRHJB
+rQMF8zbmmlZ6SC5QtqatCSCCKUyrUjD5J+4UfJqWFjiBBdwz+5VJojHw1yijEwl4
+LrS/V2yBrDJVczQQM4psonLF
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.crt b/tests/data_files/pkcs7-rsa-sha256-2.crt
new file mode 100644
index 0000000..a0df7d9
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUVk1VQCWvWZ4ycHmycg7wDfN8+3wwDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDIwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMjCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmVNZZ0/qcT+h/lVNO+gP65
+lERTTudQ15h8QTLjaKhx5SSTLnuUhD0jLbR+ng8PMqdJ8ePkZEh1+7mi9MHzID4Y
+c47jH8M+Jc/JdBr6cSjbFd23QHESUjKKmV1IjSHc6Llbxe962z4gEXYjJAMkfr6B
+g1iecK3AlnEI4F0BsQfC5dgA4Qce2okvcTuhYgvHtLZ+UN4ca50Kw0o4u5FYdl89
+KDCE4zNp8MaaxGC83xcM4A9XqjHyZ7a2wvACTlmLQ2q/E+RN/8THEel4Y+yv82Uj
+j2LqqEaA06dvSdOPdaGz9jUZauqBw7TcuGGVzrrsZ0g/sHXKng9TppehAV/HrJUC
+AwEAAaNTMFEwHQYDVR0OBBYEFI5FVrtfLwPXRERcyVX6qBVvfoduMB8GA1UdIwQY
+MBaAFI5FVrtfLwPXRERcyVX6qBVvfoduMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAKRl0wgREe6eAduJSV5fs+Ec0s2qs2lHQqt/0JGEIbZBBtka
+q1UH9CIMMAd6Kb0kh5GlJT2shg/EAYWoitMwntkeRYTln2k2/B5jux+U5Ph4HyC+
+ad2GqmsoXWDru79rltT7Pv1hS1ofJyQ4Jv88vQA/SuIIRGdTC24VAVgg00JxvDRB
+xeqsQ9Pld4ebg4VvqsInnSpmKCcxfWxFhJk/Ax8bK/tV/GnrPiwsvry1j9nZyebS
+IyI01/6DwJS2ZhFnsLGyPHFOAFNtomjIdQ6gf2L1wq0qiGOKj/K9IzFNCpCz82a+
+gMgqFzCT5TCZC16kUG2NA2pXAx9O4uppKjRk97U=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.der b/tests/data_files/pkcs7-rsa-sha256-2.der
new file mode 100644
index 0000000..fc7a3ea
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.der
Binary files differ
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.key b/tests/data_files/pkcs7-rsa-sha256-2.key
new file mode 100644
index 0000000..659c015
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJlTWWdP6nE/of
+5VTTvoD+uZREU07nUNeYfEEy42ioceUkky57lIQ9Iy20fp4PDzKnSfHj5GRIdfu5
+ovTB8yA+GHOO4x/DPiXPyXQa+nEo2xXdt0BxElIyipldSI0h3Oi5W8Xvets+IBF2
+IyQDJH6+gYNYnnCtwJZxCOBdAbEHwuXYAOEHHtqJL3E7oWILx7S2flDeHGudCsNK
+OLuRWHZfPSgwhOMzafDGmsRgvN8XDOAPV6ox8me2tsLwAk5Zi0NqvxPkTf/ExxHp
+eGPsr/NlI49i6qhGgNOnb0nTj3Whs/Y1GWrqgcO03Lhhlc667GdIP7B1yp4PU6aX
+oQFfx6yVAgMBAAECggEBAMVHm3w134qQCHfyroPTqtaftDTx+wRyn6yB3iT5XdGM
+NZ8H07Pp80kKBo7gY7uFOiNyQKKxQFuR69sPWc3+LI3YzC8IpGslhUfHdjN46gn7
+73hfAVgnf/4qmlEq0cRUOAY/hIUMjUhNhglB9tqEeu3iPjMaTFgfZJwW/czH/QMD
+w4zj5XoLgwRkqVvUceu/dBgV8KP5DpON+q8wpfWtjunv7rg5Nc3BVBrpb5SadJ7T
+i5TsS+pZQyp+mTvyCI3A1hkr2Vw5tULWO8SPhuEQkdtC/CL+luCUO7L16lU6KhFB
+qP5Fduik5skyLCVvAMUkjKcrC22k0gkhOHvfmMhjaAECgYEA68+hAQIiV9ErZGk9
+ZLu+VJHBSPmEQCkUcbviwzoRo8YSyka12TZERy+NJcvmD9deNgFbp8GyZf01XJWH
+slSYt6LyInrJrTpv+3q2Vl5GQp0f+39i7MHnwGGKbWsDbSAm+L9yKTJzYJz1O5fo
+in06AiyyGPwnXd1cm5bTXVX+dQECgYEA2tdi6DXF8awE23pv4HphPBhXS5hmYP/D
+NC7CtP8wQsxjPdiIxkBFFVEaFCC2njq1VhTyJb5noJM4kOIwcoaQ/zgyyxQa0u7w
++CqvAh1WwG+sT/B7vivrtDmmYeyGQapFo5DRIz+MflKAhzDhtnEyT9vLuCdn8J95
+0YvxZJ9+k5UCgYEAh+e7SER9nJUt6AoLWyIlGMKEXlWIFh5W7RG3KIMwJW6D59aG
++fAfu9M5Cx6PsnOSlZeExpOJCOS9O2Xmti2xcqzT1nFkCJWUcqCPtAlTfxLlmuIZ
+FpDOy36r9FHnwJ32OAjGd93ex0DOyZDMcfyoURaHcoTo/10UAYwUt0dXhwECgYAI
+xad2TWmA1XdgYNkJM36gTQ16v0IjUz084z70yGHj25OC0CIzaDIct6KG+gS39Px9
+1dsa/jXjLuOOkzKD9LbtNBB9KXIl0GQiXnujZw+qKQ/MKISdS99n2wO7WyLKkQu3
+kb+AXTTBf4cdZC04BfORVesll5bIA2x7pNNpSCdnvQKBgG7VXYcPlIV7iAyi2xFa
+uN1jccu/AK7xA0G1jz2SHNlpet74LmWR8XsTujJeo8WG1IRFxSky4h/pAP0XWIFO
+0LPK7eeDtnFq6y1/DXpI+/9BWX5T/8+4Yk93p37YrBVWKfd21dhrAklQs11m3rlQ
+Qn6c/zyvMKSyrCVxo5pTd5Il
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.pem b/tests/data_files/pkcs7-rsa-sha256-2.pem
new file mode 100644
index 0000000..b11a00a
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.pem
@@ -0,0 +1,48 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUVk1VQCWvWZ4ycHmycg7wDfN8+3wwDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDIwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMjCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmVNZZ0/qcT+h/lVNO+gP65
+lERTTudQ15h8QTLjaKhx5SSTLnuUhD0jLbR+ng8PMqdJ8ePkZEh1+7mi9MHzID4Y
+c47jH8M+Jc/JdBr6cSjbFd23QHESUjKKmV1IjSHc6Llbxe962z4gEXYjJAMkfr6B
+g1iecK3AlnEI4F0BsQfC5dgA4Qce2okvcTuhYgvHtLZ+UN4ca50Kw0o4u5FYdl89
+KDCE4zNp8MaaxGC83xcM4A9XqjHyZ7a2wvACTlmLQ2q/E+RN/8THEel4Y+yv82Uj
+j2LqqEaA06dvSdOPdaGz9jUZauqBw7TcuGGVzrrsZ0g/sHXKng9TppehAV/HrJUC
+AwEAAaNTMFEwHQYDVR0OBBYEFI5FVrtfLwPXRERcyVX6qBVvfoduMB8GA1UdIwQY
+MBaAFI5FVrtfLwPXRERcyVX6qBVvfoduMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAKRl0wgREe6eAduJSV5fs+Ec0s2qs2lHQqt/0JGEIbZBBtka
+q1UH9CIMMAd6Kb0kh5GlJT2shg/EAYWoitMwntkeRYTln2k2/B5jux+U5Ph4HyC+
+ad2GqmsoXWDru79rltT7Pv1hS1ofJyQ4Jv88vQA/SuIIRGdTC24VAVgg00JxvDRB
+xeqsQ9Pld4ebg4VvqsInnSpmKCcxfWxFhJk/Ax8bK/tV/GnrPiwsvry1j9nZyebS
+IyI01/6DwJS2ZhFnsLGyPHFOAFNtomjIdQ6gf2L1wq0qiGOKj/K9IzFNCpCz82a+
+gMgqFzCT5TCZC16kUG2NA2pXAx9O4uppKjRk97U=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJlTWWdP6nE/of
+5VTTvoD+uZREU07nUNeYfEEy42ioceUkky57lIQ9Iy20fp4PDzKnSfHj5GRIdfu5
+ovTB8yA+GHOO4x/DPiXPyXQa+nEo2xXdt0BxElIyipldSI0h3Oi5W8Xvets+IBF2
+IyQDJH6+gYNYnnCtwJZxCOBdAbEHwuXYAOEHHtqJL3E7oWILx7S2flDeHGudCsNK
+OLuRWHZfPSgwhOMzafDGmsRgvN8XDOAPV6ox8me2tsLwAk5Zi0NqvxPkTf/ExxHp
+eGPsr/NlI49i6qhGgNOnb0nTj3Whs/Y1GWrqgcO03Lhhlc667GdIP7B1yp4PU6aX
+oQFfx6yVAgMBAAECggEBAMVHm3w134qQCHfyroPTqtaftDTx+wRyn6yB3iT5XdGM
+NZ8H07Pp80kKBo7gY7uFOiNyQKKxQFuR69sPWc3+LI3YzC8IpGslhUfHdjN46gn7
+73hfAVgnf/4qmlEq0cRUOAY/hIUMjUhNhglB9tqEeu3iPjMaTFgfZJwW/czH/QMD
+w4zj5XoLgwRkqVvUceu/dBgV8KP5DpON+q8wpfWtjunv7rg5Nc3BVBrpb5SadJ7T
+i5TsS+pZQyp+mTvyCI3A1hkr2Vw5tULWO8SPhuEQkdtC/CL+luCUO7L16lU6KhFB
+qP5Fduik5skyLCVvAMUkjKcrC22k0gkhOHvfmMhjaAECgYEA68+hAQIiV9ErZGk9
+ZLu+VJHBSPmEQCkUcbviwzoRo8YSyka12TZERy+NJcvmD9deNgFbp8GyZf01XJWH
+slSYt6LyInrJrTpv+3q2Vl5GQp0f+39i7MHnwGGKbWsDbSAm+L9yKTJzYJz1O5fo
+in06AiyyGPwnXd1cm5bTXVX+dQECgYEA2tdi6DXF8awE23pv4HphPBhXS5hmYP/D
+NC7CtP8wQsxjPdiIxkBFFVEaFCC2njq1VhTyJb5noJM4kOIwcoaQ/zgyyxQa0u7w
++CqvAh1WwG+sT/B7vivrtDmmYeyGQapFo5DRIz+MflKAhzDhtnEyT9vLuCdn8J95
+0YvxZJ9+k5UCgYEAh+e7SER9nJUt6AoLWyIlGMKEXlWIFh5W7RG3KIMwJW6D59aG
++fAfu9M5Cx6PsnOSlZeExpOJCOS9O2Xmti2xcqzT1nFkCJWUcqCPtAlTfxLlmuIZ
+FpDOy36r9FHnwJ32OAjGd93ex0DOyZDMcfyoURaHcoTo/10UAYwUt0dXhwECgYAI
+xad2TWmA1XdgYNkJM36gTQ16v0IjUz084z70yGHj25OC0CIzaDIct6KG+gS39Px9
+1dsa/jXjLuOOkzKD9LbtNBB9KXIl0GQiXnujZw+qKQ/MKISdS99n2wO7WyLKkQu3
+kb+AXTTBf4cdZC04BfORVesll5bIA2x7pNNpSCdnvQKBgG7VXYcPlIV7iAyi2xFa
+uN1jccu/AK7xA0G1jz2SHNlpet74LmWR8XsTujJeo8WG1IRFxSky4h/pAP0XWIFO
+0LPK7eeDtnFq6y1/DXpI+/9BWX5T/8+4Yk93p37YrBVWKfd21dhrAklQs11m3rlQ
+Qn6c/zyvMKSyrCVxo5pTd5Il
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7_data.bin b/tests/data_files/pkcs7_data.bin
new file mode 100644
index 0000000..40ee264
--- /dev/null
+++ b/tests/data_files/pkcs7_data.bin
@@ -0,0 +1 @@
+Hello

diff --git a/tests/data_files/pkcs7_data_1.bin b/tests/data_files/pkcs7_data_1.bin
new file mode 100644
index 0000000..78c6bae
--- /dev/null
+++ b/tests/data_files/pkcs7_data_1.bin
@@ -0,0 +1 @@
+2

diff --git a/tests/data_files/pkcs7_data_cert_encrypted.der b/tests/data_files/pkcs7_data_cert_encrypted.der
new file mode 100644
index 0000000..b7b1c83
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_encrypted.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_sha1.der b/tests/data_files/pkcs7_data_cert_signed_sha1.der
new file mode 100644
index 0000000..fb1deb0
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_sha1.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_sha256.der b/tests/data_files/pkcs7_data_cert_signed_sha256.der
new file mode 100644
index 0000000..8dc2f4c
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_sha256.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_sha512.der b/tests/data_files/pkcs7_data_cert_signed_sha512.der
new file mode 100644
index 0000000..a4aa587
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_sha512.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_v2.der b/tests/data_files/pkcs7_data_cert_signed_v2.der
new file mode 100644
index 0000000..4f4cb04
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_v2.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signeddata_sha256.der b/tests/data_files/pkcs7_data_cert_signeddata_sha256.der
new file mode 100644
index 0000000..cb7d751
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signeddata_sha256.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_multiple_certs_signed.der b/tests/data_files/pkcs7_data_multiple_certs_signed.der
new file mode 100644
index 0000000..4a237e9
--- /dev/null
+++ b/tests/data_files/pkcs7_data_multiple_certs_signed.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_multiple_signed.der b/tests/data_files/pkcs7_data_multiple_signed.der
new file mode 100644
index 0000000..095b80c
--- /dev/null
+++ b/tests/data_files/pkcs7_data_multiple_signed.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_signed_badcert.der b/tests/data_files/pkcs7_data_signed_badcert.der
new file mode 100644
index 0000000..ed00f65
--- /dev/null
+++ b/tests/data_files/pkcs7_data_signed_badcert.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_signed_badsigner.der b/tests/data_files/pkcs7_data_signed_badsigner.der
new file mode 100644
index 0000000..aa5447c
--- /dev/null
+++ b/tests/data_files/pkcs7_data_signed_badsigner.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_without_cert_signed.der b/tests/data_files/pkcs7_data_without_cert_signed.der
new file mode 100644
index 0000000..b47fe92
--- /dev/null
+++ b/tests/data_files/pkcs7_data_without_cert_signed.der
Binary files differ
diff --git a/tests/data_files/pkcs7_signerInfo_issuer_invalid_size.der b/tests/data_files/pkcs7_signerInfo_issuer_invalid_size.der
new file mode 100644
index 0000000..898ca67
--- /dev/null
+++ b/tests/data_files/pkcs7_signerInfo_issuer_invalid_size.der
Binary files differ
diff --git a/tests/data_files/pkcs7_signerInfo_serial_invalid_size.der b/tests/data_files/pkcs7_signerInfo_serial_invalid_size.der
new file mode 100644
index 0000000..f4b4e38
--- /dev/null
+++ b/tests/data_files/pkcs7_signerInfo_serial_invalid_size.der
Binary files differ
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 9295c9d..716495e 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1217,6 +1217,7 @@
     # Direct dependencies
     scripts/config.py unset MBEDTLS_HKDF_C
     scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_PKCS7_C
     # Indirect dependencies
     scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
     make
@@ -2104,6 +2105,7 @@
     scripts/config.py unset MBEDTLS_MD_C
     scripts/config.py unset MBEDTLS_HKDF_C # has independent PSA implementation
     scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_PKCS7_C
     scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
     scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
 
diff --git a/tests/scripts/check_files.py b/tests/scripts/check_files.py
index 5c18702..42f2e82 100755
--- a/tests/scripts/check_files.py
+++ b/tests/scripts/check_files.py
@@ -122,6 +122,7 @@
     r'tests/data_files/.*\.req\.[^/]+\Z',
     r'tests/data_files/.*malformed[^/]+\Z',
     r'tests/data_files/format_pkcs12\.fmt\Z',
+    r'tests/data_files/pkcs7_data.*\.bin\Z',
 ]
 BINARY_FILE_PATH_RE = re.compile('|'.join(BINARY_FILE_PATH_RE_LIST))
 
diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data
new file mode 100644
index 0000000..4f81b6f
--- /dev/null
+++ b/tests/suites/test_suite_pkcs7.data
@@ -0,0 +1,75 @@
+PKCS7 Signed Data Parse Pass SHA256 #1
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signed_sha256.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Parse Pass SHA1 #2
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signed_sha1.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Parse Pass Without CERT #3
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_data_without_cert_signed.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Parse Fail with multiple certs #4
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_multiple_certs_signed.der":MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE
+
+PKCS7 Signed Data Parse Fail with corrupted cert #5
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_signed_badcert.der":MBEDTLS_ERR_PKCS7_INVALID_CERT
+
+PKCS7 Signed Data Parse Fail with corrupted signer info #6
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_signed_badsigner.der":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO,MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)
+
+PKCS7 Signed Data Parse Fail Version other than 1 #7
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signed_v2.der":MBEDTLS_ERR_PKCS7_INVALID_VERSION
+
+PKCS7 Signed Data Parse Fail Encrypted Content #8
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_data_cert_encrypted.der":MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE
+
+PKCS7 Signed Data Verification Pass SHA256 #9
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Verification Pass SHA256 #9.1
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":MBEDTLS_MD_SHA256:0
+
+PKCS7 Signed Data Verification Pass SHA1 #10
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha1.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Verification Pass SHA512 #11
+depends_on:MBEDTLS_SHA512_C:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha512.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Verification Fail because of different certificate #12
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-2.der":"data_files/pkcs7_data.bin":0:MBEDTLS_ERR_RSA_VERIFY_FAILED
+
+PKCS7 Signed Data Verification Fail because of different data hash #13
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data_1.bin":0:MBEDTLS_ERR_RSA_VERIFY_FAILED
+
+PKCS7 Signed Data Parse Failure Corrupt signerInfo.issuer #15.1
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_signerInfo_issuer_invalid_size.der":MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO
+
+PKCS7 Signed Data Parse Failure Corrupt signerInfo.serial #15.2
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_signerInfo_serial_invalid_size.der":MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO
+
+PKCS7 Only Signed Data Parse Pass #15
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signeddata_sha256.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Verify with multiple signers #16
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify_multiple_signers:"data_files/pkcs7_data_multiple_signed.der":"data_files/pkcs7-rsa-sha256-1.crt":"data_files/pkcs7-rsa-sha256-2.crt":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Hash Verify with multiple signers #17
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify_multiple_signers:"data_files/pkcs7_data_multiple_signed.der":"data_files/pkcs7-rsa-sha256-1.crt":"data_files/pkcs7-rsa-sha256-2.crt":"data_files/pkcs7_data.bin":MBEDTLS_MD_SHA256:0
diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function
new file mode 100644
index 0000000..14a0882
--- /dev/null
+++ b/tests/suites/test_suite_pkcs7.function
@@ -0,0 +1,194 @@
+/* BEGIN_HEADER */
+#include "mbedtls/bignum.h"
+#include "mbedtls/pkcs7.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_crl.h"
+#include "mbedtls/oid.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PKCS7_C:MBEDTLS_RSA_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */
+void pkcs7_parse( char *pkcs7_file, int res_expect )
+{
+    unsigned char *pkcs7_buf = NULL;
+    size_t buflen;
+    int res;
+
+    mbedtls_pkcs7 pkcs7;
+
+    mbedtls_pkcs7_init( &pkcs7 );
+
+    res = mbedtls_pk_load_file( pkcs7_file, &pkcs7_buf, &buflen );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_pkcs7_parse_der( &pkcs7, pkcs7_buf, buflen );
+    TEST_ASSERT( res == res_expect );
+
+exit:
+    mbedtls_free( pkcs7_buf );
+    mbedtls_pkcs7_free( &pkcs7 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C */
+void pkcs7_verify( char *pkcs7_file, char *crt, char *filetobesigned, int do_hash_alg, int res_expect )
+{
+    unsigned char *pkcs7_buf = NULL;
+    size_t buflen;
+    unsigned char *data = NULL;
+    unsigned char hash[32];
+    struct stat st;
+    size_t datalen;
+    int res;
+    FILE *file;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+
+    mbedtls_pkcs7 pkcs7;
+    mbedtls_x509_crt x509;
+
+    USE_PSA_INIT();
+
+    mbedtls_pkcs7_init( &pkcs7 );
+    mbedtls_x509_crt_init( &x509 );
+
+    res = mbedtls_x509_crt_parse_file( &x509, crt );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_pk_load_file( pkcs7_file, &pkcs7_buf, &buflen );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_pkcs7_parse_der( &pkcs7, pkcs7_buf, buflen );
+    TEST_ASSERT( res == MBEDTLS_PKCS7_SIGNED_DATA );
+
+    res = stat( filetobesigned, &st );
+    TEST_ASSERT( res == 0 );
+
+    file = fopen( filetobesigned, "rb" );
+    TEST_ASSERT( file != NULL );
+
+    datalen = st.st_size;
+    data = mbedtls_calloc( datalen, 1 );
+    TEST_ASSERT( data != NULL );
+
+    buflen = fread( (void *)data , sizeof( unsigned char ), datalen, file );
+    TEST_ASSERT( buflen == datalen );
+    fclose( file );
+
+    if( do_hash_alg )
+    {
+        res = mbedtls_oid_get_md_alg( &pkcs7.signed_data.digest_alg_identifiers, &md_alg );
+        TEST_ASSERT( res == 0 );
+        TEST_ASSERT( md_alg == (mbedtls_md_type_t) do_hash_alg );
+        md_info = mbedtls_md_info_from_type( md_alg );
+
+        res = mbedtls_md( md_info, data, datalen, hash );
+        TEST_ASSERT( res == 0 );
+
+        res = mbedtls_pkcs7_signed_hash_verify( &pkcs7, &x509, hash, sizeof(hash) );
+    }
+    else
+    {
+        res = mbedtls_pkcs7_signed_data_verify( &pkcs7, &x509, data, datalen );
+    }
+    TEST_ASSERT( res == res_expect );
+
+exit:
+    mbedtls_x509_crt_free( &x509 );
+    mbedtls_free( data );
+    mbedtls_pkcs7_free( &pkcs7 );
+    mbedtls_free( pkcs7_buf );
+    USE_PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C */
+void pkcs7_verify_multiple_signers( char *pkcs7_file, char *crt1, char *crt2, char *filetobesigned, int do_hash_alg, int res_expect )
+{
+    unsigned char *pkcs7_buf = NULL;
+    size_t buflen;
+    unsigned char *data = NULL;
+    unsigned char hash[32];
+    struct stat st;
+    size_t datalen;
+    int res;
+    FILE *file;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+
+    mbedtls_pkcs7 pkcs7;
+    mbedtls_x509_crt x509_1;
+    mbedtls_x509_crt x509_2;
+
+    USE_PSA_INIT();
+
+    mbedtls_pkcs7_init( &pkcs7 );
+    mbedtls_x509_crt_init( &x509_1 );
+    mbedtls_x509_crt_init( &x509_2 );
+
+    res = mbedtls_pk_load_file( pkcs7_file, &pkcs7_buf, &buflen );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_pkcs7_parse_der( &pkcs7, pkcs7_buf, buflen );
+    TEST_ASSERT( res == MBEDTLS_PKCS7_SIGNED_DATA );
+
+    TEST_ASSERT( pkcs7.signed_data.no_of_signers == 2 );
+
+    res = mbedtls_x509_crt_parse_file( &x509_1, crt1 );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_x509_crt_parse_file( &x509_2, crt2 );
+    TEST_ASSERT( res == 0 );
+
+    res = stat( filetobesigned, &st );
+    TEST_ASSERT( res == 0 );
+
+    file = fopen( filetobesigned, "rb" );
+    TEST_ASSERT( file != NULL );
+
+    datalen = st.st_size;
+    data = ( unsigned char* ) calloc( datalen, sizeof(unsigned char) );
+    buflen = fread( ( void * )data , sizeof( unsigned char ), datalen, file );
+    TEST_ASSERT( buflen == datalen );
+
+    fclose( file );
+
+    if( do_hash_alg )
+    {
+        res = mbedtls_oid_get_md_alg( &pkcs7.signed_data.digest_alg_identifiers, &md_alg );
+        TEST_ASSERT( res == 0 );
+        TEST_ASSERT( md_alg == MBEDTLS_MD_SHA256 );
+
+        md_info = mbedtls_md_info_from_type( md_alg );
+
+        res = mbedtls_md( md_info, data, datalen, hash );
+        TEST_ASSERT( res == 0 );
+
+        res = mbedtls_pkcs7_signed_hash_verify( &pkcs7, &x509_1, hash, sizeof(hash) );
+        TEST_ASSERT( res == res_expect );
+    }
+    else
+    {
+        res = mbedtls_pkcs7_signed_data_verify( &pkcs7, &x509_1, data, datalen );
+        TEST_ASSERT( res == res_expect );
+    }
+
+    res = mbedtls_pkcs7_signed_data_verify( &pkcs7, &x509_2, data, datalen );
+    TEST_ASSERT( res == res_expect );
+
+exit:
+    mbedtls_x509_crt_free( &x509_1 );
+    mbedtls_x509_crt_free( &x509_2 );
+    mbedtls_pkcs7_free( &pkcs7 );
+    mbedtls_free( data );
+    mbedtls_free( pkcs7_buf );
+    USE_PSA_DONE();
+}
+/* END_CASE */