Message ID | 20200401003426.7198-13-erichte@linux.ibm.com |
---|---|
State | Superseded |
Headers | show |
Series | Add initial secure variable storage and backend drivers | expand |
Context | Check | Description |
---|---|---|
snowpatch_ozlabs/apply_patch | fail | Failed to apply to any branch |
snowpatch_ozlabs/apply_patch | warning | Failed to apply on branch master (6826095796c91583f344950ff76ef8ccf6e756b5) |
On 3/31/20 8:34 PM, Eric Richter wrote: > From: Nayna Jain <nayna@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. It looks like it implements a subset of pkcs7, basically only the parts you need, right? > > Signed-off-by: Nayna Jain <nayna@linux.ibm.com> > Signed-off-by: Eric Richter <erichte@linux.ibm.com> > --- > libstb/crypto/Makefile.inc | 4 +- > libstb/crypto/mbedtls-config.h | 1 + > libstb/crypto/pkcs7/Makefile.inc | 12 + > libstb/crypto/pkcs7/pkcs7.c | 508 +++++++++++++++++++++++++++++++ > libstb/crypto/pkcs7/pkcs7.h | 151 +++++++++ > 5 files changed, 675 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..b1952aef 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_USE_C > //#define MBEDTLS_PK_WRITE_C > #define MBEDTLS_PLATFORM_C > #define MBEDTLS_RSA_C > 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..f8097720 > --- /dev/null > +++ b/libstb/crypto/pkcs7/pkcs7.c > @@ -0,0 +1,508 @@ > +/* 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_USE_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; > + struct stat st; > + int rc; > + > + rc = stat( path, &st ); > + if ( rc ) > + return ( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR ); A style issue here for mbedtls. It looks like mbedtls does not want a space between 'return' and '('. Applies to everywhere... > + > + if( ( file = fopen( path, "rb" ) ) == NULL ) > + return ( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR ); > + > + mbedtls_printf( "file size is %lu\n", st.st_size ); > + > + *n = (size_t) st.st_size; > + > + *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_VERSION + ret ); > + > + 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; You changed the indentation. From what I can see mbedtls uses 4 spaces. > + > + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED > + | MBEDTLS_ASN1_SEQUENCE ); > + if ( ret ) > + return ( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret ); > + > + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID ); > + if ( ret ) > + 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 ) > + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret ); > + > + return ( 0 ); > +} > + > +/** > + * certificates :: SET OF ExtendedCertificateOrCertificate, > + * ExtendedCertificateOrCertificate ::= CHOICE { > + * certificate Certificate -- x509, > + * extendedCertificate[0] IMPLICIT ExtendedCertificate } > + **/ > +static int pkcs7_get_certificates( unsigned char **buf, size_t buflen, > + mbedtls_x509_crt *certs ) > +{ > + int ret; > + > + if ( ( ret = mbedtls_x509_crt_parse( certs, *buf, buflen ) ) < 0 ) > + return ( ret ); > + > + /** > + * Currently we do not check for certificate chain, so we are not handling "> 0" case. > + * Might have to revisit soon. > + **/ > + > + 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; > + > + return ( 0 ); > +} > + > +/** > + * SignerInfo ::= SEQUENCE { > + * version Version; > + * issuerAndSerialNumber IssuerAndSerialNumber, > + * digestAlgorithm DigestAlgorithmIdentifier, > + * authenticatedAttributes > + * [0] IMPLICIT Attributes OPTIONAL, > + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, > + * encryptedDigest EncryptedDigest, > + * unauthenticatedAttributes > + * [1] IMPLICIT Attributes OPTIONAL, You are not parsing all of this, are you? > + **/ > +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 ); > + > + 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 ); > + > + 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, &signers_set->sig ); > + if ( ret != 0 ) > + return ( ret ); > + > + signers_set->next = NULL; > + > + 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; > + size_t len = 0; > + int ret; > + > + ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED > + | MBEDTLS_ASN1_SEQUENCE ); > + if ( ret != 0 ) > + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); > + > + /* Get version of signed data */ > + ret = pkcs7_get_version( &p, end, &signed_data->version ); > + if ( ret != 0 ) > + return ( ret ); > + > + /* If version != 1, return invalid version */ > + if ( signed_data->version != MBEDTLS_PKCS7_SUPPORTED_VERSION ) { > + mbedtls_printf("Invalid version\n"); > + return ( MBEDTLS_ERR_PKCS7_INVALID_VERSION ); > + } > + > + /* Get digest algorithm */ > + ret = pkcs7_get_digest_algorithm_set( &p, end, > + &signed_data->digest_alg_identifiers ); > + if ( ret != 0 ) { > + mbedtls_printf("error getting digest algorithms\n"); > + return ( ret ); > + } > + > + if ( signed_data->digest_alg_identifiers.len != strlen( MBEDTLS_OID_DIGEST_ALG_SHA256 ) ) > + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG ); > + > + if ( memcmp( signed_data->digest_alg_identifiers.p, MBEDTLS_OID_DIGEST_ALG_SHA256, > + signed_data->digest_alg_identifiers.len ) ) { > + mbedtls_fprintf(stdout, "Digest Algorithm other than SHA256 is not supported\n"); > + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG ); > + } > + > + /* Do not expect any content */ > + ret = pkcs7_get_content_info_type( &p, end, &signed_data->content.oid ); > + if ( ret != 0 ) > + return ( ret ); > + > + if ( memcmp( signed_data->content.oid.p, MBEDTLS_OID_PKCS7_DATA, > + signed_data->content.oid.len ) ) { > + mbedtls_printf("Invalid PKCS7 data\n"); > + return ( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO ) ; > + } > + > + p = p + signed_data->content.oid.len; > + > + ret = pkcs7_get_next_content_len( &p, end, &len ); > + if ( ret != 0 ) > + return ( ret ); > + > + /* Get certificates */ > + mbedtls_x509_crt_init( &signed_data->certs ); > + ret = pkcs7_get_certificates( &p, len, &signed_data->certs ); > + if ( ret != 0 ) > + return ( ret ) ; > + > + p = p + len; > + > + /* Get signers info */ > + ret = pkcs7_get_signers_info_set( &p, end, &signed_data->signers ); > + if ( ret != 0 ) > + return ( ret ); > + > + 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; > + > + /* use internal buffer for parsing */ > + start = ( unsigned char * )buf; What mbedtls seems to be doing in similar(!) cases is mbedtls_calloc() a buffer and copy things over [mbedtls_x509_crl_parse_der]. So they have functions with signature 'const unsigned char*' but then don't seem to cast like you do here but use a 2nd buffer, but then they keep the plain buffer around. In your case it's the asn1 parser functions that don't seem to take a 'const' buffer, so you never know whether you can offer the 'const'. > + 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 ) > + goto out; > + > + if ( ( !memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_DATA, > + pkcs7->content_type_oid.len ) ) > + || ( !memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, > + pkcs7->content_type_oid.len ) ) > + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENVELOPED_DATA, > + pkcs7->content_type_oid.len ) ) > + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, > + pkcs7->content_type_oid.len ) ) > + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_DIGESTED_DATA, > + pkcs7->content_type_oid.len ) ) > + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, > + pkcs7->content_type_oid.len ) ) ) { > + mbedtls_printf("Unsupported PKCS7 data type\n"); > + ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE; > + goto out; > + } > + > + if ( ( memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_SIGNED_DATA, > + pkcs7->content_type_oid.len ) ) ) { > + mbedtls_printf("Invalid PKCS7 data type\n"); > + ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA; > + goto out; > + } > + mbedtls_printf("Content type is SignedData\n"); > + > + start = start + pkcs7->content_type_oid.len; > + > + ret = pkcs7_get_next_content_len( &start, end, &len ); > + if ( ret != 0 ) > + goto out; > + > + ret = pkcs7_get_signed_data( start, len, &pkcs7->signed_data ); > + if ( ret != 0 ) > + goto out; > + > +out: > + return ( ret ); > +} > + > +int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *data, int datalen ) > +{ > + > + int ret; > + unsigned char hash[32]; > + mbedtls_pk_context pk_cxt = cert->pk; > + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); > + > + mbedtls_md( md_info, data, datalen, hash ); > + ret = mbedtls_pk_verify( &pk_cxt, MBEDTLS_MD_SHA256, hash, sizeof(hash), pkcs7->signed_data.signers.sig.p, pkcs7->signed_data.signers.sig.len ); > + > + mbedtls_printf("Verification return code is %04x\n", ret); > + > + 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 ); > + } > +} > + > +#endif > diff --git a/libstb/crypto/pkcs7/pkcs7.h b/libstb/crypto/pkcs7/pkcs7.h > new file mode 100644 > index 00000000..7f14b4b8 > --- /dev/null > +++ b/libstb/crypto/pkcs7/pkcs7.h > @@ -0,0 +1,151 @@ > +/** > + * \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 -0x7080 /**< Unavailable feature, e.g. anything other than signed data. */ > +#define MBEDTLS_ERR_PKCS7_INVALID_FORMAT -0x7100 /**< The CRT/CRL format is invalid, e.g. different type expected. */ > +#define MBEDTLS_ERR_PKCS7_INVALID_VERSION -0x7180 /**< The PKCS7 version element is invalid or cannot be parsed. */ > +#define MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO -0x7200 /**< The PKCS7 content info invalid or cannot be parsed. */ > +#define MBEDTLS_ERR_PKCS7_INVALID_ALG -0x7280 /**< The algorithm tag or value is invalid or cannot be parsed. */ > +#define MBEDTLS_ERR_PKCS7_INVALID_SIGNATURE -0x7300 /**< Error parsing the signature */ > +#define MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO -0x7380 /**< Error parsing the signer's info */ > +#define MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA -0x7400 /**< Input invalid. */ > +#define MBEDTLS_ERR_PKCS7_ALLOC_FAILED -0x7480 /**< Allocation of memory failed. */ > +#define MBEDTLS_ERR_PKCS7_FILE_IO_ERROR -0x7500 /**< 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; > + > +/** > + * 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; > + > +void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 ); > + > +int mbedtls_pkcs7_parse_der(const unsigned char *buf, const int buflen, mbedtls_pkcs7 *pkcs7); > + > +int mbedtls_pkcs7_signed_data_verify(mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *data, int datalen); > + > +int mbedtls_pkcs7_load_file( const char *path, unsigned char **buf, size_t *n ); > + > +void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 ); > + > +/* > + * PKCS#7 OIDs > + */ > +#define MBEDTLS_OID_PKCS7 MBEDTLS_OID_PKCS "\x07" /**< pkcs-7 */ > +#define MBEDTLS_OID_PKCS7_DATA MBEDTLS_OID_PKCS7 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ > +#define MBEDTLS_OID_PKCS7_SIGNED_DATA MBEDTLS_OID_PKCS7 "\x02" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ > +#define MBEDTLS_OID_PKCS7_ENVELOPED_DATA MBEDTLS_OID_PKCS7 "\x03" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ > +#define MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA MBEDTLS_OID_PKCS7 "\x04" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ > +#define MBEDTLS_OID_PKCS7_DIGESTED_DATA MBEDTLS_OID_PKCS7 "\x05" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ > +#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA MBEDTLS_OID_PKCS7 "\x06" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif /* 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..b1952aef 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_USE_C //#define MBEDTLS_PK_WRITE_C #define MBEDTLS_PLATFORM_C #define MBEDTLS_RSA_C 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..f8097720 --- /dev/null +++ b/libstb/crypto/pkcs7/pkcs7.c @@ -0,0 +1,508 @@ +/* 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_USE_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; + struct stat st; + int rc; + + rc = stat( path, &st ); + if ( rc ) + return ( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR ); + + if( ( file = fopen( path, "rb" ) ) == NULL ) + return ( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR ); + + mbedtls_printf( "file size is %lu\n", st.st_size ); + + *n = (size_t) st.st_size; + + *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_VERSION + ret ); + + 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; + + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE ); + if ( ret ) + return ( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO + ret ); + + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID ); + if ( ret ) + 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 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret ); + + return ( 0 ); +} + +/** + * certificates :: SET OF ExtendedCertificateOrCertificate, + * ExtendedCertificateOrCertificate ::= CHOICE { + * certificate Certificate -- x509, + * extendedCertificate[0] IMPLICIT ExtendedCertificate } + **/ +static int pkcs7_get_certificates( unsigned char **buf, size_t buflen, + mbedtls_x509_crt *certs ) +{ + int ret; + + if ( ( ret = mbedtls_x509_crt_parse( certs, *buf, buflen ) ) < 0 ) + return ( ret ); + + /** + * Currently we do not check for certificate chain, so we are not handling "> 0" case. + * Might have to revisit soon. + **/ + + 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; + + return ( 0 ); +} + +/** + * 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 ); + + 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 ); + + 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, &signers_set->sig ); + if ( ret != 0 ) + return ( ret ); + + signers_set->next = NULL; + + 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; + size_t len = 0; + int ret; + + ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + /* Get version of signed data */ + ret = pkcs7_get_version( &p, end, &signed_data->version ); + if ( ret != 0 ) + return ( ret ); + + /* If version != 1, return invalid version */ + if ( signed_data->version != MBEDTLS_PKCS7_SUPPORTED_VERSION ) { + mbedtls_printf("Invalid version\n"); + return ( MBEDTLS_ERR_PKCS7_INVALID_VERSION ); + } + + /* Get digest algorithm */ + ret = pkcs7_get_digest_algorithm_set( &p, end, + &signed_data->digest_alg_identifiers ); + if ( ret != 0 ) { + mbedtls_printf("error getting digest algorithms\n"); + return ( ret ); + } + + if ( signed_data->digest_alg_identifiers.len != strlen( MBEDTLS_OID_DIGEST_ALG_SHA256 ) ) + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG ); + + if ( memcmp( signed_data->digest_alg_identifiers.p, MBEDTLS_OID_DIGEST_ALG_SHA256, + signed_data->digest_alg_identifiers.len ) ) { + mbedtls_fprintf(stdout, "Digest Algorithm other than SHA256 is not supported\n"); + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG ); + } + + /* Do not expect any content */ + ret = pkcs7_get_content_info_type( &p, end, &signed_data->content.oid ); + if ( ret != 0 ) + return ( ret ); + + if ( memcmp( signed_data->content.oid.p, MBEDTLS_OID_PKCS7_DATA, + signed_data->content.oid.len ) ) { + mbedtls_printf("Invalid PKCS7 data\n"); + return ( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO ) ; + } + + p = p + signed_data->content.oid.len; + + ret = pkcs7_get_next_content_len( &p, end, &len ); + if ( ret != 0 ) + return ( ret ); + + /* Get certificates */ + mbedtls_x509_crt_init( &signed_data->certs ); + ret = pkcs7_get_certificates( &p, len, &signed_data->certs ); + if ( ret != 0 ) + return ( ret ) ; + + p = p + len; + + /* Get signers info */ + ret = pkcs7_get_signers_info_set( &p, end, &signed_data->signers ); + if ( ret != 0 ) + return ( ret ); + + 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; + + /* 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 ) + goto out; + + if ( ( !memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENVELOPED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_DIGESTED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, + pkcs7->content_type_oid.len ) ) ) { + mbedtls_printf("Unsupported PKCS7 data type\n"); + ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE; + goto out; + } + + if ( ( memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_SIGNED_DATA, + pkcs7->content_type_oid.len ) ) ) { + mbedtls_printf("Invalid PKCS7 data type\n"); + ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA; + goto out; + } + mbedtls_printf("Content type is SignedData\n"); + + start = start + pkcs7->content_type_oid.len; + + ret = pkcs7_get_next_content_len( &start, end, &len ); + if ( ret != 0 ) + goto out; + + ret = pkcs7_get_signed_data( start, len, &pkcs7->signed_data ); + if ( ret != 0 ) + goto out; + +out: + return ( ret ); +} + +int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *data, int datalen ) +{ + + int ret; + unsigned char hash[32]; + mbedtls_pk_context pk_cxt = cert->pk; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); + + mbedtls_md( md_info, data, datalen, hash ); + ret = mbedtls_pk_verify( &pk_cxt, MBEDTLS_MD_SHA256, hash, sizeof(hash), pkcs7->signed_data.signers.sig.p, pkcs7->signed_data.signers.sig.len ); + + mbedtls_printf("Verification return code is %04x\n", ret); + + 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 ); + } +} + +#endif diff --git a/libstb/crypto/pkcs7/pkcs7.h b/libstb/crypto/pkcs7/pkcs7.h new file mode 100644 index 00000000..7f14b4b8 --- /dev/null +++ b/libstb/crypto/pkcs7/pkcs7.h @@ -0,0 +1,151 @@ +/** + * \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 -0x7080 /**< Unavailable feature, e.g. anything other than signed data. */ +#define MBEDTLS_ERR_PKCS7_INVALID_FORMAT -0x7100 /**< The CRT/CRL format is invalid, e.g. different type expected. */ +#define MBEDTLS_ERR_PKCS7_INVALID_VERSION -0x7180 /**< The PKCS7 version element is invalid or cannot be parsed. */ +#define MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO -0x7200 /**< The PKCS7 content info invalid or cannot be parsed. */ +#define MBEDTLS_ERR_PKCS7_INVALID_ALG -0x7280 /**< The algorithm tag or value is invalid or cannot be parsed. */ +#define MBEDTLS_ERR_PKCS7_INVALID_SIGNATURE -0x7300 /**< Error parsing the signature */ +#define MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO -0x7380 /**< Error parsing the signer's info */ +#define MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA -0x7400 /**< Input invalid. */ +#define MBEDTLS_ERR_PKCS7_ALLOC_FAILED -0x7480 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_PKCS7_FILE_IO_ERROR -0x7500 /**< 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; + +/** + * 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; + +void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 ); + +int mbedtls_pkcs7_parse_der(const unsigned char *buf, const int buflen, mbedtls_pkcs7 *pkcs7); + +int mbedtls_pkcs7_signed_data_verify(mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *data, int datalen); + +int mbedtls_pkcs7_load_file( const char *path, unsigned char **buf, size_t *n ); + +void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 ); + +/* + * PKCS#7 OIDs + */ +#define MBEDTLS_OID_PKCS7 MBEDTLS_OID_PKCS "\x07" /**< pkcs-7 */ +#define MBEDTLS_OID_PKCS7_DATA MBEDTLS_OID_PKCS7 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_SIGNED_DATA MBEDTLS_OID_PKCS7 "\x02" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_ENVELOPED_DATA MBEDTLS_OID_PKCS7 "\x03" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA MBEDTLS_OID_PKCS7 "\x04" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_DIGESTED_DATA MBEDTLS_OID_PKCS7 "\x05" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA MBEDTLS_OID_PKCS7 "\x06" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs7.h */