arrfab / rpms / shim

Forked from rpms/shim 4 years ago
Clone

Blame SOURCES/0030-Check-the-first-4-bytes-of-the-certificate.patch

e97c83
From 5f18e2e3643524c6b6b38c44c6ce4eabdcfd59d1 Mon Sep 17 00:00:00 2001
e97c83
From: Gary Ching-Pang Lin <glin@suse.com>
e97c83
Date: Tue, 27 May 2014 17:42:00 +0800
e97c83
Subject: [PATCH 30/74] Check the first 4 bytes of the certificate
e97c83
e97c83
A non-DER encoding x509 certificate may be mistakenly enrolled into
e97c83
db or MokList. This commit checks the first 4 bytes of the certificate
e97c83
to ensure that it's DER encoding.
e97c83
e97c83
This commit also removes the iteration of the x509 signature list.
e97c83
Per UEFI SPEC, each x509 signature list contains only one x509 certificate.
e97c83
Besides, the size of certificate is incorrect. The size of the header must
e97c83
be substracted from the signature size.
e97c83
e97c83
Signed-off-by: Gary Ching-Pang Lin <glin@suse.com>
e97c83
---
e97c83
 MokManager.c | 23 +++++++++++++++++++++--
e97c83
 shim.c       | 45 +++++++++++++++++++++++++++++++--------------
e97c83
 2 files changed, 52 insertions(+), 16 deletions(-)
e97c83
e97c83
diff --git a/MokManager.c b/MokManager.c
e97c83
index 3da61f4..c9fbbac 100644
e97c83
--- a/MokManager.c
e97c83
+++ b/MokManager.c
e97c83
@@ -1306,11 +1306,30 @@ static INTN mok_pw_prompt (void *MokPW, UINTN MokPWSize) {
e97c83
 	return -1;
e97c83
 }
e97c83
 
e97c83
-static BOOLEAN verify_certificate(void *cert, UINTN size)
e97c83
+static BOOLEAN verify_certificate(UINT8 *cert, UINTN size)
e97c83
 {
e97c83
 	X509 *X509Cert;
e97c83
-	if (!cert || size == 0)
e97c83
+	UINTN length;
e97c83
+	if (!cert || size < 0)
e97c83
+		return FALSE;
e97c83
+
e97c83
+	/*
e97c83
+	 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
e97c83
+	 * the number of length bytes, and the number of value bytes.
e97c83
+	 * The size of a x509 certificate is usually between 127 bytes
e97c83
+	 * and 64KB. For convenience, assume the number of value bytes
e97c83
+	 * is 2, i.e. the second byte is 0x82.
e97c83
+	 */
e97c83
+	if (cert[0] != 0x30 || cert[1] != 0x82) {
e97c83
+		console_notify(L"Not a DER encoding X509 certificate");
e97c83
 		return FALSE;
e97c83
+	}
e97c83
+
e97c83
+	length = (cert[2]<<8 | cert[3]);
e97c83
+	if (length != (size - 4)) {
e97c83
+		console_notify(L"Invalid X509 certificate: Inconsistent size");
e97c83
+		return FALSE;
e97c83
+	}
e97c83
 
e97c83
 	if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) ||
e97c83
 	    X509Cert == NULL) {
e97c83
diff --git a/shim.c b/shim.c
e97c83
index d8699f9..cd26ce6 100644
e97c83
--- a/shim.c
e97c83
+++ b/shim.c
e97c83
@@ -226,44 +226,61 @@ static EFI_STATUS relocate_coff (PE_COFF_LOADER_IMAGE_CONTEXT *context,
e97c83
 	return EFI_SUCCESS;
e97c83
 }
e97c83
 
e97c83
+static BOOLEAN verify_x509(UINT8 *Cert, UINTN CertSize)
e97c83
+{
e97c83
+	UINTN length;
e97c83
+
e97c83
+	if (!Cert || CertSize < 4)
e97c83
+		return FALSE;
e97c83
+
e97c83
+	/*
e97c83
+	 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
e97c83
+	 * the number of length bytes, and the number of value bytes.
e97c83
+	 * The size of a x509 certificate is usually between 127 bytes
e97c83
+	 * and 64KB. For convenience, assume the number of value bytes
e97c83
+	 * is 2, i.e. the second byte is 0x82.
e97c83
+	 */
e97c83
+	if (Cert[0] != 0x30 || Cert[1] != 0x82)
e97c83
+		return FALSE;
e97c83
+
e97c83
+	length = Cert[2]<<8 | Cert[3];
e97c83
+	if (length != (CertSize - 4))
e97c83
+		return FALSE;
e97c83
+
e97c83
+	return TRUE;
e97c83
+}
e97c83
+
e97c83
 static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
e97c83
 					 UINTN dbsize,
e97c83
 					 WIN_CERTIFICATE_EFI_PKCS *data,
e97c83
 					 UINT8 *hash)
e97c83
 {
e97c83
 	EFI_SIGNATURE_DATA *Cert;
e97c83
-	UINTN CertCount, Index;
e97c83
+	UINTN CertSize;
e97c83
 	BOOLEAN IsFound = FALSE;
e97c83
 	EFI_GUID CertType = X509_GUID;
e97c83
 
e97c83
 	while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
e97c83
 		if (CompareGuid (&CertList->SignatureType, &CertType) == 0) {
e97c83
-			CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
e97c83
 			Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
e97c83
-			for (Index = 0; Index < CertCount; Index++) {
e97c83
+			CertSize = CertList->SignatureSize - sizeof(EFI_GUID);
e97c83
+			if (verify_x509(Cert->SignatureData, CertSize)) {
e97c83
 				IsFound = AuthenticodeVerify (data->CertData,
e97c83
 							      data->Hdr.dwLength - sizeof(data->Hdr),
e97c83
 							      Cert->SignatureData,
e97c83
-							      CertList->SignatureSize,
e97c83
+							      CertSize,
e97c83
 							      hash, SHA256_DIGEST_SIZE);
e97c83
 				if (IsFound)
e97c83
-					break;
e97c83
-
e97c83
-				Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
e97c83
+					return DATA_FOUND;
e97c83
+			} else if (verbose) {
e97c83
+				console_notify(L"Not a DER encoding x.509 Certificate");
e97c83
 			}
e97c83
-
e97c83
 		}
e97c83
 
e97c83
-		if (IsFound)
e97c83
-			break;
e97c83
-
e97c83
 		dbsize -= CertList->SignatureListSize;
e97c83
 		CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
e97c83
 	}
e97c83
 
e97c83
-	if (IsFound)
e97c83
-		return DATA_FOUND;
e97c83
-
e97c83
 	return DATA_NOT_FOUND;
e97c83
 }
e97c83
 
e97c83
-- 
e97c83
1.9.3
e97c83