openssl.py 11 KB

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