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/client/caller/packed-c/crypto_caller.h b/components/service/crypto/client/caller/packed-c/crypto_caller.h
index d834bc2..d5dd0f7 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 0000000..73825b9
--- /dev/null
+++ b/components/service/crypto/client/caller/packed-c/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
@@ -0,0 +1,93 @@
+/*
+ * 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_INVALID_PARAMETER;
+	size_t req_len = 0;
+
+	if (signature_cert_len > UINT16_MAX)
+		return efi_status;
+
+	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);
+		if (!tlv_encode(&req_iter, &signature_record))
+			return efi_status;
+
+		context->rpc_status = rpc_caller_session_invoke(
+			call_handle, TS_CRYPTO_OPCODE_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT, &resp_buf, &resp_len,
+			&service_status);
+
+		efi_status = (efi_status_t)service_status;
+
+		if (context->rpc_status == RPC_SUCCESS) {
+
+			if (efi_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);
+					efi_status = EFI_SUCCESS;
+				} else {
+					/* Mandatory response parameter missing */
+					efi_status = EFI_PROTOCOL_ERROR;
+				}
+			}
+		}
+
+		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/caller/psa_ipc/crypto_caller.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller.h
index 68d489f..5821f13 100644
--- a/components/service/crypto/client/caller/psa_ipc/crypto_caller.h
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller.h
@@ -23,6 +23,7 @@
 #include "crypto_caller_generate_key.h"
 #include "crypto_caller_generate_random.h"
 #include "crypto_caller_get_key_attributes.h"
+#include "crypto_caller_get_uefi_priv_auth_var_fingerprint.h"
 #include "crypto_caller_hash.h"
 #include "crypto_caller_import_key.h"
 #include "crypto_caller_key_derivation.h"
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_uefi_priv_auth_var_fingerprint.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
new file mode 100644
index 0000000..04e87ad
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
+#define PSA_IPC_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
+
+#include <rpc/common/interface/rpc_status.h>
+#include <service/common/client/service_client.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)
+{
+	(void)context;
+	(void)signature_cert;
+	(void)signature_cert_len;
+	(void)output;
+
+	return RPC_ERROR_INTERNAL;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H */
diff --git a/components/service/crypto/client/caller/stub/crypto_caller.h b/components/service/crypto/client/caller/stub/crypto_caller.h
index 1931d02..0e88a13 100644
--- a/components/service/crypto/client/caller/stub/crypto_caller.h
+++ b/components/service/crypto/client/caller/stub/crypto_caller.h
@@ -26,6 +26,7 @@
 #include "crypto_caller_asymmetric_encrypt.h"
 #include "crypto_caller_export_key.h"
 #include "crypto_caller_get_key_attributes.h"
+#include "crypto_caller_get_uefi_priv_auth_var_fingerprint.h"
 #include "crypto_caller_sign_hash.h"
 #include "crypto_caller_cipher.h"
 #include "crypto_caller_export_public_key.h"
diff --git a/components/service/crypto/client/caller/stub/crypto_caller_get_uefi_priv_auth_var_fingerprint.h b/components/service/crypto/client/caller/stub/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
new file mode 100644
index 0000000..d8c286b
--- /dev/null
+++ b/components/service/crypto/client/caller/stub/crypto_caller_get_uefi_priv_auth_var_fingerprint.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef STUB_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
+#define STUB_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H
+
+#include <rpc/common/interface/rpc_status.h>
+#include <service/common/client/service_client.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)
+{
+	(void)context;
+	(void)signature_cert;
+	(void)signature_cert_len;
+	(void)output;
+
+	return RPC_ERROR_INTERNAL;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STUB_CRYPTO_CALLER_GET_UEFI_PRIV_AUTH_VAR_FINGERPRINT_H */
diff --git a/components/service/crypto/client/cpp/crypto_client.h b/components/service/crypto/client/cpp/crypto_client.h
index 6792a17..80fbe24 100644
--- a/components/service/crypto/client/cpp/crypto_client.h
+++ b/components/service/crypto/client/cpp/crypto_client.h
@@ -240,6 +240,10 @@
 					   uint64_t hash_len, const uint8_t *public_key_cert,
 					   uint64_t public_key_cert_len) = 0;
 
+	virtual int get_uefi_priv_auth_var_fingerprint(const uint8_t *signature_cert,
+						       uint64_t signature_cert_len,
+						       uint8_t *output) = 0;
+
 protected:
 	crypto_client();
 	crypto_client(struct rpc_caller_session *session);
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 aaa71f0..4791feb 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,12 @@
 						    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 8d4f60c..ec6c51c 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 @@
 	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/cpp/protocol/protobuf/protobuf_crypto_client.cpp b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
index 6bae7a8..1170255 100644
--- a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
+++ b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.cpp
@@ -1174,3 +1174,14 @@
 
 	return PSA_ERROR_NOT_SUPPORTED;
 }
+
+int protobuf_crypto_client::get_uefi_priv_auth_var_fingerprint(const uint8_t *signature_cert,
+							       uint64_t signature_cert_len,
+							       uint8_t *output)
+{
+	(void)signature_cert;
+	(void)signature_cert_len;
+	(void)output;
+
+	return PSA_ERROR_NOT_SUPPORTED;
+}
diff --git a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
index 9ad43f7..52f8a02 100644
--- a/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
+++ b/components/service/crypto/client/cpp/protocol/protobuf/protobuf_crypto_client.h
@@ -237,6 +237,10 @@
 				   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);
+
 private:
 
 	psa_status_t asym_sign(uint32_t opcode,
diff --git a/components/service/crypto/client/psa/component.cmake b/components/service/crypto/client/psa/component.cmake
index 359db3b..5bee0c6 100644
--- a/components/service/crypto/client/psa/component.cmake
+++ b/components/service/crypto/client/psa/component.cmake
@@ -32,4 +32,5 @@
 	"${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 4b59bbe..af04df1 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 0000000..702aaa0
--- /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);
+}