From patchwork Thu Jul 18 21:29:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1133854 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 45qS5Q0m2xz9s3l for ; Fri, 19 Jul 2019 07:32:10 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 45qS5P3jz9zDqLg for ; Fri, 19 Jul 2019 07:32:09 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 45qS314NH2zDqXD for ; Fri, 19 Jul 2019 07:30:05 +1000 (AEST) Received: from pps.filterd (m0098417.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x6ILLvW0109768 for ; Thu, 18 Jul 2019 17:30:03 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tu03k9cnd-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 18 Jul 2019 17:30:02 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 18 Jul 2019 22:30:01 +0100 Received: from b06cxnps4074.portsmouth.uk.ibm.com (9.149.109.196) by e06smtp02.uk.ibm.com (192.168.101.132) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Thu, 18 Jul 2019 22:29:59 +0100 Received: from d06av23.portsmouth.uk.ibm.com (d06av23.portsmouth.uk.ibm.com [9.149.105.59]) by b06cxnps4074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x6ILTvUp43712532 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 18 Jul 2019 21:29:57 GMT Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8DAD8A4053; Thu, 18 Jul 2019 21:29:57 +0000 (GMT) Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 93CD2A4040; Thu, 18 Jul 2019 21:29:56 +0000 (GMT) Received: from yorha.ibmuc.com (unknown [9.80.231.223]) by d06av23.portsmouth.uk.ibm.com (Postfix) with ESMTP; Thu, 18 Jul 2019 21:29:56 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Thu, 18 Jul 2019 16:29:48 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190718212949.29121-1-erichte@linux.ibm.com> References: <20190718212949.29121-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19071821-0008-0000-0000-000002FEC618 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19071821-0009-0000-0000-0000226C45F3 Message-Id: <20190718212949.29121-3-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-07-18_11:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=4 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1907180218 Subject: [Skiboot] [PATCH 2/3] crypto: add 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 Jain Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" From: Nayna Jain The secure boot key management involves verification of the key updates which are signed using PKCS7 structure. Though the mbedtls crypto API comes with various crypto API support, it doesn't support PKCS7. This patch implements the PKCS7 parser that extracts the signer's info and the signature using mbedtls ASN.1 parsing library. The pkcs7 parser is not fully implemented, but limited to the OpenPOWER key update authentication requirements (eg. single certificate, no CRLs, single signer info, NULL content data, NULL parametes for digest algorithms). It currently supports the following validation checks: * Supports only signed data * Version should be 1 * Supports only SHA256 hash algorithm Signed-off-by: Nayna Jain Signed-off-by: Eric Richter --- libstb/Makefile.inc | 1 + libstb/crypto/Makefile.inc | 4 +- libstb/crypto/include/pkcs7.h | 87 +++++++ libstb/crypto/pkcs7/Makefile.inc | 11 + libstb/crypto/pkcs7/pkcs7.c | 373 +++++++++++++++++++++++++++++++ 5 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 libstb/crypto/include/pkcs7.h create mode 100644 libstb/crypto/pkcs7/Makefile.inc create mode 100644 libstb/crypto/pkcs7/pkcs7.c diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc index 30904df0..93e55bb2 100644 --- a/libstb/Makefile.inc +++ b/libstb/Makefile.inc @@ -13,6 +13,7 @@ include $(SRC)/$(LIBSTB_DIR)/tss/Makefile.inc include $(SRC)/$(LIBSTB_DIR)/crypto/Makefile.inc CPPFLAGS += -I$(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/include +CPPFLAGS += -I$(SRC)/$(LIBSTB_DIR)/crypto/include $(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(CRYPTO) diff --git a/libstb/crypto/Makefile.inc b/libstb/crypto/Makefile.inc index 3d71b236..194859c1 100644 --- a/libstb/crypto/Makefile.inc +++ b/libstb/crypto/Makefile.inc @@ -17,6 +17,8 @@ MBEDTLS_CFLAGS += $(CPPFLAGS) $(MBEDTLS): @$(MAKE) -C $(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/library/ CFLAGS="$(MBEDTLS_CFLAGS)" CC=$(CC) AR=$(AR) libmbedcrypto.a libmbedx509.a +include $(CRYPTO_DIR)/pkcs7/Makefile.inc + CRYPTO = $(CRYPTO_DIR)/built-in.a -$(CRYPTO): $(MBEDTLS) +$(CRYPTO): $(MBEDTLS) $(PKCS7) diff --git a/libstb/crypto/include/pkcs7.h b/libstb/crypto/include/pkcs7.h new file mode 100644 index 00000000..1f2503b0 --- /dev/null +++ b/libstb/crypto/include/pkcs7.h @@ -0,0 +1,87 @@ +/* Copyright 2013-2016 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. + */ +#ifndef SKIBOOT_PKCS7_H +#define SKIBOOT_PKCS7_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/** define the OID constants **/ +#define PKCS7_SIGNED_DATA_OID "\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02" +#define PKCS7_DATA_OID "\x2a\x86\x48\x86\xf7\x0d\x01\x07\x01" +#define PKCS7_SHA256_OID "\x60\x86\x48\x01\x65\x03\x04\x02\x01" +#define PKCS7_RSAeNCRYPTION_OID "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01" + + +/** define the pkcs7 errors **/ +#define PKCS7_UNSUPPORTED_CONTENT_TYPE 0x01 +#define PKCS7_INVALID_VALUE 0x02 +#define PKCS7_CERTIFICATE_NOT_FOUND 0x03 +#define PKCS7_PARSING_ERROR 0x04 +#define PKCS7_UNSUPPORTED_VERSION 0x05 +#define PKCS7_UNSUPPORTED_DIGEST_ALGORITHM 0x06 +#define PKCS7_UNSUPPORTED_SIGNING_ALGORITHM 0x07 + +typedef mbedtls_asn1_buf pkcs7_buf; + +typedef mbedtls_asn1_named_data pkcs7_name; + +typedef mbedtls_asn1_sequence pkcs7_sequence; + +struct 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 pkcs7_signer_info *next; +}; + +struct pkcs7_data { + pkcs7_buf oid; + pkcs7_buf data; +}; + +struct pkcs7; + +struct pkcs7_signed_data { + int version; + pkcs7_buf digest_alg_identifiers; + struct pkcs7_data content; + mbedtls_x509_crt certs; + mbedtls_x509_crl crl; + struct pkcs7_signer_info signers; +}; + +struct pkcs7 { + pkcs7_buf content_type_oid; + struct pkcs7_signed_data signed_data; +}; + +void pkcs7_printf(const unsigned char *buf, size_t buflen); + +int pkcs7_parse_message(const unsigned char *buf, const int buflen, + struct pkcs7 *pkcs7); + +#endif diff --git a/libstb/crypto/pkcs7/Makefile.inc b/libstb/crypto/pkcs7/Makefile.inc new file mode 100644 index 00000000..8f9bcd90 --- /dev/null +++ b/libstb/crypto/pkcs7/Makefile.inc @@ -0,0 +1,11 @@ +# -*-Makefile-*- + +PKCS7_DIR = libstb/crypto/pkcs7 + +SUBDIRS += $(PKCS7_DIR) + +PKCS7_SRCS = pkcs7.c +PKCS7_OBJS = $(PKCS7_SRCS:%.c=%.o) +PKCS7 = $(PKCS7_DIR)/built-in.a + +$(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..5df27cc8 --- /dev/null +++ b/libstb/crypto/pkcs7/pkcs7.c @@ -0,0 +1,373 @@ +/* Copyright 2013-2016 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. + */ +#include +#include +#include + +static int pkcs7_get_next_content_len(unsigned char **p, unsigned char *end, + size_t *len) +{ + int rc; + + rc = mbedtls_asn1_get_tag(p, end, len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_CONTEXT_SPECIFIC); + + return rc; +} + +/** + * version Version + * Version ::= INTEGER + **/ +static int pkcs7_get_version(unsigned char **p, unsigned char *end, int *ver) +{ + int rc; + + rc = mbedtls_asn1_get_int(p, end, ver); + + return rc; +} + +/** + * 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, + pkcs7_buf *pkcs7) +{ + size_t len = 0; + int rc; + + rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE); + if (rc) + return rc; + + rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OID); + if (rc) + return rc; + + pkcs7->tag = MBEDTLS_ASN1_OID; + pkcs7->len = len; + pkcs7->p = *p; + + return rc; +} + +/** + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * This is from x509.h + **/ +static int pkcs7_get_digest_algorithm(unsigned char **p, unsigned char *end, + mbedtls_x509_buf *alg) +{ + int rc; + + rc = mbedtls_asn1_get_alg_null(p, end, alg); + + return rc; +} + +/** + * 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 rc; + + rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SET); + if (rc) + return rc; + + end = *p + len; + + /** For now, it assumes there is only one digest algorithm specified **/ + rc = mbedtls_asn1_get_alg_null(p, end, alg); + if (rc) + return rc; + + return rc; +} + +/** + * 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 rc; + + rc = mbedtls_x509_crt_parse(certs, *buf, buflen); + if (rc) + return rc; + + return rc; +} + +/** + * EncryptedDigest ::= OCTET STRING + **/ +static int pkcs7_get_signature(unsigned char **p, unsigned char *end, + pkcs7_buf *signature) +{ + int rc; + size_t len = 0; + + rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + if (rc) + return rc; + + signature->tag = MBEDTLS_ASN1_OCTET_STRING; + signature->len = len; + signature->p = *p; + + return rc; +} + +/** + * 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, + struct pkcs7_signer_info *signers_set) +{ + unsigned char *end_set; + int rc; + size_t len = 0; + + rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SET); + if (rc) { + printf("failed\n"); + return rc; + } + + end_set = *p + len; + + rc = mbedtls_asn1_get_tag(p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE); + if (rc) + return rc; + + rc = mbedtls_asn1_get_int(p, end_set, &signers_set->version); + if (rc) + return rc; + + rc = mbedtls_asn1_get_tag(p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE); + if (rc) + return rc; + + signers_set->issuer_raw.p = *p; + + rc = mbedtls_asn1_get_tag(p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE); + if (rc) + return rc; + + rc = mbedtls_x509_get_name(p, *p + len, &signers_set->issuer); + if (rc) + return rc; + + signers_set->issuer_raw.len = *p - signers_set->issuer_raw.p; + + rc = mbedtls_x509_get_serial(p, end_set, &signers_set->serial); + if (rc) + return rc; + + rc = pkcs7_get_digest_algorithm(p, end_set, + &signers_set->alg_identifier); + if (rc) { + printf("error getting digest algorithms\n"); + return rc; + } + + rc = pkcs7_get_digest_algorithm(p, end_set, + &signers_set->sig_alg_identifier); + if (rc) { + printf("error getting signature digest algorithms\n"); + return rc; + } + + rc = pkcs7_get_signature(p, end, &signers_set->sig); + signers_set->next = NULL; + + return rc; +} + +/** + * 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, + struct pkcs7_signed_data *signed_data) +{ + unsigned char *p = buf; + unsigned char *end = buf + buflen; + size_t len = 0; + size_t rc; + + rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE); + if (rc) + return rc; + + /* get version of signed data */ + rc = pkcs7_get_version(&p, end, &signed_data->version); + if (rc) + return rc; + printf("version is %d\n", signed_data->version); + + /* if version != 1, return invalid version */ + if (signed_data->version != 1) { + printf("invalid version\n"); + return PKCS7_UNSUPPORTED_VERSION; + } + + /* get digest algorithm */ + rc = pkcs7_get_digest_algorithm_set(&p, end, + &signed_data->digest_alg_identifiers); + if (rc) { + printf("error getting digest algorithms\n"); + return rc; + } + + if (signed_data->digest_alg_identifiers.len != strlen(PKCS7_SHA256_OID)) + return PKCS7_INVALID_VALUE; + + if (memcmp(signed_data->digest_alg_identifiers.p, PKCS7_SHA256_OID, + signed_data->digest_alg_identifiers.len)) { + printf("Digest Algorithm other than SHA256 is not supported\n"); + return PKCS7_UNSUPPORTED_DIGEST_ALGORITHM; + } + + /* do not expect any content */ + rc = pkcs7_get_content_info_type(&p, end, &signed_data->content.oid); + if (rc) + return rc; + + if (memcmp(signed_data->content.oid.p, PKCS7_DATA_OID, + signed_data->content.oid.len)) { + printf("Invalid PKCS7 data\n"); + return PKCS7_INVALID_VALUE; + } + + p = p + signed_data->content.oid.len; + + rc = pkcs7_get_next_content_len(&p, end, &len); + if (rc) + return rc; + + /* get certificates */ + printf("----Loading Signer's certificate----\n"); + printf("\n"); + + mbedtls_x509_crt_init(&signed_data->certs); + rc = pkcs7_get_certificates(&p, len, &signed_data->certs); + if (rc) + return rc; + + p = p + len; + + /* get signers info */ + printf("Loading signer's signature\n"); + rc = pkcs7_get_signers_info_set(&p, end, &signed_data->signers); + + return rc; +} + +void pkcs7_printf(const unsigned char *buf, size_t buflen) +{ + unsigned int i; + char *sbuf; + int j = 0; + + sbuf = malloc(buflen*2 + 1); + memset(sbuf, 0, buflen*2 + 1); + + for (i = 0; i < buflen; i++) + j += snprintf(sbuf+j, sizeof(sbuf), "%02x", buf[i]); + + printf("Length of sbuf is %lu\n", strlen(sbuf)); + printf("%s\n", sbuf); + printf("\n"); + + free(sbuf); +} + +int pkcs7_parse_message(const unsigned char *buf, const int buflen, + struct pkcs7 *pkcs7) +{ + unsigned char *start; + unsigned char *end; + size_t len = 0; + int rc; + + /* use internal buffer for parsing */ + start = (unsigned char *)buf; + end = start + buflen; + + rc = pkcs7_get_content_info_type(&start, end, &(pkcs7->content_type_oid)); + if (rc) + goto out; + + if (memcmp(pkcs7->content_type_oid.p, PKCS7_SIGNED_DATA_OID, + pkcs7->content_type_oid.len)) { + printf("PKCS7 is not the signed data\n"); + rc = PKCS7_UNSUPPORTED_CONTENT_TYPE; + goto out; + } + + printf("Content type is signedData, continue...\n"); + + start = start + pkcs7->content_type_oid.len; + + rc = pkcs7_get_next_content_len(&start, end, &len); + if (rc) + goto out; + + rc = pkcs7_get_signed_data(start, len, &(pkcs7->signed_data)); + if (rc) + goto out; + +out: + return rc; +}