arrfab / rpms / shim

Forked from rpms/shim 4 years ago
Clone

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

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