]> git.proxmox.com Git - efi-boot-shim.git/commitdiff
Extend PCR 7
authorMatthew Garrett <mjg59@google.com>
Mon, 22 May 2017 22:36:48 +0000 (15:36 -0700)
committerPeter Jones <pjones@redhat.com>
Tue, 1 Aug 2017 16:54:49 +0000 (12:54 -0400)
It's desirable to be able to use PCR 7 for all TPM policy on Secure Boot
systems, but right now Shim doesn't record any information about its
configuration or the signature used to launch the second stage loader. Add
support for that.

shim.c
tpm.c
tpm.h

diff --git a/shim.c b/shim.c
index 6e040c4fef5c1fae7fd7b6b658f506291686cd9e..91fd926b4792133862d507f091ff95dcbf1d62f0 100644 (file)
--- a/shim.c
+++ b/shim.c
@@ -428,7 +428,8 @@ static BOOLEAN verify_eku(UINT8 *Cert, UINTN CertSize)
 static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
                                         UINTN dbsize,
                                         WIN_CERTIFICATE_EFI_PKCS *data,
-                                        UINT8 *hash)
+                                        UINT8 *hash, CHAR16 *dbname,
+                                        EFI_GUID guid)
 {
        EFI_SIGNATURE_DATA *Cert;
        UINTN CertSize;
@@ -446,8 +447,10 @@ static CHECK_STATUS check_db_cert_in_ram(EFI_SIGNATURE_LIST *CertList,
                                                                      Cert->SignatureData,
                                                                      CertSize,
                                                                      hash, SHA256_DIGEST_SIZE);
-                                       if (IsFound)
+                                       if (IsFound) {
+                                               tpm_measure_variable(dbname, guid, CertSize, Cert->SignatureData);
                                                return DATA_FOUND;
+                                       }
                                }
                        } else if (verbose) {
                                console_notify(L"Not a DER encoding x.509 Certificate");
@@ -477,7 +480,7 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
 
        CertList = (EFI_SIGNATURE_LIST *)db;
 
-       rc = check_db_cert_in_ram(CertList, dbsize, data, hash);
+       rc = check_db_cert_in_ram(CertList, dbsize, data, hash, dbname, guid);
 
        FreePool(db);
 
@@ -489,7 +492,8 @@ static CHECK_STATUS check_db_cert(CHAR16 *dbname, EFI_GUID guid,
  */
 static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
                                         UINTN dbsize, UINT8 *data,
-                                        int SignatureSize, EFI_GUID CertType)
+                                        int SignatureSize, EFI_GUID CertType,
+                                        CHAR16 *dbname, EFI_GUID guid)
 {
        EFI_SIGNATURE_DATA *Cert;
        UINTN CertCount, Index;
@@ -505,6 +509,7 @@ static CHECK_STATUS check_db_hash_in_ram(EFI_SIGNATURE_LIST *CertList,
                                        // Find the signature in database.
                                        //
                                        IsFound = TRUE;
+                                       tpm_measure_variable(dbname, guid, SignatureSize, data);
                                        break;
                                }
 
@@ -545,7 +550,8 @@ static CHECK_STATUS check_db_hash(CHAR16 *dbname, EFI_GUID guid, UINT8 *data,
        CertList = (EFI_SIGNATURE_LIST *)db;
 
        CHECK_STATUS rc = check_db_hash_in_ram(CertList, dbsize, data,
-                                               SignatureSize, CertType);
+                                              SignatureSize, CertType,
+                                              dbname, guid);
        FreePool(db);
        return rc;
 
@@ -563,15 +569,18 @@ static EFI_STATUS check_blacklist (WIN_CERTIFICATE_EFI_PKCS *cert,
        EFI_SIGNATURE_LIST *dbx = (EFI_SIGNATURE_LIST *)vendor_dbx;
 
        if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha256hash,
-                                SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID) ==
+                                SHA256_DIGEST_SIZE, EFI_CERT_SHA256_GUID,
+                                L"dbx", secure_var) ==
                                DATA_FOUND)
                return EFI_SECURITY_VIOLATION;
        if (check_db_hash_in_ram(dbx, vendor_dbx_size, sha1hash,
-                                SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID) ==
+                                SHA1_DIGEST_SIZE, EFI_CERT_SHA1_GUID,
+                                L"dbx", secure_var) ==
                                DATA_FOUND)
                return EFI_SECURITY_VIOLATION;
        if (cert && check_db_cert_in_ram(dbx, vendor_dbx_size, cert,
-                                        sha256hash) == DATA_FOUND)
+                                        sha256hash, L"dbx",
+                                        secure_var) == DATA_FOUND)
                return EFI_SECURITY_VIOLATION;
 
        if (check_db_hash(L"dbx", secure_var, sha256hash, SHA256_DIGEST_SIZE,
@@ -960,6 +969,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
        EFI_STATUS status = EFI_SECURITY_VIOLATION;
        WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
        unsigned int size = datasize;
+       EFI_GUID shim_var = SHIM_LOCK_GUID;
 
        if (context->SecDir->Size != 0) {
                if (context->SecDir->Size >= size) {
@@ -1026,6 +1036,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
                               shim_cert, sizeof(shim_cert), sha256hash,
                               SHA256_DIGEST_SIZE)) {
                        update_verification_method(VERIFIED_BY_CERT);
+                       tpm_measure_variable(L"Shim", shim_var, sizeof(shim_cert), shim_cert);
                        status = EFI_SUCCESS;
                        return status;
                }
@@ -1039,6 +1050,7 @@ static EFI_STATUS verify_buffer (char *data, int datasize,
                                       vendor_cert, vendor_cert_size,
                                       sha256hash, SHA256_DIGEST_SIZE)) {
                        update_verification_method(VERIFIED_BY_CERT);
+                       tpm_measure_variable(L"Shim", shim_var, vendor_cert_size, vendor_cert);
                        status = EFI_SUCCESS;
                        return status;
                }
@@ -1888,7 +1900,11 @@ EFI_STATUS init_grub(EFI_HANDLE image_handle)
 }
 
 /*
- * Measure some of the MOK variables into the TPM
+ * Measure some of the MOK variables into the TPM. We measure the entirety
+ * of MokList into PCR 14, and also measure the raw MokSBState there. PCR 7
+ * will be extended with MokSBState in the Microsoft format, and we'll
+ * measure any matching hashes or certificates later on in order to behave
+ * consistently with the PCR 7 spec.
  */
 EFI_STATUS measure_mok()
 {
@@ -1915,9 +1931,14 @@ EFI_STATUS measure_mok()
        if (efi_status != EFI_SUCCESS)
                return efi_status;
 
+       efi_status = tpm_measure_variable(L"MokSBState", shim_lock_guid,
+                                         DataSize, Data);
+       if (efi_status != EFI_SUCCESS)
+               goto out;
+
        efi_status = tpm_log_event((EFI_PHYSICAL_ADDRESS)(UINTN)Data,
                                   DataSize, 14, (CHAR8 *)"MokSBState");
-
+out:
        FreePool(Data);
 
        return efi_status;
diff --git a/tpm.c b/tpm.c
index c37cc484f9d0bc6b8897c416fd6daada7dbe6daa..6e3933cb10e7974137526f57ac7c81f606e702e8 100644 (file)
--- a/tpm.c
+++ b/tpm.c
@@ -14,6 +14,16 @@ extern UINT8 in_protocol;
                })
 
 
+typedef struct {
+       CHAR16 *VariableName;
+       EFI_GUID *VendorGuid;
+       VOID *Data;
+       UINTN Size;
+} VARIABLE_RECORD;
+
+UINTN measuredcount = 0;
+VARIABLE_RECORD *measureddata = NULL;
+
 EFI_GUID tpm_guid = EFI_TPM_GUID;
 EFI_GUID tpm2_guid = EFI_TPM2_GUID;
 
@@ -108,8 +118,9 @@ static EFI_STATUS trigger_tcg2_final_events_table(efi_tpm2_protocol_t *tpm2,
                                 &start, &end, &truncated);
 }
 
-EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
-                        const CHAR8 *description)
+static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
+                                   UINT8 pcr, const CHAR8 *log, UINTN logsize,
+                                   UINT32 type)
 {
        EFI_STATUS status;
        efi_tpm_protocol_t *tpm;
@@ -138,7 +149,7 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
                        return status;
                }
 
-               event = AllocatePool(sizeof(*event) + strlen(description) + 1);
+               event = AllocatePool(sizeof(*event) + logsize);
                if (!event) {
                        perror(L"Unable to allocate event structure\n");
                        return EFI_OUT_OF_RESOURCES;
@@ -147,9 +158,9 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
                event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
                event->Header.HeaderVersion = 1;
                event->Header.PCRIndex = pcr;
-               event->Header.EventType = EV_IPL;
-               event->Size = sizeof(*event) - sizeof(event->Event) + strlen(description) + 1;
-               memcpy(event->Event, description, strlen(description) + 1);
+               event->Header.EventType = type;
+               event->Size = sizeof(*event) - sizeof(event->Event) + logsize + 1;
+               CopyMem(event->Event, (VOID *)log, logsize);
                status = uefi_call_wrapper(tpm2->hash_log_extend_event, 5, tpm2,
                                           0, buf, (UINT64) size, event);
                FreePool(event);
@@ -167,7 +178,7 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
                if (!tpm_present(tpm))
                        return EFI_SUCCESS;
 
-               event = AllocatePool(sizeof(*event) + strlen(description) + 1);
+               event = AllocatePool(sizeof(*event) + logsize);
 
                if (!event) {
                        perror(L"Unable to allocate event structure\n");
@@ -175,8 +186,9 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
                }
 
                event->PCRIndex = pcr;
-               event->EventType = EV_IPL;
-               event->EventSize = strlen(description) + 1;
+               event->EventType = type;
+               event->EventSize = logsize;
+               CopyMem(event->Event, (VOID *)log, logsize);
                status = uefi_call_wrapper(tpm->log_extend_event, 7, tpm, buf,
                                           (UINT64)size, TPM_ALG_SHA, event,
                                           &eventnum, &lastevent);
@@ -186,3 +198,109 @@ EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
 
        return EFI_SUCCESS;
 }
+EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
+                        const CHAR8 *description)
+{
+       return tpm_log_event_raw(buf, size, pcr, description,
+                                strlen(description) + 1, 0xd);
+}
+
+typedef struct {
+       EFI_GUID VariableName;
+       UINT64 UnicodeNameLength;
+       UINT64 VariableDataLength;
+       CHAR16 UnicodeName[1];
+       INT8 VariableData[1];
+} EFI_VARIABLE_DATA_TREE;
+
+static BOOLEAN tpm_data_measured(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
+{
+       UINTN i;
+
+       for (i=0; i<measuredcount; i++) {
+               if ((StrCmp (VarName, measureddata[i].VariableName) == 0) &&
+                   (CompareGuid (&VendorGuid, measureddata[i].VendorGuid)) &&
+                   (VarSize == measureddata[i].Size) &&
+                   (CompareMem (VarData, measureddata[i].Data, VarSize) == 0)) {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static EFI_STATUS tpm_record_data_measurement(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
+{
+       if (measureddata == NULL) {
+               measureddata = AllocatePool(sizeof(*measureddata));
+       } else {
+               measureddata = ReallocatePool(measureddata, measuredcount * sizeof(*measureddata),
+                                             (measuredcount + 1) * sizeof(*measureddata));
+       }
+
+       if (measureddata == NULL)
+               return EFI_OUT_OF_RESOURCES;
+
+       measureddata[measuredcount].VariableName = AllocatePool(StrSize(VarName));
+       measureddata[measuredcount].VendorGuid = AllocatePool(sizeof(EFI_GUID));
+       measureddata[measuredcount].Data = AllocatePool(VarSize);
+
+       if (measureddata[measuredcount].VariableName == NULL ||
+           measureddata[measuredcount].VendorGuid == NULL ||
+           measureddata[measuredcount].Data == NULL) {
+               return EFI_OUT_OF_RESOURCES;
+       }
+
+       StrCpy(measureddata[measuredcount].VariableName, VarName);
+       CopyMem(measureddata[measuredcount].VendorGuid, &VendorGuid, sizeof(EFI_GUID));
+       CopyMem(measureddata[measuredcount].Data, VarData, VarSize);
+       measureddata[measuredcount].Size = VarSize;
+       measuredcount++;
+
+       return EFI_SUCCESS;
+}
+
+EFI_STATUS tpm_measure_variable(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
+{
+       EFI_STATUS Status;
+       UINTN VarNameLength;
+       EFI_VARIABLE_DATA_TREE *VarLog;
+       UINT32 VarLogSize;
+
+       /* Don't measure something that we've already measured */
+       if (tpm_data_measured(VarName, VendorGuid, VarSize, VarData))
+               return EFI_SUCCESS;
+
+       VarNameLength = StrLen (VarName);
+       VarLogSize = (UINT32)(sizeof (*VarLog) +
+                             VarNameLength * sizeof (*VarName) +
+                             VarSize -
+                             sizeof (VarLog->UnicodeName) -
+                             sizeof (VarLog->VariableData));
+
+       VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
+       if (VarLog == NULL) {
+               return EFI_OUT_OF_RESOURCES;
+       }
+
+       CopyMem (&VarLog->VariableName, &VendorGuid,
+                sizeof(VarLog->VariableName));
+       VarLog->UnicodeNameLength  = VarNameLength;
+       VarLog->VariableDataLength = VarSize;
+       CopyMem (VarLog->UnicodeName, VarName,
+                VarNameLength * sizeof (*VarName));
+       CopyMem ((CHAR16 *)VarLog->UnicodeName + VarNameLength, VarData,
+                VarSize);
+
+       Status = tpm_log_event_raw((EFI_PHYSICAL_ADDRESS)VarLog, VarLogSize, 7,
+                                  (CHAR8 *)VarLog, VarLogSize,
+                                  EV_EFI_VARIABLE_AUTHORITY);
+
+       FreePool(VarLog);
+
+       if (Status != EFI_SUCCESS)
+               return Status;
+
+       return tpm_record_data_measurement(VarName, VendorGuid, VarSize,
+                                          VarData);
+}
diff --git a/tpm.h b/tpm.h
index cc1bbedb1778efc82fbe40d6c2fa46e8bd8878ac..3769a1d41c0c99ca8db1549d0852e3a8d1d38a56 100644 (file)
--- a/tpm.h
+++ b/tpm.h
@@ -7,6 +7,8 @@
 EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
                         const CHAR8 *description);
 
+EFI_STATUS tpm_measure_variable(CHAR16 *dbname, EFI_GUID guid, UINTN size, void *data);
+
 typedef struct {
   uint8_t Major;
   uint8_t Minor;
@@ -154,3 +156,17 @@ struct efi_tpm2_protocol
 };
 
 typedef struct efi_tpm2_protocol efi_tpm2_protocol_t;
+
+typedef UINT32                     TCG_EVENTTYPE;
+
+#define EV_EFI_EVENT_BASE                   ((TCG_EVENTTYPE) 0x80000000)
+#define EV_EFI_VARIABLE_DRIVER_CONFIG       (EV_EFI_EVENT_BASE + 1)
+#define EV_EFI_VARIABLE_BOOT                (EV_EFI_EVENT_BASE + 2)
+#define EV_EFI_BOOT_SERVICES_APPLICATION    (EV_EFI_EVENT_BASE + 3)
+#define EV_EFI_BOOT_SERVICES_DRIVER         (EV_EFI_EVENT_BASE + 4)
+#define EV_EFI_RUNTIME_SERVICES_DRIVER      (EV_EFI_EVENT_BASE + 5)
+#define EV_EFI_GPT_EVENT                    (EV_EFI_EVENT_BASE + 6)
+#define EV_EFI_ACTION                       (EV_EFI_EVENT_BASE + 7)
+#define EV_EFI_PLATFORM_FIRMWARE_BLOB       (EV_EFI_EVENT_BASE + 8)
+#define EV_EFI_HANDOFF_TABLES               (EV_EFI_EVENT_BASE + 9)
+#define EV_EFI_VARIABLE_AUTHORITY           (EV_EFI_EVENT_BASE + 0xE0)