Extend crypto SP to support signature verification

The UEFI service of SMM gateway needs pkcs7 signature verification
to authorize variable accesses. Instead of duplicating the mbedtls
entities, crypto SP will provide an interface to do the signature
verification.

Signed-off-by: Gabor Toth <gabor.toth2@arm.com>
Change-Id: I7b0472435ac1620c4fe42d0592e1c64faaf10df7
diff --git a/components/service/crypto/provider/crypto_provider.c b/components/service/crypto/provider/crypto_provider.c
index d1798d7..8992b93 100644
--- a/components/service/crypto/provider/crypto_provider.c
+++ b/components/service/crypto/provider/crypto_provider.c
@@ -1,8 +1,11 @@
 /*
- * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
+#include <mbedtls/build_info.h>
+#include <mbedtls/pkcs7.h>
+#include <mbedtls/x509_crt.h>
 #include <protocols/rpc/common/packed-c/status.h>
 #include <protocols/service/crypto/packed-c/opcodes.h>
 #include <psa/crypto.h>
@@ -26,24 +29,26 @@
 static rpc_status_t copy_key_handler(void *context, struct rpc_request *req);
 static rpc_status_t purge_key_handler(void *context, struct rpc_request *req);
 static rpc_status_t get_key_attributes_handler(void *context, struct rpc_request *req);
+static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_request *req);
 
 /* Handler mapping table for service */
 static const struct service_handler handler_table[] = {
-	{ TS_CRYPTO_OPCODE_GENERATE_KEY, generate_key_handler },
-	{ TS_CRYPTO_OPCODE_DESTROY_KEY, destroy_key_handler },
-	{ TS_CRYPTO_OPCODE_EXPORT_KEY, export_key_handler },
-	{ TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, export_public_key_handler },
-	{ TS_CRYPTO_OPCODE_IMPORT_KEY, import_key_handler },
-	{ TS_CRYPTO_OPCODE_SIGN_HASH, asymmetric_sign_handler },
-	{ TS_CRYPTO_OPCODE_VERIFY_HASH, asymmetric_verify_handler },
-	{ TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, asymmetric_decrypt_handler },
-	{ TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, asymmetric_encrypt_handler },
-	{ TS_CRYPTO_OPCODE_GENERATE_RANDOM, generate_random_handler },
-	{ TS_CRYPTO_OPCODE_COPY_KEY, copy_key_handler },
-	{ TS_CRYPTO_OPCODE_PURGE_KEY, purge_key_handler },
-	{ TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES, get_key_attributes_handler },
-	{ TS_CRYPTO_OPCODE_SIGN_MESSAGE, asymmetric_sign_handler },
-	{ TS_CRYPTO_OPCODE_VERIFY_MESSAGE, asymmetric_verify_handler },
+	{ TS_CRYPTO_OPCODE_GENERATE_KEY,           generate_key_handler },
+	{ TS_CRYPTO_OPCODE_DESTROY_KEY,            destroy_key_handler },
+	{ TS_CRYPTO_OPCODE_EXPORT_KEY,             export_key_handler },
+	{ TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY,      export_public_key_handler },
+	{ TS_CRYPTO_OPCODE_IMPORT_KEY,             import_key_handler },
+	{ TS_CRYPTO_OPCODE_SIGN_HASH,              asymmetric_sign_handler },
+	{ TS_CRYPTO_OPCODE_VERIFY_HASH,            asymmetric_verify_handler },
+	{ TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT,     asymmetric_decrypt_handler },
+	{ TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT,     asymmetric_encrypt_handler },
+	{ TS_CRYPTO_OPCODE_GENERATE_RANDOM,        generate_random_handler },
+	{ TS_CRYPTO_OPCODE_COPY_KEY,               copy_key_handler },
+	{ TS_CRYPTO_OPCODE_PURGE_KEY,              purge_key_handler },
+	{ TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES,     get_key_attributes_handler },
+	{ TS_CRYPTO_OPCODE_SIGN_MESSAGE,           asymmetric_sign_handler },
+	{ TS_CRYPTO_OPCODE_VERIFY_MESSAGE,         asymmetric_verify_handler },
+	{ TS_CRYPTO_OPCODE_VERIFY_PKCS7_SIGNATURE, verify_pkcs7_signature_handler },
 };
 
 struct rpc_service_interface *
@@ -595,3 +600,80 @@
 
 	return rpc_status;
 }
+
+static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_request *req)
+{
+	rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+	struct rpc_buffer *req_buf = &req->request;
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+
+	int mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+
+	uint8_t *signature_cert = NULL;
+	uint64_t signature_cert_len = 0;
+	uint8_t *hash = NULL;
+	uint64_t hash_len = 0;
+	uint8_t *public_key_cert = NULL;
+	uint64_t public_key_cert_len = 0;
+
+	if (serializer) {
+		/* First collect the lengths of the fields */
+		rpc_status = serializer->deserialize_verify_pkcs7_signature_req(
+			req_buf, NULL, &signature_cert_len, NULL, &hash_len, NULL,
+			&public_key_cert_len);
+
+		if (rpc_status == RPC_SUCCESS) {
+			/* Allocate the needed space and get the data */
+			signature_cert = (uint8_t *)malloc(signature_cert_len);
+			hash = (uint8_t *)malloc(hash_len);
+			public_key_cert = (uint8_t *)malloc(public_key_cert_len);
+
+			if (signature_cert && hash && public_key_cert) {
+				rpc_status = serializer->deserialize_verify_pkcs7_signature_req(
+					req_buf, signature_cert, &signature_cert_len, hash,
+					&hash_len, public_key_cert, &public_key_cert_len);
+			} else {
+				rpc_status = RPC_ERROR_RESOURCE_FAILURE;
+			}
+		}
+	}
+
+	if (rpc_status == RPC_SUCCESS) {
+		/* Parse the public key certificate */
+		mbedtls_x509_crt signer_certificate;
+
+		mbedtls_x509_crt_init(&signer_certificate);
+
+		mbedtls_status = mbedtls_x509_crt_parse_der(&signer_certificate, public_key_cert,
+							    public_key_cert_len);
+
+		if (mbedtls_status == 0) {
+			/* Parse the PKCS#7 DER encoded signature block */
+			mbedtls_pkcs7 pkcs7_structure;
+
+			mbedtls_pkcs7_init(&pkcs7_structure);
+
+			mbedtls_status = mbedtls_pkcs7_parse_der(&pkcs7_structure, signature_cert,
+								 signature_cert_len);
+
+			if (mbedtls_status == MBEDTLS_PKCS7_SIGNED_DATA) {
+				/* Verify hash against signed hash */
+				mbedtls_status = mbedtls_pkcs7_signed_hash_verify(
+					&pkcs7_structure, &signer_certificate, hash, hash_len);
+			}
+
+			mbedtls_pkcs7_free(&pkcs7_structure);
+		}
+
+		mbedtls_x509_crt_free(&signer_certificate);
+	}
+
+	free(signature_cert);
+	free(hash);
+	free(public_key_cert);
+
+	/* Provide the result of the verification */
+	req->service_status = mbedtls_status;
+
+	return rpc_status;
+}
diff --git a/components/service/crypto/provider/serializer/crypto_provider_serializer.h b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
index afc2f05..1a0ce3c 100644
--- a/components/service/crypto/provider/serializer/crypto_provider_serializer.h
+++ b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -118,6 +118,14 @@
 
 	rpc_status_t (*serialize_generate_random_resp)(struct rpc_buffer *resp_buf,
 						       const uint8_t *output, size_t output_len);
+
+	/* Operation: verify_pkcs7_signature */
+	rpc_status_t (*deserialize_verify_pkcs7_signature_req)(struct rpc_buffer *req_buf,
+							       uint8_t *signature_cert,
+							       uint64_t *signature_cert_len,
+							       uint8_t *hash, uint64_t *hash_len,
+							       uint8_t *public_key_cert,
+							       uint64_t *public_key_cert_len);
 };
 
 #endif /* CRYPTO_PROVIDER_SERIALIZER_H */
diff --git a/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
index 2ca39ea..f59173d 100644
--- a/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
+++ b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,7 @@
 #include <protocols/service/crypto/packed-c/purge_key.h>
 #include <protocols/service/crypto/packed-c/sign_hash.h>
 #include <protocols/service/crypto/packed-c/verify_hash.h>
+#include <protocols/service/crypto/packed-c/verify_pkcs7_signature.h>
 #include <psa/crypto.h>
 #include <stdlib.h>
 #include <string.h>
@@ -620,22 +621,89 @@
 	return rpc_status;
 }
 
+/* Operation: mbedtls_verify_pkcs7_signature */
+static rpc_status_t deserialize_verify_pkcs7_signature_req(
+	struct rpc_buffer *req_buf, uint8_t *signature_cert, uint64_t *signature_cert_len,
+	uint8_t *hash, uint64_t *hash_len, uint8_t *public_key_cert, uint64_t *public_key_cert_len)
+{
+	rpc_status_t rpc_status = RPC_ERROR_INVALID_REQUEST_BODY;
+
+	if (req_buf->data_length) {
+		struct tlv_const_iterator req_iter;
+		struct tlv_record decoded_record;
+
+		rpc_status = RPC_SUCCESS;
+
+		tlv_const_iterator_begin(&req_iter, (uint8_t *)req_buf->data, req_buf->data_length);
+
+		if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_SIGNATURE,
+				    &decoded_record)) {
+			*signature_cert_len = decoded_record.length;
+
+			if (signature_cert)
+				memcpy(signature_cert, decoded_record.value, decoded_record.length);
+		} else {
+			/* Default to a zero length */
+			*signature_cert_len = 0;
+		}
+
+		if (tlv_find_decode(&req_iter, TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_HASH,
+				    &decoded_record)) {
+			*hash_len = decoded_record.length;
+
+			if (hash)
+				memcpy(hash, decoded_record.value, decoded_record.length);
+		} else {
+			/* Default to a zero length */
+			*hash_len = 0;
+		}
+
+		if (tlv_find_decode(&req_iter,
+				    TS_CRYPTO_VERIFY_PKCS7_SIGNATURE_IN_TAG_PUBLIC_KEY_CERT,
+				    &decoded_record)) {
+			*public_key_cert_len = decoded_record.length;
+
+			if (public_key_cert)
+				memcpy(public_key_cert, decoded_record.value,
+				       decoded_record.length);
+		} else {
+			/* Default to a zero length */
+			*public_key_cert_len = 0;
+		}
+	}
+
+	return rpc_status;
+}
+
 /* Singleton method to provide access to the serializer instance */
 const struct crypto_provider_serializer *packedc_crypto_provider_serializer_instance(void)
 {
 	static const struct crypto_provider_serializer instance = {
-		max_deserialised_parameter_size,    deserialize_generate_key_req,
-		serialize_generate_key_resp,	    deserialize_destroy_key_req,
-		deserialize_export_key_req,	    serialize_export_key_resp,
-		deserialize_export_public_key_req,  serialize_export_public_key_resp,
-		deserialize_import_key_req,	    serialize_import_key_resp,
-		deserialize_copy_key_req,	    serialize_copy_key_resp,
-		deserialize_purge_key_req,	    deserialize_get_key_attributes_req,
-		serialize_get_key_attributes_resp,  deserialize_asymmetric_sign_req,
-		serialize_asymmetric_sign_resp,	    deserialize_asymmetric_verify_req,
-		deserialize_asymmetric_decrypt_req, serialize_asymmetric_decrypt_resp,
-		deserialize_asymmetric_encrypt_req, serialize_asymmetric_encrypt_resp,
-		deserialize_generate_random_req,    serialize_generate_random_resp
+		max_deserialised_parameter_size,
+		deserialize_generate_key_req,
+		serialize_generate_key_resp,
+		deserialize_destroy_key_req,
+		deserialize_export_key_req,
+		serialize_export_key_resp,
+		deserialize_export_public_key_req,
+		serialize_export_public_key_resp,
+		deserialize_import_key_req,
+		serialize_import_key_resp,
+		deserialize_copy_key_req,
+		serialize_copy_key_resp,
+		deserialize_purge_key_req,
+		deserialize_get_key_attributes_req,
+		serialize_get_key_attributes_resp,
+		deserialize_asymmetric_sign_req,
+		serialize_asymmetric_sign_resp,
+		deserialize_asymmetric_verify_req,
+		deserialize_asymmetric_decrypt_req,
+		serialize_asymmetric_decrypt_resp,
+		deserialize_asymmetric_encrypt_req,
+		serialize_asymmetric_encrypt_resp,
+		deserialize_generate_random_req,
+		serialize_generate_random_resp,
+		deserialize_verify_pkcs7_signature_req,
 	};
 
 	return &instance;