blob: 47c86af055e74c87f0c9ad5bc7e2a2ffb3039b4c [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001#!/usr/bin/env python
2# -*- coding: UTF-8 -*-
3"""
4This module supports image signing, including single bin and multi bin.
5Multi bin means a composite image composed of multiple sub-images.
6"""
7import sys
8import os
9import struct
10import re
11import subprocess
12import ntpath
13import shutil
14import stat
15import lib.mkimghdr
16import lib.getPublicKey
17import lib.cert
18import cert_gen
19
20CERT1_REPLACE_TARGET = r"(\s)*pubk2"
21CERT2_REPLACE_HASH = r"(\s)*imgHash EXTERNAL_BITSTRING"
22CERT2_REPLACE_HEADER_HASH = r"(\s)*imgHdrHash EXTERNAL_BITSTRING"
23CERT2_REPLACE_IMG_HASH_MULTI = r"(\s)*imgHash_Multi EXTERNAL_BITSTRING"
24CERT2_REPLACE_SOCID = r"(\s)*socid PRINTABLESTRING"
25CERT1MD_REPLACE_TARGET = r"(\s)*pubkHash EXTERNAL_BITSTRING"
26SW_ID_REPLACE_TARGET = r"(\s)*swID INTEGER"
27IMG_VER_REPLACE_TARGET = r"(\s)*imgVer INTEGER"
28IMG_GROUP_REPLACE_TARGET = r"(\s)*imgGroup INTEGER"
29MKIMAGE_HDR_MAGIC = 0x58881688
30MKIMAGE_HDR_FMT = "<2I 32s 2I 8I"
31BOOTIMG_HDR_MAGIC = "ANDROID"
32BOOTIMG_HDR_FMT = "<8c 10I 16c 512c 8I 1024c I Q I I Q"
33CCCI_HDR_FMT = "<8c 10I 16c 512c 8I"
34DTBO_HDR_MAGIC = 0xD7B7AB1E
35DTBO_HDR_FMT = ">8I"
36
37class Sign(object):
38 """
39 Sign is used to pass parameter to module 'sign'.
40 """
41 def __init__(self):
42 """
43 initialization of arguments
44 """
45 self.args = {}
46 self.context = {}
47
48 self.args['type'] = 0
49 self.args['img'] = 0
50 self.args['privk'] = 0
51 self.args['pubk'] = 0
52 self.args['cert1'] = 0
53 self.args['swID'] = 0
54 self.args['ver'] = 0
55 self.args['name'] = ''
56 self.args['group'] = 0
57 self.args['root_key_padding'] = 0
58 self.args['getHashList'] = 0
59 self.args['platform'] = 'NOT_SET'
60 self.args['project'] = 'NOT_SET'
61 self.args['env_cfg'] = os.path.join(os.path.dirname(__file__), \
62 'env.cfg')
63 self.args['socid'] = '0'
64
65 return
66
67 def reset(self):
68 """
69 reset all arguments
70 """
71 self.__init__()
72
73 def get_arg(self, field_name):
74 """
75 get value of field and returns 'NOT_SET' if it's not defined
76 """
77 try:
78 return self.args[field_name]
79 except KeyError, error:
80 print 'KeyError: ' + str(error)
81 return 'NOT_SET'
82
83 def set_context(self):
84 """
85 Set temporary path for certificate generation.
86 """
87 img_name = self.args['name']
88 if self.args['img'] != 0:
89 package_name = os.path.splitext(os.path.basename(self.args['img']))[0]
90 else:
91 package_name = ''
92
93 print '=============================='
94 print 'env_cfg parsing'
95 print '=============================='
96 cfg_file = open(self.args['env_cfg'], 'r')
97 cfg_file_dir = os.path.dirname(os.path.abspath(self.args['env_cfg']))
98 for line in cfg_file.readlines():
99 line = line.strip()
100 if line:
101 elements = line.split('=')
102 field = elements[0].strip()
103 value = elements[1].strip()
104 value = value.replace("${PLATFORM}", self.get_arg('platform'))
105 value = value.replace("${PROJECT}", self.get_arg('project'))
106 if field == 'out_path':
107 self.context['out'] = os.environ.get('PRODUCT_OUT')
108 if self.context['out'] is None:
109 print 'Use out path in env.cfg'
110 self.context['out'] = os.path.join(cfg_file_dir, value)
111 else:
112 print 'Use out path in Android'
113 self.context['out_path'] = os.path.join(self.context['out'], "resign")
114 elif field == 'x509_template_path':
115 x509_template_path = os.path.join(cfg_file_dir, value)
116 elif field == 'mkimage_tool_path':
117 mkimage_tool_path = os.path.join(cfg_file_dir, value)
118 else:
119 print 'ignored: ' + field
120 print '=============================='
121
122 self.context['bin_path'] = os.path.join(self.context['out_path'], "bin")
123 self.context['tmpcert_name'] = os.path.join(self.context['out_path'], \
124 "cert", \
125 package_name, \
126 img_name, \
127 "tmp.der")
128
129 #tool path
130 mkimage_config = os.path.join(mkimage_tool_path, "img_hdr.cfg")
131 cert_out = os.path.join(self.context['out_path'], "cert", package_name, img_name)
132
133 self.context['mkimage_config'] = mkimage_config
134
135 mkimage_config_out = ""
136 if self.args['type'] == "cert1md":
137 cert1md_tmp = os.path.join(cert_out, "cert1md", "intermediate")
138 cert1md_name = os.path.join(cert_out, "cert1md", "cert1md.der")
139 cert1md_hash_path = os.path.join(cert1md_tmp, "hash")
140 cert1md_config = os.path.join(x509_template_path, "cert1md.cfg")
141 cert1md_config_out = os.path.join(cert1md_tmp, "cert1md.cfg")
142 mkimage_config_out = os.path.join(cert1md_tmp, "img_hdr.cfg")
143 self.context['cert1md_name'] = cert1md_name
144 self.context['cert1md_config'] = cert1md_config
145 self.context['cert1md_config_out'] = cert1md_config_out
146 self.context['cert1md_hash_path'] = cert1md_hash_path
147 elif self.args['type'] == "cert1":
148 cert1_tmp = os.path.join(cert_out, "cert1", "intermediate")
149 cert1_name = os.path.join(cert_out, "cert1", "cert1.der")
150 cert1_config = os.path.join(x509_template_path, "cert1.cfg")
151 cert1_config_out = os.path.join(cert1_tmp, "cert1.cfg")
152 mkimage_config_out = os.path.join(cert1_tmp, "img_hdr.cfg")
153 self.context['cert1_name'] = cert1_name
154 self.context['cert1_config'] = cert1_config
155 self.context['cert1_config_out'] = cert1_config_out
156 elif self.args['type'] == "cert2":
157 cert2_tmp = os.path.join(cert_out, "cert2", "intermediate")
158 cert2_name = os.path.join(cert_out, "cert2", "cert2.der")
159 cert2_hash_path = os.path.join(cert2_tmp, "hash")
160 cert2_config = os.path.join(x509_template_path, "cert2.cfg")
161 cert2_config_out = os.path.join(cert2_tmp, "cert2.cfg")
162 dm_cert = os.path.join(cert2_tmp, "dm_cert.der")
163 bin_tmp_path = os.path.join(cert2_tmp, "tmp_bin")
164 sig_path = os.path.join(self.context['out'], "sig", package_name)
165 mkimage_config_out = os.path.join(cert2_tmp, "img_hdr.cfg")
166 self.context['bin_tmp_path'] = bin_tmp_path
167 self.context['cert2_name'] = cert2_name
168 self.context['cert2_config'] = cert2_config
169 self.context['cert2_config_out'] = cert2_config_out
170 self.context['cert2_hash_path'] = cert2_hash_path
171 self.context['dm_cert'] = dm_cert
172 self.context['sig_path'] = sig_path
173
174 self.context['mkimage_config_out'] = mkimage_config_out
175 return
176
177 def __create_out_dir(self, path):
178 """
179 create output folder
180 """
181 dir_path = os.path.dirname(path)
182 print "Create dir:" + dir_path
183
184 try:
185 os.makedirs(dir_path)
186 except OSError, error:
187 if error.errno != os.errno.EEXIST:
188 raise
189
190 def __create_abs_dir(self, path):
191 """
192 create output folder based on absolute path
193 """
194 dir_path = os.path.abspath(path)
195 print "Create dir:" + dir_path
196
197 try:
198 os.makedirs(dir_path)
199 except OSError, error:
200 if error.errno != os.errno.EEXIST:
201 raise
202
203 def __create_folder(self):
204 """
205 Create output folder for certificate generation.
206 """
207 mkimage_config_out = self.context['mkimage_config_out']
208 bin_path = self.context['bin_path']
209
210 self.__create_out_dir(mkimage_config_out)
211 self.__create_abs_dir(bin_path)
212
213 if self.args['type'] == "cert1md":
214 cert1md_name = self.context['cert1md_name']
215 cert1md_hash_path = self.context['cert1md_hash_path']
216 self.__create_out_dir(cert1md_name)
217 self.__create_abs_dir(cert1md_hash_path)
218 elif self.args['type'] == "cert1":
219 cert1_name = self.context['cert1_name']
220 cert1_config_out = self.context['cert1_config_out']
221 self.__create_out_dir(cert1_name)
222 self.__create_out_dir(cert1_config_out)
223 elif self.args['type'] == "cert2":
224 cert2_name = self.context['cert2_name']
225 cert2_hash_path = self.context['cert2_hash_path']
226 sig_path = self.context['sig_path']
227 bin_tmp_path = self.context['bin_tmp_path']
228 self.__create_out_dir(cert2_name)
229 self.__create_abs_dir(cert2_hash_path)
230 self.__create_abs_dir(sig_path)
231 self.__create_abs_dir(bin_tmp_path)
232 return
233
234 def gen_cert(self, cert_config, privk_key, cert_der, root_key_padding):
235 """
236 Generate certificate based on the configuration given.
237 """
238 cert_gen_args = cert_gen.CertGenArgs()
239 cert_gen_args.config_file = cert_config
240 cert_gen_args.prvk_file_path = privk_key
241 #root key padding will be set to 'legacy' by default
242 if root_key_padding != 0:
243 cert_gen_args.root_key_padding = root_key_padding
244 cert_gen_args.x509cert_file = cert_der
245 cert_gen.cert_gen_op(cert_gen_args)
246
247 def gen_cert1(self):
248 """
249 Generate cert1, which is key certificate for images
250 other than modem image.
251 """
252 cert1_config = self.context['cert1_config']
253 cert1_config_out = self.context['cert1_config_out']
254 #copy cert1 config
255 shutil.copy2(cert1_config, cert1_config_out)
256 sw_id = self.args['swID']
257 img_ver = self.args['ver']
258 img_group = self.args['group']
259
260 cert1_name = self.context['cert1_name']
261
262 if self.args['root_key_padding'] == 0:
263 root_key_padding = 'legacy'
264 else:
265 root_key_padding = self.args['root_key_padding']
266 print "root_key_padding = " + root_key_padding
267
268 if int(sw_id) != 0:
269 fill_cert_config(cert1_config_out, sw_id, SW_ID_REPLACE_TARGET)
270 if int(img_ver) != 0:
271 fill_cert_config(cert1_config_out, img_ver, IMG_VER_REPLACE_TARGET)
272 if int(img_group) != 0:
273 fill_cert_config(cert1_config_out, img_group, IMG_GROUP_REPLACE_TARGET)
274
275 fill_cert_config(cert1_config_out, self.args['pubk'], CERT1_REPLACE_TARGET)
276 #gen cert
277 self.gen_cert(cert1_config_out, \
278 self.args['privk'], \
279 cert1_name, \
280 root_key_padding)
281 cert1_img_type = 0x2 << 24
282 add_mkimg_header(cert1_name, 0, cert1_img_type, "cert1", self.context)
283 print "output path:" + cert1_name
284 return
285
286 def gen_cert1md(self):
287 """
288 Generate cert1md, which is key certificate for modem image.
289 """
290 img_file = self.args['img']
291 cert_privk = self.args['privk']
292 cert1md_hash_path = self.context['cert1md_hash_path']
293 cert1md_config = self.context['cert1md_config']
294 cert1md_config_out = self.context['cert1md_config_out']
295
296 if self.args['root_key_padding'] == 0:
297 root_key_padding = 'legacy'
298 else:
299 root_key_padding = self.args['root_key_padding']
300 print "root_key_padding = " + root_key_padding
301
302 print img_file
303 #check is Raw
304 is_raw, is_md, hdr_size = check_is_raw(img_file)
305
306 if is_raw == 0:
307 print "Is not raw image"
308 return
309
310 if is_md < 1:
311 print "Wrong MD image type"
312 return
313
314 cert1md_name = self.context['cert1md_name']
315
316 #SV5 Image(MD)
317 split_header, split_image = img_split(img_file, cert1md_hash_path, hdr_size)
318 key_hash_tmp = os.path.join(cert1md_hash_path, "key_tmp.hash")
319 key_hash = os.path.join(cert1md_hash_path, "key.hash")
320 header_hash = os.path.join(cert1md_hash_path, "header.hash")
321
322 #get md key
323 md_key = get_md_key(split_image, is_md, self.context)
324 #gen header hash
325 lib.cert.hash_gen(split_header, header_hash)
326 #gen key hash
327 lib.cert.hash_gen(md_key, key_hash_tmp)
328 #Endiness conversion
329 endiness_convert(key_hash_tmp, key_hash)
330
331 #fill config
332 shutil.copy2(cert1md_config, cert1md_config_out)
333 fill_cert_config(cert1md_config_out, key_hash, CERT1MD_REPLACE_TARGET)
334 fill_cert_config(cert1md_config_out, self.args['pubk'], CERT1_REPLACE_TARGET)
335
336 sw_id = self.args['swID']
337 img_ver = self.args['ver']
338 img_group = self.args['group']
339 if int(sw_id) != 0:
340 fill_cert_config(cert1md_config_out, sw_id, SW_ID_REPLACE_TARGET)
341 if int(img_ver) != 0:
342 fill_cert_config(cert1md_config_out, img_ver, IMG_VER_REPLACE_TARGET)
343 if int(img_group) != 0:
344 fill_cert_config(cert1md_config_out, img_group, IMG_GROUP_REPLACE_TARGET)
345 #gen cert
346 self.gen_cert(cert1md_config_out, cert_privk, cert1md_name, root_key_padding)
347 #add mkimage header on cert1md
348
349 cert1md_img_type = 0x2 << 24 | 0x1
350 add_mkimg_header(cert1md_name, 0, cert1md_img_type, "cert1md", self.context)
351 print "output path:" + cert1md_name
352
353 def gen_cert2(self):
354 """
355 Generate cert2, which is content certificate.
356 """
357 img_file = self.args['img']
358 cert1 = self.args['cert1']
359 cert_privk = self.args['privk']
360 img_name = self.args['name']
361 img_ver = self.args['ver']
362 socid = self.args['socid']
363 is_img_hash_list = 0
364 is_raw = 0
365 is_boot = 0
366 is_dtbo = 0
367
368 if self.get_arg('getHashList') is '1':
369 is_img_hash_list = 1
370
371 img_array = []
372 size_array = []
373 offset_array = []
374 img_name_array = []
375
376 bin_path = self.context['bin_path']
377 bin_tmp_path = self.context['bin_tmp_path']
378 cert2_name = self.context['cert2_name']
379 cert2_config = self.context['cert2_config']
380 cert2_config_out = self.context['cert2_config_out']
381 cert2_hash_path = self.context['cert2_hash_path']
382 dm_cert = self.context['dm_cert']
383 sig_path = self.context['sig_path']
384 out = self.context['out']
385
386 is_raw, is_md, hdr_size = check_is_raw(img_file)
387 if not is_raw:
388 is_boot, boot_img_size, hdr_size = check_is_boot(img_file)
389
390 if is_boot:
391 has_dm_cert = get_vboot10_cert(img_file, boot_img_size, self.context)
392
393 if (not is_raw) and (not is_boot):
394 is_dtbo, dtbo_img_size, hdr_size = check_is_dtbo(img_file)
395
396 if is_raw:
397 img_array, \
398 size_array, \
399 offset_array, \
400 img_name_array = parse_multi_bin(img_file, img_name, self.context)
401 if img_array is None:
402 return
403 elif is_boot:
404 img_array.append(os.path.join(bin_tmp_path, "tmp.bin"))
405 size_array.append(boot_img_size)
406 offset_array.append(0)
407 img_name_array.append(img_name)
408 elif is_dtbo:
409 img_array.append(os.path.join(bin_tmp_path, "tmp.bin"))
410 size_array.append(dtbo_img_size)
411 offset_array.append(0)
412 img_name_array.append(img_name)
413 elif not is_img_hash_list:
414 print "wrong image format"
415 return
416
417 if is_img_hash_list:
418 print "get pure image hash..."
419 self.gen_img_hash_list(img_file, cert1, cert_privk, img_name, img_ver)
420 return
421
422 get_pure_img(img_file, img_array, size_array, offset_array)
423 print "bin_number:" + str(len(img_array))
424 #Get hash from image
425 i = 0
426 img_list_end = 0
427 for img in img_array:
428 if i == len(img_array) - 1:
429 img_list_end = 1
430
431 if is_raw == 1 or is_boot == 1 or is_md == 1 or is_md == 2 or is_dtbo:
432 #Raw Image
433 if img_name_array[i] == img_name:
434 split_header, split_image = img_split(img, cert2_hash_path, hdr_size)
435
436 image_hash = os.path.join(cert2_hash_path, "image.hash")
437 header_hash = os.path.join(cert2_hash_path, "header.hash")
438
439 #gen header hash
440 lib.cert.hash_gen(split_header, header_hash)
441 #gen image hash
442 lib.cert.hash_gen(split_image, image_hash)
443
444 #if exist DM cert, append it after hash calculate
445 if is_boot == 1 and has_dm_cert == 1:
446 append_file(img, dm_cert)
447
448 #cat cert1
449 append_file(img, cert1)
450
451 #fill cert2 config
452 shutil.copy2(cert2_config, cert2_config_out)
453 fill_cert_config(cert2_config_out, image_hash, CERT2_REPLACE_HASH)
454 fill_cert_config(cert2_config_out, header_hash, CERT2_REPLACE_HEADER_HASH)
455 fill_cert_config(cert2_config_out, socid.upper(), CERT2_REPLACE_SOCID)
456
457 if int(img_ver) != 0:
458 fill_cert_config(cert2_config_out, img_ver, IMG_VER_REPLACE_TARGET)
459 #gen cert2
460 self.gen_cert(cert2_config_out, cert_privk, cert2_name, 0)
461 #add mkimage header on cert2
462 cert2_img_type = 0x2 << 24 | 0x2
463 add_mkimg_header(cert2_name, \
464 img_list_end, \
465 cert2_img_type, \
466 "cert2", \
467 self.context)
468 #cat cert2
469 append_file(img, cert2_name)
470 #cat sig file
471 sig_file = os.path.join(sig_path, img_name + ".sig")
472 print img_ver
473 print "sig:" + sig_file
474 shutil.copy2(cert1, sig_file)
475 append_file(sig_file, cert2_name)
476
477 i += 1
478
479 img_name = ntpath.split(img_file)[1]
480 img_name = img_name.split(".")[0] + "-verified." + img_name.split(".")[1]
481 final_bin = os.path.join(bin_tmp_path, img_name)
482
483 #cat all bin to img_array[0]
484 cat_img(img_array, final_bin)
485
486 #Post Process
487 shutil.copy2(final_bin, os.path.join(bin_path, img_name))
488 shutil.copy2(os.path.join(bin_path, img_name), os.path.join(out, img_name))
489 print "output path:" + os.path.join(out, img_name)
490 return
491
492 def gen_img_hash_list(self, img_file, cert1, cert_privk, img_name, img_ver):
493 """
494 Generate image hash list. This is a verified boot mechanism
495 for images that are too big to fit into DRAM at once. In this
496 case, image is split into 128MB chunks and sent to DA one by one.
497 DA will receive a signed image hash list and verifies it before
498 flashing. After that, DA will calculate hash on receiving a chunk
499 and compares it against the hash in signed image hash list.
500 """
501 data_size = 128 * 1048576
502
503 img_size = os.path.getsize(img_file)
504 print "img_size => "+ str(img_size)
505 file1 = open(img_file, 'rb')
506 package_num = (img_size + (data_size - 1)) / data_size
507 print "package_num => "+ str(package_num)
508 print "get " + img_name + " hash list..."
509
510 bin_tmp_path = self.context['bin_tmp_path']
511 cert2_name = self.context['cert2_name']
512 cert2_config = self.context['cert2_config']
513 cert2_config_out = self.context['cert2_config_out']
514 cert2_hash_path = self.context['cert2_hash_path']
515 sig_path = self.context['sig_path']
516 out = self.context['out']
517
518 for i in range(package_num):
519 div_out = os.path.join(bin_tmp_path, img_name + "_" + str(i) + ".bin")
520 div_hash_out = os.path.join(cert2_hash_path, img_name + "_" + str(i) + ".hash")
521 output_file = open(div_out, 'wb')
522 content = file1.read(data_size)
523 output_file.write(content)
524 output_file.close()
525 lib.cert.hash_gen(div_out, div_hash_out)
526 file1.close()
527
528 img_hash_file = os.path.join(cert2_hash_path, img_name + "_total.hash")
529 file2 = open(img_hash_file, 'wb')
530 for i in range(package_num):
531 hash_file = open(os.path.join(cert2_hash_path, img_name + "_" + str(i) + ".hash"), 'rb')
532 img_hash = hash_file.read()
533 file2.write(img_hash)
534 file2.close()
535
536 shutil.copy2(cert2_config, cert2_config_out)
537
538 fill_cert_config(cert2_config_out, img_hash_file, CERT2_REPLACE_IMG_HASH_MULTI)
539 if int(img_ver) != 0:
540 fill_cert_config(cert2_config_out, img_ver, IMG_VER_REPLACE_TARGET)
541 #gen cert2
542 self.gen_cert(cert2_config_out, cert_privk, cert2_name, 0)
543 img_list_end = 1
544 #add mkimage header on cert2
545 cert2_img_type = 0x2 << 24 | 0x2
546 add_mkimg_header(cert2_name, img_list_end, cert2_img_type, "cert2", self.context)
547 sig_file = os.path.join(sig_path, img_name + ".sig")
548 shutil.copy2(cert1, sig_file)
549 append_file(sig_file, cert2_name)
550 shutil.copy2(sig_file, os.path.join(out, img_name + ".sig"))
551
552 return
553
554 def sign_op(self):
555 """
556 perform image signing
557 """
558 self.set_context()
559
560 if self.args['type'] == "cert1":
561 self.__create_folder()
562 self.gen_cert1()
563 elif self.args['type'] == "cert2":
564 self.__create_folder()
565 self.gen_cert2()
566 elif self.args['type'] == "cert1md":
567 self.__create_folder()
568 self.gen_cert1md()
569 else:
570 print "wrong cert type !"
571
572 return
573
574 def dump(self):
575 """
576 dump parameters
577 """
578 print 'cert_type = ' + self.get_arg(self.args['type'])
579 print 'platform = ' + self.get_arg(self.args['platform'])
580 print 'project = ' + self.get_arg(self.args['project'])
581 print 'img = ' + self.get_arg(self.args['img'])
582 print 'name = ' + self.get_arg(self.args['name'])
583 print 'cert1_path = ' + self.get_arg(self.args['cert1'])
584 print 'root_prvk = ' + self.get_arg(self.args['privk'])
585 print 'img_pubk = ' + self.get_arg(self.args['pubk'])
586 print 'group = ' + self.get_arg(self.args['group'])
587 print 'ver = ' + self.get_arg(self.args['ver'])
588 print 'root_padding = ' + self.get_arg(self.args['root_key_padding'])
589 print 'getHashList = ' + self.get_arg(self.args['getHashList'])
590 print 'env_cfg = ' + self.get_arg(self.args['env_cfg'])
591 return
592
593def parse_multi_bin(img_file, target_img_name, context):
594 """
595 we may concatenate multiple images to form a composite image.
596 This function is used to parse the composite image to get
597 information of sub-image with name target_img_name.
598 """
599 #parse bin
600 img_size = 0
601 index = 0
602 file1 = open(img_file, 'rb')
603 last_pos = 0
604 pre_pos = 0
605
606 img_array = []
607 size_array = []
608 offset_array = []
609 img_name_array = []
610
611 file_size = os.path.getsize(img_file)
612 print "file_size: "+ str(hex(file_size))
613
614 first_img = 1
615 final_size = 0
616 match_target = 0
617 img_name = 0
618
619 bin_tmp_path = context['bin_tmp_path']
620
621 while True:
622 file1.seek(last_pos)
623 header_size = struct.calcsize(MKIMAGE_HDR_FMT)
624 fin = file1.read(header_size)
625 unpack_array = struct.unpack(MKIMAGE_HDR_FMT, fin)
626 file1.seek(last_pos)
627
628 magic_number = unpack_array[0]
629 dsize = unpack_array[1]
630 hdr_size = unpack_array[6]
631 align_size = unpack_array[10]
632 img_type = unpack_array[8]
633
634 if ~cmp(magic_number, int(MKIMAGE_HDR_MAGIC)) == 0:
635 print "wrong image header magic"
636 sys.exit()
637
638 # include header + image + padding size to 16 bytes align
639 img_size = (dsize + hdr_size + (align_size - 1)) / align_size * align_size
640 print "img-" + str(index) + " size:" + hex(img_size)
641
642 img_type_byte3 = (img_type >> 24) & 0xFF
643
644 if img_type_byte3 != 2:
645 # image not cert
646 pre_img_name = img_name
647 img_name = unpack_array[2].rstrip('\t\r\n\0')
648 if target_img_name == img_name:
649 print "Target image, remove cert for replace"
650 is_target = 1
651 match_target = 1
652 else:
653 print "Not target image, retain cert"
654 is_target = 0
655 is_raw = 1
656 else:
657 #image is cert
658 is_raw = 0
659
660 if is_raw and first_img == 0:
661 print "add index" + str(index) + " image"
662 img_str = os.path.join(bin_tmp_path, "tmp_" + str(index) + ".bin")
663 img_array.append(img_str)
664 size_array.append(final_size)
665 offset_array.append(pre_pos)
666 img_name_array.append(pre_img_name)
667 pre_pos = last_pos
668 final_size = 0
669 index += 1
670
671 first_img = 0
672
673 if is_target:
674 if is_raw:
675 final_size = img_size
676 else:
677 print "is cert, discard it"
678 else:
679 final_size += img_size
680
681 last_pos += img_size
682
683 if last_pos >= file_size:
684 print "add index" + str(index) + " image, this is final image"
685 img_str = os.path.join(bin_tmp_path, "tmp_" + str(index) + ".bin")
686 img_array.append(img_str)
687 size_array.append(final_size)
688 offset_array.append(pre_pos)
689 img_name_array.append(img_name)
690 pre_pos = last_pos
691 final_size = 0
692 break
693
694 file1.close()
695 if match_target == 0:
696 print "img name not match,exit!!"
697 return None, None, None, None
698 return img_array, size_array, offset_array, img_name_array
699
700def check_is_raw(img_file):
701 """
702 check whether image is raw image format, which includes
703 images with mkimage header and modem image.
704 """
705 is_raw = 0
706 is_md = 0
707 print img_file
708 file1 = open(img_file, 'rb')
709 header_size = struct.calcsize(MKIMAGE_HDR_FMT)
710 fin = file1.read(header_size)
711
712 unpack_array = struct.unpack(MKIMAGE_HDR_FMT, fin)
713 file1.close()
714
715 hdr_size = unpack_array[6]
716 img_type = unpack_array[8]
717
718 if cmp(unpack_array[0], int(MKIMAGE_HDR_MAGIC)) == 0:
719 img_type_byte0 = img_type & 0xFF
720 img_type_byte3 = (img_type >> 24) & 0xFF
721
722 if img_type == 0:
723 print "Raw IMG"
724 is_raw = 1
725 elif img_type_byte3 == 1:
726 if img_type_byte0 == 0:
727 print "MD IMG:LTE"
728 is_raw = 1
729 is_md = 1
730 elif img_type_byte0 == 1:
731 print "MD IMG:C2K"
732 is_raw = 1
733 is_md = 2
734 else:
735 print "Not Raw Img"
736 is_raw = 0
737 return is_raw, is_md, hdr_size
738
739def get_vboot10_cert(img_file, img_size, context):
740 """
741 parse certificate that follows boot image on vboot1.0
742 """
743 has_dm_cert = 0
744 dm_cert = context['dm_cert']
745 file_size = os.path.getsize(img_file)
746 if file_size <= img_size + 4:
747 return has_dm_cert
748
749 file1 = open(img_file, 'rb')
750 fin = file1.read(img_size)
751 fin = file1.read(4)
752
753 unpack_array = struct.unpack("<4c", fin)
754
755 if ord(unpack_array[0]) == 0x30:
756 cert_size = (ord(unpack_array[2]) << 8) + ord(unpack_array[3]) + 4
757 print hex(cert_size)
758 file2 = open(dm_cert, 'wb')
759 file1.seek(img_size)
760 file2.write(file1.read(cert_size))
761 file2.close()
762 has_dm_cert = 1
763 padding_file(dm_cert, 16)
764 file1.close()
765 return has_dm_cert
766
767
768def check_is_md(img_file):
769 """
770 check whether it's modem image.
771 """
772 #parse bin
773 file1 = open(img_file, 'rb')
774 header_size = struct.calcsize(CCCI_HDR_FMT)
775 fin = file1.read(header_size)
776 unpack_array = struct.unpack(CCCI_HDR_FMT, fin)
777 file1.close()
778 magic_str = ""
779 for i in range(0, 7):
780 magic_str = magic_str + unpack_array[i]
781 return 0
782
783def check_is_boot(img_file):
784 """
785 check whether it's boot/recovery image.
786 """
787 #parse bin
788 img_size = 0
789 is_boot = 0
790 hdr_size = 0
791
792 file1 = open(img_file, 'rb')
793 header_size = struct.calcsize(BOOTIMG_HDR_FMT)
794
795 fin = file1.read(header_size)
796 unpack_array = struct.unpack(BOOTIMG_HDR_FMT, fin)
797 file1.close()
798 magic_str = ""
799 for i in range(0, 7):
800 magic_str = magic_str + unpack_array[i]
801
802 if cmp(magic_str, BOOTIMG_HDR_MAGIC) == 0:
803 print "Is Boot Img"
804 page_size = unpack_array[15]
805 hdr_size = page_size
806 kernel_size = (unpack_array[8] + (page_size - 1)) / page_size * page_size
807 ramdisk_size = (unpack_array[10] + (page_size - 1)) / page_size * page_size
808 #recovery dtbo image
809 dtbo_size = (unpack_array[1578] + (page_size - 1)) / page_size * page_size
810 #dtb image
811 dtb_size = (unpack_array[1581] + (page_size - 1)) / page_size * page_size
812 print "Header size:" + `hex(header_size)`
813 print "Kernel size:" + `hex(kernel_size)`
814 print "Ramdisk size:" + `hex(ramdisk_size)`
815 print "DTBO size:" + `hex(dtbo_size)`
816 print "dtb size:" + `hex(dtb_size)`
817 print "page size:" + `hex(unpack_array[15])`
818 img_size = (kernel_size + ramdisk_size + hdr_size + dtbo_size + dtb_size + (16 - 1)) / 16 * 16
819 print "Total Size(include header and padding):" + `hex(img_size)`
820 print hex(img_size)
821 is_boot = 1
822 else:
823 print "Not Boot Img"
824
825 return is_boot, img_size, hdr_size
826
827def check_is_dtbo(img_file):
828 """
829 check whether it's dtbo image.
830 """
831 #parse bin
832 img_size = 0
833 is_dtbo = 0
834 hdr_size = 0
835 file1 = open(img_file, 'rb')
836 header_size = struct.calcsize(DTBO_HDR_FMT)
837
838 fin = file1.read(header_size)
839 unpack_array = struct.unpack(DTBO_HDR_FMT, fin)
840 file1.close()
841
842 if unpack_array[0] == DTBO_HDR_MAGIC:
843 print "Is DTBO Img"
844 hdr_size = unpack_array[2]
845 img_size = unpack_array[1]
846 print "Header size:" + `hex(hdr_size)`
847 print "Image size:" + `hex(img_size)`
848 print "Total Size" + `hex(unpack_array[1])`
849 is_dtbo = 1
850 else:
851 print "Not dtbo Img"
852
853 return is_dtbo, img_size, hdr_size
854
855def fill_cert_config(cert_path, replace_str, tgt_line_pattern):
856 """
857 We provide certificate configuration template and could
858 generate cerificate based on the configuration. Before that,
859 you need to fill up the configuration template so certificate
860 generation engine knows how to generate certificate.
861 """
862 os.chmod(cert_path, stat.S_IWRITE + stat.S_IREAD)
863
864 file1 = open(cert_path, 'r')
865 lines = file1.readlines()
866 file1.close()
867
868 file2 = open(cert_path, 'w')
869
870 format1 = re.compile(tgt_line_pattern)
871 for line in lines:
872 if format1.match(line):
873 print line
874 line2 = line.split("::=")[0] + "::= " + replace_str + "\n"
875 print line2
876 file2.write(line2)
877 else:
878 file2.write(line)
879
880def padding_file(input_file, align_num):
881 """
882 Fill 0 to make input_file size multiple of align_num.
883 """
884 filesize = os.stat(input_file).st_size
885 file1 = open(input_file, 'ab+')
886 padding = filesize % align_num
887 if padding != 0:
888 padding = align_num - padding
889 for _ in range(padding):
890 file1.write("\x00")
891 file1.close()
892
893def append_file(img_file, cert_file):
894 """
895 Append cert_file to the end of img_file.
896 """
897 padding_file(img_file, 16)
898 file1 = open(img_file, 'ab+')
899 file2 = open(cert_file, 'rb')
900 file1.write(file2.read())
901 file1.close()
902 file2.close()
903
904def get_pure_img(img_file, img_array, size_array, offset_array):
905 """
906 Put sub-image data into array for composite image.
907 """
908 index = 0
909 file2 = open(img_file, 'rb')
910 for sub_img in img_array:
911 img_size = size_array[index]
912 offset = offset_array[index]
913 file2.seek(offset)
914 file1 = open(sub_img, 'wb+')
915 file1.write(file2.read(img_size))
916 file1.close()
917 index += 1
918 file2.close()
919
920def backup_file(tmp_file, target_file, backup_file_path):
921 """
922 Backup target_file to backup_file_path
923 """
924 if backup_file_path != "":
925 shutil.move(target_file, backup_file_path)
926 shutil.move(tmp_file, target_file)
927
928def cat_img(img_array, final_bin):
929 """
930 Concatenate data in img_array to form final_bin,
931 which is a composite image.
932 """
933 file1 = open(final_bin, 'wb')
934 index = 0
935 for img in img_array:
936 file2 = open(img, 'rb')
937 file1.write(file2.read())
938 file2.close()
939 index += 1
940 file1.close()
941
942def add_mkimg_header(cert_name, img_list_end, img_type, img_name, context):
943 """
944 mkimage header is the header for Mediatek proprietary images.
945 This function is used to generate mkimage header for
946 certificate files.
947
948 """
949 mkimage_config = context['mkimage_config']
950 mkimage_config_out = context['mkimage_config_out']
951 tmpcert_name = context['tmpcert_name']
952 file1 = open(mkimage_config, 'r')
953 file2 = open(mkimage_config_out, 'w+')
954 format1 = re.compile("IMG_LIST_END")
955 format2 = re.compile("IMG_TYPE")
956 format3 = re.compile("NAME")
957 for line in file1:
958 if format1.match(line):
959 end = line.split("=")[1]
960 line2 = line.replace(end, str(img_list_end))
961 file2.write(line2 + "\n")
962 elif format2.match(line):
963 end = line.split("=")[1]
964 line2 = line.replace(end, str(img_type))
965 file2.write(line2 + "\n")
966 elif format3.match(line):
967 end = line.split("=")[1]
968 line2 = line.replace(end, str(img_name))
969 file2.write(line2 + "\n")
970 else:
971 file2.write(line)
972
973 file1.close()
974 file2.close()
975
976 img_hdr = lib.mkimghdr.mkimage_hdr()
977 img_hdr.update_mkimage_hdr(cert_name, mkimage_config_out)
978 img_hdr.pack()
979 img_hdr.output(cert_name, tmpcert_name)
980 shutil.move(tmpcert_name, cert_name)
981
982def get_md_key(md_img, is_md, context):
983 """
984 Get modem public key from modem image
985 """
986 found = 0
987 cert1md_hash_path = context['cert1md_hash_path']
988 md_key_path = os.path.join(cert1md_hash_path, "md_key.bin")
989
990 if is_md == 1:
991 md1_handler = lib.getPublicKey.md1_image()
992 found = md1_handler.parse(md_img)
993 if found:
994 md1_handler.output(md_img, md_key_path)
995 print "output file done"
996 elif is_md == 2:
997 md3_handler = lib.getPublicKey.md3_image()
998 found = md3_handler.parse(md_img)
999 if found:
1000 md3_handler.output(md_img, md_key_path)
1001 print "output file done"
1002 else:
1003 print "wrong md type!!!"
1004
1005 return md_key_path
1006
1007def img_split(img, split_path, hdr_size):
1008 """
1009 split image into header and image body
1010 """
1011 split_header = os.path.join(split_path, "header.bin")
1012 split_image = os.path.join(split_path, "image.bin")
1013
1014 file1 = open(img, 'rb')
1015 file2 = open(split_header, 'wb')
1016 file2.write(file1.read(hdr_size))
1017 file2.close()
1018 file2 = open(split_image, 'wb')
1019 file2.write(file1.read())
1020 file2.close()
1021 file1.close()
1022 padding_file(split_image, 16)
1023
1024 return split_header, split_image
1025
1026def endiness_convert(in_file, out_file):
1027 """
1028 Converts endian of in_file and save result to out_file.
1029 """
1030 endian = sys.byteorder
1031 if endian == "little":
1032 file1 = open(out_file, "wb")
1033 file2 = open(in_file, "rb")
1034 from array import array
1035 for _ in range(8, 0, -1):
1036 tmp = array("B", file2.read(4))
1037 tmp.reverse()
1038 tmp.tofile(file1)
1039 file2.close()
1040 file1.close()
1041
1042def fill_arg_dict(input_string, key, args):
1043 """
1044 Fill up argument dictionary from input parameters
1045 """
1046 prefix = input_string.split("=")[0].strip()
1047 fmt = re.compile(key, re.I)
1048 if fmt.search(prefix):
1049 val = input_string.split("=")[1].strip()
1050 args[key] = val
1051 print key + ": " + val
1052 print args[key]
1053 return args
1054
1055def parse_arg(argv):
1056 """
1057 Parse input arguments and save the result into argument dictionary.
1058 """
1059 args = {'type': 0, \
1060 'img': 0, \
1061 'privk': 0, \
1062 'pubk': 0, \
1063 'cert1': 0, \
1064 'swID': 0, \
1065 'ver': 0, \
1066 'name': '', \
1067 'group': 0, \
1068 'root_key_padding': 0, \
1069 'getHashList': 0, \
1070 'env_cfg': 0, \
1071 'platform': 'NOT_SET', \
1072 'project': 'NOT_SET', \
1073 'socid': '0'}
1074 for input_string in argv:
1075 for key in args:
1076 args = fill_arg_dict(input_string, key, args)
1077 input_wrong = 0
1078
1079 #check input
1080 if args['type'] == "cert1":
1081 if args['privk'] == "" or args['pubk'] == "":
1082 print "wrong cert1 input"
1083 input_wrong = 1
1084 elif args['type'] == "cert2":
1085 if args['privk'] == "" or args['cert1'] == "" or args['img'] == "" or args['name'] == "":
1086 print "wrong cert2 input"
1087 elif args['type'] == "cert1md":
1088 if args['img'] == "" or args['privk'] == "":
1089 print "wrong cert1md input"
1090 else:
1091 print "wrong cert type!"
1092 input_wrong = 1
1093 if input_wrong == 1:
1094 help_menu()
1095 sys.exit()
1096
1097 if args['env_cfg'] == 0:
1098 #env_cfg is not given, we set it to env.cfg in path of this tool
1099 args['env_cfg'] = os.path.join(os.path.dirname(__file__), 'env.cfg')
1100 return args
1101
1102def help_menu():
1103 """
1104 Print usage for this tool.
1105 """
1106 print "Gen Cert1:"
1107 print " usage: python sign.py type=cert1 privk=[cert1_privk.pem] pubk=[cert2_pubk.pem]"
1108 print " optional: swID=[number] ver=[number] group=[number] "
1109 print " output: cert1"
1110 print "Gen Cert2 and append cert1,cert2 to the image:"
1111 print " usage: python sign.py type=cert2 img=[xxx.bin] name=[img name] cert1=[cert1.der] \
1112privk=[cert2_privk.pem]"
1113 print " optional:ver=number"
1114 print " output: image append with cert1 and cert2"
1115 print "Gen Cert1md:"
1116 print " usage: python sign.py type=cert1md img=[xxx.bin] privk=[cert1md_privk.pem] \
1117pubk=[cert2_pubk.pem]"
1118 print " output: cert1md"
1119
1120def main():
1121 """
1122 Main function when this tool is executed from command line.
1123 """
1124 if len(sys.argv) < 3:
1125 help_menu()
1126
1127 sign = Sign()
1128 sign.args = parse_arg(sys.argv)
1129 sign.sign_op()
1130
1131if __name__ == '__main__':
1132 main()