From 4a7afb4477449178d853272ba1a6040c20043b71 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Wed, 23 Oct 2019 07:29:44 -0700 Subject: sign_rpm_ext.bbclass, user-key-store.bbclass: Add boot loader signing This changes the rpm signing setup to use a generic routine check_gpg_key(), in order that the boot loader gpg signing can use the same infrastructure. For now the boot loader gpg signing will only support grub and introduces the variable: GRUB_SIGN_VERIFY = "1" This variable is a control point to activate the code in grub-efi to perform file verification of any file it loads against a gpg key which is linked into the boot loader with grub-mkimage. It will also cause all the other files such as the kernel, initramfs and LockDown.efi to be signed such that grub will verify the files. [ Issue: LINUXEXEC-2450 ] Signed-off-by: Jason Wessel --- meta-integrity/classes/sign_rpm_ext.bbclass | 30 +++--------- meta-signing-key/classes/user-key-store.bbclass | 63 +++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/meta-integrity/classes/sign_rpm_ext.bbclass b/meta-integrity/classes/sign_rpm_ext.bbclass index d9a7f34..1d72d15 100644 --- a/meta-integrity/classes/sign_rpm_ext.bbclass +++ b/meta-integrity/classes/sign_rpm_ext.bbclass @@ -13,27 +13,13 @@ inherit sign_rpm user-key-store GPG_DEP = "${@'' if d.getVar('GPG_BIN') else 'gnupg-native:do_populate_sysroot pinentry-native:do_populate_sysroot'}" python check_rpm_public_key () { - gpg_path = d.getVar('GPG_PATH', True) - gpg_bin = d.getVar('GPG_BIN', True) or \ - bb.utils.which(os.getenv('PATH'), 'gpg') - gpg_keyid = d.getVar('RPM_GPG_NAME', True) - - # Check RPM_GPG_NAME and RPM_GPG_PASSPHRASE - cmd = "%s --homedir %s --list-keys %s" % \ - (gpg_bin, gpg_path, gpg_keyid) - status, output = oe.utils.getstatusoutput(cmd) - if not status: - return - - # Import RPM_GPG_NAME if not found - gpg_key = uks_rpm_keys_dir(d) + 'RPM-GPG-PRIVKEY-' + gpg_keyid - cmd = '%s --batch --homedir %s --passphrase %s --import %s' % \ - (gpg_bin, gpg_path, d.getVar('RPM_GPG_PASSPHRASE', True), gpg_key) - status, output = oe.utils.getstatusoutput(cmd) - if status: - bb.fatal('Failed to import gpg key (%s): %s' % (gpg_key, output)) + check_gpg_key('RPM', uks_rpm_keys_dir, d) } -check_rpm_public_key[lockfiles] = "${TMPDIR}/check_rpm_public_key.lock" + +check_rpm_public_key[lockfiles] = "${TMPDIR}/gpg_key.lock" +do_package_write_rpm[prefuncs] += "check_rpm_public_key" +do_rootfs[prefuncs] += "check_rpm_public_key" + check_rpm_public_key[prefuncs] += "check_deploy_keys" do_package_write_rpm[depends] += "${GPG_DEP}" do_rootfs[depends] += "${GPG_DEP}" @@ -52,8 +38,4 @@ python () { gpg_path = d.getVar('TMPDIR', True) + '/.gnupg' d.setVar('GPG_PATH', gpg_path) - if not os.path.exists(gpg_path): - status, output = oe.utils.getstatusoutput('mkdir -m 0700 -p %s' % gpg_path) - if status: - bb.fatal('Failed to create gpg keying %s: %s' % (gpg_path, output)) } diff --git a/meta-signing-key/classes/user-key-store.bbclass b/meta-signing-key/classes/user-key-store.bbclass index 88d7290..7abe1cf 100644 --- a/meta-signing-key/classes/user-key-store.bbclass +++ b/meta-signing-key/classes/user-key-store.bbclass @@ -42,6 +42,10 @@ def uks_rpm_keys_dir(d): set_keys_dir('RPM', d) return d.getVar('RPM_KEYS_DIR', True) + '/' +def uks_boot_keys_dir(d): + set_keys_dir('BOOT', d) + return d.getVar('BOOT_KEYS_DIR', True) + '/' + def sign_efi_image(key, cert, input, output, d): import bb.process @@ -460,3 +464,62 @@ python check_deploy_keys() { } check_deploy_keys[lockfiles] = "${TMPDIR}/check_deploy_keys.lock" + +def check_gpg_key(basekeyname, keydirfunc, d): + gpg_path = d.getVar('GPG_PATH', True) + if not gpg_path: + gpg_path = d.getVar('TMPDIR', True) + '/.gnupg' + d.setVar('GPG_PATH', gpg_path) + if not os.path.exists(gpg_path): + status, output = oe.utils.getstatusoutput('mkdir -m 0700 -p %s' % gpg_path) + if status: + bb.fatal('Failed to create gpg keying %s: %s' % (gpg_path, output)) + f = open(os.path.join(gpg_path, 'gpg-agent.conf'), 'w') + f.write('allow-loopback-pinentry\n') + f.write('auto-expand-secmem\n') + f.close() + gpg_bin = d.getVar('GPG_BIN', True) or \ + bb.utils.which(os.getenv('PATH'), 'gpg') + gpg_keyid = d.getVar(basekeyname + '_GPG_NAME', True) + + # Check for keyid + cmd = "%s --homedir %s --list-keys %s" % \ + (gpg_bin, gpg_path, gpg_keyid) + status, output = oe.utils.getstatusoutput(cmd) + if not status: + return + + # Import gpg key if not found + gpg_key = keydirfunc(d) + basekeyname + '-GPG-PRIVKEY-' + gpg_keyid + cmd = '%s --batch --homedir %s --passphrase %s --import %s' % \ + (gpg_bin, gpg_path, d.getVar(basekeyname + '_GPG_PASSPHRASE', True), gpg_key) + status, output = oe.utils.getstatusoutput(cmd) + if status: + bb.fatal('Failed to import gpg key (%s): %s' % (gpg_key, output)) + +python check_boot_public_key () { + check_gpg_key('BOOT', uks_boot_keys_dir, d) +} + +check_boot_public_key[lockfiles] = "${TMPDIR}/gpg_key.lock" + +def boot_sign(input, d): + import bb.process + + gpg_path = d.getVar('GPG_PATH', True) + gpg_keyid = d.getVar('BOOT_GPG_NAME', True) + gpg_pass = d.getVar('BOOT_GPG_PASSPHRASE', True) + gpg_bin = d.getVar('GPG_BIN', True) or \ + bb.utils.which(os.getenv('PATH'), 'gpg') + if os.path.exists(input + '.sig'): + os.unlink(input + '.sig') + cmd = 'echo "%s" | %s --pinentry-mode loopback --batch --homedir %s -u "%s" --detach-sign --passphrase-fd 0 "%s"' % \ + (gpg_pass, gpg_bin, gpg_path, gpg_keyid, input) + vprint("Running: %s" % cmd, d) + status, output = oe.utils.getstatusoutput(cmd) + if status: + bb.fatal('Failed to sign: %s' % (input)) + +def uks_boot_sign(input, d): + if d.getVar('GRUB_SIGN_VERIFY', True) == '1': + boot_sign(input, d) -- cgit v1.2.3-54-g00ecf