1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
#!/usr/bin/python
#
# SPDX-License-Identifier: GPL-2.0-only
# (c) 2023 Gerd Hoffmann
#
""" efi x509 certificates """
import datetime
import tempfile
import importlib_resources
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
# redhat: PK + KEK key
REDHAT_PK = importlib_resources.files('virt.firmware') / 'certs/RedHatSecureBootPKKEKkey1.pem'
# microsoft: KEK key
MS_KEK_2011 = importlib_resources.files('virt.firmware') / 'certs/MicrosoftCorporationKEKCA2011.pem'
MS_KEK_2023 = importlib_resources.files('virt.firmware') / 'certs/MicrosoftCorporationKEK2KCA2023.pem'
# microsoft: used to sign windows
MS_WIN_2011 = importlib_resources.files('virt.firmware') / 'certs/MicrosoftWindowsProductionPCA2011.pem'
MS_WIN_2023 = importlib_resources.files('virt.firmware') / 'certs/WindowsUEFICA2023.pem'
# microsoft: used to sign 3rd party binaries (shim.efi, drivers).
MS_3RD_2011 = importlib_resources.files('virt.firmware') / 'certs/MicrosoftCorporationUEFICA2011.pem'
MS_3RD_2023 = importlib_resources.files('virt.firmware') / 'certs/MicrosoftUEFICA2023.pem'
# for backward compatibility
MS_KEK = MS_KEK_2011
MS_WIN = MS_WIN_2011
MS_3RD = MS_3RD_2011
# linux distro ca keys
DISTRO_CA = {
#
# microsoft keys
#
'windows' : {
'desc' : 'Microsoft Windows',
'certs' : [
MS_WIN_2011,
MS_WIN_2023,
],
},
'ms-uefi' : {
'desc' : 'Microsoft UEFI CA',
'certs' : [
MS_3RD_2011,
MS_3RD_2023,
],
},
#
# redhat / rhel keys
#
'rhel-2014' : {
'desc' : 'Red Hat Enterprise Linux (obsoleted by 2020 signing key rotation)',
'certs' : [
importlib_resources.files('virt.firmware') / 'certs/RedHatSecureBootCA3.pem',
],
},
'rhel' : {
'desc' : 'Red Hat Enterprise Linux',
'certs' : [
importlib_resources.files('virt.firmware') / 'certs/RedHatSecureBootCA5.pem',
importlib_resources.files('virt.firmware') / 'certs/RedHatSecureBootCA8.pem',
],
},
'rh-uefi' : {
'desc' : 'Red Hat UEFI CA',
'certs' : [
importlib_resources.files('virt.firmware') / 'certs/RedHatUEFICA2024.pem',
],
},
#
# fedora keys
#
'fedora' : {
'desc' : 'Fedora Linux',
'certs' : [
importlib_resources.files('virt.firmware') / 'certs/fedoraca-20200709.pem',
],
},
#
# centos keys
#
'centos-2018' : {
'desc' : 'CentOS Stream (obsoleted by 2020 signing key rotation)',
'certs' : [
importlib_resources.files('virt.firmware') / 'certs/CentOSSecureBootCAkey1.pem',
],
},
'centos' : {
'desc' : 'CentOS Stream',
'certs' : [
importlib_resources.files('virt.firmware') / 'certs/CentOSSecureBootCA2.pem',
],
},
}
def list_distros():
print('known distro certs:')
for (key, val) in DISTRO_CA.items():
print(f' {key:12s} - {val["desc"]}')
def pk_generate(cn = 'random secure boot platform',
org = None, city = None, state = None, country = None):
key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
attrs = [
x509.NameAttribute(x509.NameOID.COMMON_NAME, cn),
]
if org:
attrs.append(x509.NameAttribute(x509.NameOID.ORGANIZATION_NAME, org))
if city:
attrs.append(x509.NameAttribute(x509.NameOID.LOCALITY_NAME, city))
if state:
attrs.append(x509.NameAttribute(x509.NameOID.STATE_OR_PROVINCE_NAME, state))
if country:
attrs.append(x509.NameAttribute(x509.NameOID.COUNTRY_NAME, country))
subject = issuer = x509.Name(attrs)
now = datetime.datetime.now(datetime.timezone.utc)
cert = x509.CertificateBuilder().subject_name(
subject
).issuer_name(
issuer
).public_key(
key.public_key()
).serial_number(
x509.random_serial_number()
).not_valid_before(
now
).not_valid_after(
now + datetime.timedelta(days = 365 * 10)
).add_extension(
x509.BasicConstraints(ca = False, path_length = None),
critical = False,
).sign(key, hashes.SHA256())
# pylint: disable=consider-using-with
tf = tempfile.NamedTemporaryFile()
tf.write(cert.public_bytes(serialization.Encoding.PEM))
tf.flush()
return tf
|