All of lore.kernel.org
 help / color / mirror / Atom feed
* SMBIOS-provided encryption key patch
@ 2008-09-21 12:35 W. Michael Petullo
  2008-09-21 15:04 ` Felix Zielcke
  2008-09-24  9:57 ` Robert Millan
  0 siblings, 2 replies; 3+ messages in thread
From: W. Michael Petullo @ 2008-09-21 12:35 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 894 bytes --]

I have attached a patch that implements reading an encryption key  
from a SMBIOS record. This is useful for hardware that provides a key  
to a system using SMBIOS when a physical token is attached to a  
system. This patch is dependent on Michael Gorven's encryption patch  
[1].

My system is written to use the SMBIOS BIOS vendor field for testing.  
Presently, this needs to be changed to the appropriate field for a  
given device. Also, there are a lot of grub_printf statements that  
would be removed in a production environment. The patch adds the  
command "dmiloadkey" to GRUB. This command sets the "passphrase"  
environment variable that will then be picked up by Michael's  
encryption functions.

I wanted to make this project available in its current state to  
determine if anyone is interested in it.

[1] http://lists.gnu.org/archive/html/grub-devel/2008-05/msg00127.html


[-- Attachment #2: grub-1.96-20080813-dmi.patch --]
[-- Type: application/octet-stream, Size: 11712 bytes --]

diff -u --recursive --new-file grub2-20080813-luks-vanilla/ChangeLog grub2-20080813-dmi/ChangeLog
--- grub2-20080813-luks-vanilla/ChangeLog	2008-08-24 08:46:48.000000000 -0400
+++ grub2-20080813-dmi/ChangeLog	2008-08-24 08:54:15.000000000 -0400
@@ -1,3 +1,8 @@
+2008-08-23  W. Michael Petullo  <mike@flyn.org>
+
+        * commands/rmi.c: New file
+	* conf/common.rmk: Add rmi.mod
+
 2008-08-13  Robert Millan  <rmh@aybabtu.com>
 
 	* docs/grub.cfg: Remove `/dev/' prefix in GNU/Hurd boot entry.
diff -u --recursive --new-file grub2-20080813-luks-vanilla/commands/dmi.c grub2-20080813-dmi/commands/dmi.c
--- grub2-20080813-luks-vanilla/commands/dmi.c	1969-12-31 19:00:00.000000000 -0500
+++ grub2-20080813-dmi/commands/dmi.c	2008-08-26 19:43:38.000000000 -0400
@@ -0,0 +1,305 @@
+/*
+ * dmi.c - Read information from BIOS's DMI data
+ * Copyright (C) 2008 W. Michael Petullo <mike@flyn.org>
+ */
+
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/err.h>
+
+/* See the "System Management BIOS (SMBIOS) Reference Specification"
+ * for details on the following structures 
+ */
+
+typedef struct smbios_entry_point {
+  unsigned char anchor[4];
+  unsigned char checksum;
+  unsigned char length;
+  unsigned char bios_major_version;
+  unsigned char bios_minor_version;
+  unsigned short max_struct_size;
+  unsigned char revision;
+  unsigned char formatted_area[5];
+  unsigned char intermediate_anchor[5];
+  unsigned char intermediate_checksum;
+  unsigned short structure_table_length;
+  unsigned int structure_table_address;
+  unsigned short num_structures;
+  unsigned char bcd_version;
+} smbios_entry_point_t;
+
+typedef struct smbios_generic_header {
+  unsigned char type;
+  unsigned char length;
+  unsigned short handle;
+} smbios_generic_header_t;
+
+/* NOTE: there are more fields in the specification. However, the
+ * fields beginning with "BIOS Characteristics Extension Bytes" are
+ * not included because this field has a variable number of bytes.
+ */
+typedef struct smbios_bios_information {
+  unsigned char type;
+  unsigned char length;
+  unsigned short handle;
+  unsigned char vendor;
+  unsigned char version;
+  unsigned short start_addr;
+  unsigned char release_date;
+  unsigned char rom_size;
+  unsigned long long characteristics;
+} smbios_bios_information_t;
+
+typedef struct smbios_system_information {
+  unsigned char type;
+  unsigned char length;
+  unsigned short handle;
+  unsigned char manufacturer;
+  unsigned char product;
+  unsigned char version;
+  unsigned char serial_number;
+  unsigned char uuid[16];
+  unsigned char wakeup_time;
+  unsigned char sku;
+  unsigned char family;
+} smbios_system_information_t;
+
+static const struct grub_arg_option options[] = {
+  {0, 0, 0, 0, 0, 0}
+};
+
+static int grub_dmi_checksum (char *ptr, int length)
+{
+  unsigned char sum = 0;
+  length--;
+  while(length >= 0) {
+    sum += ptr[length--];
+  }
+  return sum;
+}
+
+static char *
+grub_dmi_get_string (char *ptr, char n)
+/* Given ptr to beginning of SMBIOS structure and structure length, 
+ * print nth string, if n is too big, will return pointer to 0x00
+ * that terminates string list (empty string).
+ */
+{
+  ptr += *(ptr + 1); /* Skip header, ptr + 1 byte is header length */
+  /* String numbering starts at 1, so --n */
+  while (--n > 0 && *ptr != 0x00) {
+      ptr += grub_strlen(ptr) + 1;
+  }
+  return ptr;
+}
+
+static void
+grub_dmi_read_generic_header (char *ptr)
+{
+  ptr += *(ptr + 1); /* Skip header, ptr + 1 byte is header length */
+
+  /* If we see a 0x00 here, it's the second one, as we've already 
+  * incremented past the null terminator with ptr += ... below.
+  * The empty string is indicated by a 0 in the SMBIOS structure
+  * above, so we won't see one here.
+  */
+  while (*ptr != 0x00) {
+    grub_printf("%s\n", ptr);
+    ptr += grub_strlen(ptr) + 1;
+  }
+}
+
+static void
+grub_dmi_read_bios_information (char *ptr)
+{
+  smbios_bios_information_t bios_information;
+  grub_memcpy(&bios_information, ptr, sizeof(smbios_bios_information_t));
+
+  grub_printf("Length:        %d\n", bios_information.length);
+  grub_printf("Handle:        0x%x\n", bios_information.handle);
+  grub_printf("Vendor:        %s\n", 
+              grub_dmi_get_string(ptr, bios_information.vendor));
+  grub_printf("Version:       %s\n",
+              grub_dmi_get_string(ptr, bios_information.version));
+  grub_printf("BIOS Addr.:    0x%x\n", bios_information.start_addr);
+  grub_printf("Rel. Date:     %s\n",
+              grub_dmi_get_string(ptr, bios_information.release_date));
+  grub_printf("BIOS ROM Size: %d\n", bios_information.rom_size);
+
+  if (grub_env_get("passphrase") == 0x00) {
+    grub_env_set("passphrase", grub_dmi_get_string(ptr, bios_information.vendor));
+  } else {
+    grub_printf("Env. var. passphrase already set!\n");
+  }
+}
+
+static void
+grub_dmi_read_system_information (char *ptr)
+{
+  smbios_system_information_t system_information;
+  grub_memcpy(&system_information, ptr, sizeof(smbios_system_information_t));
+
+  grub_printf("Length:        %d\n", system_information.length);
+  grub_printf("Handle:        0x%x\n", system_information.handle);
+  grub_printf("Manufacturer:  %s\n", 
+              grub_dmi_get_string(ptr, system_information.manufacturer));
+  grub_printf("Product:       %s\n",
+              grub_dmi_get_string(ptr, system_information.product));
+  grub_printf("Version:       0x%s\n",
+              grub_dmi_get_string(ptr, system_information.version));
+  grub_printf("Serial Num:    %s\n",
+              grub_dmi_get_string(ptr, system_information.serial_number));
+  grub_printf("Wake-up Time:  %x\n", system_information.wakeup_time);
+  grub_printf("SKU:           %s\n",
+              grub_dmi_get_string(ptr, system_information.sku));
+  grub_printf("Family:        %s\n",
+              grub_dmi_get_string(ptr, system_information.family));
+}
+
+static grub_err_t
+grub_cmd_dmiloadkey (struct grub_arg_list *state, int argc, char **args)
+{
+  char *ptr;
+  grub_err_t err = GRUB_ERR_NONE;
+
+  for (ptr = (char *) 0x000f0000; ptr < (char *) 0x000fffff; ptr++) {
+    if (0 == grub_strncmp("_SM_", ptr, 4)) {
+      int i;
+      smbios_entry_point_t entry_point;
+
+      grub_printf("Found '_SM_' at 0x%x\n", (unsigned int) ptr);
+
+      if (0 != grub_dmi_checksum(ptr, *(ptr + 0x05))) {
+        grub_printf("Checksum failed!\n");
+        continue;
+      } else {
+        grub_printf("Checksum passed\n");
+      }
+
+      grub_memcpy(&entry_point, ptr, sizeof(smbios_entry_point_t));
+
+      if (0 != grub_strncmp("_DMI_", entry_point.intermediate_anchor, 5)) {
+        grub_printf("Missing '_DMI_'!\n");
+        continue;
+      }
+
+      if (0 != grub_dmi_checksum((char *) &(entry_point.intermediate_anchor), 0x0F)) {
+        grub_printf("Intermediate checksum failed!\n");
+        continue;
+      } else {
+        grub_printf("Intermediate checksum passed\n");
+      }
+
+      for (i = 0; i < entry_point.length; i+=2) {
+        grub_printf("0x%x", ptr[i]);
+        grub_printf("%x ", ptr[i+1]);
+        if (i % 8 == 0) {
+          grub_printf("\n");
+        }
+      }
+
+      grub_printf("Table Length:  %d\n", entry_point.structure_table_length);
+      grub_printf("Table Address: 0x%x\n", entry_point.structure_table_address);
+
+      ptr = (char *) entry_point.structure_table_address;
+
+      do {
+        smbios_generic_header_t generic_header;
+        grub_memcpy(&generic_header, ptr, sizeof(smbios_generic_header_t));
+
+        switch (*ptr) {
+          case 0:
+            grub_printf("Found BIOS information struct at 0x%x\n", 
+                        (unsigned int) ptr);
+            grub_dmi_read_bios_information (ptr);
+            break;
+          case 1:
+            grub_printf("Found system information struct at 0x%x\n",
+                        (unsigned int) ptr);
+            grub_dmi_read_system_information (ptr);
+            break;
+          default:
+            grub_printf("Unknown information stuct (%d) at 0x%x\n", *ptr, 
+                        (unsigned int) ptr);
+            grub_dmi_read_generic_header (ptr);
+            break;
+        }
+
+        grub_printf("Advance past struct (%d)\n", generic_header.length);
+        ptr += generic_header.length; /* Advance past struct to strings */
+
+        do { /* Advance past strings: */
+          grub_printf("Advance past string (%d)\n", grub_strlen(ptr) + 1);
+          ptr += grub_strlen(ptr) + 1;
+        } while (*ptr != 0x00);
+        /* This is a do...while instead of a while because:
+         *
+         *   a. if there is a string it will be advanced over and the
+         *   string's null may be the first of the double null terminator
+         *
+         *   b. if there are no strings at all, the first null of the
+         *   double null terminator will be advanced over as if it were 
+         *   part of an empty string
+         *
+         * If we see a 0x00 here, it's the second one, as we've already 
+         * incremented past the null terminator with ptr += ... above.
+         * The empty string is indicated by a 0 in the SMBIOS structure
+         * above, so we won't see one here.
+         */
+
+        grub_printf("Advance one more\n");
+        ptr++; /* Advance past second 0x00 that signifies end of strings */
+
+        grub_millisleep(1000);
+
+      } while (ptr < (char *) entry_point.structure_table_address + entry_point.structure_table_length);
+
+      break;
+    }
+  }
+
+  if (ptr == (char *) 0x000fffff) {
+    grub_printf("Did not find DMI data!\n");
+    err = GRUB_ERR_READ_ERROR;
+    goto _return;
+  }
+_return:
+  return err;
+}
+
+GRUB_MOD_INIT(dmi)
+{
+  grub_register_command ("dmiloadkey", grub_cmd_dmiloadkey, 
+                         GRUB_COMMAND_FLAG_BOTH,
+			 "dmiloadkey",
+			 "Read data from DMI.",
+			 options);
+}
+
+GRUB_MOD_FINI(dmi)
+{
+  grub_unregister_command("dmiloadkey");
+}
+
+/* vi: set et sw=2 sts=2: */
diff -u --recursive --new-file grub2-20080813-luks-vanilla/conf/common.rmk grub2-20080813-dmi/conf/common.rmk
--- grub2-20080813-luks-vanilla/conf/common.rmk	2008-08-24 08:46:48.000000000 -0400
+++ grub2-20080813-dmi/conf/common.rmk	2008-08-24 08:55:04.000000000 -0400
@@ -281,7 +281,7 @@
 	cmp.mod cat.mod help.mod font.mod search.mod		\
 	loopback.mod fs_uuid.mod configfile.mod echo.mod	\
 	terminfo.mod test.mod blocklist.mod hexdump.mod		\
-	read.mod sleep.mod loadenv.mod crc.mod
+	read.mod sleep.mod loadenv.mod crc.mod dmi.mod
 
 # For hello.mod.
 hello_mod_SOURCES = hello/hello.c
@@ -460,6 +460,11 @@
 crc_mod_CFLAGS = $(COMMON_CFLAGS)
 crc_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For dmi.mod.
+dmi_mod_SOURCES = commands/dmi.c
+dmi_mod_CFLAGS = $(COMMON_CFLAGS)
+dmi_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # Misc.
 pkglib_MODULES += gzio.mod bufio.mod elf.mod
 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: SMBIOS-provided encryption key patch
  2008-09-21 12:35 SMBIOS-provided encryption key patch W. Michael Petullo
@ 2008-09-21 15:04 ` Felix Zielcke
  2008-09-24  9:57 ` Robert Millan
  1 sibling, 0 replies; 3+ messages in thread
From: Felix Zielcke @ 2008-09-21 15:04 UTC (permalink / raw)
  To: The development of GRUB 2

Am Sonntag, den 21.09.2008, 08:35 -0400 schrieb W. Michael Petullo:
Hi,

> Also, there are a lot of grub_printf statements that  
> would be removed in a production environment. 

Instead of grub_printf you could just use grub_dprintf ("dmi", ...)
and then they get shown with `set debug=dmi' command in real GRUB.


-- 
Felix Zielcke




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: SMBIOS-provided encryption key patch
  2008-09-21 12:35 SMBIOS-provided encryption key patch W. Michael Petullo
  2008-09-21 15:04 ` Felix Zielcke
@ 2008-09-24  9:57 ` Robert Millan
  1 sibling, 0 replies; 3+ messages in thread
From: Robert Millan @ 2008-09-24  9:57 UTC (permalink / raw)
  To: The development of GRUB 2; +Cc: Yoshinori K. Okuji

On Sun, Sep 21, 2008 at 08:35:52AM -0400, W. Michael Petullo wrote:
> I have attached a patch that implements reading an encryption key  
> from a SMBIOS record. This is useful for hardware that provides a key  
> to a system using SMBIOS when a physical token is attached to a  
> system.

Can you be more specific about the application of this?  (e.g. with an
example use case)

> This patch is dependent on Michael Gorven's encryption patch  
> [1].

Unfortunately we haven't sorted out that patch yet.  Although I expect we're
almost there... we need some response from Marco or Okuji.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2008-09-24  9:59 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-21 12:35 SMBIOS-provided encryption key patch W. Michael Petullo
2008-09-21 15:04 ` Felix Zielcke
2008-09-24  9:57 ` Robert Millan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.