From patchwork Mon Nov 30 15:16:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Alcantara X-Patchwork-Id: 1408346 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=cjr.nz Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=cjr.nz header.i=@cjr.nz header.a=rsa-sha256 header.s=dkim header.b=kqGiaMyC; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Cl83Q0n3Sz9ryj for ; Tue, 1 Dec 2020 02:17:06 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 5B6B482638; Mon, 30 Nov 2020 16:16:53 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=cjr.nz Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; secure) header.d=cjr.nz header.i=@cjr.nz header.b="kqGiaMyC"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D475282648; Mon, 30 Nov 2020 16:16:50 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-4.3 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_MED,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mx.cjr.nz (mx.cjr.nz [51.158.111.142]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 0577C82636 for ; Mon, 30 Nov 2020 16:16:47 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=quarantine dis=none) header.from=cjr.nz Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=pc@cjr.nz Received: from authenticated-user (mx.cjr.nz [51.158.111.142]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pc) by mx.cjr.nz (Postfix) with ESMTPSA id AD06A7FD0A; Mon, 30 Nov 2020 15:16:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjr.nz; s=dkim; t=1606749406; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=UEC6P/PxiwzzbG0/1zWnwiboFWkb+3xmolIfS7P60MM=; b=kqGiaMyCgjkoidN/VaN9Wx0TiBoA3MHknl1IohijZxhJV8ci0ZUpWs6YpaNjMVodHnIC+i QS9l4+/sUtn3V0dfFIiSbK14MuFe9RJcfFMZxBSJuRBnosSukgPTEGKYOVxAvZldhH5hvq 9z3VgYFspEEcd3CRMqq3t5LIis2qHX4bOpR24E55EcevejX8zZFzfxRjq1rTe8eNWdMgDH 6MaJB82IB2CNSUSYnWiOAEgx1pOAJFn67zc1DDY3cIZ2ROEzOH0ZMyXHXSEL0/Z0SkMcMa OG+qrNo41gQIoHorI45FhQFOXHNPaM7NagZXadPmCyNny8uuGiEz3ur5N4Ef3Q== From: Paulo Alcantara To: xypron.glpk@gmx.de, agraf@csgraf.de, u-boot@lists.denx.de Cc: Paulo Alcantara Subject: [PATCH] tools: add a simple script to generate EFI variables Date: Mon, 30 Nov 2020 12:16:34 -0300 Message-Id: <20201130151634.3927-1-pc@cjr.nz> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean This script generates EFI variables for U-Boot variable store format. An example of generating secure boot variables $ openssl x509 -in foo.crt -outform DER -out foo.der $ efisiglist -a -c foo.der -o foo.esl $ efivar.py -i ubootefi.var add -n db -d foo.esl -t file $ efivar.py -i ubootefi.var add -n kek -d foo.esl -t file $ efivar.py -i ubootefi.var add -n pk -d foo.esl -t file Signed-off-by: Paulo Alcantara (SUSE) --- tools/efivar.py | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100755 tools/efivar.py diff --git a/tools/efivar.py b/tools/efivar.py new file mode 100755 index 000000000000..31e5508f08fd --- /dev/null +++ b/tools/efivar.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +## SPDX-License-Identifier: GPL-2.0-only +# +# Generate UEFI variables for U-Boot. +# +# (c) 2020 Paulo Alcantara +# + +import os +import struct +import uuid +import time +import zlib +import argparse +import subprocess as sp + +# U-Boot variable store format (version 1) +UBOOT_EFI_VAR_FILE_MAGIC = 0x0161566966456255 + +# UEFI variable attributes +EFI_VARIABLE_NON_VOLATILE = 0x1 +EFI_VARIABLE_BOOTSERVICE_ACCESS = 0x2 +EFI_VARIABLE_RUNTIME_ACCESS = 0x4 +EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS = 0x20 +NV_BS = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS +NV_BS_RT = NV_BS | EFI_VARIABLE_RUNTIME_ACCESS +NV_BS_RT_AT = NV_BS_RT | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + +# UEFI variable GUIDs +EFI_GLOBAL_VARIABLE_GUID = '{8be4df61-93ca-11d2-aa0d-00e098032b8c}' +EFI_IMAGE_SECURITY_DATABASE_GUID = '{d719b2cb-3d3a-4596-a3bc-dad00e67656f}' + +class EfiStruct: + # struct efi_var_file + var_file_fmt = ' self.efi.var_file_size: + with open(self.infile, 'rb') as f: + # skip header since it will be recreated by save() + self.buf = f.read()[self.efi.var_file_size:] + else: + self.buf = bytearray() + + def _set_var(self, guid, name_data, size, attr, tsec): + ent = struct.pack(self.efi.var_entry_fmt, + size, + attr, + tsec, + uuid.UUID(guid).bytes_le) + ent += name_data + self.buf += ent + + def set_var(self, guid, name, data, size, attr): + tsec = int(time.time()) if attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS else 0 + nd = name.encode('utf_16_le') + b"\x00\x00" + data + # U-Boot variable format requires the name + data blob to be 8-byte aligned + pad = ((len(nd) + 7) & ~7) - len(nd) + nd += bytes([0] * pad) + + return self._set_var(guid, nd, size, attr, tsec) + + def save(self): + hdr = struct.pack(self.efi.var_file_fmt, + 0, + UBOOT_EFI_VAR_FILE_MAGIC, + len(self.buf) + self.efi.var_file_size, + zlib.crc32(self.buf) & 0xffffffff) + + with open(self.infile, 'wb') as f: + f.write(hdr) + f.write(self.buf) + +def parse_attrs(attr): + attrs = { + 'nv': EFI_VARIABLE_NON_VOLATILE, + 'bs': EFI_VARIABLE_BOOTSERVICE_ACCESS, + 'rt': EFI_VARIABLE_RUNTIME_ACCESS, + 'at': EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS, + } + v = 0 + for i in attr.split(','): + v |= attrs[i.lower()] + return v + +def parse_data(val, vtype): + fmt = { 'u8': '