mirror of
https://git.yoctoproject.org/meta-arm
synced 2026-01-12 03:10:15 +00:00
arm-bsp/trusted-services: corstone1000: add fixes for private auth vars
Signed-off-by: Bence Balogh <bence.balogh@arm.com> Signed-off-by: Jon Mason <jon.mason@arm.com>
This commit is contained in:
@@ -0,0 +1,758 @@
|
||||
From 370811420cfa1c14146f45de308bbccf70408eb8 Mon Sep 17 00:00:00 2001
|
||||
From: Gabor Toth <gabor.toth2@arm.com>
|
||||
Date: Fri, 5 Apr 2024 11:19:37 +0200
|
||||
Subject: [PATCH] Provide crypto api to create uefi priv var fingerprint
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add new call to the crypto backend to calculate a hash of the common
|
||||
name of the signing certificate’s Subject and the tbsCertificate
|
||||
of the top-level issuer certificate.
|
||||
|
||||
Signed-off-by: Gabor Toth <gabor.toth2@arm.com>
|
||||
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TS/trusted-services/+/27953]
|
||||
---
|
||||
.../client/caller/packed-c/crypto_caller.h | 1 +
|
||||
...aller_get_uefi_priv_auth_var_fingerprint.h | 90 ++++++++
|
||||
.../packed-c/packedc_crypto_client.cpp | 8 +
|
||||
.../protocol/packed-c/packedc_crypto_client.h | 4 +
|
||||
.../service/crypto/client/psa/component.cmake | 1 +
|
||||
.../service/crypto/client/psa/crypto_client.h | 5 +
|
||||
.../psa/get_uefi_priv_auth_var_fingerprint.c | 21 ++
|
||||
.../service/crypto/provider/crypto_provider.c | 212 +++++++++++++++---
|
||||
.../serializer/crypto_provider_serializer.h | 8 +
|
||||
.../packedc_crypto_provider_serializer.c | 54 +++++
|
||||
.../backend/direct/uefi_direct_backend.c | 90 ++++++++
|
||||
deployments/smm-gateway/smm-gateway.cmake | 5 +
|
||||
.../get_uefi_priv_auth_var_fingerprint.h | 21 ++
|
||||
protocols/service/crypto/packed-c/opcodes.h | 1 +
|
||||
14 files changed, 488 insertions(+), 33 deletions(-)
|
||||
create mode 100644 components/service/crypto/client/caller/packed-c/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
|
||||
create mode 100644 components/service/crypto/client/psa/get_uefi_priv_auth_var_fingerprint.c
|
||||
create mode 100644 protocols/service/crypto/packed-c/get_uefi_priv_auth_var_fingerprint.h
|
||||
|
||||
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller.h b/components/service/crypto/client/caller/packed-c/crypto_caller.h
|
||||
index d834bc207..d5dd0f70d 100644
|
||||
--- a/components/service/crypto/client/caller/packed-c/crypto_caller.h
|
||||
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller.h
|
||||
@@ -31,5 +31,6 @@
|
||||
#include "crypto_caller_sign_hash.h"
|
||||
#include "crypto_caller_verify_hash.h"
|
||||
#include "crypto_caller_verify_pkcs7_signature.h"
|
||||
+#include "crypto_caller_get_uefi_priv_auth_var_fingerprint.h"
|
||||
|
||||
#endif /* PACKEDC_CRYPTO_CALLER_H */
|
||||
diff --git a/components/service/crypto/client/caller/packed-c/crypto_caller_get_uefi_priv_auth_var_fingerprint.h b/components/service/crypto/client/caller/packed-c/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
|
||||
new file mode 100644
|
||||
index 000000000..d3446e445
|
||||
--- /dev/null
|
||||
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
|
||||
@@ -0,0 +1,90 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: BSD-3-Clause
|
||||
+ */
|
||||
+
|
||||
+#ifndef PACKEDC_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
|
||||
+#define PACKEDC_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
|
||||
+
|
||||
+#include <common/tlv/tlv.h>
|
||||
+#include <protocols/common/efi/efi_status.h>
|
||||
+#include <protocols/rpc/common/packed-c/status.h>
|
||||
+#include <protocols/service/crypto/packed-c/opcodes.h>
|
||||
+#include <protocols/service/crypto/packed-c/get_uefi_priv_auth_var_fingerprint.h>
|
||||
+#include <service/common/client/service_client.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#ifdef __cplusplus
|
||||
+extern "C" {
|
||||
+#endif
|
||||
+
|
||||
+static inline int crypto_caller_get_uefi_priv_auth_var_fingerprint(struct service_client *context,
|
||||
+ const uint8_t *signature_cert,
|
||||
+ uint64_t signature_cert_len,
|
||||
+ uint8_t *output)
|
||||
+{
|
||||
+ efi_status_t efi_status = EFI_SUCCESS;
|
||||
+ size_t req_len = 0;
|
||||
+
|
||||
+ if (signature_cert_len > UINT16_MAX)
|
||||
+ return RPC_ERROR_INVALID_VALUE;
|
||||
+
|
||||
+ struct tlv_record signature_record = {
|
||||
+ .tag = TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_IN_TAG_SIGNATURE,
|
||||
+ .length = (uint16_t)signature_cert_len,
|
||||
+ .value = signature_cert
|
||||
+ };
|
||||
+
|
||||
+ req_len += tlv_required_space(signature_record.length);
|
||||
+
|
||||
+ rpc_call_handle call_handle;
|
||||
+ uint8_t *req_buf;
|
||||
+
|
||||
+ call_handle = rpc_caller_session_begin(context->session, &req_buf, req_len, 0);
|
||||
+
|
||||
+ if (call_handle) {
|
||||
+ uint8_t *resp_buf;
|
||||
+ size_t resp_len;
|
||||
+ service_status_t service_status;
|
||||
+ struct tlv_iterator req_iter;
|
||||
+
|
||||
+ tlv_iterator_begin(&req_iter, req_buf, req_len);
|
||||
+ tlv_encode(&req_iter, &signature_record);
|
||||
+
|
||||
+ context->rpc_status = rpc_caller_session_invoke(
|
||||
+ call_handle, TS_CRYPTO_OPCODE_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT, &resp_buf, &resp_len,
|
||||
+ &service_status);
|
||||
+
|
||||
+ if (context->rpc_status == RPC_SUCCESS) {
|
||||
+
|
||||
+ if (service_status == EFI_SUCCESS) {
|
||||
+
|
||||
+ struct tlv_const_iterator resp_iter;
|
||||
+ struct tlv_record decoded_record;
|
||||
+ tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
|
||||
+
|
||||
+ if (tlv_find_decode(&resp_iter,
|
||||
+ TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_OUT_TAG_IDENTIFIER, &decoded_record)) {
|
||||
+
|
||||
+ memcpy(output, decoded_record.value, PSA_HASH_MAX_SIZE);
|
||||
+ }
|
||||
+ else {
|
||||
+ /* Mandatory response parameter missing */
|
||||
+ efi_status = EFI_INVALID_PARAMETER;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ rpc_caller_session_end(call_handle);
|
||||
+ }
|
||||
+
|
||||
+ return efi_status;
|
||||
+}
|
||||
+
|
||||
+#ifdef __cplusplus
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+#endif /* PACKEDC_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H */
|
||||
diff --git a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
|
||||
index aaa71f0c8..e0f6a15a8 100644
|
||||
--- a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
|
||||
+++ b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.cpp
|
||||
@@ -428,3 +428,11 @@ int packedc_crypto_client::verify_pkcs7_signature(const uint8_t *signature_cert,
|
||||
hash, hash_len, public_key_cert,
|
||||
public_key_cert_len);
|
||||
}
|
||||
+
|
||||
+int packedc_crypto_client::get_uefi_priv_auth_var_fingerprint(const uint8_t *signature_cert,
|
||||
+ uint64_t signature_cert_len,
|
||||
+ uint8_t *output)
|
||||
+{
|
||||
+ return crypto_caller_get_uefi_priv_auth_var_fingerprint(&m_client, signature_cert, signature_cert_len,
|
||||
+ output);
|
||||
+}
|
||||
diff --git a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
|
||||
index 8d4f60cf9..ec6c51c7f 100644
|
||||
--- a/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
|
||||
+++ b/components/service/crypto/client/cpp/protocol/packed-c/packedc_crypto_client.h
|
||||
@@ -236,6 +236,10 @@ public:
|
||||
int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
|
||||
const uint8_t *hash, uint64_t hash_len,
|
||||
const uint8_t *public_key_cert, uint64_t public_key_cert_len);
|
||||
+
|
||||
+ int get_uefi_priv_auth_var_fingerprint(const uint8_t *signature_cert,
|
||||
+ uint64_t signature_cert_len,
|
||||
+ uint8_t *output);
|
||||
};
|
||||
|
||||
#endif /* PACKEDC_CRYPTO_CLIENT_H */
|
||||
diff --git a/components/service/crypto/client/psa/component.cmake b/components/service/crypto/client/psa/component.cmake
|
||||
index 359db3b4a..5bee0c652 100644
|
||||
--- a/components/service/crypto/client/psa/component.cmake
|
||||
+++ b/components/service/crypto/client/psa/component.cmake
|
||||
@@ -32,4 +32,5 @@ target_sources(${TGT} PRIVATE
|
||||
"${CMAKE_CURRENT_LIST_DIR}/psa_sign_message.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/psa_verify_message.c"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/verify_pkcs7_signature.c"
|
||||
+ "${CMAKE_CURRENT_LIST_DIR}/get_uefi_priv_auth_var_fingerprint.c"
|
||||
)
|
||||
diff --git a/components/service/crypto/client/psa/crypto_client.h b/components/service/crypto/client/psa/crypto_client.h
|
||||
index 4b59bbe32..af04df11e 100644
|
||||
--- a/components/service/crypto/client/psa/crypto_client.h
|
||||
+++ b/components/service/crypto/client/psa/crypto_client.h
|
||||
@@ -7,10 +7,15 @@
|
||||
#ifndef CRYPTO_CLIENT_H
|
||||
#define CRYPTO_CLIENT_H
|
||||
|
||||
+#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
|
||||
const uint8_t *hash, uint64_t hash_len, const uint8_t *public_key_cert,
|
||||
uint64_t public_key_cert_len);
|
||||
|
||||
+int get_uefi_priv_auth_var_fingerprint_handler(const uint8_t *signature_cert,
|
||||
+ uint64_t signature_cert_len,
|
||||
+ uint8_t *output);
|
||||
+
|
||||
#endif /* CRYPTO_CLIENT_H */
|
||||
diff --git a/components/service/crypto/client/psa/get_uefi_priv_auth_var_fingerprint.c b/components/service/crypto/client/psa/get_uefi_priv_auth_var_fingerprint.c
|
||||
new file mode 100644
|
||||
index 000000000..702aaa0c4
|
||||
--- /dev/null
|
||||
+++ b/components/service/crypto/client/psa/get_uefi_priv_auth_var_fingerprint.c
|
||||
@@ -0,0 +1,21 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: BSD-3-Clause
|
||||
+ */
|
||||
+
|
||||
+#include "crypto_caller_selector.h"
|
||||
+#include "crypto_client.h"
|
||||
+#include "psa_crypto_client.h"
|
||||
+
|
||||
+int get_uefi_priv_auth_var_fingerprint_handler(const uint8_t *signature_cert,
|
||||
+ uint64_t signature_cert_len,
|
||||
+ uint8_t *output)
|
||||
+{
|
||||
+ if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
|
||||
+ return psa_crypto_client_instance.init_status;
|
||||
+
|
||||
+ return crypto_caller_get_uefi_priv_auth_var_fingerprint(&psa_crypto_client_instance.base,
|
||||
+ signature_cert, signature_cert_len,
|
||||
+ output);
|
||||
+}
|
||||
diff --git a/components/service/crypto/provider/crypto_provider.c b/components/service/crypto/provider/crypto_provider.c
|
||||
index 9cd520859..4535d6dbe 100644
|
||||
--- a/components/service/crypto/provider/crypto_provider.c
|
||||
+++ b/components/service/crypto/provider/crypto_provider.c
|
||||
@@ -3,12 +3,15 @@
|
||||
*
|
||||
* 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"
|
||||
@@ -28,25 +31,27 @@ 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);
|
||||
+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 +669,44 @@ static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_req
|
||||
}
|
||||
|
||||
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 +718,128 @@ static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_req
|
||||
|
||||
return rpc_status;
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * Official value: http://www.oid-info.com/get/2.5.4.3
|
||||
+ * Hex converter: https://misc.daniel-marschall.de/asn.1/oid-converter/online.php
|
||||
+ */
|
||||
+static const mbedtls_asn1_buf* findCommonName(const mbedtls_x509_name *name)
|
||||
+{
|
||||
+ uint8_t CN_oid_tag = 0x06;
|
||||
+ uint8_t CN_oid_len = 0x03;
|
||||
+ uint8_t CN_oid_val[3] = {0x55, 0x04, 0x03};
|
||||
+
|
||||
+ while (name)
|
||||
+ {
|
||||
+ if (name->oid.tag == CN_oid_tag && name->oid.len == CN_oid_len) {
|
||||
+ if (name->oid.p != NULL) {
|
||||
+ if (!memcmp(name->oid.p, CN_oid_val, CN_oid_len))
|
||||
+ return &name->val;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ name = name->next;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+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;
|
||||
+
|
||||
+ /* 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;
|
||||
+
|
||||
+ if (psa_hash_update(&op, signerCertCN->p, signerCertCN->len)) {
|
||||
+ psa_hash_abort(&op);
|
||||
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
|
||||
+ }
|
||||
+
|
||||
+ if (psa_hash_update(&op, toplevelCertTbs->p, toplevelCertTbs->len)) {
|
||||
+ psa_hash_abort(&op);
|
||||
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ /* 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);
|
||||
+ }
|
||||
+
|
||||
+ 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 +848,12 @@ static rpc_status_t verify_pkcs7_signature_handler(void *context, struct rpc_req
|
||||
|
||||
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 bd5336c3d..2b965afdb 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 @@ struct crypto_provider_serializer {
|
||||
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 050ef2f7d..89e07e2c8 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 @@ static rpc_status_t deserialize_verify_pkcs7_signature_req(
|
||||
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 @@ const struct crypto_provider_serializer *packedc_crypto_provider_serializer_inst
|
||||
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;
|
||||
diff --git a/components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c b/components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c
|
||||
index bf978c5dd..c7ca07254 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c
|
||||
+++ b/components/service/uefi/smm_variable/backend/direct/uefi_direct_backend.c
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <mbedtls/pkcs7.h>
|
||||
#include <mbedtls/x509_crt.h>
|
||||
#include <stdint.h>
|
||||
+#include <string.h>
|
||||
+#include <compiler.h>
|
||||
|
||||
int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cert_len,
|
||||
const uint8_t *hash, uint64_t hash_len, const uint8_t *public_key_cert,
|
||||
@@ -46,3 +48,91 @@ int verify_pkcs7_signature(const uint8_t *signature_cert, uint64_t signature_cer
|
||||
|
||||
return mbedtls_status;
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * Official value: http://www.oid-info.com/get/2.5.4.3
|
||||
+ * Hex converter: https://misc.daniel-marschall.de/asn.1/oid-converter/online.php
|
||||
+ */
|
||||
+static const mbedtls_asn1_buf* findCommonName(const mbedtls_x509_name *name)
|
||||
+{
|
||||
+ uint8_t CN_oid_tag = 0x06;
|
||||
+ uint8_t CN_oid_len = 0x03;
|
||||
+ uint8_t CN_oid_val[3] = {0x55, 0x04, 0x03};
|
||||
+
|
||||
+ while (name)
|
||||
+ {
|
||||
+ if (name->oid.tag == CN_oid_tag && name->oid.len == CN_oid_len) {
|
||||
+ if (name->oid.p != NULL) {
|
||||
+ if (!memcmp(name->oid.p, CN_oid_val, CN_oid_len))
|
||||
+ return &name->val;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ name = name->next;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+int get_uefi_priv_auth_var_fingerprint_handler(const uint8_t *signature_cert,
|
||||
+ uint64_t signature_cert_len,
|
||||
+ uint8_t *output)
|
||||
+{
|
||||
+ int mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
|
||||
+
|
||||
+ /* 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;
|
||||
+ 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;
|
||||
+
|
||||
+ /* 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;
|
||||
+
|
||||
+ if (psa_hash_update(&op, signerCertCN->p, signerCertCN->len)) {
|
||||
+ psa_hash_abort(&op);
|
||||
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
|
||||
+ }
|
||||
+
|
||||
+ if (psa_hash_update(&op, toplevelCertTbs->p, toplevelCertTbs->len)) {
|
||||
+ psa_hash_abort(&op);
|
||||
+ mbedtls_status = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ /* Clear the remaining part of the buffer for consistency */
|
||||
+ memset(&output_buffer[output_size], 0, PSA_HASH_MAX_SIZE - output_size);
|
||||
+ }
|
||||
+
|
||||
+ mbedtls_pkcs7_free(&pkcs7_structure);
|
||||
+
|
||||
+ return mbedtls_status;
|
||||
+}
|
||||
diff --git a/deployments/smm-gateway/smm-gateway.cmake b/deployments/smm-gateway/smm-gateway.cmake
|
||||
index e5ee03b60..de519892d 100644
|
||||
--- a/deployments/smm-gateway/smm-gateway.cmake
|
||||
+++ b/deployments/smm-gateway/smm-gateway.cmake
|
||||
@@ -17,6 +17,11 @@ include(${TS_ROOT}/external/MbedTLS/MbedTLS.cmake)
|
||||
target_link_libraries(smm-gateway PRIVATE MbedTLS::mbedcrypto)
|
||||
target_link_libraries(smm-gateway PRIVATE MbedTLS::mbedx509)
|
||||
|
||||
+# Pass the location of the mbedtls config file to C preprocessor.
|
||||
+target_compile_definitions(smm-gateway PRIVATE
|
||||
+ MBEDTLS_USER_CONFIG_FILE="${MBEDTLS_USER_CONFIG_FILE}"
|
||||
+)
|
||||
+
|
||||
target_compile_definitions(smm-gateway PRIVATE
|
||||
-DUEFI_INTERNAL_CRYPTO
|
||||
)
|
||||
diff --git a/protocols/service/crypto/packed-c/get_uefi_priv_auth_var_fingerprint.h b/protocols/service/crypto/packed-c/get_uefi_priv_auth_var_fingerprint.h
|
||||
new file mode 100644
|
||||
index 000000000..29964b33c
|
||||
--- /dev/null
|
||||
+++ b/protocols/service/crypto/packed-c/get_uefi_priv_auth_var_fingerprint.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
|
||||
+ * SPDX-License-Identifier: BSD-3-Clause
|
||||
+ */
|
||||
+
|
||||
+#ifndef TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
|
||||
+#define TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+/* Variable length output parameter tags */
|
||||
+enum {
|
||||
+ TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_OUT_TAG_IDENTIFIER = 1,
|
||||
+};
|
||||
+
|
||||
+/* Variable length input parameter tags */
|
||||
+enum {
|
||||
+ TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_IN_TAG_SIGNATURE = 1,
|
||||
+};
|
||||
+
|
||||
+#endif /* TS_CRYPTO_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H */
|
||||
diff --git a/protocols/service/crypto/packed-c/opcodes.h b/protocols/service/crypto/packed-c/opcodes.h
|
||||
index 35b81599b..8bc2b49b0 100644
|
||||
--- a/protocols/service/crypto/packed-c/opcodes.h
|
||||
+++ b/protocols/service/crypto/packed-c/opcodes.h
|
||||
@@ -28,6 +28,7 @@
|
||||
#define TS_CRYPTO_OPCODE_SIGN_MESSAGE (TS_CRYPTO_OPCODE_BASE + 16)
|
||||
#define TS_CRYPTO_OPCODE_VERIFY_MESSAGE (TS_CRYPTO_OPCODE_BASE + 17)
|
||||
#define TS_CRYPTO_OPCODE_VERIFY_PKCS7_SIGNATURE (TS_CRYPTO_OPCODE_BASE + 18)
|
||||
+#define TS_CRYPTO_OPCODE_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT (TS_CRYPTO_OPCODE_BASE + 19)
|
||||
|
||||
/* Hash operations */
|
||||
#define TS_CRYPTO_OPCODE_HASH_BASE (0x0200)
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
From 5b418e141aadcb6604406f75e156317bd143d898 Mon Sep 17 00:00:00 2001
|
||||
From: Gabor Toth <gabor.toth2@arm.com>
|
||||
Date: Fri, 5 Apr 2024 11:27:15 +0200
|
||||
Subject: [PATCH 1/3] Add timestamp validation for uefi variables
|
||||
|
||||
Return failure if uefi variable creation or update is not
|
||||
requested with newer timestamp.
|
||||
|
||||
Signed-off-by: Gabor Toth <gabor.toth2@arm.com>
|
||||
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TS/trusted-services/+/27955]
|
||||
---
|
||||
.../backend/uefi_variable_store.c | 35 +++++++++++++++----
|
||||
.../smm_variable/backend/variable_index.c | 1 +
|
||||
.../smm_variable/backend/variable_index.h | 1 +
|
||||
3 files changed, 30 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/components/service/uefi/smm_variable/backend/uefi_variable_store.c b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
index c1691dc8f..1b624f0c9 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
@@ -76,6 +76,7 @@ static efi_status_t verify_var_by_key_var(const efi_data_map *new_var,
|
||||
const uint8_t *hash_buffer, size_t hash_len);
|
||||
|
||||
static efi_status_t authenticate_variable(const struct uefi_variable_store *context,
|
||||
+ EFI_TIME *timestamp,
|
||||
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
|
||||
#endif
|
||||
|
||||
@@ -197,6 +198,7 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
|
||||
{
|
||||
bool should_sync_index = false;
|
||||
+ EFI_TIME timestamp = { 0 };
|
||||
|
||||
/* Validate incoming request */
|
||||
efi_status_t status = check_name_terminator(var->Name, var->NameSize);
|
||||
@@ -225,6 +227,9 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
+ /* Save the timestamp into a buffer, which can be overwritten by the authentication function */
|
||||
+ memcpy(×tamp, &info->metadata.timestamp, sizeof(EFI_TIME));
|
||||
+
|
||||
/* Control access */
|
||||
status = check_access_permitted_on_set(context, info, var);
|
||||
|
||||
@@ -240,7 +245,7 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
if (info->metadata.attributes &
|
||||
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
|
||||
status = authenticate_variable(
|
||||
- context, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
+ context, ×tamp, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
@@ -326,7 +331,7 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
*/
|
||||
if (var->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
|
||||
status = authenticate_variable(
|
||||
- context, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
+ context, ×tamp, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
@@ -358,9 +363,11 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
if (should_sync_index)
|
||||
status = sync_variable_index(context);
|
||||
|
||||
- /* Store any variable data to the storage backend */
|
||||
- if (info->is_variable_set && (status == EFI_SUCCESS))
|
||||
+ /* Store any variable data to the storage backend with the updated metadata */
|
||||
+ if (info->is_variable_set && (status == EFI_SUCCESS)) {
|
||||
+ memcpy(&info->metadata.timestamp, ×tamp, sizeof(EFI_TIME));
|
||||
status = store_variable_data(context, info, var);
|
||||
+ }
|
||||
}
|
||||
|
||||
variable_index_remove_unused_entry(&context->variable_index, info);
|
||||
@@ -1106,6 +1113,7 @@ static efi_status_t verify_var_by_key_var(const efi_data_map *new_var,
|
||||
* then verifies it.
|
||||
*/
|
||||
static efi_status_t authenticate_variable(const struct uefi_variable_store *context,
|
||||
+ EFI_TIME *timestamp,
|
||||
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
|
||||
{
|
||||
efi_status_t status = EFI_SUCCESS;
|
||||
@@ -1223,9 +1231,7 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
*
|
||||
* UEFI: Page 253
|
||||
* 2. Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components
|
||||
- * of the TimeStamp value are set to zero. Unless the EFI_VARIABLE_APPEND_WRITE
|
||||
- * attribute is set, verify that the TimeStamp value is later than the current
|
||||
- * timestamp value associated with the variable
|
||||
+ * of the TimeStamp value are set to zero.
|
||||
*/
|
||||
if ((var_map.efi_auth_descriptor->TimeStamp.Pad1 != 0) ||
|
||||
(var_map.efi_auth_descriptor->TimeStamp.Pad2 != 0) ||
|
||||
@@ -1235,6 +1241,21 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * UEFI: Page 253
|
||||
+ * Unless the EFI_VARIABLE_APPEND_WRITE attribute is set, verify
|
||||
+ * that the TimeStamp value is later than the current
|
||||
+ * timestamp value associated with the variable
|
||||
+ */
|
||||
+ if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) {
|
||||
+ if (memcmp(&var_map.efi_auth_descriptor->TimeStamp, timestamp, sizeof(EFI_GUID)) <= 0) {
|
||||
+ EMSG("Timestamp violation");
|
||||
+ return EFI_SECURITY_VIOLATION;
|
||||
+ }
|
||||
+
|
||||
+ /* Save new timestamp */
|
||||
+ memcpy(timestamp, &var_map.efi_auth_descriptor->TimeStamp, sizeof(EFI_TIME));
|
||||
+ }
|
||||
/* Calculate hash for the variable only once */
|
||||
hash_result = calc_variable_hash(&var_map, (uint8_t *)&hash_buffer, sizeof(hash_buffer),
|
||||
&hash_len);
|
||||
diff --git a/components/service/uefi/smm_variable/backend/variable_index.c b/components/service/uefi/smm_variable/backend/variable_index.c
|
||||
index e2fe6dd38..f4194d2d3 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/variable_index.c
|
||||
+++ b/components/service/uefi/smm_variable/backend/variable_index.c
|
||||
@@ -198,6 +198,7 @@ static struct variable_entry *add_entry(const struct variable_index *context, co
|
||||
/* Initialize metadata */
|
||||
info->metadata.uid = generate_uid(context, guid, name_size, name);
|
||||
info->metadata.guid = *guid;
|
||||
+ memset(&info->metadata.timestamp, 0, sizeof(EFI_TIME));
|
||||
info->metadata.attributes = 0;
|
||||
info->metadata.name_size = name_size;
|
||||
memcpy(info->metadata.name, name, name_size);
|
||||
diff --git a/components/service/uefi/smm_variable/backend/variable_index.h b/components/service/uefi/smm_variable/backend/variable_index.h
|
||||
index 5d3b7a7c6..7eef7b86b 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/variable_index.h
|
||||
+++ b/components/service/uefi/smm_variable/backend/variable_index.h
|
||||
@@ -32,6 +32,7 @@ extern "C" {
|
||||
*/
|
||||
struct variable_metadata {
|
||||
EFI_GUID guid;
|
||||
+ EFI_TIME timestamp;
|
||||
size_t name_size;
|
||||
int16_t name[VARIABLE_INDEX_MAX_NAME_SIZE];
|
||||
uint32_t attributes;
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
From 19e79008e0fa3193b54bf6499516dc75cb10f6ec Mon Sep 17 00:00:00 2001
|
||||
From: Gabor Toth <gabor.toth2@arm.com>
|
||||
Date: Thu, 11 Apr 2024 13:42:03 +0200
|
||||
Subject: [PATCH 2/3] Isolate common uefi variable authentication steps
|
||||
|
||||
Currently all auth variables are authenticated with the secure boot
|
||||
keys. To introduce corrent check for Private Authenticated Variables
|
||||
first separate the common steps from the secure boot related steps.
|
||||
|
||||
Signed-off-by: Gabor Toth <gabor.toth2@arm.com>
|
||||
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TS/trusted-services/+/27956]
|
||||
---
|
||||
.../backend/uefi_variable_store.c | 191 ++++++++++--------
|
||||
1 file changed, 103 insertions(+), 88 deletions(-)
|
||||
|
||||
diff --git a/components/service/uefi/smm_variable/backend/uefi_variable_store.c b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
index 1b624f0c9..1384d0def 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
@@ -78,6 +78,12 @@ static efi_status_t verify_var_by_key_var(const efi_data_map *new_var,
|
||||
static efi_status_t authenticate_variable(const struct uefi_variable_store *context,
|
||||
EFI_TIME *timestamp,
|
||||
SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
|
||||
+
|
||||
+static efi_status_t authenticate_secure_boot_variable(const struct uefi_variable_store *context,
|
||||
+ efi_data_map* var_map,
|
||||
+ uint8_t* hash_buffer,
|
||||
+ size_t hash_len,
|
||||
+ uint64_t max_variable_size);
|
||||
#endif
|
||||
|
||||
static efi_status_t store_variable_data(const struct uefi_variable_store *context,
|
||||
@@ -1118,30 +1124,109 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
{
|
||||
efi_status_t status = EFI_SUCCESS;
|
||||
EFI_GUID pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID;
|
||||
- EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE;
|
||||
- EFI_GUID security_database_guid = EFI_IMAGE_SECURITY_DATABASE_GUID;
|
||||
SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO variable_info = { 0, 0, 0, 0 };
|
||||
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *pk_variable = NULL;
|
||||
- size_t pk_payload_size = 0;
|
||||
efi_data_map var_map = { NULL, NULL, NULL, 0, 0, NULL, 0, NULL };
|
||||
uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
|
||||
size_t hash_len = 0;
|
||||
- bool hash_result = false;
|
||||
|
||||
/* Create a map of the fields of the new variable including the auth header */
|
||||
if (!init_efi_data_map(var, true, &var_map))
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
|
||||
- /* database variables can be verified by either PK or KEK while images
|
||||
- * should be checked by db and dbx so the length of two will be enough.
|
||||
- */
|
||||
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *allowed_key_store_variables[] = { NULL, NULL };
|
||||
-
|
||||
/* Find the maximal size of variables for the GetVariable operation */
|
||||
status = uefi_variable_store_query_variable_info(context, &variable_info);
|
||||
if (status != EFI_SUCCESS)
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
|
||||
+ /**
|
||||
+ * UEFI: Page 246
|
||||
+ * If the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set in a
|
||||
+ * SetVariable() call, and firmware does not support signature type of the certificate
|
||||
+ * included in the EFI_VARIABLE_AUTHENTICATION_2 descriptor, then the SetVariable() call
|
||||
+ * shall return EFI_INVALID_PARAMETER. The list of signature types supported by the
|
||||
+ * firmware is defined by the SignatureSupport variable. Signature type of the certificate
|
||||
+ * is defined by its digest and encryption algorithms.
|
||||
+ */
|
||||
+ /* TODO: Should support WIN_CERT_TYPE_PKCS_SIGNED_DATA and WIN_CERT_TYPE_EFI_PKCS115 */
|
||||
+ if (var_map.efi_auth_descriptor->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
|
||||
+ return EFI_INVALID_PARAMETER;
|
||||
+
|
||||
+ /* Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted */
|
||||
+ if (!compare_guid(&var_map.efi_auth_descriptor->AuthInfo.CertType, &pkcs7_guid))
|
||||
+ return EFI_SECURITY_VIOLATION;
|
||||
+
|
||||
+ /**
|
||||
+ * Time associated with the authentication descriptor. For the TimeStamp value,
|
||||
+ * components Pad1, Nanosecond, TimeZone, Daylight and Pad2 shall be set to 0.
|
||||
+ * This means that the time shall always be expressed in GMT.
|
||||
+ *
|
||||
+ * UEFI: Page 253
|
||||
+ * 2. Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components
|
||||
+ * of the TimeStamp value are set to zero.
|
||||
+ */
|
||||
+ if ((var_map.efi_auth_descriptor->TimeStamp.Pad1 != 0) ||
|
||||
+ (var_map.efi_auth_descriptor->TimeStamp.Pad2 != 0) ||
|
||||
+ (var_map.efi_auth_descriptor->TimeStamp.Nanosecond != 0) ||
|
||||
+ (var_map.efi_auth_descriptor->TimeStamp.TimeZone != 0) ||
|
||||
+ (var_map.efi_auth_descriptor->TimeStamp.Daylight != 0)) {
|
||||
+ return EFI_SECURITY_VIOLATION;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * UEFI: Page 253
|
||||
+ * Unless the EFI_VARIABLE_APPEND_WRITE attribute is set, verify
|
||||
+ * that the TimeStamp value is later than the current
|
||||
+ * timestamp value associated with the variable
|
||||
+ */
|
||||
+ if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) {
|
||||
+ if (memcmp(&var_map.efi_auth_descriptor->TimeStamp, timestamp, sizeof(EFI_GUID)) <= 0) {
|
||||
+ EMSG("Timestamp violation");
|
||||
+ return EFI_SECURITY_VIOLATION;
|
||||
+ }
|
||||
+
|
||||
+ /* Save new timestamp */
|
||||
+ memcpy(timestamp, &var_map.efi_auth_descriptor->TimeStamp, sizeof(EFI_TIME));
|
||||
+ }
|
||||
+ /* Calculate hash for the variable only once */
|
||||
+ if (calc_variable_hash(&var_map, (uint8_t *)&hash_buffer, sizeof(hash_buffer), &hash_len) == 0) {
|
||||
+ status = EFI_SECURITY_VIOLATION;
|
||||
+ }
|
||||
+
|
||||
+ /* Run Secure Boot related authentication steps */
|
||||
+ status = authenticate_secure_boot_variable(context, &var_map, (uint8_t*) &hash_buffer, hash_len, variable_info.MaximumVariableSize);
|
||||
+
|
||||
+ /* Remove the authentication header from the variable if the authentication is successful */
|
||||
+ if (status == EFI_SUCCESS) {
|
||||
+ uint8_t *smm_payload =
|
||||
+ (uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
|
||||
+
|
||||
+ memmove(smm_payload, var_map.payload, var_map.payload_len);
|
||||
+ memset((uint8_t *)smm_payload + var_map.payload_len, 0,
|
||||
+ var_map.efi_auth_descriptor_len);
|
||||
+
|
||||
+ var->DataSize -= var_map.efi_auth_descriptor_len;
|
||||
+ }
|
||||
+
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+static efi_status_t authenticate_secure_boot_variable(const struct uefi_variable_store *context,
|
||||
+ efi_data_map* var_map,
|
||||
+ uint8_t* hash_buffer,
|
||||
+ size_t hash_len,
|
||||
+ uint64_t max_variable_size)
|
||||
+{
|
||||
+ efi_status_t status = EFI_SUCCESS;
|
||||
+ EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE;
|
||||
+ EFI_GUID security_database_guid = EFI_IMAGE_SECURITY_DATABASE_GUID;
|
||||
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *pk_variable = NULL;
|
||||
+ size_t pk_payload_size = 0;
|
||||
+
|
||||
+ /* database variables can be verified by either PK or KEK while images
|
||||
+ * should be checked by db and dbx so the length of two will be enough.
|
||||
+ */
|
||||
+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *allowed_key_store_variables[] = { NULL, NULL };
|
||||
+
|
||||
/**
|
||||
* UEFI: Page 253
|
||||
* 3. If the variable SetupMode==1, and the variable is a secure
|
||||
@@ -1166,14 +1251,14 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
* Platform Key is checked to enable or disable authentication.
|
||||
*/
|
||||
create_smm_variable(&pk_variable, sizeof(EFI_PLATFORM_KEY_NAME),
|
||||
- variable_info.MaximumVariableSize, (uint8_t *)EFI_PLATFORM_KEY_NAME,
|
||||
+ max_variable_size, (uint8_t *)EFI_PLATFORM_KEY_NAME,
|
||||
&global_variable_guid);
|
||||
|
||||
if (!pk_variable)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
status = uefi_variable_store_get_variable(
|
||||
- context, pk_variable, variable_info.MaximumVariableSize, &pk_payload_size);
|
||||
+ context, pk_variable, max_variable_size, &pk_payload_size);
|
||||
|
||||
/* If PK does not exist authentication is disabled */
|
||||
if (status != EFI_SUCCESS) {
|
||||
@@ -1207,66 +1292,8 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
goto end;
|
||||
}
|
||||
|
||||
- /**
|
||||
- * UEFI: Page 246
|
||||
- * If the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set in a
|
||||
- * SetVariable() call, and firmware does not support signature type of the certificate
|
||||
- * included in the EFI_VARIABLE_AUTHENTICATION_2 descriptor, then the SetVariable() call
|
||||
- * shall return EFI_INVALID_PARAMETER. The list of signature types supported by the
|
||||
- * firmware is defined by the SignatureSupport variable. Signature type of the certificate
|
||||
- * is defined by its digest and encryption algorithms.
|
||||
- */
|
||||
- /* TODO: Should support WIN_CERT_TYPE_PKCS_SIGNED_DATA and WIN_CERT_TYPE_EFI_PKCS115 */
|
||||
- if (var_map.efi_auth_descriptor->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
|
||||
- return EFI_INVALID_PARAMETER;
|
||||
-
|
||||
- /* Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted */
|
||||
- if (!compare_guid(&var_map.efi_auth_descriptor->AuthInfo.CertType, &pkcs7_guid))
|
||||
- return EFI_SECURITY_VIOLATION;
|
||||
-
|
||||
- /**
|
||||
- * Time associated with the authentication descriptor. For the TimeStamp value,
|
||||
- * components Pad1, Nanosecond, TimeZone, Daylight and Pad2 shall be set to 0.
|
||||
- * This means that the time shall always be expressed in GMT.
|
||||
- *
|
||||
- * UEFI: Page 253
|
||||
- * 2. Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components
|
||||
- * of the TimeStamp value are set to zero.
|
||||
- */
|
||||
- if ((var_map.efi_auth_descriptor->TimeStamp.Pad1 != 0) ||
|
||||
- (var_map.efi_auth_descriptor->TimeStamp.Pad2 != 0) ||
|
||||
- (var_map.efi_auth_descriptor->TimeStamp.Nanosecond != 0) ||
|
||||
- (var_map.efi_auth_descriptor->TimeStamp.TimeZone != 0) ||
|
||||
- (var_map.efi_auth_descriptor->TimeStamp.Daylight != 0)) {
|
||||
- return EFI_SECURITY_VIOLATION;
|
||||
- }
|
||||
-
|
||||
- /**
|
||||
- * UEFI: Page 253
|
||||
- * Unless the EFI_VARIABLE_APPEND_WRITE attribute is set, verify
|
||||
- * that the TimeStamp value is later than the current
|
||||
- * timestamp value associated with the variable
|
||||
- */
|
||||
- if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) {
|
||||
- if (memcmp(&var_map.efi_auth_descriptor->TimeStamp, timestamp, sizeof(EFI_GUID)) <= 0) {
|
||||
- EMSG("Timestamp violation");
|
||||
- return EFI_SECURITY_VIOLATION;
|
||||
- }
|
||||
-
|
||||
- /* Save new timestamp */
|
||||
- memcpy(timestamp, &var_map.efi_auth_descriptor->TimeStamp, sizeof(EFI_TIME));
|
||||
- }
|
||||
- /* Calculate hash for the variable only once */
|
||||
- hash_result = calc_variable_hash(&var_map, (uint8_t *)&hash_buffer, sizeof(hash_buffer),
|
||||
- &hash_len);
|
||||
-
|
||||
- if (!hash_result) {
|
||||
- status = EFI_SECURITY_VIOLATION;
|
||||
- goto end;
|
||||
- }
|
||||
-
|
||||
- status = select_verification_keys(var_map, global_variable_guid, security_database_guid,
|
||||
- variable_info.MaximumVariableSize,
|
||||
+ status = select_verification_keys(*var_map, global_variable_guid, security_database_guid,
|
||||
+ max_variable_size,
|
||||
&allowed_key_store_variables[0]);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
@@ -1280,8 +1307,8 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
continue;
|
||||
|
||||
status = uefi_variable_store_get_variable(context, allowed_key_store_variables[i],
|
||||
- variable_info.MaximumVariableSize,
|
||||
- &actual_variable_length);
|
||||
+ max_variable_size,
|
||||
+ &actual_variable_length);
|
||||
|
||||
if (status) {
|
||||
/* When the parent does not exist it is considered verification failure */
|
||||
@@ -1297,8 +1324,8 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
goto end;
|
||||
}
|
||||
|
||||
- status = verify_var_by_key_var(&var_map, &allowed_key_store_var_map,
|
||||
- (uint8_t *)&hash_buffer, hash_len);
|
||||
+ status = verify_var_by_key_var(var_map, &allowed_key_store_var_map,
|
||||
+ hash_buffer, hash_len);
|
||||
|
||||
if (status == EFI_SUCCESS)
|
||||
goto end;
|
||||
@@ -1311,18 +1338,6 @@ end:
|
||||
free(allowed_key_store_variables[i]);
|
||||
}
|
||||
|
||||
- /* Remove the authentication header from the variable if the authentication is successful */
|
||||
- if (status == EFI_SUCCESS) {
|
||||
- uint8_t *smm_payload =
|
||||
- (uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var);
|
||||
-
|
||||
- memmove(smm_payload, var_map.payload, var_map.payload_len);
|
||||
- memset((uint8_t *)smm_payload + var_map.payload_len, 0,
|
||||
- var_map.efi_auth_descriptor_len);
|
||||
-
|
||||
- var->DataSize -= var_map.efi_auth_descriptor_len;
|
||||
- }
|
||||
-
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
From a172c6e8269915db1b25e2749bae06dc0220cfb8 Mon Sep 17 00:00:00 2001
|
||||
From: Gabor Toth <gabor.toth2@arm.com>
|
||||
Date: Thu, 11 Apr 2024 13:48:14 +0200
|
||||
Subject: [PATCH 3/3] Implement Private Authenticated Variable verification
|
||||
|
||||
Refactor the implementation to only use the PK, KEK, DB authentication
|
||||
chain for boot variables, and implement the self authentication for
|
||||
private authenticated variables.
|
||||
|
||||
Signed-off-by: Gabor Toth <gabor.toth2@arm.com>
|
||||
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TS/trusted-services/+/27957]
|
||||
---
|
||||
.../backend/uefi_variable_store.c | 126 +++++++++++++++---
|
||||
.../smm_variable/backend/variable_index.c | 1 +
|
||||
.../smm_variable/backend/variable_index.h | 2 +
|
||||
.../config/default-opteesp/CMakeLists.txt | 2 +-
|
||||
.../config/default-sp/CMakeLists.txt | 2 +-
|
||||
5 files changed, 112 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/components/service/uefi/smm_variable/backend/uefi_variable_store.c b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
index 1384d0def..97c43dc74 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.c
|
||||
@@ -75,15 +75,25 @@ static efi_status_t verify_var_by_key_var(const efi_data_map *new_var,
|
||||
const efi_data_map *key_store_var,
|
||||
const uint8_t *hash_buffer, size_t hash_len);
|
||||
|
||||
+static bool isPrivateAuthVar(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
|
||||
+
|
||||
static efi_status_t authenticate_variable(const struct uefi_variable_store *context,
|
||||
- EFI_TIME *timestamp,
|
||||
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
|
||||
+ EFI_TIME *timestamp, uint8_t (*fingerprint)[FINGERPRINT_SIZE],
|
||||
+ bool new_variable, SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var);
|
||||
|
||||
static efi_status_t authenticate_secure_boot_variable(const struct uefi_variable_store *context,
|
||||
efi_data_map* var_map,
|
||||
uint8_t* hash_buffer,
|
||||
size_t hash_len,
|
||||
uint64_t max_variable_size);
|
||||
+
|
||||
+static efi_status_t authenticate_private_variable(const struct uefi_variable_store *context,
|
||||
+ efi_data_map* var_map,
|
||||
+ uint8_t* hash_buffer,
|
||||
+ size_t hash_len,
|
||||
+ uint64_t max_variable_size,
|
||||
+ bool new_variable,
|
||||
+ uint8_t (*fingerprint)[FINGERPRINT_SIZE]);
|
||||
#endif
|
||||
|
||||
static efi_status_t store_variable_data(const struct uefi_variable_store *context,
|
||||
@@ -205,6 +215,7 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
{
|
||||
bool should_sync_index = false;
|
||||
EFI_TIME timestamp = { 0 };
|
||||
+ uint8_t fingerprint[FINGERPRINT_SIZE] = { 0 };
|
||||
|
||||
/* Validate incoming request */
|
||||
efi_status_t status = check_name_terminator(var->Name, var->NameSize);
|
||||
@@ -233,8 +244,9 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
- /* Save the timestamp into a buffer, which can be overwritten by the authentication function */
|
||||
+ /* Save the timestamp and fingerprints into a buffer, which can be overwritten by the authentication function */
|
||||
memcpy(×tamp, &info->metadata.timestamp, sizeof(EFI_TIME));
|
||||
+ memcpy(&fingerprint, &info->metadata.fingerprint, FINGERPRINT_SIZE);
|
||||
|
||||
/* Control access */
|
||||
status = check_access_permitted_on_set(context, info, var);
|
||||
@@ -251,7 +263,8 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
if (info->metadata.attributes &
|
||||
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
|
||||
status = authenticate_variable(
|
||||
- context, ×tamp, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
+ context, ×tamp, &fingerprint, false,
|
||||
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
@@ -337,7 +350,8 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
*/
|
||||
if (var->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
|
||||
status = authenticate_variable(
|
||||
- context, ×tamp, (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
+ context, ×tamp, &fingerprint, true,
|
||||
+ (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)var);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
@@ -372,6 +386,7 @@ efi_status_t uefi_variable_store_set_variable(const struct uefi_variable_store *
|
||||
/* Store any variable data to the storage backend with the updated metadata */
|
||||
if (info->is_variable_set && (status == EFI_SUCCESS)) {
|
||||
memcpy(&info->metadata.timestamp, ×tamp, sizeof(EFI_TIME));
|
||||
+ memcpy(&info->metadata.fingerprint, &fingerprint, FINGERPRINT_SIZE);
|
||||
status = store_variable_data(context, info, var);
|
||||
}
|
||||
}
|
||||
@@ -1030,15 +1045,6 @@ select_verification_keys(const efi_data_map new_var, EFI_GUID global_variable_gu
|
||||
create_smm_variable(&(allowed_key_store_variables[1]),
|
||||
sizeof(EFI_KEY_EXCHANGE_KEY_NAME), maximum_variable_size,
|
||||
(uint8_t *)EFI_KEY_EXCHANGE_KEY_NAME, &global_variable_guid);
|
||||
- } else {
|
||||
- /*
|
||||
- * Any other variable is considered Private Authenticated Variable.
|
||||
- * These are verified by db
|
||||
- */
|
||||
- create_smm_variable(&(allowed_key_store_variables[0]),
|
||||
- sizeof(EFI_IMAGE_SECURITY_DATABASE), maximum_variable_size,
|
||||
- (uint8_t *)EFI_IMAGE_SECURITY_DATABASE,
|
||||
- &security_database_guid);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
@@ -1114,13 +1120,39 @@ static efi_status_t verify_var_by_key_var(const efi_data_map *new_var,
|
||||
return EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
-/* Basic verification of the authentication header of the new variable.
|
||||
+static bool isPrivateAuthVar(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
|
||||
+{
|
||||
+ if (compare_name_to_key_store_name(var->Name,
|
||||
+ var->NameSize, EFI_PLATFORM_KEY_NAME,
|
||||
+ sizeof(EFI_PLATFORM_KEY_NAME)) ||
|
||||
+ compare_name_to_key_store_name(
|
||||
+ var->Name, var->NameSize,
|
||||
+ EFI_KEY_EXCHANGE_KEY_NAME, sizeof(EFI_KEY_EXCHANGE_KEY_NAME)) ||
|
||||
+ compare_name_to_key_store_name(
|
||||
+ var->Name, var->NameSize,
|
||||
+ EFI_IMAGE_SECURITY_DATABASE, sizeof(EFI_IMAGE_SECURITY_DATABASE)) ||
|
||||
+ compare_name_to_key_store_name(
|
||||
+ var->Name, var->NameSize,
|
||||
+ EFI_IMAGE_SECURITY_DATABASE1, sizeof(EFI_IMAGE_SECURITY_DATABASE1)) ||
|
||||
+ compare_name_to_key_store_name(
|
||||
+ var->Name, var->NameSize,
|
||||
+ EFI_IMAGE_SECURITY_DATABASE2, sizeof(EFI_IMAGE_SECURITY_DATABASE2)) ||
|
||||
+ compare_name_to_key_store_name(
|
||||
+ var->Name, var->NameSize,
|
||||
+ EFI_IMAGE_SECURITY_DATABASE3, sizeof(EFI_IMAGE_SECURITY_DATABASE3)))
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Basic verification of the authentication header of the new variable.
|
||||
* First finds the key variable responsible for the authentication of the new variable,
|
||||
* then verifies it.
|
||||
*/
|
||||
static efi_status_t authenticate_variable(const struct uefi_variable_store *context,
|
||||
- EFI_TIME *timestamp,
|
||||
- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
|
||||
+ EFI_TIME *timestamp, uint8_t (*fingerprint)[FINGERPRINT_SIZE],
|
||||
+ bool new_variable, SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
|
||||
{
|
||||
efi_status_t status = EFI_SUCCESS;
|
||||
EFI_GUID pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID;
|
||||
@@ -1192,8 +1224,13 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont
|
||||
status = EFI_SECURITY_VIOLATION;
|
||||
}
|
||||
|
||||
- /* Run Secure Boot related authentication steps */
|
||||
- status = authenticate_secure_boot_variable(context, &var_map, (uint8_t*) &hash_buffer, hash_len, variable_info.MaximumVariableSize);
|
||||
+ if (isPrivateAuthVar(var)) {
|
||||
+ /* Run Private Authenticated Variable related authentication steps */
|
||||
+ status = authenticate_private_variable(context, &var_map, (uint8_t*) &hash_buffer, hash_len, variable_info.MaximumVariableSize, new_variable, fingerprint);
|
||||
+ } else {
|
||||
+ /* Run Secure Boot related authentication steps */
|
||||
+ status = authenticate_secure_boot_variable(context, &var_map, (uint8_t*) &hash_buffer, hash_len, variable_info.MaximumVariableSize);
|
||||
+ }
|
||||
|
||||
/* Remove the authentication header from the variable if the authentication is successful */
|
||||
if (status == EFI_SUCCESS) {
|
||||
@@ -1340,6 +1377,57 @@ end:
|
||||
|
||||
return status;
|
||||
}
|
||||
+
|
||||
+static efi_status_t authenticate_private_variable(const struct uefi_variable_store *context,
|
||||
+ efi_data_map* var_map,
|
||||
+ uint8_t* hash_buffer,
|
||||
+ size_t hash_len,
|
||||
+ uint64_t max_variable_size,
|
||||
+ bool new_variable,
|
||||
+ uint8_t (*fingerprint)[FINGERPRINT_SIZE])
|
||||
+{
|
||||
+ efi_status_t status = EFI_SUCCESS;
|
||||
+ uint8_t new_fingerprint[PSA_HASH_MAX_SIZE] = { 0 };
|
||||
+
|
||||
+ /* Verify the signature of the variable */
|
||||
+ if (verify_pkcs7_signature(
|
||||
+ var_map->efi_auth_descriptor->AuthInfo.CertData,
|
||||
+ var_map->efi_auth_descriptor_certdata_len, hash_buffer,
|
||||
+ hash_len, NULL, 0) == 0)
|
||||
+ status = EFI_SUCCESS;
|
||||
+ else
|
||||
+ return EFI_SECURITY_VIOLATION;
|
||||
+
|
||||
+ /**
|
||||
+ * UEFI: Page 254
|
||||
+ * CN of the signing certificate’s Subject and the hash of the tbsCertificate of the top-level issuer certificate
|
||||
+ * (or the signing certificate itself if no other certificates are present or the certificate chain is of length 1)
|
||||
+ * in SignedData.certificates is registered for use in subsequent verifications of this variable. Implementations
|
||||
+ * may store just a single hash of these two elements to reduce storage requirements.
|
||||
+ */
|
||||
+ if (get_uefi_priv_auth_var_fingerprint_handler(var_map->efi_auth_descriptor->AuthInfo.CertData,
|
||||
+ var_map->efi_auth_descriptor_certdata_len,
|
||||
+ (uint8_t*)&new_fingerprint)) {
|
||||
+ EMSG("Failed to querry variable fingerprint input");
|
||||
+ return EFI_SECURITY_VIOLATION;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * The hash is SHA256 so only 32 bytes contain non zero values.
|
||||
+ * Use only that part to decrease metadata size.
|
||||
+ */
|
||||
+ if (!new_variable) {
|
||||
+ if (memcmp(&new_fingerprint, fingerprint, FINGERPRINT_SIZE)) {
|
||||
+ EMSG("Fingerprint verification failed");
|
||||
+ return EFI_SECURITY_VIOLATION;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Save fingerprint */
|
||||
+ memcpy(fingerprint, &new_fingerprint, FINGERPRINT_SIZE);
|
||||
+ }
|
||||
+
|
||||
+ return status;
|
||||
+}
|
||||
#endif
|
||||
|
||||
static efi_status_t store_variable_data(const struct uefi_variable_store *context,
|
||||
diff --git a/components/service/uefi/smm_variable/backend/variable_index.c b/components/service/uefi/smm_variable/backend/variable_index.c
|
||||
index f4194d2d3..7f2fbe0ba 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/variable_index.c
|
||||
+++ b/components/service/uefi/smm_variable/backend/variable_index.c
|
||||
@@ -199,6 +199,7 @@ static struct variable_entry *add_entry(const struct variable_index *context, co
|
||||
info->metadata.uid = generate_uid(context, guid, name_size, name);
|
||||
info->metadata.guid = *guid;
|
||||
memset(&info->metadata.timestamp, 0, sizeof(EFI_TIME));
|
||||
+ memset(&info->metadata.fingerprint, 0, sizeof(FINGERPRINT_SIZE));
|
||||
info->metadata.attributes = 0;
|
||||
info->metadata.name_size = name_size;
|
||||
memcpy(info->metadata.name, name, name_size);
|
||||
diff --git a/components/service/uefi/smm_variable/backend/variable_index.h b/components/service/uefi/smm_variable/backend/variable_index.h
|
||||
index 7eef7b86b..726bc985a 100644
|
||||
--- a/components/service/uefi/smm_variable/backend/variable_index.h
|
||||
+++ b/components/service/uefi/smm_variable/backend/variable_index.h
|
||||
@@ -24,6 +24,7 @@ extern "C" {
|
||||
* Implementation limits
|
||||
*/
|
||||
#define VARIABLE_INDEX_MAX_NAME_SIZE (64)
|
||||
+#define FINGERPRINT_SIZE (32)
|
||||
|
||||
/**
|
||||
* \brief variable_metadata structure definition
|
||||
@@ -33,6 +34,7 @@ extern "C" {
|
||||
struct variable_metadata {
|
||||
EFI_GUID guid;
|
||||
EFI_TIME timestamp;
|
||||
+ uint8_t fingerprint[FINGERPRINT_SIZE];
|
||||
size_t name_size;
|
||||
int16_t name[VARIABLE_INDEX_MAX_NAME_SIZE];
|
||||
uint32_t attributes;
|
||||
diff --git a/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
|
||||
index 0e281a377..d3df61ded 100644
|
||||
--- a/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
|
||||
+++ b/deployments/smm-gateway/config/default-opteesp/CMakeLists.txt
|
||||
@@ -42,7 +42,7 @@ set(SP_BOOT_ORDER "8" CACHE STRING "Boot order of the SP")
|
||||
add_platform(TARGET "smm-gateway")
|
||||
|
||||
# SMM variable and RPC caller settings
|
||||
-set(SMM_GATEWAY_MAX_UEFI_VARIABLES 40 CACHE STRING "Maximum UEFI variable count")
|
||||
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 35 CACHE STRING "Maximum UEFI variable count")
|
||||
set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 2*4096 CACHE STRING "RPC caller buffer size in SMMGW")
|
||||
if (UEFI_AUTH_VAR)
|
||||
set(SMM_SP_HEAP_SIZE 64*1024 CACHE STRING "SMM gateway SP heap size")
|
||||
diff --git a/deployments/smm-gateway/config/default-sp/CMakeLists.txt b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
|
||||
index 8df9256e4..bb97cf8e3 100644
|
||||
--- a/deployments/smm-gateway/config/default-sp/CMakeLists.txt
|
||||
+++ b/deployments/smm-gateway/config/default-sp/CMakeLists.txt
|
||||
@@ -47,7 +47,7 @@ set(SP_BOOT_ORDER "8" CACHE STRING "Boot order of the SP")
|
||||
add_platform(TARGET "smm-gateway")
|
||||
|
||||
# SMM variable and RPC caller settings
|
||||
-set(SMM_GATEWAY_MAX_UEFI_VARIABLES 40 CACHE STRING "Maximum UEFI variable count")
|
||||
+set(SMM_GATEWAY_MAX_UEFI_VARIABLES 35 CACHE STRING "Maximum UEFI variable count")
|
||||
set(SMM_RPC_CALLER_SESSION_SHARED_MEMORY_SIZE 2*4096 CACHE STRING "RPC caller buffer size in SMMGW")
|
||||
if (UEFI_AUTH_VAR)
|
||||
set(SMM_SP_HEAP_SIZE 64*1024 CACHE STRING "SMM gateway SP heap size")
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@@ -15,6 +15,10 @@ SRC_URI:append:corstone1000 = " \
|
||||
file://0011-Fix-Avoid-redefinition-of-variables.patch \
|
||||
file://0012-Fix-GetNextVariableName-NameSize-input.patch \
|
||||
file://0013-Fix-error-handling-of-variable-index-loading.patch \
|
||||
file://0014-Provide-crypto-api-to-create-uefi-priv-var-fingerpri.patch \
|
||||
file://0015-Add-timestamp-validation-for-uefi-variables.patch \
|
||||
file://0016-Isolate-common-uefi-variable-authentication-steps.patch \
|
||||
file://0017-Implement-Private-Authenticated-Variable-verificatio.patch \
|
||||
"
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ EXTRA_OECMAKE:append:corstone1000 = " -DMM_COMM_BUFFER_ADDRESS="0x00000000 0x81F
|
||||
-DMM_COMM_BUFFER_PAGE_COUNT="1" \
|
||||
-DUEFI_AUTH_VAR=ON \
|
||||
-DUEFI_INTERNAL_CRYPTO=ON \
|
||||
-DSMM_GATEWAY_MAX_UEFI_VARIABLES=60 \
|
||||
"
|
||||
|
||||
EXTRA_OECMAKE:append:fvp-base = " -DMM_COMM_BUFFER_ADDRESS="0x00000000 0x81000000" \
|
||||
|
||||
Reference in New Issue
Block a user