[Skiboot] [PATCH 2/3] crypto: add pkcs7 parser

Eric Richter erichte at linux.ibm.com
Fri Jul 19 07:29:48 AEST 2019


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

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 <nayna at linux.ibm.com>
Signed-off-by: Eric Richter <erichte at linux.ibm.com>
---
 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mbedtls/asn1.h>
+#include <mbedtls/config.h>
+#include <mbedtls/x509.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/x509_crl.h>
+
+/** 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 <string.h>
+#include <ccan/endian/endian.h>
+#include <pkcs7.h>
+
+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;
+}
-- 
2.20.1



More information about the Skiboot mailing list