blob: 7ee2683ab236bae455da777999c90a55df2b0ce5 [file] [log] [blame]
Simon Glassc3fe97f2023-03-02 17:02:45 -07001# SPDX-License-Identifier: GPL-2.0+
2# Copyright 2022 Google LLC
3#
4"""Bintool implementation for openssl
5
6openssl provides a number of features useful for signing images
7
8Documentation is at https://www.coreboot.org/CBFS
9
10Source code is at https://www.openssl.org/
11"""
12
13import hashlib
14
15from binman import bintool
16from u_boot_pylib import tools
17
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +053018
19VALID_SHAS = [256, 384, 512, 224]
20SHA_OIDS = {256:'2.16.840.1.101.3.4.2.1',
21 384:'2.16.840.1.101.3.4.2.2',
22 512:'2.16.840.1.101.3.4.2.3',
23 224:'2.16.840.1.101.3.4.2.4'}
24
Simon Glassc3fe97f2023-03-02 17:02:45 -070025class Bintoolopenssl(bintool.Bintool):
26 """openssl tool
27
28 This bintool supports creating new openssl certificates.
29
30 It also supports fetching a binary openssl
31
32 Documentation about openssl is at https://www.openssl.org/
33 """
34 def __init__(self, name):
35 super().__init__(
36 name, 'openssl cryptography toolkit',
37 version_regex=r'OpenSSL (.*) \(', version_args='version')
38
39 def x509_cert(self, cert_fname, input_fname, key_fname, cn, revision,
40 config_fname):
41 """Create a certificate
42
43 Args:
44 cert_fname (str): Filename of certificate to create
45 input_fname (str): Filename containing data to sign
46 key_fname (str): Filename of .pem file
47 cn (str): Common name
48 revision (int): Revision number
49 config_fname (str): Filename to write fconfig into
50
51 Returns:
52 str: Tool output
53 """
54 indata = tools.read_file(input_fname)
55 hashval = hashlib.sha512(indata).hexdigest()
56 with open(config_fname, 'w', encoding='utf-8') as outf:
57 print(f'''[ req ]
58distinguished_name = req_distinguished_name
59x509_extensions = v3_ca
60prompt = no
61dirstring_type = nobmp
62
63[ req_distinguished_name ]
64CN = {cert_fname}
65
66[ v3_ca ]
67basicConstraints = CA:true
681.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv
691.3.6.1.4.1.294.1.34 = ASN1:SEQUENCE:sysfw_image_integrity
70
71[ swrv ]
72swrv = INTEGER:{revision}
73
74[ sysfw_image_integrity ]
75shaType = OID:2.16.840.1.101.3.4.2.3
76shaValue = FORMAT:HEX,OCT:{hashval}
77imageSize = INTEGER:{len(indata)}
78''', file=outf)
79 args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
80 '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
81 '-sha512']
82 return self.run_cmd(*args)
83
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +053084 def x509_cert_sysfw(self, cert_fname, input_fname, key_fname, sw_rev,
85 config_fname, req_dist_name_dict):
86 """Create a certificate to be booted by system firmware
87
88 Args:
89 cert_fname (str): Filename of certificate to create
90 input_fname (str): Filename containing data to sign
91 key_fname (str): Filename of .pem file
92 sw_rev (int): Software revision
93 config_fname (str): Filename to write fconfig into
94 req_dist_name_dict (dict): Dictionary containing key-value pairs of
95 req_distinguished_name section extensions, must contain extensions for
96 C, ST, L, O, OU, CN and emailAddress
97
98 Returns:
99 str: Tool output
100 """
101 indata = tools.read_file(input_fname)
102 hashval = hashlib.sha512(indata).hexdigest()
103 with open(config_fname, 'w', encoding='utf-8') as outf:
104 print(f'''[ req ]
105distinguished_name = req_distinguished_name
106x509_extensions = v3_ca
107prompt = no
108dirstring_type = nobmp
109
110[ req_distinguished_name ]
111C = {req_dist_name_dict['C']}
112ST = {req_dist_name_dict['ST']}
113L = {req_dist_name_dict['L']}
114O = {req_dist_name_dict['O']}
115OU = {req_dist_name_dict['OU']}
116CN = {req_dist_name_dict['CN']}
117emailAddress = {req_dist_name_dict['emailAddress']}
118
119[ v3_ca ]
120basicConstraints = CA:true
1211.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv
1221.3.6.1.4.1.294.1.34 = ASN1:SEQUENCE:sysfw_image_integrity
1231.3.6.1.4.1.294.1.35 = ASN1:SEQUENCE:sysfw_image_load
124
125[ swrv ]
126swrv = INTEGER:{sw_rev}
127
128[ sysfw_image_integrity ]
129shaType = OID:2.16.840.1.101.3.4.2.3
130shaValue = FORMAT:HEX,OCT:{hashval}
131imageSize = INTEGER:{len(indata)}
132
133[ sysfw_image_load ]
134destAddr = FORMAT:HEX,OCT:00000000
135authInPlace = INTEGER:2
136''', file=outf)
137 args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
138 '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
139 '-sha512']
140 return self.run_cmd(*args)
141
142 def x509_cert_rom(self, cert_fname, input_fname, key_fname, sw_rev,
143 config_fname, req_dist_name_dict, cert_type, bootcore,
144 bootcore_opts, load_addr, sha):
145 """Create a certificate
146
147 Args:
148 cert_fname (str): Filename of certificate to create
149 input_fname (str): Filename containing data to sign
150 key_fname (str): Filename of .pem file
151 sw_rev (int): Software revision
152 config_fname (str): Filename to write fconfig into
153 req_dist_name_dict (dict): Dictionary containing key-value pairs of
154 req_distinguished_name section extensions, must contain extensions for
155 C, ST, L, O, OU, CN and emailAddress
156 cert_type (int): Certification type
157 bootcore (int): Booting core
Neha Malcom Francis14e93422023-10-23 13:31:02 +0530158 bootcore_opts(int): Booting core option, lockstep (0) or split (2) mode
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530159 load_addr (int): Load address of image
160 sha (int): Hash function
161
162 Returns:
163 str: Tool output
164 """
165 indata = tools.read_file(input_fname)
166 hashval = hashlib.sha512(indata).hexdigest()
167 with open(config_fname, 'w', encoding='utf-8') as outf:
168 print(f'''
169[ req ]
170 distinguished_name = req_distinguished_name
171 x509_extensions = v3_ca
172 prompt = no
173 dirstring_type = nobmp
174
175 [ req_distinguished_name ]
176C = {req_dist_name_dict['C']}
177ST = {req_dist_name_dict['ST']}
178L = {req_dist_name_dict['L']}
179O = {req_dist_name_dict['O']}
180OU = {req_dist_name_dict['OU']}
181CN = {req_dist_name_dict['CN']}
182emailAddress = {req_dist_name_dict['emailAddress']}
183
184 [ v3_ca ]
185 basicConstraints = CA:true
186 1.3.6.1.4.1.294.1.1 = ASN1:SEQUENCE:boot_seq
187 1.3.6.1.4.1.294.1.2 = ASN1:SEQUENCE:image_integrity
188 1.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv
189# 1.3.6.1.4.1.294.1.4 = ASN1:SEQUENCE:encryption
190 1.3.6.1.4.1.294.1.8 = ASN1:SEQUENCE:debug
191
192 [ boot_seq ]
193 certType = INTEGER:{cert_type}
194 bootCore = INTEGER:{bootcore}
195 bootCoreOpts = INTEGER:{bootcore_opts}
196 destAddr = FORMAT:HEX,OCT:{load_addr:08x}
197 imageSize = INTEGER:{len(indata)}
198
199 [ image_integrity ]
200 shaType = OID:{SHA_OIDS[sha]}
201 shaValue = FORMAT:HEX,OCT:{hashval}
202
203 [ swrv ]
204 swrv = INTEGER:{sw_rev}
205
206# [ encryption ]
207# initalVector = FORMAT:HEX,OCT:TEST_IMAGE_ENC_IV
208# randomString = FORMAT:HEX,OCT:TEST_IMAGE_ENC_RS
209# iterationCnt = INTEGER:TEST_IMAGE_KEY_DERIVE_INDEX
210# salt = FORMAT:HEX,OCT:TEST_IMAGE_KEY_DERIVE_SALT
211
212 [ debug ]
213 debugUID = FORMAT:HEX,OCT:0000000000000000000000000000000000000000000000000000000000000000
214 debugType = INTEGER:4
215 coreDbgEn = INTEGER:0
216 coreDbgSecEn = INTEGER:0
217''', file=outf)
218 args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
219 '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
220 '-sha512']
221 return self.run_cmd(*args)
222
223 def x509_cert_rom_combined(self, cert_fname, input_fname, key_fname, sw_rev,
224 config_fname, req_dist_name_dict, load_addr, sha, total_size, num_comps,
225 sysfw_inner_cert_ext_boot_sequence_string, dm_data_ext_boot_sequence_string,
226 imagesize_sbl, hashval_sbl, load_addr_sysfw, imagesize_sysfw,
227 hashval_sysfw, load_addr_sysfw_data, imagesize_sysfw_data,
228 hashval_sysfw_data, sysfw_inner_cert_ext_boot_block,
Neha Malcom Francis14e93422023-10-23 13:31:02 +0530229 dm_data_ext_boot_block, bootcore_opts):
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530230 """Create a certificate
231
232 Args:
233 cert_fname (str): Filename of certificate to create
234 input_fname (str): Filename containing data to sign
235 key_fname (str): Filename of .pem file
236 sw_rev (int): Software revision
237 config_fname (str): Filename to write fconfig into
238 req_dist_name_dict (dict): Dictionary containing key-value pairs of
239 req_distinguished_name section extensions, must contain extensions for
240 C, ST, L, O, OU, CN and emailAddress
241 cert_type (int): Certification type
242 bootcore (int): Booting core
243 load_addr (int): Load address of image
244 sha (int): Hash function
Neha Malcom Francis14e93422023-10-23 13:31:02 +0530245 bootcore_opts (int): Booting core option, lockstep (0) or split (2) mode
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530246
247 Returns:
248 str: Tool output
249 """
250 indata = tools.read_file(input_fname)
251 hashval = hashlib.sha512(indata).hexdigest()
252 sha_type = SHA_OIDS[sha]
253 with open(config_fname, 'w', encoding='utf-8') as outf:
254 print(f'''
255[ req ]
256distinguished_name = req_distinguished_name
257x509_extensions = v3_ca
258prompt = no
259dirstring_type = nobmp
260
261[ req_distinguished_name ]
262C = {req_dist_name_dict['C']}
263ST = {req_dist_name_dict['ST']}
264L = {req_dist_name_dict['L']}
265O = {req_dist_name_dict['O']}
266OU = {req_dist_name_dict['OU']}
267CN = {req_dist_name_dict['CN']}
268emailAddress = {req_dist_name_dict['emailAddress']}
269
270[ v3_ca ]
271basicConstraints = CA:true
2721.3.6.1.4.1.294.1.3=ASN1:SEQUENCE:swrv
2731.3.6.1.4.1.294.1.9=ASN1:SEQUENCE:ext_boot_info
274
275[swrv]
276swrv=INTEGER:{sw_rev}
277
278[ext_boot_info]
279extImgSize=INTEGER:{total_size}
280numComp=INTEGER:{num_comps}
281sbl=SEQUENCE:sbl
282sysfw=SEQUENCE:sysfw
283sysfw_data=SEQUENCE:sysfw_data
284{sysfw_inner_cert_ext_boot_sequence_string}
285{dm_data_ext_boot_sequence_string}
286
287[sbl]
288compType = INTEGER:1
289bootCore = INTEGER:16
Neha Malcom Francis14e93422023-10-23 13:31:02 +0530290compOpts = INTEGER:{bootcore_opts}
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530291destAddr = FORMAT:HEX,OCT:{load_addr:08x}
292compSize = INTEGER:{imagesize_sbl}
293shaType = OID:{sha_type}
294shaValue = FORMAT:HEX,OCT:{hashval_sbl}
295
296[sysfw]
297compType = INTEGER:2
298bootCore = INTEGER:0
299compOpts = INTEGER:0
300destAddr = FORMAT:HEX,OCT:{load_addr_sysfw:08x}
301compSize = INTEGER:{imagesize_sysfw}
302shaType = OID:{sha_type}
303shaValue = FORMAT:HEX,OCT:{hashval_sysfw}
304
305[sysfw_data]
306compType = INTEGER:18
307bootCore = INTEGER:0
308compOpts = INTEGER:0
309destAddr = FORMAT:HEX,OCT:{load_addr_sysfw_data:08x}
310compSize = INTEGER:{imagesize_sysfw_data}
311shaType = OID:{sha_type}
312shaValue = FORMAT:HEX,OCT:{hashval_sysfw_data}
313
314{sysfw_inner_cert_ext_boot_block}
315
316{dm_data_ext_boot_block}
317 ''', file=outf)
318 args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
319 '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
320 '-sha512']
321 return self.run_cmd(*args)
322
Simon Glassc3fe97f2023-03-02 17:02:45 -0700323 def fetch(self, method):
324 """Fetch handler for openssl
325
326 This installs the openssl package using the apt utility.
327
328 Args:
329 method (FETCH_...): Method to use
330
331 Returns:
332 True if the file was fetched and now installed, None if a method
333 other than FETCH_BIN was requested
334
335 Raises:
336 Valuerror: Fetching could not be completed
337 """
338 if method != bintool.FETCH_BIN:
339 return None
340 return self.apt_install('openssl')