From patchwork Wed Sep 16 16:21:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1365465 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Bs5DY23Myz9sTS for ; Thu, 17 Sep 2020 02:30:21 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linux.ibm.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=icq2HjJF; dkim-atps=neutral Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 4Bs5DY00FjzDqCq for ; Thu, 17 Sep 2020 02:30:21 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=icq2HjJF; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4Bs52w00rRzDqNw for ; Thu, 17 Sep 2020 02:21:59 +1000 (AEST) Received: from pps.filterd (m0098393.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 08GG25Cc082036 for ; Wed, 16 Sep 2020 12:21:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=MrhB8Ol3WmVkRmaNPguL/b8kuI+j4Wy7hg+YIyJVmcc=; b=icq2HjJFm1i1JbcivdQVD3ihMwn6pFbAVjdP+HtWcgk3Y2N3DUlfRNPMuy+sJRqMrAa+ 1R++kozPigkLfd967ZArz5NhLZTsMLTIwa/AXxsdk32s5vuuJXlSlnU1JQZvk8yTLV5E RVFQEITPWtlgKlAnsZF6iLDwx4NPWRg2lp0pMgU8rHddnhoYdoiv8V9OEbZnaEWwavKX ILj+7DI97+0DaBiNd6eYlB804ep3VpwaLSE40LPv8V2Peo/m6XWHEOCPo5QXB+yqCVLe Vh+6AhXfs7Sw4LGQuFDdCkho+Qlj+BbZ83IuOT93ZQZgyEd3mVYJP0cw00IR+yvJ65ll Hg== Received: from ppma04fra.de.ibm.com (6a.4a.5195.ip4.static.sl-reverse.com [149.81.74.106]) by mx0a-001b2d01.pphosted.com with ESMTP id 33knsnrsgy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 16 Sep 2020 12:21:57 -0400 Received: from pps.filterd (ppma04fra.de.ibm.com [127.0.0.1]) by ppma04fra.de.ibm.com (8.16.0.42/8.16.0.42) with SMTP id 08GGIdxu021809 for ; Wed, 16 Sep 2020 16:21:55 GMT Received: from b06cxnps4075.portsmouth.uk.ibm.com (d06relay12.portsmouth.uk.ibm.com [9.149.109.197]) by ppma04fra.de.ibm.com with ESMTP id 33k64s8e8b-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 16 Sep 2020 16:21:55 +0000 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 08GGLqpC29360630 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 16 Sep 2020 16:21:52 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7203C11C052; Wed, 16 Sep 2020 16:21:52 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C418611C058; Wed, 16 Sep 2020 16:21:51 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.160.109.67]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Wed, 16 Sep 2020 16:21:51 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Wed, 16 Sep 2020 11:21:28 -0500 Message-Id: <20200916162131.22478-18-erichte@linux.ibm.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200916162131.22478-1-erichte@linux.ibm.com> References: <20200916162131.22478-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.235, 18.0.687 definitions=2020-09-16_10:2020-09-16, 2020-09-16 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 clxscore=1015 malwarescore=0 mlxlogscore=999 phishscore=0 suspectscore=0 lowpriorityscore=0 mlxscore=0 impostorscore=0 spamscore=0 bulkscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2009160114 Subject: [Skiboot] [PATCH v6 17/20] crypto: add out-of-tree mbedtls pkcs7 parser X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: nayna@linux.ibm.com Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" From: Nayna Jain 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 Signed-off-by: Eric Richter --- 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='' + +$(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 +#include +#include +#if defined(MBEDTLS_FS_IO) +#include +#include +#endif +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" +#else +#include +#include +#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 +#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 */