[Skiboot] [PATCH v6 17/20] crypto: add out-of-tree mbedtls pkcs7 parser

Eric Richter erichte at linux.ibm.com
Thu Sep 17 02:21:28 AEST 2020


From: Nayna Jain <nayna at linux.ibm.com>

This patch adds a pkcs7 parser for mbedtls that hasn't yet
gone upstream. Once/if that implementation is accepted,
this patch can be removed.

Signed-off-by: Nayna Jain <nayna at linux.ibm.com>
Signed-off-by: Eric Richter <erichte at linux.ibm.com>
---
V6:
 - allow parsing bare SignedData blobs
 - mbedtls_pkcs7_parse_der now returns the data type instead of 0 on
   success
 - adjusted for feedback based on ongoing pull request
 - now errors if it detects multiple signers (only single is supported
   for now)

 libstb/crypto/Makefile.inc                  |   4 +-
 libstb/crypto/mbedtls-config.h              |   1 +
 libstb/crypto/mbedtls/include/mbedtls/oid.h |  11 +
 libstb/crypto/pkcs7/Makefile.inc            |  12 +
 libstb/crypto/pkcs7/pkcs7.c                 | 596 ++++++++++++++++++++
 libstb/crypto/pkcs7/pkcs7.h                 | 225 ++++++++
 6 files changed, 848 insertions(+), 1 deletion(-)
 create mode 100644 libstb/crypto/pkcs7/Makefile.inc
 create mode 100644 libstb/crypto/pkcs7/pkcs7.c
 create mode 100644 libstb/crypto/pkcs7/pkcs7.h

diff --git a/libstb/crypto/Makefile.inc b/libstb/crypto/Makefile.inc
index 42b5d8b9..ed2387e3 100644
--- a/libstb/crypto/Makefile.inc
+++ b/libstb/crypto/Makefile.inc
@@ -42,6 +42,8 @@ MBEDTLS_SRCS = $(addprefix mbedtls/library/,$(MBED_CRYPTO_SRCS) $(MBED_X509_SRCS
 
 MBEDTLS_OBJS = $(MBEDTLS_SRCS:%.c=%.o)
 
+include $(CRYPTO_DIR)/pkcs7/Makefile.inc
+
 CRYPTO = $(CRYPTO_DIR)/built-in.a
 
-$(CRYPTO): $(MBEDTLS_OBJS:%=$(CRYPTO_DIR)/%)
+$(CRYPTO): $(MBEDTLS_OBJS:%=$(CRYPTO_DIR)/%) $(PKCS7)
diff --git a/libstb/crypto/mbedtls-config.h b/libstb/crypto/mbedtls-config.h
index 414bbfd8..9560993b 100644
--- a/libstb/crypto/mbedtls-config.h
+++ b/libstb/crypto/mbedtls-config.h
@@ -72,6 +72,7 @@
 //#define MBEDTLS_PEM_PARSE_C
 #define MBEDTLS_PK_C
 #define MBEDTLS_PK_PARSE_C
+#define MBEDTLS_PKCS7_C
 //#define MBEDTLS_PK_WRITE_C
 #define MBEDTLS_PLATFORM_C
 #define MBEDTLS_RSA_C
diff --git a/libstb/crypto/mbedtls/include/mbedtls/oid.h b/libstb/crypto/mbedtls/include/mbedtls/oid.h
index 6fbd018a..a879d7df 100644
--- a/libstb/crypto/mbedtls/include/mbedtls/oid.h
+++ b/libstb/crypto/mbedtls/include/mbedtls/oid.h
@@ -190,6 +190,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 } */
 
@@ -274,6 +275,16 @@
 #define MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC      MBEDTLS_OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */
 #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 1} */
+#define MBEDTLS_OID_PKCS7_ENVELOPED_DATA              MBEDTLS_OID_PKCS7 "\x03" /**< Content type is Enveloped Data OBJECT IDENTIFIER ::= {pkcs-7 1} */
+#define MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA   MBEDTLS_OID_PKCS7 "\x04" /**< Content type is Signed and Enveloped Data OBJECT IDENTIFIER ::= {pkcs-7 1} */
+#define MBEDTLS_OID_PKCS7_DIGESTED_DATA               MBEDTLS_OID_PKCS7 "\x05" /**< Content type is Digested Data OBJECT IDENTIFIER ::= {pkcs-7 1} */
+#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA              MBEDTLS_OID_PKCS7 "\x06" /**< Content type is Encrypted Data OBJECT IDENTIFIER ::= {pkcs-7 1} */
+
 /*
  * PKCS#8 OIDs
  */
diff --git a/libstb/crypto/pkcs7/Makefile.inc b/libstb/crypto/pkcs7/Makefile.inc
new file mode 100644
index 00000000..bef339b5
--- /dev/null
+++ b/libstb/crypto/pkcs7/Makefile.inc
@@ -0,0 +1,12 @@
+
+PKCS7_DIR = libstb/crypto/pkcs7
+
+SUBDIRS += $(PKCS7_DIR)
+
+PKCS7_SRCS = pkcs7.c
+PKCS7_OBJS = $(PKCS7_SRCS:%.c=%.o)
+PKCS7 = $(PKCS7_DIR)/built-in.a
+
+CFLAGS_$(PKCS7_DIR)/ = -I$(SRC)/$(LIBSTB_DIR)/crypto -DMBEDTLS_CONFIG_FILE='<mbedtls-config.h>'
+
+$(PKCS7): $(PKCS7_OBJS:%=$(PKCS7_DIR)/%)
diff --git a/libstb/crypto/pkcs7/pkcs7.c b/libstb/crypto/pkcs7/pkcs7.c
new file mode 100644
index 00000000..4407e201
--- /dev/null
+++ b/libstb/crypto/pkcs7/pkcs7.c
@@ -0,0 +1,596 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * 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.
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+#if defined(MBEDTLS_PKCS7_C)
+
+#include "mbedtls/x509.h"
+#include "mbedtls/asn1.h"
+#include "pkcs7.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_crl.h"
+#include "mbedtls/oid.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 <unistd.h>
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#include "mbedtls/platform_util.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_free      free
+#define mbedtls_calloc    calloc
+#define mbedtls_printf    printf
+#define mbedtls_snprintf  snprintf
+#endif
+
+#if defined(MBEDTLS_HAVE_TIME)
+#include "mbedtls/platform_time.h"
+#endif
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+#include <time.h>
+#endif
+
+#if defined(MBEDTLS_FS_IO)
+/*
+ * Load all data from a file into a given buffer.
+ *
+ * The file is expected to contain DER encoded data.
+ * A terminating null byte is always appended.
+ */
+int mbedtls_pkcs7_load_file( const char *path, unsigned char **buf, size_t *n )
+{
+    FILE *file;
+
+    if( ( file = fopen( path, "rb" ) ) == NULL )
+        return( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR );
+
+    fseek( file, 0, SEEK_END );
+    *n = (size_t) ftell( file );
+    fseek( file, 0, SEEK_SET );
+
+    *buf = mbedtls_calloc( 1, *n + 1 );
+    if( *buf == NULL )
+        return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED );
+
+    if( fread( *buf, 1, *n, file ) != *n )
+    {
+        fclose( file );
+
+        mbedtls_platform_zeroize( *buf, *n + 1 );
+        mbedtls_free( *buf );
+
+        return( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR );
+    }
+
+    fclose( file );
+
+    (*buf)[*n] = '\0';
+
+    return( 0 );
+}
+#endif
+
+/**
+ * Initializes the pkcs7 structure.
+ */
+void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 )
+{
+    memset( pkcs7, 0, sizeof( mbedtls_pkcs7 ) );
+}
+
+static int pkcs7_get_next_content_len( unsigned char **p, unsigned char *end,
+                                       size_t *len )
+{
+    int ret;
+
+    if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_CONSTRUCTED
+                    | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
+    {
+        return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
+    }
+
+    return( 0 );
+}
+
+/**
+ * version Version
+ * Version ::= INTEGER
+ **/
+static int pkcs7_get_version( unsigned char **p, unsigned char *end, int *ver )
+{
+    int ret;
+
+    if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
+
+    /* If version != 1, return invalid version */
+    if( *ver != MBEDTLS_PKCS7_SUPPORTED_VERSION )
+        return( MBEDTLS_ERR_PKCS7_INVALID_VERSION );
+
+    return( 0 );
+}
+
+/**
+ * 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;
+    unsigned char *start = *p;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret );
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID );
+    if( ret != 0 ) {
+        *p = start;
+        return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret );
+	}
+
+    pkcs7->tag = MBEDTLS_ASN1_OID;
+    pkcs7->len = len;
+    pkcs7->p = *p;
+
+    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;
+
+    if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
+
+    return( 0 );
+}
+
+/**
+ * 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;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                            | MBEDTLS_ASN1_SET );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
+
+    end = *p + len;
+
+    /** For now, it assumes there is only one digest algorithm specified **/
+    ret = mbedtls_asn1_get_alg_null( p, end, alg );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
+
+    if (*p != end)
+        return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT );
+
+    return( 0 );
+}
+
+/**
+ * certificates :: SET OF ExtendedCertificateOrCertificate,
+ * ExtendedCertificateOrCertificate ::= CHOICE {
+ *      certificate Certificate -- x509,
+ *      extendedCertificate[0] IMPLICIT ExtendedCertificate }
+ **/
+static int pkcs7_get_certificates( unsigned char **p, unsigned char *end,
+                                   mbedtls_x509_crt *certs )
+{
+    int ret;
+    size_t len1 = 0;
+    size_t len2 = 0;
+    unsigned char *end_set, *end_cert;
+    unsigned char *start = *p;
+
+    if( ( ret = mbedtls_asn1_get_tag( p, end, &len1, MBEDTLS_ASN1_CONSTRUCTED
+                    | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
+    {
+        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
+            return( 0 );
+
+        return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
+    }
+    start = *p;
+    end_set = *p + len1;
+
+    /* This is to verify that there is only signer certificate, it can
+       have its chain though. */
+    ret = mbedtls_asn1_get_tag( p, end_set, &len2, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
+
+    end_cert = *p + len2;
+
+    if (end_cert != end_set)
+        return (MBEDTLS_ERR_PKCS7_INVALID_FORMAT);
+
+    /* Since it satisfies the condition of single signer, continue parsing */
+    *p = start;
+    if( ( ret = mbedtls_x509_crt_parse( certs, *p, len1 ) ) < 0 )
+        return( ret );
+
+    *p = *p + len1;
+
+    /**
+     * Currently we do not check for certificate chain, so we are not handling
+     * "> 0" case. Return if atleast one certificate in the chain is correctly
+     * parsed.
+     **/
+
+    return( 0 );
+}
+
+/**
+ * EncryptedDigest ::= OCTET STRING
+ **/
+static int pkcs7_get_signature( unsigned char **p, unsigned char *end,
+                                mbedtls_pkcs7_buf *signature )
+{
+    int ret;
+    size_t len = 0;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OCTET_STRING );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_SIGNATURE + ret );
+
+    signature->tag = MBEDTLS_ASN1_OCTET_STRING;
+    signature->len = len;
+    signature->p = *p;
+
+    *p = *p + len;
+
+    return( 0 );
+}
+
+/**
+ * SignerInfos ::= SET of SignerInfo
+ * SignerInfo ::= SEQUENCE {
+ *      version Version;
+ *      issuerAndSerialNumber   IssuerAndSerialNumber,
+ *      digestAlgorithm DigestAlgorithmIdentifier,
+ *      authenticatedAttributes
+ *              [0] IMPLICIT Attributes OPTIONAL,
+ *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ *      encryptedDigest EncryptedDigest,
+ *      unauthenticatedAttributes
+ *              [1] IMPLICIT Attributes OPTIONAL,
+ **/
+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;
+    size_t len = 0;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SET );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
+
+    end_set = *p + len;
+
+    ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
+
+    end_set = *p + len;
+
+    ret = mbedtls_asn1_get_int( p, end_set, &signers_set->version );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
+
+    ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
+
+	/* Parsing IssuerAndSerialNumber */
+    signers_set->issuer_raw.p = *p;
+
+    ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + ret );
+
+    ret  = mbedtls_x509_get_name( p, *p + len, &signers_set->issuer );
+    if( ret != 0 )
+        return( ret );
+
+    signers_set->issuer_raw.len =  *p - signers_set->issuer_raw.p;
+
+    ret = mbedtls_x509_get_serial( p, end_set, &signers_set->serial );
+    if( ret != 0 )
+        return( ret );
+
+    ret = pkcs7_get_digest_algorithm( p, end_set,
+            &signers_set->alg_identifier );
+    if( ret != 0 )
+        return( ret );
+
+    ret = pkcs7_get_digest_algorithm( p, end_set,
+            &signers_set->sig_alg_identifier );
+    if( ret != 0 )
+        return( ret );
+
+    ret = pkcs7_get_signature( p, end_set, &signers_set->sig );
+    if( ret != 0 )
+        return( ret );
+
+    signers_set->next = NULL;
+
+    if (*p != end_set)
+        return ( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO );
+
+    return( 0 );
+}
+
+/**
+ * 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_md_type_t md_alg;
+
+    ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret );
+
+    end_set = p + len;
+
+    /* Get version of signed data */
+    ret = pkcs7_get_version( &p, end_set, &signed_data->version );
+    if( ret != 0 )
+        return( ret );
+
+    /* Get digest algorithm */
+    ret = pkcs7_get_digest_algorithm_set( &p, end_set,
+            &signed_data->digest_alg_identifiers );
+    if( ret != 0 )
+        return( ret );
+
+    ret = mbedtls_oid_get_md_alg( &signed_data->digest_alg_identifiers, &md_alg );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
+
+    /* Do not expect any content */
+    ret = pkcs7_get_content_info_type( &p, end_set, &signed_data->content.oid );
+    if( ret != 0 )
+        return( ret );
+
+    if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &signed_data->content.oid ) )
+	{
+        return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO ) ;
+    }
+
+    p = p + signed_data->content.oid.len;
+
+	/* 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 )
+        return( ret ) ;
+
+    /* TODO: optional CRLs go here, currently no CRLs are expected */
+
+    /* Get signers info */
+    ret = pkcs7_get_signers_info_set( &p, end_set, &signed_data->signers );
+    if( ret != 0 )
+        return( ret );
+
+    if ( p != end )
+        ret = MBEDTLS_ERR_PKCS7_INVALID_FORMAT;
+
+    return( ret );
+}
+
+int mbedtls_pkcs7_parse_der( const unsigned char *buf, const int buflen,
+        mbedtls_pkcs7 *pkcs7 )
+{
+    unsigned char *start;
+    unsigned char *end;
+    size_t len = 0;
+    int ret;
+    int isoidset = 0;
+
+    /* use internal buffer for parsing */
+    start = (unsigned char *)buf;
+    end = start + buflen;
+
+    if( !pkcs7 )
+        return( MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA );
+
+    ret = pkcs7_get_content_info_type( &start, 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;
+    start = start + pkcs7->content_type_oid.len;
+
+    ret = pkcs7_get_next_content_len( &start, end, &len );
+    if( ret != 0 )
+        goto out;
+
+try_data:
+    ret = pkcs7_get_signed_data( start, 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 );
+}
+
+int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
+                                      mbedtls_x509_crt *cert,
+                                      const unsigned char *data,
+                                      size_t datalen )
+{
+
+    int ret;
+    unsigned char *hash;
+    mbedtls_pk_context pk_cxt = cert->pk;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+
+    ret = mbedtls_oid_get_md_alg( &pkcs7->signed_data.digest_alg_identifiers, &md_alg );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
+
+    md_info = mbedtls_md_info_from_type( md_alg );
+
+    hash = mbedtls_calloc( mbedtls_md_get_size( md_info ), 1 );
+    if( hash == NULL ) {
+        return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED );
+    }
+
+    mbedtls_md( md_info, data, datalen, hash );
+
+    ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, sizeof(hash),
+                                      pkcs7->signed_data.signers.sig.p,
+                                      pkcs7->signed_data.signers.sig.len );
+
+    mbedtls_free( hash );
+
+    return( ret );
+}
+
+int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
+                                      mbedtls_x509_crt *cert,
+                                      const unsigned char *hash, int hashlen)
+{
+    int ret;
+    mbedtls_md_type_t md_alg;
+    mbedtls_pk_context pk_cxt;
+
+    ret = mbedtls_oid_get_md_alg( &pkcs7->signed_data.digest_alg_identifiers, &md_alg );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret );
+
+    pk_cxt = cert->pk;
+    ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, hashlen,
+                             pkcs7->signed_data.signers.sig.p,
+                             pkcs7->signed_data.signers.sig.len );
+
+    return ( ret );
+}
+
+/*
+ * Unallocate all pkcs7 data
+ */
+void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 )
+{
+    mbedtls_x509_name *name_cur;
+    mbedtls_x509_name *name_prv;
+
+    if( pkcs7 == NULL )
+        return;
+
+    mbedtls_x509_crt_free( &pkcs7->signed_data.certs );
+    mbedtls_x509_crl_free( &pkcs7->signed_data.crl );
+
+    name_cur = pkcs7->signed_data.signers.issuer.next;
+    while( name_cur != NULL )
+    {
+        name_prv = name_cur;
+        name_cur = name_cur->next;
+        mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
+        mbedtls_free( name_prv );
+    }
+
+    mbedtls_platform_zeroize( pkcs7, sizeof( mbedtls_pkcs7 ) );
+}
+
+#endif
diff --git a/libstb/crypto/pkcs7/pkcs7.h b/libstb/crypto/pkcs7/pkcs7.h
new file mode 100644
index 00000000..df898a61
--- /dev/null
+++ b/libstb/crypto/pkcs7/pkcs7.h
@@ -0,0 +1,225 @@
+/**
+ * \file pkcs7.h
+ *
+ * \brief PKCS7 generic defines and structures
+ */
+/*
+ *  Copyright (C) 2019,  IBM Corp, All Rights Reserved
+ *  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.
+ *
+ *  This file is part of mbed TLS (https://tls.mbed.org)
+ */
+#ifndef MBEDTLS_PKCS7_H
+#define MBEDTLS_PKCS7_H
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "mbedtls/asn1.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crt.h"
+
+/**
+ * \name PKCS7 Error codes
+ * \{
+ */
+#define MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE              -0x5300  /**< Unavailable feature, e.g. anything other than signed data. */
+#define MBEDTLS_ERR_PKCS7_INVALID_FORMAT                   -0x53F0  /**< The CRT/CRL format is invalid, e.g. different type expected. */
+#define MBEDTLS_ERR_PKCS7_INVALID_VERSION                  -0x5400  /**< The PKCS7 version element is invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO             -0x54F0  /**< 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_SIGNATURE                -0x55F0  /**< Error parsing the signature */
+#define MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO              -0x5600  /**< Error parsing the signer's info */
+#define MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA                   -0x56F0  /**< Input invalid. */
+#define MBEDTLS_ERR_PKCS7_ALLOC_FAILED                     -0x5700  /**< Allocation of memory failed. */
+#define MBEDTLS_ERR_PKCS7_FILE_IO_ERROR                    -0x57F0  /**< File Read/Write Error */
+/* \} 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_DAYA,
+    MBEDTLS_PKCS7_DIGESTED_DATA,
+    MBEDTLS_PKCS7_ENCRYPTED_DATA,
+}
+mbedtls_pkcs7_type;
+
+/**
+ * Structure holding PKCS7 signer info
+ */
+typedef struct mbedtls_pkcs7_signer_info
+{
+    int version;
+    mbedtls_x509_buf serial;
+    mbedtls_x509_name issuer;
+    mbedtls_x509_buf issuer_raw;
+    mbedtls_x509_buf alg_identifier;
+    mbedtls_x509_buf sig_alg_identifier;
+    mbedtls_x509_buf sig;
+    struct mbedtls_pkcs7_signer_info *next;
+}
+mbedtls_pkcs7_signer_info;
+
+/**
+ * Structure holding attached data as part of PKCS7 signed data format
+ */
+typedef struct mbedtls_pkcs7_data
+{
+    mbedtls_pkcs7_buf oid;
+    mbedtls_pkcs7_buf data;
+}
+mbedtls_pkcs7_data;
+
+/**
+ * Structure holding the signed data section
+ */
+typedef struct mbedtls_pkcs7_signed_data
+{
+    int version;
+    mbedtls_pkcs7_buf digest_alg_identifiers;
+    struct mbedtls_pkcs7_data content;
+    mbedtls_x509_crt certs;
+    mbedtls_x509_crl crl;
+    struct mbedtls_pkcs7_signer_info signers;
+}
+mbedtls_pkcs7_signed_data;
+
+/**
+ * Structure holding PKCS7 structure, only signed data for now
+ */
+typedef struct mbedtls_pkcs7
+{
+    mbedtls_pkcs7_buf content_type_oid;
+    struct mbedtls_pkcs7_signed_data 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 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         \c 0, if successful.
+ * \return         A negative error code on failure.
+ */
+int mbedtls_pkcs7_parse_der( const unsigned char *buf, const int buflen,
+                             mbedtls_pkcs7 *pkcs7 );
+
+/**
+ * \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,
+                                      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,
+                                      mbedtls_x509_crt *cert,
+                                      const unsigned char *hash, int hashlen);
+
+/**
+ * \brief          Reads the PKCS7 data from the file in a buffer.
+ *
+ * \param path     Path of the file.
+ * \param buf      Buffer to store the PKCS7 contents from the file.
+ * \param n        Size of the buffer (the contents read from the file).
+ *
+ * \return         A negative error code on failure.
+ */
+int mbedtls_pkcs7_load_file( const char *path, unsigned char **buf, size_t *n );
+
+/**
+ * \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 */
-- 
2.21.1



More information about the Skiboot mailing list