Support authentication of uefi priv. variables
To authenticate private uefi variables a fingerprint has to be
calculated based on the common name of the signing certificate's
Subject field and the tbsCertificate of the top-level issuer
certificate.
These variables have a public key certificate attached so the
verify_pkcs7_signature_handler is also reorganized to be able
to verify its own signature with its internal public key.
This commit implements the changes needed for the described
functionality.
Signed-off-by: Gabor Toth <gabor.toth2@arm.com>
Change-Id: Ida22977f3ef1a730ea95834ca5c9f9e4ed78d927
diff --git a/components/service/crypto/provider/crypto_provider.c b/components/service/crypto/provider/crypto_provider.c
index 9cd5208..f94b47e 100644
--- a/components/service/crypto/provider/crypto_provider.c
+++ b/components/service/crypto/provider/crypto_provider.c
@@ -3,16 +3,23 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <protocols/common/efi/efi_status.h>
#include <protocols/rpc/common/packed-c/status.h>
#include <protocols/service/crypto/packed-c/opcodes.h>
#include <service/crypto/backend/crypto_backend.h>
#include <service/crypto/provider/crypto_provider.h>
+#include <compiler.h>
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include "crypto_partition.h"
#include "crypto_uuid.h"
+#if defined(MBEDTLS_PKCS7_C) && defined(MBEDTLS_X509_CRT_PARSE_C)
+#include "common/mbedtls/mbedtls_utils.h"
+#endif
+
/* Service request handlers */
static rpc_status_t generate_key_handler(void *context, struct rpc_request *req);
static rpc_status_t destroy_key_handler(void *context, struct rpc_request *req);
@@ -28,25 +35,27 @@
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);
+static rpc_status_t get_uefi_priv_auth_var_fingerprint_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_VERIFY_PKCS7_SIGNATURE, verify_pkcs7_signature_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 },
+ { TS_CRYPTO_OPCODE_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT, get_uefi_priv_auth_var_fingerprint_handler },
};
struct rpc_service_interface *
@@ -664,33 +673,44 @@
}
if (rpc_status == RPC_SUCCESS) {
- /* Parse the public key certificate */
- mbedtls_x509_crt signer_certificate;
+ /* Parse the PKCS#7 DER encoded signature block */
+ mbedtls_pkcs7 pkcs7_structure;
- mbedtls_x509_crt_init(&signer_certificate);
+ mbedtls_pkcs7_init(&pkcs7_structure);
- mbedtls_status = mbedtls_x509_crt_parse_der(&signer_certificate, public_key_cert,
- public_key_cert_len);
+ mbedtls_status = mbedtls_pkcs7_parse_der(&pkcs7_structure, signature_cert,
+ signature_cert_len);
- if (mbedtls_status == 0) {
- /* Parse the PKCS#7 DER encoded signature block */
- mbedtls_pkcs7 pkcs7_structure;
+ if (mbedtls_status == MBEDTLS_PKCS7_SIGNED_DATA) {
- mbedtls_pkcs7_init(&pkcs7_structure);
+ /*
+ * If a separate public key is provided, verify the signature with it,
+ * else use the key from the pkcs7 signature structure, because it is
+ * a self-signed certificate.
+ */
+ if(public_key_cert_len) {
+ /* Parse the public key certificate */
+ mbedtls_x509_crt signer_certificate;
- mbedtls_status = mbedtls_pkcs7_parse_der(&pkcs7_structure, signature_cert,
- signature_cert_len);
+ mbedtls_x509_crt_init(&signer_certificate);
- if (mbedtls_status == MBEDTLS_PKCS7_SIGNED_DATA) {
- /* Verify hash against signed hash */
+ mbedtls_status = mbedtls_x509_crt_parse_der(&signer_certificate, public_key_cert,
+ public_key_cert_len);
+
+ if (mbedtls_status == 0) {
+ /* Verify hash against signed hash */
+ mbedtls_status = mbedtls_pkcs7_signed_hash_verify(
+ &pkcs7_structure, &signer_certificate, hash, hash_len);
+ }
+
+ mbedtls_x509_crt_free(&signer_certificate);
+ } else {
mbedtls_status = mbedtls_pkcs7_signed_hash_verify(
- &pkcs7_structure, &signer_certificate, hash, hash_len);
+ &pkcs7_structure, &pkcs7_structure.private_signed_data.private_certs, hash, hash_len);
}
-
- mbedtls_pkcs7_free(&pkcs7_structure);
}
- mbedtls_x509_crt_free(&signer_certificate);
+ mbedtls_pkcs7_free(&pkcs7_structure);
}
free(signature_cert);
@@ -702,6 +722,111 @@
return rpc_status;
}
+
+static rpc_status_t get_uefi_priv_auth_var_fingerprint_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;
+
+ if (serializer) {
+ /* First collect the lengths of the field */
+ rpc_status = serializer->deserialize_get_uefi_priv_auth_var_fingerprint_req(
+ req_buf, NULL, &signature_cert_len);
+
+ if (rpc_status == RPC_SUCCESS) {
+ /* Allocate the needed space and get the data */
+ signature_cert = (uint8_t *)malloc(signature_cert_len);
+
+ if (signature_cert) {
+ rpc_status = serializer->deserialize_get_uefi_priv_auth_var_fingerprint_req(
+ req_buf, signature_cert, &signature_cert_len);
+ } else {
+ rpc_status = RPC_ERROR_RESOURCE_FAILURE;
+ }
+ }
+ }
+
+ if (rpc_status == RPC_SUCCESS) {
+ /* 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) {
+
+ uint8_t output_buffer[PSA_HASH_MAX_SIZE] = { 0 };
+ size_t __maybe_unused output_size = 0;
+ const mbedtls_asn1_buf *signerCertCN = NULL;
+ const mbedtls_x509_crt *topLevelCert = &pkcs7_structure.private_signed_data.private_certs;
+ const mbedtls_x509_buf *toplevelCertTbs = NULL;
+ struct rpc_buffer *resp_buf = &req->response;;
+ psa_hash_operation_t op = PSA_HASH_OPERATION_INIT;
+
+ /* Find common name field of the signing certificate, which is the first in the chain */
+ signerCertCN = findCommonName(&topLevelCert->subject);
+ if (!signerCertCN) {
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+ goto end;
+ }
+
+ /* Get the TopLevel certificate which is the last in the chain */
+ while(topLevelCert->next)
+ topLevelCert = topLevelCert->next;
+ toplevelCertTbs = &topLevelCert->tbs;
+
+ /* Hash the data to create the fingerprint */
+ op = psa_hash_operation_init();
+
+ if (psa_hash_setup(&op, PSA_ALG_SHA_256) != PSA_SUCCESS) {
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+ goto end;
+ }
+
+ if (psa_hash_update(&op, signerCertCN->p, signerCertCN->len)) {
+ psa_hash_abort(&op);
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+ goto end;
+ }
+
+ if (psa_hash_update(&op, toplevelCertTbs->p, toplevelCertTbs->len)) {
+ psa_hash_abort(&op);
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+ goto end;
+ }
+
+ if (psa_hash_finish(&op, (uint8_t*)&output_buffer, PSA_HASH_MAX_SIZE, &output_size)) {
+ psa_hash_abort(&op);
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+ goto end;
+ }
+
+ /* Clear the remaining part of the buffer for consistency */
+ memset(&output_buffer[output_size], 0, PSA_HASH_MAX_SIZE - output_size);
+
+ rpc_status = serializer->serialize_get_uefi_priv_auth_var_fingerprint_resp(
+ resp_buf, (uint8_t*)&output_buffer);
+ }
+
+end:
+ mbedtls_pkcs7_free(&pkcs7_structure);
+ }
+
+ free(signature_cert);
+
+ /* Provide the result of the verification */
+ req->service_status = (mbedtls_status == MBEDTLS_PKCS7_SIGNED_DATA) ? EFI_SUCCESS : EFI_COMPROMISED_DATA;
+
+ return rpc_status;
+}
#else
static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_request *req)
{
@@ -710,4 +835,12 @@
return RPC_ERROR_INTERNAL;
}
+
+static rpc_status_t get_uefi_priv_auth_var_fingerprint_handler(void *context, struct rpc_request *req)
+{
+ (void)context;
+ (void)req;
+
+ return RPC_ERROR_INTERNAL;
+}
#endif
diff --git a/components/service/crypto/provider/serializer/crypto_provider_serializer.h b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
index bd5336c..2b965af 100644
--- a/components/service/crypto/provider/serializer/crypto_provider_serializer.h
+++ b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
@@ -126,6 +126,14 @@
uint8_t *hash, uint64_t *hash_len,
uint8_t *public_key_cert,
uint64_t *public_key_cert_len);
+
+ /* Operation: get_uefi_priv_auth_var_fingerprintentifier */
+ rpc_status_t (*deserialize_get_uefi_priv_auth_var_fingerprint_req)(const struct rpc_buffer *req_buf,
+ uint8_t *signed_data,
+ uint64_t *signed_data_len);
+
+ rpc_status_t (*serialize_get_uefi_priv_auth_var_fingerprint_resp)(struct rpc_buffer *resp_buf,
+ const uint8_t *output);
};
#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 050ef2f..89e07e2 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
@@ -22,6 +22,7 @@
#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 <protocols/service/crypto/packed-c/get_uefi_priv_auth_var_fingerprint.h>
#include <service/crypto/backend/crypto_backend.h>
#include <stdlib.h>
#include <string.h>
@@ -675,6 +676,57 @@
return rpc_status;
}
+/* Operation: get_uefi_priv_auth_var_fingerprintentifier */
+static rpc_status_t deserialize_get_uefi_priv_auth_var_fingerprint_req(const struct rpc_buffer *req_buf,
+ uint8_t *signed_data,
+ uint64_t *signed_data_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_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_IN_TAG_SIGNATURE,
+ &decoded_record)) {
+ *signed_data_len = decoded_record.length;
+
+ if (signed_data)
+ memcpy(signed_data, decoded_record.value, decoded_record.length);
+ } else {
+ /* Default to a zero length */
+ *signed_data_len = 0;
+ }
+ }
+
+ return rpc_status;
+}
+
+static rpc_status_t serialize_get_uefi_priv_auth_var_fingerprint_resp(struct rpc_buffer *resp_buf,
+ const uint8_t *output)
+{
+ rpc_status_t rpc_status = RPC_ERROR_INTERNAL;
+ struct tlv_iterator resp_iter;
+ struct tlv_record out_record;
+
+ out_record.tag = TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_OUT_TAG_IDENTIFIER;
+ out_record.length = PSA_HASH_MAX_SIZE;
+ out_record.value = output;
+
+ tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+ if (tlv_encode(&resp_iter, &out_record)) {
+ resp_buf->data_length = tlv_required_space(PSA_HASH_MAX_SIZE);
+ rpc_status = RPC_SUCCESS;
+ }
+
+ return rpc_status;
+}
+
/* Singleton method to provide access to the serializer instance */
const struct crypto_provider_serializer *packedc_crypto_provider_serializer_instance(void)
{
@@ -704,6 +756,8 @@
deserialize_generate_random_req,
serialize_generate_random_resp,
deserialize_verify_pkcs7_signature_req,
+ deserialize_get_uefi_priv_auth_var_fingerprint_req,
+ serialize_get_uefi_priv_auth_var_fingerprint_resp
};
return &instance;