[Skiboot] [PATCH v5 18/20] secvar/backend: add edk2 derived key updates processing

Eric Richter erichte at linux.ibm.com
Sat Jun 13 06:25:12 AEST 2020


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

As part of secureboot key management, the scheme for handling key updates
is derived from tianocore reference implementation[1]. The wrappers for
holding the signed update is the Authentication Header and for holding
the public key certificate is ESL (EFI Signature List), both derived from
tianocore reference implementation[1].

This patch adds the support to process update queue. This involves:
1. Verification of the update signature using the key authorized as per the
key hierarchy
2. Handling addition/deletion of the keys
3. Support for dbx (blacklisting of hashes)
4. Validation checks for the updates
5. Supporting multiple ESLs for single variable both for update/verification
6. Timestamp check
7. Allowing only single PK
8. Failure Handling
9. Resetting keystore if the hardware key hash changes

[1] https://github.com/tianocore/edk2-staging.git

Signed-off-by: Nayna Jain <nayna at linux.ibm.com>
Signed-off-by: Eric Richter <erichte at linux.ibm.com>
---
V5:
 - rename utf8_to_ucs2 to char_to_wchar, as it is only widening the string,
    not adjusting the encoding
 - reworked get_esl_* functions
 - added const to various parameters where fitting
 - converted programming faults to asserts over return codes
 - packs the edk2-flavored timestamp into a single uint64_t for easy compare
 - incrementally calculates signature hash, instead of packing everything
    into a buffer
 - avoid calling find_secvar() for TS on each iteration of process loop
 - fixed leaking the staging bank after processing updates
 - adjusted an edk2.h struct to use zero-width array rather than of size 1
 - use key_equals() instead of strncmp()
 - updated to use struct secvar instead of struct secvar_node

 doc/secvar/edk2.rst                         |  49 ++
 include/secvar.h                            |   1 +
 libstb/crypto/pkcs7/pkcs7.c                 |  13 +
 libstb/crypto/pkcs7/pkcs7.h                 |   1 +
 libstb/secvar/backend/Makefile.inc          |   4 +-
 libstb/secvar/backend/edk2-compat-process.c | 724 ++++++++++++++++++++
 libstb/secvar/backend/edk2-compat-process.h |  62 ++
 libstb/secvar/backend/edk2-compat-reset.c   | 115 ++++
 libstb/secvar/backend/edk2-compat-reset.h   |  24 +
 libstb/secvar/backend/edk2-compat.c         | 282 ++++++++
 libstb/secvar/backend/edk2.h                | 243 +++++++
 11 files changed, 1516 insertions(+), 2 deletions(-)
 create mode 100644 doc/secvar/edk2.rst
 create mode 100644 libstb/secvar/backend/edk2-compat-process.c
 create mode 100644 libstb/secvar/backend/edk2-compat-process.h
 create mode 100644 libstb/secvar/backend/edk2-compat-reset.c
 create mode 100644 libstb/secvar/backend/edk2-compat-reset.h
 create mode 100644 libstb/secvar/backend/edk2-compat.c
 create mode 100644 libstb/secvar/backend/edk2.h

diff --git a/doc/secvar/edk2.rst b/doc/secvar/edk2.rst
new file mode 100644
index 00000000..1e4cc9e3
--- /dev/null
+++ b/doc/secvar/edk2.rst
@@ -0,0 +1,49 @@
+.. _secvar/edk2:
+
+Skiboot edk2-compatible Secure Variable Backend
+===============================================
+
+Overview
+--------
+
+The edk2 secure variable backend for skiboot borrows from edk2 concepts
+such as the three key hierarchy (PK, KEK, and db), and a similar
+structure. In general, variable updates must be signed with a key
+of a higher level. So, updates to the db must be signed with a key stored
+in the KEK; updates to the KEK must be signed with the PK. Updates to the
+PK must be signed with the previous PK (if any).
+
+Variables are stored in the efi signature list format, and updates are a
+signed variant that includes an authentication header.
+
+If no PK is currently enrolled, the system is considered to be in "Setup
+Mode". Any key can be enrolled without signature checks. However, once a
+PK is enrolled, the system switches to "User Mode", and each update must
+now be signed according to the hierarchy. Furthermore, when in "User
+Mode", the backend initialized the ``os-secure-mode`` device tree flag,
+signaling to the kernel that we are in secure mode.
+
+Updates are processed sequentially, in the order that they were provided
+in the update queue. If any update fails to validate, appears to be
+malformed, or any other error occurs, NO updates will not be applied.
+This includes updates that may have successfully applied prior to the
+error. The system will continue in an error state, reporting the error
+reason via the ``update-status`` device tree property.
+
+P9 Special Case for the Platform Key
+------------------------------------
+
+Due to the powerful nature of the platform key and the lack of lockable
+flash, the edk2 backend will store the PK in TPM NV rather than PNOR on
+P9 systems. (TODO expand on this)
+
+Update Status Return Codes
+--------------------------
+
+TODO, edk2 driver needs to actually return these properly first
+
+
+Device Tree Bindings
+--------------------
+
+TODO
diff --git a/include/secvar.h b/include/secvar.h
index 21210277..413d7997 100644
--- a/include/secvar.h
+++ b/include/secvar.h
@@ -37,6 +37,7 @@ struct secvar_backend_driver {
 };
 
 extern struct secvar_storage_driver secboot_tpm_driver;
+extern struct secvar_backend_driver edk2_compatible_v1;
 
 int secvar_main(struct secvar_storage_driver, struct secvar_backend_driver);
 
diff --git a/libstb/crypto/pkcs7/pkcs7.c b/libstb/crypto/pkcs7/pkcs7.c
index f8097720..322cb17c 100644
--- a/libstb/crypto/pkcs7/pkcs7.c
+++ b/libstb/crypto/pkcs7/pkcs7.c
@@ -481,6 +481,19 @@ int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *ce
        return ( ret );
 }
 
+int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *hash, int hashlen)
+{
+
+       int ret;
+       mbedtls_pk_context pk_cxt = cert->pk;
+
+       ret = mbedtls_pk_verify( &pk_cxt, MBEDTLS_MD_SHA256, hash, hashlen, pkcs7->signed_data.signers.sig.p, pkcs7->signed_data.signers.sig.len );
+
+       mbedtls_printf("Verification return code is %04x\n", ret);
+
+       return ( ret );
+}
+
 /*
  * Unallocate all pkcs7 data
  */
diff --git a/libstb/crypto/pkcs7/pkcs7.h b/libstb/crypto/pkcs7/pkcs7.h
index 7f14b4b8..b50f04c2 100644
--- a/libstb/crypto/pkcs7/pkcs7.h
+++ b/libstb/crypto/pkcs7/pkcs7.h
@@ -128,6 +128,7 @@ void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 );
 int mbedtls_pkcs7_parse_der(const unsigned char *buf, const int buflen, mbedtls_pkcs7 *pkcs7);
 
 int mbedtls_pkcs7_signed_data_verify(mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *data, int datalen);
+int mbedtls_pkcs7_signed_hash_verify(mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *hash, int hashlen);
 
 int mbedtls_pkcs7_load_file( const char *path, unsigned char **buf, size_t *n );
 
diff --git a/libstb/secvar/backend/Makefile.inc b/libstb/secvar/backend/Makefile.inc
index 6f491a63..bc987f69 100644
--- a/libstb/secvar/backend/Makefile.inc
+++ b/libstb/secvar/backend/Makefile.inc
@@ -1,11 +1,11 @@
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 # -*-Makefile-*-
 
-SECVAR_BACKEND_DIR = libstb/secvar/backend
+SECVAR_BACKEND_DIR = $(SRC)/libstb/secvar/backend
 
 SUBDIRS += $(SECVAR_BACKEND_DIR)
 
-SECVAR_BACKEND_SRCS =
+SECVAR_BACKEND_SRCS = edk2-compat.c edk2-compat-process.c edk2-compat-reset.c
 SECVAR_BACKEND_OBJS = $(SECVAR_BACKEND_SRCS:%.c=%.o)
 SECVAR_BACKEND = $(SECVAR_BACKEND_DIR)/built-in.a
 
diff --git a/libstb/secvar/backend/edk2-compat-process.c b/libstb/secvar/backend/edk2-compat-process.c
new file mode 100644
index 00000000..97c20ff2
--- /dev/null
+++ b/libstb/secvar/backend/edk2-compat-process.c
@@ -0,0 +1,724 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+#ifndef pr_fmt
+#define pr_fmt(fmt) "EDK2_COMPAT: " fmt
+#endif
+
+#include <opal.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <ccan/endian/endian.h>
+#include <mbedtls/error.h>
+#include <device.h>
+#include <assert.h>
+#include "libstb/crypto/pkcs7/pkcs7.h"
+#include "edk2.h"
+#include "../secvar.h"
+#include "edk2-compat-process.h"
+
+bool setup_mode;
+
+int update_variable_in_bank(struct secvar *update_var, const char *data,
+			    const uint64_t dsize, struct list_head *bank)
+{
+	struct secvar *var;
+
+	var = find_secvar(update_var->key, update_var->key_len, bank);
+	if (!var)
+		return OPAL_EMPTY;
+
+        /* Reallocate the data memory, if there is change in data size */
+	if (var->data_size < dsize)
+		if (realloc_secvar(var, dsize))
+			return OPAL_NO_MEM;
+
+	if (dsize && data)
+		memcpy(var->data, data, dsize);
+	var->data_size = dsize;
+
+        /* Clear the volatile bit only if updated with positive data size */
+	if (dsize)
+		var->flags &= ~SECVAR_FLAG_VOLATILE;
+	else
+		var->flags |= SECVAR_FLAG_VOLATILE;
+
+	if (key_equals(update_var->key, "PK") || key_equals(update_var->key, "HWKH"))
+		var->flags |= SECVAR_FLAG_PROTECTED;
+
+	return 0;
+}
+
+/* Expand char to wide character size */
+static char *char_to_wchar(const char *key, const size_t keylen)
+{
+	int i;
+	char *str;
+
+	str = zalloc(keylen * 2);
+	if (!str)
+		return NULL;
+
+	for (i = 0; i < keylen*2; key++) {
+		str[i++] = *key;
+		str[i++] = '\0';
+	}
+
+	return str;
+}
+
+/* Returns the authority that can sign the given key update */
+static void get_key_authority(const char *ret[3], const char *key)
+{
+	int i = 0;
+
+	if (key_equals(key, "PK")) {
+		ret[i++] = "PK";
+	} else if (key_equals(key, "KEK")) {
+		ret[i++] = "PK";
+	} else if (key_equals(key, "db") || key_equals(key, "dbx")) {
+		ret[i++] = "KEK";
+		ret[i++] = "PK";
+	}
+
+	ret[i] = NULL;
+}
+
+static EFI_SIGNATURE_LIST* get_esl_signature_list(const char *buf, size_t buflen)
+{
+	EFI_SIGNATURE_LIST *list = NULL;
+
+	if (buflen < sizeof(EFI_SIGNATURE_LIST) || !buf)
+		return NULL;
+
+	list = (EFI_SIGNATURE_LIST *)buf;
+
+	return list;
+}
+
+/* Returns the size of the complete ESL. */
+static int32_t get_esl_signature_list_size(const char *buf, const size_t buflen)
+{
+	EFI_SIGNATURE_LIST *list = get_esl_signature_list(buf, buflen);
+
+	if (!list)
+		return OPAL_PARAMETER;
+
+	prlog(PR_DEBUG, "size of signature list size is %u\n",
+			le32_to_cpu(list->SignatureListSize));
+
+	return le32_to_cpu(list->SignatureListSize);
+}
+
+/* 
+ * Copies the certificate from the ESL into cert buffer and returns the size
+ * of the certificate
+ */
+static int get_esl_cert(const char *buf, const size_t buflen, char **cert)
+{
+	size_t sig_data_offset;
+	size_t size;
+	EFI_SIGNATURE_LIST *list = get_esl_signature_list(buf, buflen);
+
+	if (!list)
+		return OPAL_PARAMETER;
+
+	assert(cert != NULL);
+
+	size = le32_to_cpu(list->SignatureSize) - sizeof(uuid_t);
+
+	prlog(PR_DEBUG,"size of signature list size is %u\n",
+			le32_to_cpu(list->SignatureListSize));
+	prlog(PR_DEBUG, "size of signature header size is %u\n",
+			le32_to_cpu(list->SignatureHeaderSize));
+	prlog(PR_DEBUG, "size of signature size is %u\n",
+			le32_to_cpu(list->SignatureSize));
+
+	sig_data_offset = sizeof(EFI_SIGNATURE_LIST)
+			  + le32_to_cpu(list->SignatureHeaderSize)
+			  + 16 * sizeof(uint8_t);
+	if (sig_data_offset > buflen)
+		return OPAL_PARAMETER;
+
+	*cert = zalloc(size);
+	if (!(*cert))
+		return OPAL_NO_MEM;
+
+	/* Since buf can have more than one ESL, copy only the size calculated
+	 * to return single ESL */
+	memcpy(*cert, buf + sig_data_offset, size);
+
+	return size;
+}
+
+/* 
+ * Extracts size of the PKCS7 signed data embedded in the
+ * struct Authentication 2 Descriptor Header.
+ */
+static size_t get_pkcs7_len(const struct efi_variable_authentication_2 *auth)
+{
+	uint32_t dw_length;
+	size_t size;
+
+	assert(auth != NULL);
+
+	dw_length = le32_to_cpu(auth->auth_info.hdr.dw_length);
+	size = dw_length - (sizeof(auth->auth_info.hdr.dw_length)
+			+ sizeof(auth->auth_info.hdr.w_revision)
+			+ sizeof(auth->auth_info.hdr.w_certificate_type)
+			+ sizeof(auth->auth_info.cert_type));
+
+	return size;
+}
+
+int get_auth_descriptor2(const void *buf, const size_t buflen, void **auth_buffer)
+{
+	const struct efi_variable_authentication_2 *auth = buf;
+	int auth_buffer_size;
+	size_t len;
+
+	assert(auth_buffer != NULL);
+	if (buflen < sizeof(struct efi_variable_authentication_2)
+	    || !buf)
+			return OPAL_PARAMETER;
+
+	len = get_pkcs7_len(auth);
+	/* pkcs7 content length cannot be greater than buflen */ 
+	if (len > buflen)
+		return OPAL_PARAMETER;
+
+	auth_buffer_size = sizeof(auth->timestamp) + sizeof(auth->auth_info.hdr)
+			   + sizeof(auth->auth_info.cert_type) + len;
+
+	*auth_buffer = zalloc(auth_buffer_size);
+	if (!(*auth_buffer))
+		return OPAL_NO_MEM;
+
+	/*
+	 * Data = auth descriptor + new ESL data.
+	 * Extracts only the auth descriptor from data.
+	 */
+	memcpy(*auth_buffer, buf, auth_buffer_size);
+
+	return auth_buffer_size;
+}
+
+int validate_esl_list(const char *key, const char *esl, const size_t size)
+{
+	int count = 0;
+	int signing_cert_size;
+	char *signing_cert = NULL;
+	mbedtls_x509_crt x509;
+	char *x509_buf = NULL;
+	int eslvarsize = size;
+	int eslsize;
+	int rc = OPAL_SUCCESS;
+	int offset = 0;
+
+	while (eslvarsize > 0) {
+		prlog(PR_DEBUG, "esl var size size is %d offset is %d\n", eslvarsize, offset);
+		if (eslvarsize < sizeof(EFI_SIGNATURE_LIST))
+			break;
+
+		/* Calculate the size of the ESL */
+		eslsize = get_esl_signature_list_size(esl, eslvarsize);
+		/* If could not extract the size */
+		if (eslsize <= 0) {
+			prlog(PR_ERR, "Invalid size of the ESL\n");
+			rc = OPAL_PARAMETER;
+			break;
+		}
+
+		/* Extract the certificate from the ESL */
+		signing_cert_size = get_esl_cert(esl,
+						 eslvarsize,
+						 &signing_cert);
+		if (signing_cert_size < 0) {
+			rc = signing_cert_size;
+			break;
+		}
+
+		mbedtls_x509_crt_init(&x509);
+		rc = mbedtls_x509_crt_parse(&x509,
+					    signing_cert,
+					    signing_cert_size);
+
+		/* If failure in parsing the certificate, exit */
+		if(rc) {
+			prlog(PR_INFO, "X509 certificate parsing failed %04x\n", rc);
+			rc = OPAL_PARAMETER;
+			break;
+		}
+
+		x509_buf = zalloc(CERT_BUFFER_SIZE);
+		rc = mbedtls_x509_crt_info(x509_buf,
+					   CERT_BUFFER_SIZE,
+					   "CRT:",
+					   &x509);
+		prlog(PR_INFO, "%s ", x509_buf);
+
+		/* If failure in reading the certificate, exit */
+		if (rc < 0) {
+			prlog(PR_INFO, "Failed to show X509 certificate info %04x\n", rc);
+			rc = OPAL_PARAMETER;
+			free(x509_buf);
+			break;
+		}
+		rc = 0;
+
+		free(x509_buf);
+		x509_buf = NULL;
+		count++;
+
+		/* Look for the next ESL */
+		offset = offset + eslsize;
+		eslvarsize = eslvarsize - eslsize;
+		mbedtls_x509_crt_free(&x509);
+		free(signing_cert);
+		/* Since we are going to allocate again in the next iteration */
+		signing_cert = NULL;
+	}
+
+	if (rc == OPAL_SUCCESS) {
+		if (key_equals(key, "PK") && (count > 1)) {
+			prlog(PR_ERR, "PK can only be one\n");
+			rc = OPAL_PARAMETER;
+		} else {
+			rc = count;
+		}
+	}
+
+	prlog(PR_INFO, "Total ESLs are %d\n", rc);
+	return rc;
+}
+
+/* Get the timestamp for the last update of the give key */
+static struct efi_time *get_last_timestamp(const char *key, char *last_timestamp)
+{
+	struct efi_time *timestamp = (struct efi_time*)last_timestamp;
+
+	if (!last_timestamp)
+		return NULL;
+
+	if (key_equals(key, "PK"))
+		return &timestamp[0];
+	else if (key_equals(key, "KEK"))
+		return &timestamp[1];
+	else if (key_equals(key, "db"))
+		return &timestamp[2];
+	else if (key_equals(key, "dbx"))
+		return &timestamp[3];
+	else
+		return NULL;
+}
+
+int update_timestamp(const char *key, const struct efi_time *timestamp, char *last_timestamp)
+{
+	struct efi_time *prev;
+
+	prev = get_last_timestamp(key, last_timestamp);
+	if (prev == NULL)
+		return OPAL_INTERNAL_ERROR;
+
+	/* Update with new timestamp */
+	memcpy(prev, timestamp, sizeof(struct efi_time));
+
+	prlog(PR_DEBUG, "updated prev year is %d month %d day %d\n",
+			le16_to_cpu(prev->year), prev->month, prev->day);
+
+	return OPAL_SUCCESS;
+}
+
+static uint64_t unpack_timestamp(const struct efi_time *timestamp)
+{
+	uint64_t val = 0;
+	uint16_t year = le32_to_cpu(timestamp->year);
+
+	/* pad1, nanosecond, timezone, daylight and pad2 are meant to be zero */
+	val |= ((uint64_t) timestamp->pad1 & 0xFF) << 0;
+	val |= ((uint64_t) timestamp->second & 0xFF) << (1*8);
+	val |= ((uint64_t) timestamp->minute & 0xFF) << (2*8);
+	val |= ((uint64_t) timestamp->hour & 0xFF) << (3*8);
+	val |= ((uint64_t) timestamp->day & 0xFF) << (4*8);
+	val |= ((uint64_t) timestamp->month & 0xFF) << (5*8);
+	val |= ((uint64_t) year) << (6*8);
+
+	return val;
+}
+
+int check_timestamp(const char *key, const struct efi_time *timestamp,
+		    char *last_timestamp)
+{
+	struct efi_time *prev;
+	uint64_t new;
+	uint64_t last;
+
+	prev = get_last_timestamp(key, last_timestamp);
+	if (prev == NULL)
+		return OPAL_INTERNAL_ERROR;
+
+	prlog(PR_DEBUG, "timestamp year is %d month %d day %d\n",
+			le16_to_cpu(timestamp->year), timestamp->month,
+			timestamp->day);
+	prlog(PR_DEBUG, "prev year is %d month %d day %d\n",
+			le16_to_cpu(prev->year), prev->month, prev->day);
+
+	new = unpack_timestamp(timestamp);
+	last = unpack_timestamp(prev);
+
+	if (new > last)
+		return OPAL_SUCCESS;
+
+	return OPAL_PERMISSION;
+}
+
+/* Extract PKCS7 from the authentication header */
+static mbedtls_pkcs7* get_pkcs7(const struct efi_variable_authentication_2 *auth)
+{
+	char *checkpkcs7cert = NULL;
+	size_t len;
+	mbedtls_pkcs7 *pkcs7 = NULL;
+	int rc;
+
+	len = get_pkcs7_len(auth);
+
+	pkcs7 = malloc(sizeof(struct mbedtls_pkcs7));
+	if (!pkcs7)
+		return NULL;
+
+	mbedtls_pkcs7_init(pkcs7);
+	rc = mbedtls_pkcs7_parse_der( auth->auth_info.cert_data, len, pkcs7);
+	if (rc) {
+		prlog(PR_ERR, "Parsing pkcs7 failed %04x\n", rc);
+		goto out;
+	}
+
+	checkpkcs7cert = zalloc(CERT_BUFFER_SIZE);
+	if (!checkpkcs7cert)
+		goto out;
+
+	rc = mbedtls_x509_crt_info(checkpkcs7cert, CERT_BUFFER_SIZE, "CRT:",
+				   &(pkcs7->signed_data.certs));
+	if (rc < 0) {
+		prlog(PR_ERR, "Failed to parse the certificate in PKCS7 structure\n");
+		free(checkpkcs7cert);
+		goto out;
+	}
+
+	prlog(PR_DEBUG, "%s \n", checkpkcs7cert);
+	free(checkpkcs7cert);
+	return pkcs7;
+
+out:
+	mbedtls_pkcs7_free(pkcs7);
+	pkcs7 = NULL;
+	return pkcs7;
+}
+
+/* Verify the PKCS7 signature on the signed data. */
+static int verify_signature(const struct efi_variable_authentication_2 *auth,
+			    const char *newcert, const size_t new_data_size,
+			    const struct secvar *avar)
+{
+	mbedtls_pkcs7 *pkcs7 = NULL;
+	mbedtls_x509_crt x509;
+	char *signing_cert = NULL;
+	char *x509_buf = NULL;
+	int signing_cert_size;
+	int rc = 0;
+	char *errbuf;
+	int eslvarsize;
+	int eslsize;
+	int offset = 0;
+
+	if (!auth)
+		return OPAL_PARAMETER;
+
+	/* Extract the pkcs7 from the auth structure */
+	pkcs7 = get_pkcs7(auth);
+	/* Failure to parse pkcs7 implies bad input. */
+	if (!pkcs7)
+		return OPAL_PARAMETER;
+
+	prlog(PR_INFO, "Load the signing certificate from the keystore");
+
+	eslvarsize = avar->data_size;
+
+	/* Variable is not empty */
+	while (eslvarsize > 0) {
+		prlog(PR_DEBUG, "esl var size size is %d offset is %d\n", eslvarsize, offset);
+		if (eslvarsize < sizeof(EFI_SIGNATURE_LIST))
+			break;
+
+		/* Calculate the size of the ESL */
+		eslsize = get_esl_signature_list_size(avar->data + offset,
+						      eslvarsize);
+		/* If could not extract the size */
+		if (eslsize <= 0) {
+			rc = OPAL_PARAMETER;
+			break;
+		}
+
+		/* Extract the certificate from the ESL */
+		signing_cert_size = get_esl_cert(avar->data + offset,
+						 eslvarsize, &signing_cert);
+		if (signing_cert_size < 0) {
+			rc = signing_cert_size;
+			break;
+		}
+
+		mbedtls_x509_crt_init(&x509);
+		rc = mbedtls_x509_crt_parse(&x509,
+					    signing_cert,
+					    signing_cert_size);
+
+		/* This should not happen, unless something corrupted in PNOR */
+		if(rc) {
+			prlog(PR_INFO, "X509 certificate parsing failed %04x\n", rc);
+			rc = OPAL_INTERNAL_ERROR;
+			break;
+		}
+
+		x509_buf = zalloc(CERT_BUFFER_SIZE);
+		rc = mbedtls_x509_crt_info(x509_buf,
+					   CERT_BUFFER_SIZE,
+					   "CRT:",
+					   &x509);
+
+		/* This should not happen, unless something corrupted in PNOR */
+		if (rc < 0) {
+			free(x509_buf);
+			rc = OPAL_INTERNAL_ERROR;
+			break;
+		}
+
+		prlog(PR_INFO, "%s \n", x509_buf);
+		free(x509_buf);
+		x509_buf = NULL;
+
+		rc = mbedtls_pkcs7_signed_hash_verify(pkcs7, &x509, newcert, new_data_size);
+
+		/* If you find a signing certificate, you are done */
+		if (rc == 0) {
+			prlog(PR_INFO, "Signature Verification passed\n");
+			mbedtls_x509_crt_free(&x509);
+			break;
+		}
+
+		errbuf = zalloc(MBEDTLS_ERR_BUFFER_SIZE);
+		mbedtls_strerror(rc, errbuf, MBEDTLS_ERR_BUFFER_SIZE);
+		prlog(PR_INFO, "Signature Verification failed %02x %s\n",
+				rc, errbuf);
+		free(errbuf);
+
+		/* Look for the next ESL */
+		offset = offset + eslsize;
+		eslvarsize = eslvarsize - eslsize;
+		mbedtls_x509_crt_free(&x509);
+		free(signing_cert);
+		/* Since we are going to allocate again in the next iteration */
+		signing_cert = NULL;
+
+	}
+
+	free(signing_cert);
+	mbedtls_pkcs7_free(pkcs7);
+	free(pkcs7);
+
+	return rc;
+}
+
+/* 
+ * Create the hash of the buffer
+ * name || vendor guid || attributes || timestamp || newcontent
+ * which is submitted as signed by the user.
+ * Returns the sha256 hash, else negative error code.
+ */
+static char *get_hash_to_verify(const char *key, const char *new_data,
+				const size_t new_data_size,
+				const struct efi_time *timestamp)
+{
+	le32 attr = cpu_to_le32(SECVAR_ATTRIBUTES);
+	size_t varlen;
+	char *wkey;
+	uuid_t guid;
+	unsigned char *hash = NULL;
+	const mbedtls_md_info_t *md_info;
+	mbedtls_md_context_t ctx;
+	int rc;
+
+	md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
+	mbedtls_md_init(&ctx);
+
+	rc = mbedtls_md_setup(&ctx, md_info, 0);
+	if (rc)
+		goto out;
+
+	rc = mbedtls_md_starts(&ctx);
+	if (rc)
+		goto out;
+
+	if (key_equals(key, "PK")
+	    || key_equals(key, "KEK"))
+		guid = EFI_GLOBAL_VARIABLE_GUID;
+	else if (key_equals(key, "db")
+	    || key_equals(key, "dbx"))
+		guid = EFI_IMAGE_SECURITY_DATABASE_GUID;
+	else
+		return NULL;
+
+	/* Expand char name to wide character width */
+	varlen = strlen(key) * 2;
+	wkey = char_to_wchar(key, strlen(key));
+	rc = mbedtls_md_update(&ctx, wkey, varlen);
+	free(wkey);
+	if (rc) 
+		goto out;
+
+	rc = mbedtls_md_update(&ctx, (const unsigned char *)&guid, sizeof(guid));
+	if (rc)
+		goto out;
+
+	rc = mbedtls_md_update(&ctx, (const unsigned char *)&attr, sizeof(attr));
+	if (rc)
+		goto out;
+
+	rc = mbedtls_md_update(&ctx, (const unsigned char *)timestamp,
+			       sizeof(struct efi_time));
+	if (rc)
+		goto out;
+
+	rc = mbedtls_md_update(&ctx, new_data, new_data_size);
+	if (rc)
+		goto out;
+
+	hash = zalloc(32);
+	if (!hash)
+		return NULL;
+	rc = mbedtls_md_finish(&ctx, hash);
+	if (rc) {
+		free(hash);
+		hash = NULL;
+	}
+
+out:
+	mbedtls_md_free(&ctx);
+	return hash;
+}
+
+bool is_pkcs7_sig_format(const void *data)
+{
+	const struct efi_variable_authentication_2 *auth = data;
+	uuid_t pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID;
+
+	return !memcmp(&auth->auth_info.cert_type, &pkcs7_guid, 16);
+}
+
+int process_update(const struct secvar *update, char **newesl,
+		   int *new_data_size, struct efi_time *timestamp,
+		   struct list_head *bank, char *last_timestamp)
+{
+	struct efi_variable_authentication_2 *auth = NULL;
+	void *auth_buffer = NULL;
+	int auth_buffer_size = 0;
+	const char *key_authority[3];
+	char *tbhbuffer = NULL;
+	size_t tbhbuffersize = 0;
+	struct secvar *avar = NULL;
+	int rc = 0;
+	int i;
+
+	/* We need to split data into authentication descriptor and new ESL */
+	auth_buffer_size = get_auth_descriptor2(update->data,
+						update->data_size,
+						&auth_buffer);
+	if ((auth_buffer_size < 0)
+	     || (update->data_size < auth_buffer_size)) {
+		prlog(PR_ERR, "Invalid auth buffer size\n");
+		rc = auth_buffer_size;
+		goto out;
+	}
+
+	auth = auth_buffer;
+
+	if (!timestamp) {
+		rc = OPAL_INTERNAL_ERROR;
+		goto out;
+	}
+
+	memcpy(timestamp, auth_buffer, sizeof(struct efi_time));
+
+	rc = check_timestamp(update->key, timestamp, last_timestamp);
+	/* Failure implies probably an older command being resubmitted */
+	if (rc != OPAL_SUCCESS) {
+		prlog(PR_INFO, "Timestamp verification failed for key %s\n", update->key);
+		goto out;
+	}
+
+	/* Calculate the size of new ESL data */
+	*new_data_size = update->data_size - auth_buffer_size;
+	if (*new_data_size < 0) {
+		prlog(PR_ERR, "Invalid new ESL (new data content) size\n");
+		rc = OPAL_PARAMETER;
+		goto out;
+	}
+	*newesl = zalloc(*new_data_size);
+	if (!(*newesl)) {
+		rc = OPAL_NO_MEM;
+		goto out;
+	}
+	memcpy(*newesl, update->data + auth_buffer_size, *new_data_size);
+
+	/* Validate the new ESL is in right format */
+	rc = validate_esl_list(update->key, *newesl, *new_data_size);
+	if (rc < 0) {
+		prlog(PR_ERR, "ESL validation failed for key %s with error %04x\n",
+		      update->key, rc);
+		goto out;
+	}
+
+	if (setup_mode) {
+		rc = OPAL_SUCCESS;
+		goto out;
+	}
+
+	/* Prepare the data to be verified */
+	tbhbuffer = get_hash_to_verify(update->key, *newesl, *new_data_size,
+				timestamp);
+	if (!tbhbuffer) {
+		rc = OPAL_INTERNAL_ERROR;
+		goto out;
+	}
+
+	/* Get the authority to verify the signature */
+	get_key_authority(key_authority, update->key);
+
+	/*
+	 * Try for all the authorities that are allowed to sign.
+	 * For eg. db/dbx can be signed by both PK or KEK
+	 */
+	for (i = 0; key_authority[i] != NULL; i++) {
+		prlog(PR_DEBUG, "key is %s\n", update->key);
+		prlog(PR_DEBUG, "key authority is %s\n", key_authority[i]);
+		avar = find_secvar(key_authority[i],
+				    strlen(key_authority[i]) + 1,
+				    bank);
+		if (!avar || !avar->data_size)
+			continue;
+
+		/* Verify the signature */
+		rc = verify_signature(auth, tbhbuffer, tbhbuffersize,
+				      avar);
+
+		/* Break if signature verification is successful */
+		if (rc == OPAL_SUCCESS)
+			break;
+	}
+
+out:
+	free(auth_buffer);
+	free(tbhbuffer);
+
+	return rc;
+}
diff --git a/libstb/secvar/backend/edk2-compat-process.h b/libstb/secvar/backend/edk2-compat-process.h
new file mode 100644
index 00000000..e89e9c68
--- /dev/null
+++ b/libstb/secvar/backend/edk2-compat-process.h
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+
+#ifndef __SECVAR_EDK2_COMPAT_PROCESS__
+#define __SECVAR_EDK2_COMPAT_PROCESS__
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "EDK2_COMPAT: " fmt
+#endif
+
+#include <opal.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <ccan/endian/endian.h>
+#include <mbedtls/error.h>
+#include <device.h>
+#include "libstb/crypto/pkcs7/pkcs7.h"
+#include "edk2.h"
+#include "opal-api.h"
+#include "../secvar.h"
+#include "../secvar_devtree.h"
+
+#define CERT_BUFFER_SIZE        2048
+#define MBEDTLS_ERR_BUFFER_SIZE 1024
+
+#define EDK2_MAX_KEY_LEN        SECVAR_MAX_KEY_LEN
+#define key_equals(a,b) (!strncmp(a, b, EDK2_MAX_KEY_LEN))
+
+extern bool setup_mode;
+extern struct list_head staging_bank;
+
+/* Update the variable in the variable bank with the new value. */
+int update_variable_in_bank(struct secvar *update_var, const char *data,
+			    uint64_t dsize, struct list_head *bank);
+
+/* This function outputs the Authentication 2 Descriptor in the
+ * auth_buffer and returns the size of the buffer. Please refer to
+ * edk2.h for details on Authentication 2 Descriptor
+ */
+int get_auth_descriptor2(const void *buf, const size_t buflen,
+			 void **auth_buffer);
+
+/* Check the format of the ESL */
+int validate_esl_list(const char *key, const char *esl, const size_t size);
+
+/* Update the TS variable with the new timestamp */
+int update_timestamp(const char *key, const struct efi_time *timestamp, char *last_timestamp);
+
+/* Check the new timestamp against the timestamp last update was done */
+int check_timestamp(const char *key, const struct efi_time *timestamp, char *last_timestamp);
+
+/* Check the GUID of the data type */
+bool is_pkcs7_sig_format(const void *data);
+
+/* Process the update */
+int process_update(const struct secvar *update, char **newesl,
+		   int *neweslsize, struct efi_time *timestamp,
+		   struct list_head *bank, char *last_timestamp);
+
+#endif
diff --git a/libstb/secvar/backend/edk2-compat-reset.c b/libstb/secvar/backend/edk2-compat-reset.c
new file mode 100644
index 00000000..cc3c6d08
--- /dev/null
+++ b/libstb/secvar/backend/edk2-compat-reset.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+#include <opal.h>
+#include <device.h>
+#include "edk2-compat-process.h"
+#include "edk2-compat-reset.h"
+#include "../secvar.h"
+
+int reset_keystore(struct list_head *bank)
+{
+	struct secvar *var;
+	int rc = 0;
+
+	var = find_secvar("PK", 3, bank);
+	if (var)
+		rc = update_variable_in_bank(var, NULL, 0, bank);
+	if (rc)
+		return rc;
+
+	var = find_secvar("KEK", 4, bank);
+	if (var)
+		rc = update_variable_in_bank(var, NULL, 0, bank);
+	if (rc)
+		return rc;
+
+	var = find_secvar("db", 3, bank);
+	if (var)
+		rc = update_variable_in_bank(var, NULL, 0, bank);
+	if (rc)
+		return rc;
+
+	var = find_secvar("dbx", 4, bank);
+	if (var)
+		rc = update_variable_in_bank(var, NULL, 0, bank);
+	if (rc)
+		return rc;
+
+	var = find_secvar("TS", 3, bank);
+	if (var)
+		rc = update_variable_in_bank(var, NULL, 0, bank);
+	if (rc)
+		return rc;
+
+	var = find_secvar("HWKH", 5, bank);
+	if (var)
+		rc = update_variable_in_bank(var, NULL, 0, bank);
+
+	return rc;
+}
+
+
+int add_hw_key_hash(struct list_head *bank)
+{
+	struct secvar *var;
+	uint32_t hw_key_hash_size;
+	const char *hw_key_hash;
+	struct dt_node *secureboot;
+
+	secureboot = dt_find_by_path(dt_root, "ibm,secureboot");
+	if (!secureboot)
+		return false;
+
+	hw_key_hash_size = dt_prop_get_u32(secureboot, "hw-key-hash-size");
+
+	hw_key_hash = dt_prop_get(secureboot, "hw-key-hash");
+
+	if (!hw_key_hash)
+		return OPAL_PERMISSION;
+
+	var = new_secvar("HWKH", 5, hw_key_hash,
+			hw_key_hash_size, SECVAR_FLAG_PROTECTED);
+	list_add_tail(bank, &var->link);
+
+	return OPAL_SUCCESS;
+}
+
+int delete_hw_key_hash(struct list_head *bank)
+{
+	struct secvar *var;
+	int rc;
+
+	var = find_secvar("HWKH", 5, bank);
+	if (!var)
+		return OPAL_SUCCESS;
+
+	rc = update_variable_in_bank(var, NULL, 0, bank);
+	return rc;
+}
+
+int verify_hw_key_hash(void)
+{
+	const char *hw_key_hash;
+	struct dt_node *secureboot;
+	struct secvar *var;
+
+	secureboot = dt_find_by_path(dt_root, "ibm,secureboot");
+	if (!secureboot)
+		return OPAL_INTERNAL_ERROR;
+
+	hw_key_hash = dt_prop_get(secureboot, "hw-key-hash");
+
+	if (!hw_key_hash)
+		return OPAL_INTERNAL_ERROR;
+
+	/* This value is from the protected storage */
+	var = find_secvar("HWKH", 5, &variable_bank);
+	if (!var)
+		return OPAL_PERMISSION;
+
+	if (memcmp(hw_key_hash, var->data, var->data_size) != 0)
+		return OPAL_PERMISSION;
+
+	return OPAL_SUCCESS;
+}
+
diff --git a/libstb/secvar/backend/edk2-compat-reset.h b/libstb/secvar/backend/edk2-compat-reset.h
new file mode 100644
index 00000000..bede9c9d
--- /dev/null
+++ b/libstb/secvar/backend/edk2-compat-reset.h
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+
+#ifndef __SECVAR_EDK2_COMPAT_CLEAR_KEYS__
+#define __SECVAR_EDK2_COMPAT_CLEAR_KEYS__
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "EDK2_COMPAT: " fmt
+#endif
+
+/* clear all os keys and the timestamp*/
+int reset_keystore(struct list_head *bank);
+
+/* Compares the hw-key-hash from device tree to the value stored in
+ * the protected storage to ensure it is not modified */
+int verify_hw_key_hash(void);
+
+/* Adds hw-key-hash */
+int add_hw_key_hash(struct list_head *bank);
+
+/* Delete hw-key-hash */
+int delete_hw_key_hash(struct list_head *bank);
+
+#endif
diff --git a/libstb/secvar/backend/edk2-compat.c b/libstb/secvar/backend/edk2-compat.c
new file mode 100644
index 00000000..52631c0b
--- /dev/null
+++ b/libstb/secvar/backend/edk2-compat.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+#ifndef pr_fmt
+#define pr_fmt(fmt) "EDK2_COMPAT: " fmt
+#endif
+
+#include <opal.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <skiboot.h>
+#include <ccan/endian/endian.h>
+#include <mbedtls/error.h>
+#include "libstb/crypto/pkcs7/pkcs7.h"
+#include "edk2.h"
+#include "../secvar.h"
+#include "edk2-compat-process.h"
+#include "edk2-compat-reset.h"
+
+struct list_head staging_bank;
+
+/*
+ * Initializes supported variables as empty if not loaded from
+ * storage. Variables are initialized as volatile if not found.
+ * Updates should clear this flag.
+ * Returns OPAL Error if anything fails in initialization
+ */
+static int edk2_compat_pre_process(struct list_head *variable_bank,
+				   struct list_head *update_bank __unused)
+{
+	struct secvar *pkvar;
+	struct secvar *kekvar;
+	struct secvar *dbvar;
+	struct secvar *dbxvar;
+	struct secvar *tsvar;
+
+	pkvar = find_secvar("PK", 3, variable_bank);
+	if (!pkvar) {
+		pkvar = new_secvar("PK", 3, NULL, 0, SECVAR_FLAG_VOLATILE
+				| SECVAR_FLAG_PROTECTED);
+		if (!pkvar)
+			return OPAL_NO_MEM;
+
+		list_add_tail(variable_bank, &pkvar->link);
+	}
+	if (pkvar->data_size == 0)
+		setup_mode = true;
+	else
+		setup_mode = false;
+
+	kekvar = find_secvar("KEK", 4, variable_bank);
+	if (!kekvar) {
+		kekvar = new_secvar("KEK", 4, NULL, 0, SECVAR_FLAG_VOLATILE);
+		if (!kekvar)
+			return OPAL_NO_MEM;
+
+		list_add_tail(variable_bank, &kekvar->link);
+	}
+
+	dbvar = find_secvar("db", 3, variable_bank);
+	if (!dbvar) {
+		dbvar = new_secvar("db", 3, NULL, 0, SECVAR_FLAG_VOLATILE);
+		if (!dbvar)
+			return OPAL_NO_MEM;
+
+		list_add_tail(variable_bank, &dbvar->link);
+	}
+
+	dbxvar = find_secvar("dbx", 4, variable_bank);
+	if (!dbxvar) {
+		dbxvar = new_secvar("dbx", 4, NULL, 0, SECVAR_FLAG_VOLATILE);
+		if (!dbxvar)
+			return OPAL_NO_MEM;
+
+		list_add_tail(variable_bank, &dbxvar->link);
+	}
+
+	/*
+	 * Should only ever happen on first boot. Timestamp is
+	 * initialized with all zeroes.
+	 */
+	tsvar = find_secvar("TS", 3, variable_bank);
+	if (!tsvar) {
+		tsvar = alloc_secvar(3, sizeof(struct efi_time) * 4);
+		if (!tsvar)
+			return OPAL_NO_MEM;
+
+		memcpy(tsvar->key, "TS", 3);
+		tsvar->key_len = 3;
+		tsvar->data_size = sizeof(struct efi_time) * 4;
+		memset(tsvar->data, 0, tsvar->data_size);
+		list_add_tail(variable_bank, &tsvar->link);
+	}
+
+	return OPAL_SUCCESS;
+};
+
+static int edk2_compat_process(struct list_head *variable_bank,
+			       struct list_head *update_bank)
+{
+	struct secvar *var = NULL;
+	struct secvar *tsvar = NULL;
+	struct efi_time timestamp;
+	char *newesl = NULL;
+	int neweslsize;
+	int rc = 0;
+
+	prlog(PR_INFO, "Setup mode = %d\n", setup_mode);
+
+	/* Check HW-KEY-HASH */
+	if (!setup_mode) {
+		rc = verify_hw_key_hash();
+		if (rc != OPAL_SUCCESS) {
+			prlog(PR_ERR, "Hardware key hash verification mismatch\n");
+			rc = reset_keystore(variable_bank);
+			if (rc)
+				goto cleanup;
+			setup_mode = true;
+			goto cleanup;
+		}
+	}
+
+	/* Return early if we have no updates to process */
+	if (list_empty(update_bank)) {
+		return OPAL_EMPTY;
+	}
+
+	/*
+	 * Make a working copy of variable bank that is updated
+	 * during process
+	 */
+	list_head_init(&staging_bank);
+	copy_bank_list(&staging_bank, variable_bank);
+
+	/*
+	 * Loop through each command in the update bank.
+	 * If any command fails, it just loops out of the update bank.
+	 * It should also clear the update bank.
+	 */
+
+	/* Read the TS variable first time and then keep updating it in-memory */
+	tsvar = find_secvar("TS", 3, &staging_bank);
+
+	/*
+	 * We cannot find timestamp variable, did someone tamper it ?, return
+	 * OPAL_PERMISSION
+	 */
+	if (!tsvar)
+		return OPAL_PERMISSION;
+
+	list_for_each(update_bank, var, link) {
+
+		/*
+		 * Submitted data is auth_2 descriptor + new ESL data
+		 * Extract the auth_2 2 descriptor
+		 */
+		prlog(PR_INFO, "Update for %s\n", var->key);
+
+		rc = process_update(var, &newesl,
+				    &neweslsize, &timestamp,
+				    &staging_bank,
+				    tsvar->data);
+		if (rc) {
+			prlog(PR_ERR, "Update processing failed with rc %04x\n", rc);
+			break;
+		}
+
+		/*
+		 * If reached here means, signature is verified so update the
+		 * value in the variable bank
+		 */
+		rc = update_variable_in_bank(var,
+					     newesl,
+					     neweslsize,
+					     &staging_bank);
+		if (rc) {
+			prlog(PR_ERR, "Updating the variable data failed %04x\n", rc);
+			break;
+		}
+
+		free(newesl);
+		newesl = NULL;
+		/* Update the TS variable with the new timestamp */
+		rc = update_timestamp(var->key,
+				      &timestamp,
+				      tsvar->data);
+		if (rc) {
+			prlog (PR_ERR, "Variable updated, but timestamp updated failed %04x\n", rc);
+			break;
+		}
+
+		/*
+		 * If the PK is updated, update the secure boot state of the
+		 * system at the end of processing
+		 */
+		if (key_equals(var->key, "PK")) {
+			/*
+			 * PK is tied to a particular firmware image by mapping it with
+			 * hw-key-hash of that firmware. When PK is updated, hw-key-hash
+			 * is updated. And when PK is deleted, delete hw-key-hash as well
+			 */
+			if(neweslsize == 0) {
+				setup_mode = true;
+				delete_hw_key_hash(&staging_bank);
+			} else  {
+				setup_mode = false;
+				add_hw_key_hash(&staging_bank);
+			}
+			prlog(PR_DEBUG, "setup mode is %d\n", setup_mode);
+		}
+	}
+
+	if (rc == 0) {
+		/* Update the variable bank with updated working copy */
+		clear_bank_list(variable_bank);
+		copy_bank_list(variable_bank, &staging_bank);
+	}
+
+cleanup:
+	/*
+	 * For any failure in processing update queue, we clear the update bank
+	 * and return failure
+	 */
+	free(newesl);
+	clear_bank_list(&staging_bank);
+	clear_bank_list(update_bank);
+
+	return rc;
+}
+
+static int edk2_compat_post_process(struct list_head *variable_bank,
+				    struct list_head *update_bank __unused)
+{
+	struct secvar *hwvar;
+	if (!setup_mode) {
+		secvar_set_secure_mode();
+		prlog(PR_INFO, "Enforcing OS secure mode\n");
+		/*
+		 * HW KEY HASH is no more needed after this point. It is already
+		 * visible to userspace via device-tree, so exposing via sysfs is
+		 * just a duplication. Remove it from in-memory copy.
+		 */
+		hwvar = find_secvar("HWKH", 5, variable_bank);
+		if (!hwvar) {
+			prlog(PR_ERR, "cannot find hw-key-hash, should not happen\n");
+			return OPAL_INTERNAL_ERROR;
+		}
+		list_del(&hwvar->link);
+		dealloc_secvar(hwvar);
+	}
+
+	return OPAL_SUCCESS;
+}
+
+static int edk2_compat_validate(struct secvar *var)
+{
+
+	/*
+	 * Checks if the update is for supported
+	 * Non-volatile secure variables
+	 */
+	if (!key_equals(var->key, "PK")
+			&& !key_equals(var->key, "KEK")
+			&& !key_equals(var->key, "db")
+			&& !key_equals(var->key, "dbx"))
+		return OPAL_PARAMETER;
+
+	/* Check that signature type is PKCS7 */
+	if (!is_pkcs7_sig_format(var->data))
+		return OPAL_PARAMETER;
+
+	return OPAL_SUCCESS;
+};
+
+struct secvar_backend_driver edk2_compatible_v1 = {
+	.pre_process = edk2_compat_pre_process,
+	.process = edk2_compat_process,
+	.post_process = edk2_compat_post_process,
+	.validate = edk2_compat_validate,
+	.compatible = "ibm,edk2-compat-v1",
+};
diff --git a/libstb/secvar/backend/edk2.h b/libstb/secvar/backend/edk2.h
new file mode 100644
index 00000000..5cab1347
--- /dev/null
+++ b/libstb/secvar/backend/edk2.h
@@ -0,0 +1,243 @@
+/* Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. This
+ * program and the accompanying materials are licensed and made available
+ * under the terms and conditions of the 2-Clause BSD License which
+ * accompanies this distribution.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is derived from the following files referred from edk2-staging[1] repo
+ * of tianocore
+ *
+ * MdePkg/Include/Guid/GlobalVariable.h
+ * MdePkg/Include/Guid/WinCertificate.h
+ * MdePkg/Include/Uefi/UefiMultiPhase.h
+ * MdePkg/Include/Uefi/UefiBaseType.h
+ * MdePkg/Include/Guid/ImageAuthentication.h
+ *
+ * [1] https://github.com/tianocore/edk2-staging
+ *
+ * Copyright 2020 IBM Corp.
+ */
+
+#ifndef __EDK2_H__
+#define __EDK2_H__
+
+#define UUID_SIZE 16
+
+typedef struct {
+        u8 b[UUID_SIZE];
+} uuid_t;
+
+#define EFI_GLOBAL_VARIABLE_GUID (uuid_t){{0x61, 0xDF, 0xe4, 0x8b, 0xca, 0x93, 0xd2, 0x11, 0xaa, \
+			 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c}}
+
+#define EFI_IMAGE_SECURITY_DATABASE_GUID (uuid_t){{0xcb, 0xb2, 0x19, 0xd7, 0x3a, 0x3d, 0x96, 0x45, \
+					   0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f}}
+
+#define SECVAR_ATTRIBUTES	39
+
+///
+/// This identifies a signature based on an X.509 certificate. If the signature is an X.509
+/// certificate then verification of the signature of an image should validate the public
+/// key certificate in the image using certificate path verification, up to this X.509
+/// certificate as a trusted root.  The SignatureHeader size shall always be 0. The
+/// SignatureSize may vary but shall always be 16 (size of the SignatureOwner component) +
+/// the size of the certificate itself.
+/// Note: This means that each certificate will normally be in a separate EFI_SIGNATURE_LIST.
+///
+
+#define EFI_CERT_RSA2048_GUID \
+  (UUID_INIT) (0x3c5766e8, 0x269c, 0x4e34, 0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6)
+
+#define EFI_CERT_TYPE_PKCS7_GUID (uuid_t){{0x9d, 0xd2, 0xaf, 0x4a, 0xdf, 0x68, 0xee, 0x49, \
+					   0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7}}
+
+#define EFI_VARIABLE_NON_VOLATILE				0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS				0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS				0x00000004
+
+/*
+ * Attributes of Authenticated Variable
+ */
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS	0x00000020
+#define EFI_VARIABLE_APPEND_WRITE				0x00000040
+/*
+ * NOTE: EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated and should be
+ * considered reserved.
+ */
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS			0x00000010
+
+/*
+ * win_certificate.w_certificate_type
+ */
+#define WIN_CERT_TYPE_PKCS_SIGNED_DATA	0x0002
+
+#define SECURE_BOOT_MODE_ENABLE           1
+#define SECURE_BOOT_MODE_DISABLE          0
+///
+/// Depricated value definition for SetupMode variable
+///
+#define SETUP_MODE                        1
+#define USER_MODE                         0
+
+/*
+ * EFI Time Abstraction:
+ *   Year:       1900 - 9999
+ *   Month:      1 - 12
+ *   Day:        1 - 31
+ *   Hour:       0 - 23
+ *   Minute:     0 - 59
+ *   Second:     0 - 59
+ *   Nanosecond: 0 - 999,999,999
+ *   TimeZone:   -1440 to 1440 or 2047
+ */
+struct efi_time {
+	u16 year;
+	u8 month;
+	u8 day;
+	u8 hour;
+	u8 minute;
+	u8 second;
+	u8 pad1;
+	u32 nanosecond;
+	s16 timezone;
+	u8 daylight;
+	u8 pad2;
+};
+//***********************************************************************
+// Signature Database
+//***********************************************************************
+///
+/// The format of a signature database.
+///
+#pragma pack(1)
+
+typedef struct {
+  ///
+  /// An identifier which identifies the agent which added the signature to the list.
+  ///
+  uuid_t SignatureOwner;
+  ///
+  /// The format of the signature is defined by the SignatureType.
+  ///
+  unsigned char SignatureData[0];
+} EFI_SIGNATURE_DATA;
+
+typedef struct {
+  ///
+  /// Type of the signature. GUID signature types are defined in below.
+  ///
+  uuid_t SignatureType;
+  ///
+  /// Total size of the signature list, including this header.
+  ///
+  uint32_t	SignatureListSize;
+  ///
+  /// Size of the signature header which precedes the array of signatures.
+  ///
+  uint32_t	SignatureHeaderSize;
+  ///
+  /// Size of each signature.
+  ///
+  uint32_t	SignatureSize;
+  ///
+  /// Header before the array of signatures. The format of this header is specified
+  /// by the SignatureType.
+  /// UINT8           SignatureHeader[SignatureHeaderSize];
+  ///
+  /// An array of signatures. Each signature is SignatureSize bytes in length.
+  /// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
+  ///
+} EFI_SIGNATURE_LIST;
+
+
+/*
+ * The win_certificate structure is part of the PE/COFF specification.
+ */
+struct win_certificate {
+	/*
+	 * The length of the entire certificate, including the length of the
+	 * header, in bytes.
+	 */
+	u32  dw_length;
+	/*
+	 * The revision level of the WIN_CERTIFICATE structure. The current
+	 * revision level is 0x0200.
+	 */
+	u16  w_revision;
+	/*
+	 * The certificate type. See WIN_CERT_TYPE_xxx for the UEFI certificate
+	 * types. The UEFI specification reserves the range of certificate type
+	 * values from 0x0EF0 to 0x0EFF.
+	 */
+	u16  w_certificate_type;
+	/*
+	 * The following is the actual certificate. The format of
+	 * the certificate depends on wCertificateType.
+	 */
+	/// UINT8 bCertificate[ANYSIZE_ARRAY];
+};
+
+/*
+ * Certificate which encapsulates a GUID-specific digital signature
+ */
+struct win_certificate_uefi_guid {
+	/*
+	 * This is the standard win_certificate header, where w_certificate_type
+	 * is set to WIN_CERT_TYPE_EFI_GUID.
+	 */
+	struct win_certificate hdr;
+	/*
+	 * This is the unique id which determines the format of the cert_data.
+	 */
+	uuid_t cert_type;
+	/*
+	 * The following is the certificate data. The format of the data is
+	 * determined by the @cert_type. If @cert_type is
+	 * EFI_CERT_TYPE_RSA2048_SHA256_GUID, the @cert_data will be
+	 * EFI_CERT_BLOCK_RSA_2048_SHA256 structure.
+	 */
+	u8 cert_data[];
+};
+/*
+ * When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is set,
+ * then the Data buffer shall begin with an instance of a complete (and
+ * serialized) EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be
+ * followed by the new variable value and DataSize shall reflect the combined
+ * size of the descriptor and the new variable value. The authentication
+ * descriptor is not part of the variable data and is not returned by subsequent
+ * calls to GetVariable().
+ */
+struct efi_variable_authentication_2 {
+	/*
+	 * 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.
+	 */
+	struct efi_time timestamp;
+	/*
+	 * Only a CertType of  EFI_CERT_TYPE_PKCS7_GUID is accepted.
+	 */
+	struct win_certificate_uefi_guid auth_info;
+};
+
+#endif
-- 
2.27.0



More information about the Skiboot mailing list