openubmc-bingo 0.5.242__py3-none-any.whl → 0.5.253__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of openubmc-bingo might be problematic. Click here for more details.

Files changed (68) hide show
  1. bmcgo/__init__.py +1 -1
  2. bmcgo/bmcgo_config.py +82 -1
  3. bmcgo/cli/cli.py +0 -2
  4. bmcgo/cli/config.yaml +9 -0
  5. bmcgo/codegen/lua/Makefile +13 -0
  6. bmcgo/codegen/lua/codegen.py +6 -3
  7. bmcgo/codegen/lua/script/dto/options.py +1 -0
  8. bmcgo/codegen/lua/script/{render_utils/factory.py → factory.py} +1 -1
  9. bmcgo/codegen/lua/script/gen_entry.py +6 -3
  10. bmcgo/codegen/lua/script/gen_intf_rpc_json.py +12 -0
  11. bmcgo/codegen/lua/script/gen_schema.py +2 -0
  12. bmcgo/codegen/lua/script/merge_model.py +10 -3
  13. bmcgo/codegen/lua/script/render_utils/__init__.py +5 -4
  14. bmcgo/codegen/lua/script/render_utils/client_lua.py +2 -2
  15. bmcgo/codegen/lua/script/render_utils/controller_lua.py +2 -2
  16. bmcgo/codegen/lua/script/render_utils/db_lua.py +2 -2
  17. bmcgo/codegen/lua/script/render_utils/error_lua.py +2 -2
  18. bmcgo/codegen/lua/script/render_utils/ipmi_lua.py +2 -2
  19. bmcgo/codegen/lua/script/render_utils/ipmi_message_lua.py +2 -2
  20. bmcgo/codegen/lua/script/render_utils/mdb_lua.py +2 -2
  21. bmcgo/codegen/lua/script/render_utils/message_lua.py +2 -2
  22. bmcgo/codegen/lua/script/render_utils/messages_lua.py +2 -2
  23. bmcgo/codegen/lua/script/render_utils/model_lua.py +2 -2
  24. bmcgo/codegen/lua/script/render_utils/old_model_lua.py +2 -2
  25. bmcgo/codegen/lua/script/render_utils/plugin_lua.py +2 -2
  26. bmcgo/codegen/lua/script/render_utils/redfish_proto.py +2 -2
  27. bmcgo/codegen/lua/script/render_utils/request_lua.py +2 -2
  28. bmcgo/codegen/lua/script/render_utils/service_lua.py +3 -2
  29. bmcgo/codegen/lua/script/template.py +5 -1
  30. bmcgo/codegen/lua/script/utils.py +9 -2
  31. bmcgo/codegen/lua/templates/Makefile +8 -0
  32. bmcgo/codegen/lua/templates/apps/Makefile +27 -1
  33. bmcgo/codegen/lua/templates/apps/controller.lua.mako +20 -4
  34. bmcgo/codegen/lua/v1/script/gen_schema.py +328 -0
  35. bmcgo/codegen/lua/v1/script/render_utils/model_lua.py +458 -0
  36. bmcgo/codegen/lua/v1/templates/apps/model.lua.mako +62 -0
  37. bmcgo/codegen/lua/v1/templates/apps/service.lua.mako +193 -0
  38. bmcgo/component/build.py +16 -42
  39. bmcgo/component/component_helper.py +54 -0
  40. bmcgo/component/coverage/incremental_cov.py +25 -33
  41. bmcgo/component/deploy.py +7 -9
  42. bmcgo/frame.py +9 -6
  43. bmcgo/functional/conan_index_build.py +16 -41
  44. bmcgo/functional/csr_build.py +313 -88
  45. bmcgo/functional/diff.py +3 -3
  46. bmcgo/functional/upgrade.py +31 -1
  47. bmcgo/misc.py +31 -2
  48. bmcgo/target/install_sdk.yml +6 -0
  49. bmcgo/target/personal.yml +5 -0
  50. bmcgo/target/publish.yml +5 -0
  51. bmcgo/tasks/task.py +69 -43
  52. bmcgo/tasks/task_build_conan.py +6 -2
  53. bmcgo/tasks/task_build_wbd_up.py +69 -0
  54. bmcgo/utils/config.py +20 -8
  55. bmcgo/utils/install_manager.py +75 -20
  56. bmcgo/utils/installations/base_installer.py +114 -7
  57. bmcgo/utils/installations/install_consts.py +3 -1
  58. bmcgo/utils/installations/install_plans/bingo.yml +2 -4
  59. bmcgo/utils/installations/install_workflow.py +6 -2
  60. bmcgo/utils/installations/installers/apt_installer.py +58 -136
  61. bmcgo/utils/installations/installers/pip_installer.py +52 -18
  62. bmcgo/utils/installations/version_util.py +1 -1
  63. {openubmc_bingo-0.5.242.dist-info → openubmc_bingo-0.5.253.dist-info}/METADATA +2 -1
  64. {openubmc_bingo-0.5.242.dist-info → openubmc_bingo-0.5.253.dist-info}/RECORD +68 -62
  65. /bmcgo/codegen/lua/script/{render_utils/base.py → base.py} +0 -0
  66. {openubmc_bingo-0.5.242.dist-info → openubmc_bingo-0.5.253.dist-info}/WHEEL +0 -0
  67. {openubmc_bingo-0.5.242.dist-info → openubmc_bingo-0.5.253.dist-info}/entry_points.txt +0 -0
  68. {openubmc_bingo-0.5.242.dist-info → openubmc_bingo-0.5.253.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- #! /usr/bin/env python3
1
+ #!/usr/bin/env python3
2
2
  # encoding=utf-8
3
3
  # 描述:CSR构建出包
4
4
  # Copyright (c) 2024 Huawei Technologies Co., Ltd.
@@ -13,30 +13,33 @@
13
13
 
14
14
  import os
15
15
  import json
16
- import time
17
16
  import re
18
17
  import argparse
19
- import atexit
20
18
  import shutil
21
19
  import gzip
22
20
  import io
21
+ import stat
23
22
  import binascii
24
23
  import hashlib
25
24
  import tempfile
26
25
  import subprocess
27
- import configparser
26
+ from enum import Enum
28
27
  from pathlib import Path
28
+ from hashlib import sha256
29
29
  from datetime import datetime, timezone, timedelta
30
+ import ecdsa
31
+ import json5
32
+ import requests
30
33
  from bmcgo import misc
31
- from bmcgo.logger import Logger
34
+ from bmcgo import errors
32
35
  from bmcgo.misc import CommandInfo
33
- from bmcgo.tasks.task import Task
34
36
  from bmcgo.utils.tools import Tools
35
37
  from bmcgo.utils.buffer import Buffer
36
- from bmcgo.utils.config import Config
37
38
  from bmcgo.bmcgo_config import BmcgoConfig
39
+ from bmcgo.functional.simple_sign import BmcgoCommand as SimpleSign
38
40
 
39
- tool = Tools("build_csr")
41
+
42
+ tool = Tools("csr_build")
40
43
  log = tool.log
41
44
  cwd = os.getcwd()
42
45
 
@@ -53,11 +56,29 @@ DEFAULT_EEPROM_SIZE_LIMIT = 32
53
56
  LEGACY_UIDS = [
54
57
  "00000001050302023924", "00000001030302023925", "00000001040302023945",
55
58
  "00000001040302023947", "00000001030302024340", "00000001030302023936",
56
- "00000001030302023938", "00000001100302023955", "00000001100302023956",
59
+ "00000001030302023938", "00000001100302023955", "00000001100302023956",
57
60
  "00000001040302052957", "00000001100302025549", "00000001030302023934"
58
61
  ]
59
62
 
60
63
 
64
+ class SignatureTypeEnum(Enum):
65
+ SERVER_SIGN = "server_sign"
66
+ SELF_SIGN = "self_sign"
67
+ DEFAULT = "default"
68
+
69
+
70
+ class SignInfo:
71
+ def __init__(self, sign_data: bytearray):
72
+ # 哈希SHA256算法码
73
+ self.sign_hash_code = 0x00
74
+ # ECC签名算法码
75
+ self.sign_algorithm_code = 0x00
76
+ # ECC签名算法曲线ID
77
+ self.sign_curve_id = 415
78
+ self.sign_length = len(sign_data)
79
+ self.sign_content = sign_data
80
+
81
+
61
82
  class CsrHeader:
62
83
  def __init__(self, csr_head_len, csr_bytes_arr):
63
84
  self.csr_max_count = 4
@@ -84,7 +105,7 @@ class SrMakeOptions:
84
105
  self.oem_data = oem_data
85
106
  self.uid = self.get_uid(sr_json)
86
107
  self.binary_names = [self.uid]
87
-
108
+
88
109
  def find_uid_from_object(self, parent, key, obj):
89
110
  if key == TIANCHI:
90
111
  if "UID" in obj:
@@ -97,7 +118,6 @@ class SrMakeOptions:
97
118
  if ret:
98
119
  return ret
99
120
  return ""
100
-
101
121
 
102
122
  def get_uid(self, sr_json):
103
123
  component_id = ""
@@ -120,7 +140,7 @@ class SrMakeOptions:
120
140
  if len(component_id) > SR_UID_MAX_LENGTH:
121
141
  raise Exception(f"{self.comp_name}文件UID超过最大长度,无法出包。")
122
142
  return component_id
123
-
143
+
124
144
 
125
145
  def if_available(bconfig: BmcgoConfig):
126
146
  return (
@@ -143,31 +163,29 @@ class BmcgoCommand:
143
163
  prog="bingo build_csr",
144
164
  description="csr出包,支持单个CSR和批量CSR出包",
145
165
  add_help=True,
146
- formatter_class=argparse.RawTextHelpFormatter
166
+ formatter_class=argparse.RawTextHelpFormatter,
147
167
  )
148
168
  parser.add_argument("-s", "--single", help="指定单个CSR文件出包,默认为批量出包", action=misc.STORE_TRUE, default=False)
149
- parser.add_argument("-p", "--path", help="单CSR出包时指定CSR文件路径,批量出包时指定CSR文件和OEM文件所在铺\n默认为当前路径", default=cwd)
169
+ parser.add_argument("-p", "--path", help="单CSR出包时指定CSR文件路径,批量出包时指定CSR文件和OEM文件所在目录\n默认为当前路径", default=cwd)
150
170
  parser.add_argument("-o", "--output_path", help="构建产物(hpm包或tar.gz压缩包)路径\n默认为当前路径", default=cwd)
151
- parser.add_argument("--oem", help="单CSR出包携带OEM文件的路径,仅在--single模式下有效", default=None)
152
- parser.add_argument("--hpm", help="单CSR出包生成hpm文件,仅在--single模式下有效", action=misc.STORE_TRUE, default=False)
153
- parser.add_argument("-b", "--bin", help="单CSR出包生成bin文件的路径,仅在--single模式下有效",
154
- action=misc.STORE_TRUE, default=False)
155
- parser.add_argument("-u", "--uid", help="指定UID生成二进制文件,多个uid以','分隔,仅在--single模式下有效", default=None)
171
+ parser.add_argument("--oem", help="单CSR出包携带OEM文件的路径,仅-s模式下有效", default=None)
172
+ parser.add_argument("--hpm", help="单CSR出包生成hpm文件,仅-s模式下有效", action=misc.STORE_TRUE, default=False)
173
+ parser.add_argument("-b", "--bin", help="单CSR出包生成bin文件,仅-s模式下有效", action=misc.STORE_TRUE, default=False)
174
+ parser.add_argument("-u", "--uid", help="指定UID生成二进制文件,多个uid以','分隔,仅-s模式下有效", default=None)
156
175
  parser.add_argument("-f", "--frud", help="指定打包frud文件,跳过白名单校验", action=misc.STORE_TRUE, default=False)
157
- parser.add_argument("-a", "--all", help="快捷携带-j、-b、--hpm参数,仅在--single模式下有效",
158
- action=misc.STORE_TRUE, default=False)
176
+ parser.add_argument("-a", "--all", help="快捷携带-j、-b、--hpm参数,仅-s下有效", action=misc.STORE_TRUE, default=False)
177
+ parser.add_argument("-t", "--tar", help="指定批量出包生成tar包,携带bin和hpm文件", action=misc.STORE_TRUE, default=False)
159
178
  parser.add_argument(
160
- "-j",
161
- "--json",
162
- help="单CSR出包生成json文件,仅在--single模式下有效",
179
+ "-j",
180
+ "--json",
181
+ help="单CSR出包生成json文件,仅在-s模式下有效",
163
182
  action=misc.STORE_TRUE,
164
183
  default=False
165
184
  )
166
185
  parser.add_argument(
167
- "-m",
186
+ "-m",
168
187
  "--max_config",
169
- help="设定eeprom大小限制的json配置文件路径,无配置时默认限制为32k" +
170
- "key为字符串类型,指定不带后缀的csr文件名称,value为数值类型,指定大小限制,单位KB",
188
+ help="eeprom大小限制的json配置文件路径,无配置时默认限制为32k",
171
189
  default=EEPROM_SIZE_LIMIT_CONFIG
172
190
  )
173
191
  parsed_args, _ = parser.parse_known_args(*args)
@@ -179,18 +197,22 @@ class BmcgoCommand:
179
197
  self.bin = parsed_args.bin
180
198
  self.hpm = parsed_args.hpm
181
199
  self.all = parsed_args.all
200
+ self.tar = parsed_args.tar
182
201
  self.frud = parsed_args.frud
183
202
  self.max_size_map = parsed_args.max_config
184
203
  self.uid = parsed_args.uid
185
204
  self.work_dir = None
186
205
  self.target_dir = None
206
+ self.eeprom_sign_strategy = None
207
+ self.hpm_sign_strategy = None
187
208
 
188
209
  @staticmethod
189
210
  def get_oem_data(dir_path: str, comp_name: str):
190
211
  oem_file = f'oem_{comp_name}.bin'
212
+ oem_file_path = os.path.join(dir_path, oem_file)
191
213
  oem_data = bytearray()
192
- if os.path.exists(oem_file):
193
- with open(oem_file, 'rb') as f:
214
+ if os.path.exists(oem_file_path):
215
+ with open(oem_file_path, 'rb') as f:
194
216
  oem_data = bytearray(f.read())
195
217
  return oem_data
196
218
 
@@ -200,7 +222,7 @@ class BmcgoCommand:
200
222
  for options in options_list:
201
223
  for name in options.binary_names:
202
224
  if name in bin_names:
203
- raise Exception(f"存在重复的 UID: {name},出包失败!")
225
+ raise Exception(f"存在重复的UID: {name}, 出包失败!")
204
226
  bin_names.add(name)
205
227
 
206
228
  @staticmethod
@@ -213,27 +235,52 @@ class BmcgoCommand:
213
235
  return False
214
236
  try:
215
237
  with open(path, 'r', encoding='utf-8-sig') as json_file:
216
- json.load(json_file)
238
+ json5.load(json_file)
217
239
  return True
218
240
  except (json.JSONDecodeError, UnicodeDecodeError, IOError):
219
241
  return False
220
242
 
243
+ def get_eeprom_sign_strategy(self):
244
+ if self.bconfig.e2p_server_sign:
245
+ eeprom_sign_strategy = SignatureTypeEnum.SERVER_SIGN
246
+ elif self.bconfig.e2p_self_sign:
247
+ eeprom_sign_strategy = SignatureTypeEnum.SELF_SIGN
248
+ else:
249
+ eeprom_sign_strategy = SignatureTypeEnum.DEFAULT
250
+ self.eeprom_sign_strategy = eeprom_sign_strategy
251
+ log.info(f"eeprom签名使用 {eeprom_sign_strategy.value} 方法")
252
+
253
+ def get_hpm_sign_strategy(self):
254
+ if self.bconfig.hpm_server_sign:
255
+ hpm_sign_strategy = SignatureTypeEnum.SERVER_SIGN
256
+ elif self.bconfig.hpm_self_sign:
257
+ hpm_sign_strategy = SignatureTypeEnum.SELF_SIGN
258
+ else:
259
+ hpm_sign_strategy = SignatureTypeEnum.DEFAULT
260
+ self.hpm_sign_strategy = hpm_sign_strategy
261
+ log.info(f"hpm签名使用 {hpm_sign_strategy.value} 方法")
262
+
263
+ def get_sign_strategy(self):
264
+ log.info("开始获取签名策略配置信息...")
265
+ self.get_eeprom_sign_strategy()
266
+ self.get_hpm_sign_strategy()
267
+
221
268
  def make_sr_binary(self, options: SrMakeOptions, hpm_temp_dir: str, max_size: int):
222
- eeprom_build_controller = EepromBuild(self.bconfig, options, self.work_dir)
269
+ eeprom_build_controller = EepromBuild(self.bconfig, options, self.work_dir, self.eeprom_sign_strategy)
223
270
  eeprom_data = eeprom_build_controller.build_eeprom()
224
271
  if len(eeprom_data) > max_size * 1024 - 40:
225
- raise Exception(f"Eeprom二进制文件大小超过限制:{options.comp_name}")
272
+ raise errors.BmcGoException(f"Eeprom二进制文件大小超过限制: {options.comp_name}")
226
273
  binary_files = []
227
274
  for name in options.binary_names:
228
275
  binary_files.append(os.path.join(hpm_temp_dir, f"{name}.bin"))
229
- if self.bin or self.all:
276
+ if self.bin or self.all or self.tar:
230
277
  log.info(f"生成{name}.bin文件...")
231
278
  binary_files.append(os.path.join(self.target_dir, f"{name}.bin"))
232
279
  if self.uid:
233
280
  uid_list = str(self.uid).split(',')
234
281
  for uid in uid_list:
235
282
  log.info(f"生成{uid}.bin文件...")
236
- binary_files.append(os.path.join(self.target_dir, f"{uid}.bin"))
283
+ binary_files.append(os.path.join(hpm_temp_dir, f"{uid}.bin"))
237
284
  if name not in LEGACY_UIDS and not self.frud:
238
285
  continue
239
286
  binary_files.append(os.path.join(hpm_temp_dir, f"{name}.frud"))
@@ -254,11 +301,12 @@ class BmcgoCommand:
254
301
  sr_make_options_list = self.get_sr_file_and_oem()
255
302
  else:
256
303
  sr_make_options_list = self.get_sr_files()
257
- if len(sr_make_options_list) == 0:
258
- log.info("目录下不存在sr文件!")
304
+ if len(sr_make_options_list) == 0:
305
+ log.info("目录下不存在sr文件!")
259
306
  return
260
307
  log.info("进行SR文件UID唯一性验证...")
261
308
  self.check_uid(sr_make_options_list)
309
+ self.get_sign_strategy()
262
310
  try:
263
311
  self.work_dir = tempfile.TemporaryDirectory().name
264
312
  self.target_dir = os.path.join(self.work_dir, "target")
@@ -266,15 +314,16 @@ class BmcgoCommand:
266
314
  hpm_temp_dir = os.path.join(self.work_dir, "hpm_temp")
267
315
  os.makedirs(hpm_temp_dir, exist_ok=True)
268
316
  self.make_eeprom(hpm_temp_dir, sr_make_options_list)
269
- if not self.single or self.hpm or self.all:
317
+ if not self.single or self.hpm or self.all:
270
318
  if len(sr_make_options_list) == 1:
271
319
  hpm_file = os.path.join(self.target_dir, f"{sr_make_options_list[0].comp_name}.hpm")
272
320
  else:
273
321
  hpm_file = os.path.join(self.target_dir, f"CSR-{get_timestamp()}.hpm")
274
- hpm_package = HpmBuild(self.bconfig, hpm_file, self.work_dir)
322
+ params = (self.bconfig, hpm_file, self.work_dir, self.hpm_sign_strategy)
323
+ hpm_package = HpmBuild(*params)
275
324
  log.info("开始执行hpm包构建任务...")
276
325
  hpm_package.run()
277
- if self.single or self.frud:
326
+ if self.single or self.frud or self.tar:
278
327
  output_file = os.path.join(self.output_path, f"bingo-{get_timestamp()}.tar.gz")
279
328
  tar_command = ['tar', '-czf', output_file, "-C", self.target_dir, "."]
280
329
  try:
@@ -289,17 +338,14 @@ class BmcgoCommand:
289
338
  finally:
290
339
  if os.path.exists(self.work_dir):
291
340
  shutil.rmtree(self.work_dir)
292
- temp_file = os.path.join(cwd, "temp")
293
- if os.path.exists(temp_file):
294
- shutil.rmtree(temp_file)
295
341
 
296
342
  def check_args(self):
297
343
  has_single_need_arg = self.bin or self.json or self.hpm or self.all
298
344
  if not self.single:
299
345
  if self.oem_path or self.uid or has_single_need_arg:
300
- raise Exception("以下参数仅在单个CSR出包模式(-s,--single)下有效:[--oem, --hpm, -j, -b, -u, -a],请检查命令!")
346
+ raise Exception("以下参数仅在单个CSR出包模式(-s,--single)下有效:[--oem, --hpm, -j, -b, -u, -a],请检查命令!")
301
347
  elif not has_single_need_arg:
302
- raise Exception("以下参数需至少携带一个:[--bin, --json, --hpm],可使用--all/-a指定索引选项。执行bingo build -h查看详细参数说明")
348
+ raise Exception("以下参数需至少携带一个:[--bin, --json, --hpm], 可使用--all/-a指定所有选项。 执行bingo build -h查看详细参数说明")
303
349
  if not self.is_valid_json_path(self.max_size_map):
304
350
  raise Exception(f"无效的JSON文件路径:{self.max_size_map}")
305
351
 
@@ -309,7 +355,7 @@ class BmcgoCommand:
309
355
  oem_path = self.oem_path
310
356
  oem_data = bytearray()
311
357
  if not os.path.exists(csr_path):
312
- raise FileNotFoundError(f"路径{csr_path}不存在")
358
+ raise FileNotFoundError(f"路径 {csr_path} 不存在")
313
359
  if not os.path.isfile(csr_path):
314
360
  raise Exception(f"{csr_path} 不是一个文件路径")
315
361
  _, csr_ext = os.path.splitext(csr_path)
@@ -319,18 +365,18 @@ class BmcgoCommand:
319
365
  log.info(f"执行出包的sr文件路径:{csr_path}")
320
366
  if oem_path:
321
367
  if not os.path.exists(oem_path):
322
- raise FileNotFoundError(f"OEM文件路径{oem_path}不存在")
368
+ raise FileNotFoundError(f"OEM文件路径 {oem_path} 不存在")
323
369
  if not os.path.isfile(oem_path):
324
370
  raise Exception(f"{oem_path} 不是一个文件路径")
325
371
  _, oem_ext = os.path.splitext(oem_path)
326
372
  if not oem_ext == ".bin":
327
- raise Exception(f"OEM文件{oem_path}应为.bin文件")
373
+ raise Exception(f"OEM文件{oem_path} 应为.bin文件")
328
374
  with open(oem_path, 'rb') as f:
329
375
  oem_data = bytearray(f.read())
330
376
  name = os.path.basename(csr_path)
331
377
  comp_name = os.path.splitext(name)[0]
332
378
  with open(csr_path, 'r') as f:
333
- sr_json = json.load(f)
379
+ sr_json = json5.load(f)
334
380
  sr_make_options_list.append(SrMakeOptions(comp_name, sr_json, oem_data))
335
381
  return sr_make_options_list
336
382
 
@@ -348,7 +394,7 @@ class BmcgoCommand:
348
394
  log.info(f"执行出包的sr文件:{name}")
349
395
  comp_name = os.path.splitext(name)[0]
350
396
  with open(sr_file, 'r') as f:
351
- sr_json = json.load(f)
397
+ sr_json = json5.load(f)
352
398
  oem_data = self.get_oem_data(dir_path, comp_name)
353
399
  sr_make_options = SrMakeOptions(comp_name, sr_json, oem_data)
354
400
  sr_make_options_list.append(sr_make_options)
@@ -376,7 +422,8 @@ class BmcgoCommand:
376
422
  else:
377
423
  max_eeprom_size = max_size_map.get(options.comp_name, DEFAULT_EEPROM_SIZE_LIMIT)
378
424
  if not isinstance(max_eeprom_size, int) or max_eeprom_size <= 0:
379
- raise Exception(f"{options.comp_name}sr文件的eeprom大小限制设定值{max_eeprom_size}错误,应为大于0的整数,单位(kb)")
425
+ msg = f"{options.comp_name}sr文件的eeprom大小限制设定值{max_eeprom_size}错误,应为大于0的整数,单位(kb)"
426
+ raise errors.BmcGoException(msg)
380
427
  self.make_sr_binary(options, hpm_temp_dir, max_eeprom_size)
381
428
 
382
429
  def do_build_eeprom(self):
@@ -389,8 +436,11 @@ class BmcgoCommand:
389
436
 
390
437
 
391
438
  class EepromBuild:
392
- def __init__(self, bconfig, options, work_dir):
439
+ def __init__(self, bconfig, options, work_dir, strategy):
393
440
  self.bconfig = bconfig
441
+ # eeprom签名策略
442
+ self.strategy = strategy
443
+ # 签名参数
394
444
  self.comp_name = options.comp_name
395
445
  # devkit数据,json结构
396
446
  self.dev_data = options.sr_json
@@ -410,7 +460,7 @@ class EepromBuild:
410
460
  self.reserved_len = 73
411
461
  # 组件UID数据长度,24 bytes
412
462
  self.unique_id_len = 24
413
- # 电子标签域数据长度 2048 bytes
463
+ # 电子标签域数据长度,2048 bytes
414
464
  self.elabel_len = 2048
415
465
  # 系统信息域数据长度,1024 bytes
416
466
  self.system_len = 1024
@@ -430,11 +480,11 @@ class EepromBuild:
430
480
  self.psr_data = bytearray()
431
481
  # 组件域数据
432
482
  self.csr_data = bytearray()
433
- # 数字签名数据, 当前全0
434
- self.sign_data = bytearray(self.sign_len)
483
+ # 数字签名数据
484
+ self.sign_data = bytearray()
435
485
  # 自描述固件版本号数据,低字节在前高字节在后
436
486
  self.des_ver_data = bytearray()
437
- # 制化预留数据
487
+ # 定制化预留数据
438
488
  self.des_reserve_data = bytearray()
439
489
 
440
490
  @staticmethod
@@ -450,7 +500,7 @@ class EepromBuild:
450
500
 
451
501
  @staticmethod
452
502
  def resize_bytes_supplement(byte_arr: bytearray) -> bytearray:
453
- '''将字节数组进行8位补齐'''
503
+ """将字节数组进行8位补齐"""
454
504
  new_size = round_up_data_size(len(byte_arr))
455
505
  if new_size == len(byte_arr):
456
506
  return byte_arr
@@ -459,10 +509,10 @@ class EepromBuild:
459
509
  return out_bytes
460
510
 
461
511
  @staticmethod
462
- def get_sha256_hash(data: bytearray) -> bytearray:
463
- sha256 = hashlib.sha256()
464
- sha256.update(data)
465
- return bytearray(sha256.digest())
512
+ def get_sha256_hash(data: bytearray):
513
+ sha256_hash = hashlib.sha256()
514
+ sha256_hash.update(data)
515
+ return bytearray(sha256_hash.digest())
466
516
 
467
517
  @staticmethod
468
518
  def get_crc32_check_sum(data: bytearray):
@@ -470,18 +520,26 @@ class EepromBuild:
470
520
  return crc32_value
471
521
 
472
522
  @staticmethod
473
- def zip_data(json_str) -> bytearray:
474
- if not json_str:
523
+ def zip_data(data) -> bytearray:
524
+ if not data:
475
525
  return bytearray()
476
- byte_data = json_str.encode("utf-8")
526
+ byte_data = data.encode('utf-8')
477
527
  output_stream = io.BytesIO()
478
528
  # 创建一个压缩流并写入到内存的BytesIO对象
479
- with gzip.GzipFile(fileobj=output_stream, mode="wb") as f:
529
+ with gzip.GzipFile(fileobj=output_stream, mode='wb') as f:
480
530
  f.write(byte_data)
481
531
  # 读取压缩后的字节流
482
532
  compressed_data = output_stream.getvalue()
483
533
  return compressed_data
484
534
 
535
+ @staticmethod
536
+ def sign_file(file_path, signing_key):
537
+ with open(file_path, "rb") as fp:
538
+ file_data = fp.read()
539
+ signature = signing_key.sign(file_data, sigencode=ecdsa.util.sigencode_der)
540
+ with open("signature.bin", "wb") as fp:
541
+ fp.write(signature)
542
+
485
543
  def build_eeprom(self):
486
544
  # 1. 从自描述数据中提取版本号信息
487
545
  self.des_ver_data = self.build_description_version()
@@ -512,8 +570,10 @@ class EepromBuild:
512
570
  eeprom_buf.put(self.internal_data)
513
571
  eeprom_buf.put(self.psr_data)
514
572
  eeprom_buf.put(self.csr_data)
573
+ # 9. 创建数字签名区域数据
574
+ self.sign_data = self.sign_eeprom(eeprom_buf.array()[:eeprom_buf_len])
515
575
  eeprom_buf.put(self.sign_data)
516
- log.info(f"{self.comp_name}: eeprom数据写入成功")
576
+ log.info(f"{self.comp_name}eeprom数据写入成功")
517
577
  return eeprom_buf.array()
518
578
 
519
579
  # 创建固件自定义描述版本号数据
@@ -534,7 +594,7 @@ class EepromBuild:
534
594
  # 构建uniqueID
535
595
  def build_unique_id(self):
536
596
  unique_id_buf = Buffer(self.unique_id_len)
537
- array_uid = bytearray(self.component_uid, "utf-8")
597
+ array_uid = bytearray(self.component_uid, 'utf-8')
538
598
  unique_id_buf.put(array_uid)
539
599
  return unique_id_buf.array()
540
600
 
@@ -552,9 +612,74 @@ class EepromBuild:
552
612
  buf.put(oem_data)
553
613
  return buf.array()
554
614
 
615
+ # 创建数字签名域数据
616
+ def sign_eeprom(self, un_sign_data: bytearray):
617
+ if self.strategy == SignatureTypeEnum.DEFAULT:
618
+ return self.get_eeprom_default_sign()
619
+ elif not (self.strategy == SignatureTypeEnum.SERVER_SIGN or
620
+ self.strategy == SignatureTypeEnum.SELF_SIGN):
621
+ raise errors.BmcGoException("Invalid signing strategy.")
622
+ else:
623
+ tmp_sign_path = os.path.join(self.work_dir, "tmp_sign")
624
+ bin_file_path = os.path.join(tmp_sign_path, "tmpEeprom.bin")
625
+ if os.path.exists(tmp_sign_path):
626
+ shutil.rmtree(tmp_sign_path)
627
+ os.makedirs(tmp_sign_path, exist_ok=True)
628
+ with open(bin_file_path, 'wb') as f:
629
+ f.write(un_sign_data)
630
+ if self.strategy == SignatureTypeEnum.SELF_SIGN:
631
+ sign_data = self.get_eeprom_self_sign(un_sign_data)
632
+ else:
633
+ sign_data = self.get_eeprom_server_sign(tmp_sign_path, bin_file_path)
634
+ if os.path.exists(tmp_sign_path):
635
+ shutil.rmtree(tmp_sign_path)
636
+ return self.build_sign(sign_data)
637
+
638
+ def get_eeprom_default_sign(self):
639
+ return bytearray(self.sign_len)
640
+
641
+ def get_eeprom_self_sign(self, un_sign_data):
642
+ signing_key = self.load_key()
643
+ signature = signing_key.sign(un_sign_data, sigencode=ecdsa.util.sigencode_der)
644
+ return bytearray(signature)
645
+
646
+ def get_eeprom_server_sign(self, tmp_sign_path, bin_file_path):
647
+ os.chdir(tmp_sign_path)
648
+ url = self.bconfig.e2p_server_sign.url
649
+ try:
650
+ fp = os.fdopen(os.open(bin_file_path, os.O_RDONLY, stat.S_IRUSR), 'rb')
651
+ res = requests.post(url, files={'file': fp})
652
+ res.raise_for_status()
653
+ except requests.exceptions.RequestException as e:
654
+ raise errors.BmcGoException(f"签名服务器返回错误,文件 {bin_file_path} 签名失败")
655
+ return bytearray(res.content)
656
+
657
+ def load_key(self):
658
+ priv_pem_path = self.bconfig.e2p_self_sign.pem
659
+ if os.path.exists(priv_pem_path):
660
+ with open(priv_pem_path, "rb") as f:
661
+ signing_key = ecdsa.SigningKey.from_pem(f.read(), hashfunc=sha256)
662
+ return signing_key
663
+ else:
664
+ raise errors.BmcGoException("ECC私钥路径不存在!")
665
+
666
+ def build_sign(self, sign_data: bytearray):
667
+ sign_info = SignInfo(sign_data)
668
+ sign_buf = Buffer(self.sign_len)
669
+ # 1. Hash算法,1字节
670
+ sign_buf.put_uint8(sign_info.sign_hash_code)
671
+ # 2. 签名算法,1字节
672
+ sign_buf.put_uint8(sign_info.sign_algorithm_code)
673
+ # 3. 签名算法曲线ID,2字节
674
+ sign_buf.put_uint16(sign_info.sign_curve_id)
675
+ # 4. 签名数据长度,4字节
676
+ sign_buf.put_uint32(sign_info.sign_length)
677
+ sign_buf.put(bytearray(sign_info.sign_content))
678
+ return sign_buf.array()
679
+
555
680
  # 创建组件域描述数据
556
681
  def build_csr(self):
557
- csr_json_str = json.dumps(self.dev_data, separators=(",", ":"))
682
+ csr_json_str = json.dumps(self.dev_data, separators=(',', ':'))
558
683
  csr_bytes_arr = [bytearray(), bytearray(), bytearray(), bytearray()]
559
684
  csr_body = self.build_csr_body(csr_json_str)
560
685
  csr_bytes_arr[0] = csr_body
@@ -565,7 +690,7 @@ class EepromBuild:
565
690
  return csr_data.array()
566
691
 
567
692
  def build_csr_body(self, csr_body_str: str):
568
- # 1.处理CSR数据, 获取压缩后字节
693
+ # 1. 处理CSR数据,获取压缩后字节
569
694
  zip_data = self.resize_bytes_supplement(self.zip_data(csr_body_str))
570
695
  # 2. 计算CSR body数据域长度
571
696
  body_size = len(zip_data) + 40
@@ -583,7 +708,7 @@ class EepromBuild:
583
708
  csr_body_buf.set_position(csr_body_buf.position() + 4)
584
709
  # 9. CSR压缩数据填充,字节数组
585
710
  csr_body_buf.put(zip_data)
586
- # 10 CSR完整性校验
711
+ # 10. CSR完整性校验
587
712
  csr_body_buf.set_position(0)
588
713
  csr_body_buf.put(self.get_sha256_hash(csr_body_buf.array()))
589
714
  return csr_body_buf.array()
@@ -592,7 +717,7 @@ class EepromBuild:
592
717
  csr_header = CsrHeader(self.csr_header_len, csr_bytes_arr)
593
718
  # 1. 初始化csr header buffer
594
719
  csr_header_buf = Buffer(self.csr_header_len)
595
- # 2. csr域格式版本, 1字节
720
+ # 2. csr域格式版本,1字节
596
721
  csr_header_buf.put_uint8(csr_header.csr_ver)
597
722
  # 3. CSR域数量,1字节
598
723
  csr_header_buf.put_uint8(csr_header.csr_count)
@@ -611,11 +736,11 @@ class EepromBuild:
611
736
  eeprom_header_buf.put(e_header.code)
612
737
  # 2. 规范版本号 1字节
613
738
  eeprom_header_buf.put_uint8(e_header.header_ver)
614
- # 3. 电子组标签域偏移,0x00填充 2字节 16
739
+ # 3. 电子标签域偏移,0x00填充 2字节 16
615
740
  eeprom_header_buf.put_uint16(e_header.elabel_off)
616
- # 4. 系统定制化描述信息(System Description Address) 偏移,0x00填充,2字节
741
+ # 4. 系统定制化描述信息(System Description Address)偏移,0x00填充,2字节
617
742
  eeprom_header_buf.put_uint16(e_header.system_off) # 272
618
- # 5,内部适用域(Internal Use Area Address)偏移,0x00填充,2字节
743
+ # 5. 内部适用域(Internal Use Area Address)偏移,0x00填充,2字节
619
744
  eeprom_header_buf.put_uint16(e_header.internal_area_off)
620
745
  # 6. 整机描述域偏移,2字节
621
746
  eeprom_header_buf.put_uint16(e_header.psr_off)
@@ -623,7 +748,7 @@ class EepromBuild:
623
748
  eeprom_header_buf.put_uint16(e_header.csr_off)
624
749
  # 8. 数据签名区域偏移,2字节
625
750
  eeprom_header_buf.put_uint16(e_header.sign_off)
626
- # 9. 定制化预留数据填充0x0073字节
751
+ # 9. 定制化预留数据填充0x00, 73字节
627
752
  eeprom_header_buf.put(self.des_reserve_data)
628
753
  # 10. 自描述固件版本号数据,低字节在前高字节在后,2字节
629
754
  eeprom_header_buf.put(self.des_ver_data)
@@ -631,7 +756,7 @@ class EepromBuild:
631
756
  eeprom_header_buf.put(self.component_uid_data)
632
757
  # 12. CRC32 校验和(4字节)
633
758
  eeprom_header_buf.put_uint32(self.get_crc32_check_sum(eeprom_header_buf.array()))
634
- return eeprom_header_buf.array()
759
+ return eeprom_header_buf.array()
635
760
 
636
761
 
637
762
  class EepromHeader:
@@ -659,8 +784,9 @@ class EepromHeader:
659
784
 
660
785
  class HpmBuild:
661
786
  # Description: hpm打包初始化函数
662
- def __init__(self, bconfig, dest_file, work_dir):
787
+ def __init__(self, bconfig, dest_file, work_dir, strategy):
663
788
  self.bconfig = bconfig
789
+ self.strategy = strategy
664
790
  # hpm包文件名
665
791
  self.hpm_name = "devkit.hpm"
666
792
  # 打包后结果文件存放路径
@@ -678,40 +804,139 @@ class HpmBuild:
678
804
  # 打包后得到的hpm包
679
805
  self.hpm_file = os.path.join(self.hpm_temp_dir, self.hpm_name)
680
806
 
681
- # hpm包制作工具检查
682
807
  @staticmethod
683
- def check_hpm_tools():
684
- log.info("开始hpm包制作工具检查...")
685
- ret = tool.run_command("which hpmimage filesizecheck")
686
- if ret is None or ret.returncode != 0:
687
- raise Exception("hpm 包制作工具缺失,请检查bingo是否正确安装")
808
+ def sign_hpm_default():
809
+ cms_file = os.path.realpath("image.filelist.cms")
810
+ tool.pipe_command([f"echo 'cms placeholder'"], out_file=cms_file)
811
+ crl_file = os.path.realpath("crldata.crl")
812
+ tool.pipe_command([f"echo 'crl placeholder'"], out_file=crl_file)
688
813
 
689
814
  # 打包路径下配置文件校验
690
815
  def check_dir(self):
816
+ if self.strategy and self.strategy != SignatureTypeEnum.DEFAULT:
817
+ return
691
818
  for config_file in self.package_list:
692
819
  if not os.path.exists(os.path.join(self.hpm_temp_dir, config_file)):
693
- raise Exception(f"Failed to find hpm package config file: {config_file}")
820
+ raise errors.BmcGoException(f"Failed to find hpm package config file: {config_file}")
821
+
822
+ # hpm包制作工具检查
823
+ def check_hpm_tools(self):
824
+ log.info("开始hpm包制作工具检查...")
825
+ ret = tool.run_command("which hpmimage filesizecheck")
826
+ if ret is None or ret.returncode != 0:
827
+ raise errors.BmcGoException("hpm包制作工具缺失,请检查bingo是否正确安装")
828
+ if self.bconfig.hpm_encrypt and self.bconfig.hpm_encrypt.need_encrypt \
829
+ and not self.bconfig.hpm_encrypt.tool_path:
830
+ raise errors.BmcGoException("配置hpm加密但加密工具不存在,请联系PAE获取")
694
831
 
695
832
  # 执行脚本构建hpm
696
833
  def packet_hpm(self):
697
834
  log.info("开始执行构建脚本生成hpm包...")
698
835
  packet_script = os.path.join(self.hpm_temp_dir, "packet.sh")
699
836
  os.chdir(self.hpm_temp_dir)
700
- ret = tool.run_command(f"bash {packet_script} package {self.hpm_temp_dir}", command_echo=False)
837
+ need_encrypt = self.bconfig.hpm_encrypt and self.bconfig.hpm_encrypt.need_encrypt
838
+ ret = tool.run_command(f"bash {packet_script} package {self.hpm_temp_dir} {need_encrypt}", command_echo=False)
701
839
  if ret.returncode != 0:
702
- raise Exception(f"Failed to pack the hpm, error msg: {ret}")
840
+ raise errors.BmcGoException(f"Failed to pack the hpm, error msg: {ret}")
703
841
  elif not os.path.exists(self.hpm_file):
704
- raise Exception("Failed to pack the hpm.")
842
+ raise errors.BmcGoException("Failed to pack the hpm.")
843
+
844
+ # 对hpm包进行签名
845
+ def sign_hpm(self):
846
+ if self.strategy == SignatureTypeEnum.DEFAULT:
847
+ log.info("未配置签名策略,跳过hpm包签名...")
848
+ self.sign_hpm_default()
849
+ elif self.strategy == SignatureTypeEnum.SELF_SIGN or\
850
+ self.strategy == SignatureTypeEnum.SERVER_SIGN:
851
+ # 生成.filelist文件
852
+ tool.run_command(f"cms_sign_hpm.sh 1 {self.hpm_name}", command_echo=False)
853
+ shutil.copy("devkit.filelist", "image.filelist")
854
+ SignGenerator(self.bconfig, self.strategy, "image.filelist").sign_generate()
855
+ else:
856
+ raise errors.BmcGoException("Invalid signing strategy.")
857
+
858
+ # 签名后使用签名结果文件重新构造hpm包
859
+ def rebuild_hpm(self):
860
+ log.info("签名成功,使用签名结果重新构造hpm包...")
705
861
  os.chdir(self.hpm_temp_dir)
706
862
  ret = tool.run_command(f"bash {self.hpm_temp_dir}/packet.sh rebuild {self.hpm_temp_dir}", command_echo=False)
707
863
  if ret.returncode != 0 or not os.path.exists(self.hpm_file):
708
- raise Exception(f"构造hpm包失败:{ret.stderr}.")
864
+ raise errors.BmcGoException(f"构造hpm包失败:{ret.stderr}.")
709
865
  shutil.move(self.hpm_file, self.dest_path)
710
866
 
711
867
  def run(self):
712
868
  self.check_dir()
713
869
  self.check_hpm_tools()
714
870
  self.packet_hpm()
871
+ self.sign_hpm()
872
+ self.rebuild_hpm()
873
+
874
+
875
+ class SignGenerator:
876
+ def __init__(self, bconfig: BmcgoConfig, sign_strategy: str, unsigned_file: str):
877
+ self.bconfig = bconfig
878
+ self.sign_strategy = sign_strategy
879
+ self.unsigned_file = unsigned_file
880
+ self.sign_suffix = ".cms"
881
+ self.cms_output = f"{self.unsigned_file}{self.sign_suffix}"
882
+ self.crl_output = "crldata.crl"
883
+ self.ca_output = "rootca.der"
884
+
885
+ def sign_generate(self):
886
+ if self.sign_strategy == SignatureTypeEnum.SELF_SIGN:
887
+ self.self_sign_generate()
888
+ elif self.sign_strategy == SignatureTypeEnum.SERVER_SIGN:
889
+ self.server_sign_generate()
890
+ else:
891
+ raise errors.BmcGoException("Invalid sign strategy")
892
+
893
+ def self_sign_generate(self):
894
+ """使用本地签名方法"""
895
+ unsigned_file = os.path.realpath(self.unsigned_file)
896
+ cms_output = os.path.realpath(self.cms_output)
897
+ crl_output = os.path.realpath(self.crl_output)
898
+ ca_output = os.path.realpath(self.ca_output)
899
+ tmp_dir = tempfile.TemporaryDirectory()
900
+ t_cwd = os.getcwd()
901
+ os.chdir(tmp_dir.name)
902
+ rootca_der = self.bconfig.hpm_self_sign.rootca_der
903
+ rootca_crl = self.bconfig.hpm_self_sign.rootca_crl
904
+ signer_pem = self.bconfig.hpm_self_sign.signer_pem
905
+ ts_signer_pem = self.bconfig.hpm_self_sign.ts_signer_pem
906
+ ts_signer_cnf = self.bconfig.hpm_self_sign.ts_signer_cnf
907
+ tool.run_command(f"openssl x509 -in {rootca_der} -inform der -outform pem -out rootca.pem", command_echo=False)
908
+ tool.run_command(f"openssl crl -in {rootca_crl} -inform der -outform pem -out cms.crl.pem", command_echo=False)
909
+ cmd = f"hpm_signer -s {signer_pem} -t {ts_signer_pem} -T {ts_signer_cnf} -i {unsigned_file} -o {cms_output}"
910
+ tool.run_command(cmd)
911
+ tool.run_command(f"hpm_verify -r rootca.pem -C cms.crl.pem -c {unsigned_file} -s {cms_output}")
912
+ os.chdir(t_cwd)
913
+ tool.copy(rootca_crl, crl_output)
914
+ tool.copy(rootca_der, ca_output)
915
+
916
+ def server_sign_generate(self):
917
+ """使用简易服务器签名方法"""
918
+ cert_id = self.bconfig.hpm_server_sign.cert_id
919
+ url = self.bconfig.hpm_server_sign.url
920
+ ssl_verify = self.bconfig.hpm_server_sign.ssl_verify
921
+ rootca_der = self.bconfig.hpm_server_sign.rootca_der
922
+ if not os.path.isfile(rootca_der):
923
+ raise errors.BmcGoException(f"签名根证书{rootca_der}不存在")
924
+ unsigned_file = os.path.realpath(self.unsigned_file)
925
+ cms_output = os.path.realpath(self.cms_output)
926
+ crl_output = os.path.realpath(self.crl_output)
927
+ ca_output = os.path.realpath(self.ca_output)
928
+ t_cwd = os.getcwd()
929
+ tmpdir = tempfile.TemporaryDirectory()
930
+ os.chdir(tmpdir.name)
931
+ args = ["-i", unsigned_file, "-s", cert_id, "-u", url, "-v", ssl_verify]
932
+ cmd = SimpleSign(self.bconfig, args)
933
+ cmd.run()
934
+ # 签名工具吐出rootca.crl和signed.cms复制到image.filelist.cms、crldata.crl
935
+ tool.copy("signed.cms", cms_output)
936
+ tool.copy("rootca.crl", crl_output)
937
+ # csr出包签名根证书由开发者在bmcgo.conf中配置
938
+ tool.copy(rootca_der, ca_output)
939
+ os.chdir(t_cwd)
715
940
 
716
941
 
717
942
  # 文件名生成时间戳