blob: aad3b61ae27ce58ad0e40e4d61a6319f18543318 [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
158 load_addr (int): Load address of image
159 sha (int): Hash function
160
161 Returns:
162 str: Tool output
163 """
164 indata = tools.read_file(input_fname)
165 hashval = hashlib.sha512(indata).hexdigest()
166 with open(config_fname, 'w', encoding='utf-8') as outf:
167 print(f'''
168[ req ]
169 distinguished_name = req_distinguished_name
170 x509_extensions = v3_ca
171 prompt = no
172 dirstring_type = nobmp
173
174 [ req_distinguished_name ]
175C = {req_dist_name_dict['C']}
176ST = {req_dist_name_dict['ST']}
177L = {req_dist_name_dict['L']}
178O = {req_dist_name_dict['O']}
179OU = {req_dist_name_dict['OU']}
180CN = {req_dist_name_dict['CN']}
181emailAddress = {req_dist_name_dict['emailAddress']}
182
183 [ v3_ca ]
184 basicConstraints = CA:true
185 1.3.6.1.4.1.294.1.1 = ASN1:SEQUENCE:boot_seq
186 1.3.6.1.4.1.294.1.2 = ASN1:SEQUENCE:image_integrity
187 1.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv
188# 1.3.6.1.4.1.294.1.4 = ASN1:SEQUENCE:encryption
189 1.3.6.1.4.1.294.1.8 = ASN1:SEQUENCE:debug
190
191 [ boot_seq ]
192 certType = INTEGER:{cert_type}
193 bootCore = INTEGER:{bootcore}
194 bootCoreOpts = INTEGER:{bootcore_opts}
195 destAddr = FORMAT:HEX,OCT:{load_addr:08x}
196 imageSize = INTEGER:{len(indata)}
197
198 [ image_integrity ]
199 shaType = OID:{SHA_OIDS[sha]}
200 shaValue = FORMAT:HEX,OCT:{hashval}
201
202 [ swrv ]
203 swrv = INTEGER:{sw_rev}
204
205# [ encryption ]
206# initalVector = FORMAT:HEX,OCT:TEST_IMAGE_ENC_IV
207# randomString = FORMAT:HEX,OCT:TEST_IMAGE_ENC_RS
208# iterationCnt = INTEGER:TEST_IMAGE_KEY_DERIVE_INDEX
209# salt = FORMAT:HEX,OCT:TEST_IMAGE_KEY_DERIVE_SALT
210
211 [ debug ]
212 debugUID = FORMAT:HEX,OCT:0000000000000000000000000000000000000000000000000000000000000000
213 debugType = INTEGER:4
214 coreDbgEn = INTEGER:0
215 coreDbgSecEn = INTEGER:0
216''', file=outf)
217 args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
218 '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
219 '-sha512']
220 return self.run_cmd(*args)
221
222 def x509_cert_rom_combined(self, cert_fname, input_fname, key_fname, sw_rev,
223 config_fname, req_dist_name_dict, load_addr, sha, total_size, num_comps,
224 sysfw_inner_cert_ext_boot_sequence_string, dm_data_ext_boot_sequence_string,
225 imagesize_sbl, hashval_sbl, load_addr_sysfw, imagesize_sysfw,
226 hashval_sysfw, load_addr_sysfw_data, imagesize_sysfw_data,
227 hashval_sysfw_data, sysfw_inner_cert_ext_boot_block,
228 dm_data_ext_boot_block):
229 """Create a certificate
230
231 Args:
232 cert_fname (str): Filename of certificate to create
233 input_fname (str): Filename containing data to sign
234 key_fname (str): Filename of .pem file
235 sw_rev (int): Software revision
236 config_fname (str): Filename to write fconfig into
237 req_dist_name_dict (dict): Dictionary containing key-value pairs of
238 req_distinguished_name section extensions, must contain extensions for
239 C, ST, L, O, OU, CN and emailAddress
240 cert_type (int): Certification type
241 bootcore (int): Booting core
242 load_addr (int): Load address of image
243 sha (int): Hash function
244
245 Returns:
246 str: Tool output
247 """
248 indata = tools.read_file(input_fname)
249 hashval = hashlib.sha512(indata).hexdigest()
250 sha_type = SHA_OIDS[sha]
251 with open(config_fname, 'w', encoding='utf-8') as outf:
252 print(f'''
253[ req ]
254distinguished_name = req_distinguished_name
255x509_extensions = v3_ca
256prompt = no
257dirstring_type = nobmp
258
259[ req_distinguished_name ]
260C = {req_dist_name_dict['C']}
261ST = {req_dist_name_dict['ST']}
262L = {req_dist_name_dict['L']}
263O = {req_dist_name_dict['O']}
264OU = {req_dist_name_dict['OU']}
265CN = {req_dist_name_dict['CN']}
266emailAddress = {req_dist_name_dict['emailAddress']}
267
268[ v3_ca ]
269basicConstraints = CA:true
2701.3.6.1.4.1.294.1.3=ASN1:SEQUENCE:swrv
2711.3.6.1.4.1.294.1.9=ASN1:SEQUENCE:ext_boot_info
272
273[swrv]
274swrv=INTEGER:{sw_rev}
275
276[ext_boot_info]
277extImgSize=INTEGER:{total_size}
278numComp=INTEGER:{num_comps}
279sbl=SEQUENCE:sbl
280sysfw=SEQUENCE:sysfw
281sysfw_data=SEQUENCE:sysfw_data
282{sysfw_inner_cert_ext_boot_sequence_string}
283{dm_data_ext_boot_sequence_string}
284
285[sbl]
286compType = INTEGER:1
287bootCore = INTEGER:16
288compOpts = INTEGER:0
289destAddr = FORMAT:HEX,OCT:{load_addr:08x}
290compSize = INTEGER:{imagesize_sbl}
291shaType = OID:{sha_type}
292shaValue = FORMAT:HEX,OCT:{hashval_sbl}
293
294[sysfw]
295compType = INTEGER:2
296bootCore = INTEGER:0
297compOpts = INTEGER:0
298destAddr = FORMAT:HEX,OCT:{load_addr_sysfw:08x}
299compSize = INTEGER:{imagesize_sysfw}
300shaType = OID:{sha_type}
301shaValue = FORMAT:HEX,OCT:{hashval_sysfw}
302
303[sysfw_data]
304compType = INTEGER:18
305bootCore = INTEGER:0
306compOpts = INTEGER:0
307destAddr = FORMAT:HEX,OCT:{load_addr_sysfw_data:08x}
308compSize = INTEGER:{imagesize_sysfw_data}
309shaType = OID:{sha_type}
310shaValue = FORMAT:HEX,OCT:{hashval_sysfw_data}
311
312{sysfw_inner_cert_ext_boot_block}
313
314{dm_data_ext_boot_block}
315 ''', file=outf)
316 args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
317 '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
318 '-sha512']
319 return self.run_cmd(*args)
320
Simon Glassc3fe97f2023-03-02 17:02:45 -0700321 def fetch(self, method):
322 """Fetch handler for openssl
323
324 This installs the openssl package using the apt utility.
325
326 Args:
327 method (FETCH_...): Method to use
328
329 Returns:
330 True if the file was fetched and now installed, None if a method
331 other than FETCH_BIN was requested
332
333 Raises:
334 Valuerror: Fetching could not be completed
335 """
336 if method != bintool.FETCH_BIN:
337 return None
338 return self.apt_install('openssl')