File: certs.py

package info (click to toggle)
virt-firmware 24.11-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 712 kB
  • sloc: python: 4,643; sh: 292; makefile: 68
file content (153 lines) | stat: -rw-r--r-- 4,532 bytes parent folder | download
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