8 from pyasn1_modules
import pem, rfc2459, rfc3279, rfc2314
9 from pyasn1.codec.der
import decoder, encoder
10 from pyasn1.type
import univ
12 sys.stdout.write(
"\n\n\n*** You must install the python package 'pyasn1_modules' first. Run the command:\n\n" + \
13 " pip install pyasn1_modules\n\n" + \
14 "More details here: https://pypi.org/project/pyasn1-modules\n\n\n")
19 parser = argparse.ArgumentParser(description=
'Generate atcacert_def_t structure from sample certificate.')
20 group = parser.add_mutually_exclusive_group(required=
True)
23 dest=
'signer_cert_filename',
27 help=
'Generate signer certificate definition from sample certificate.')
30 dest=
'device_cert_filename',
34 help=
'Generate device certificate definition from sample certificate.')
37 dest=
'device_csr_filename',
41 help=
'Generate device CSR definition from sample CSR.')
42 args = parser.parse_args()
44 if args.signer_cert_filename
is not None:
45 print(gen_cert_def_c_signer(args.signer_cert_filename))
48 if args.device_cert_filename
is not None:
49 print(gen_cert_def_c_device(args.device_cert_filename))
52 if args.device_csr_filename
is not None:
53 print(gen_cert_def_c_device_csr(args.device_csr_filename))
59 def gen_cert_def_c_signer(cert_path):
60 cert_der = pem.readPemFromFile(open(cert_path))
62 cert = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
67 params[
'ca_public_key'] = bin_to_c_hex(bytearray(
'\x00'*64))
69 info = cert_sn_offset_length(cert)
70 params[
'cert_sn_cert_loc_offset'] = info[
'offset']
71 params[
'cert_sn_cert_loc_count'] = info[
'length']
72 if info[
'length'] < 1
or info[
'length'] > 20:
73 raise ValueError(
'Invalid certificate SN length (no more than 20 bytes).')
75 not_before = set_time_params(params, cert,
'notBefore')
76 not_after = set_time_params(params, cert,
'notAfter')
78 expire_years = not_after.year - not_before.year
79 if expire_years < 1
or expire_years > 31:
81 params[
'expire_years'] = expire_years
83 info = cert_signer_id_offset_length(cert,
'subject')
84 params[
'signer_id_cert_loc_offset'] = info[
'offset']
85 params[
'signer_id_cert_loc_count'] = info[
'length']
87 info = cert_public_key_offset_length(cert)
88 params[
'public_key_cert_loc_offset'] = info[
'offset']
89 params[
'public_key_cert_loc_count'] = info[
'length']
91 info = cert_subj_key_id_offset_length(cert)
93 params[
'subj_key_id_cert_loc_offset'] = info[
'offset']
94 params[
'subj_key_id_cert_loc_count'] = info[
'length']
96 params[
'subj_key_id_cert_loc_offset'] = 0
97 params[
'subj_key_id_cert_loc_count'] = 0
99 info = cert_auth_key_id_offset_length(cert)
101 params[
'auth_key_id_cert_loc_offset'] = info[
'offset']
102 params[
'auth_key_id_cert_loc_count'] = info[
'length']
104 params[
'auth_key_id_cert_loc_offset'] = 0
105 params[
'auth_key_id_cert_loc_count'] = 0
107 info = cert_tbs_offset_length(cert)
108 params[
'tbs_cert_loc_offset'] = info[
'offset']
109 params[
'tbs_cert_loc_count'] = info[
'length']
111 info = cert_sig_offset_length(cert)
112 params[
'signature_cert_loc_offset'] = info[
'offset']
113 params[
'signature_cert_loc_count'] = info[
'length']
115 params[
'cert_template'] = bin_to_c_hex(cert_der)
117 return bytearray(string.Template(cert_def_1_signer_c).substitute(params))
120 def gen_cert_def_c_device(cert_path):
121 cert_der = pem.readPemFromFile(open(cert_path))
123 cert = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
127 info = cert_sn_offset_length(cert)
128 params[
'cert_sn_cert_loc_offset'] = info[
'offset']
129 params[
'cert_sn_cert_loc_count'] = info[
'length']
130 if info[
'length'] < 1
or info[
'length'] > 20:
131 raise ValueError(
'Invalid certificate SN length (no more than 20 bytes).')
133 info = cert_signer_id_offset_length(cert,
'issuer')
134 params[
'signer_id_cert_loc_offset'] = info[
'offset']
135 params[
'signer_id_cert_loc_count'] = info[
'length']
137 not_before = set_time_params(params, cert,
'notBefore')
138 not_after = set_time_params(params, cert,
'notAfter')
140 expire_years = not_after.year - not_before.year
141 if expire_years < 1
or expire_years > 31:
144 params[
'expire_date_cert_loc_offset'] = 0
145 params[
'expire_date_cert_loc_count'] = 0
146 params[
'expire_years'] = expire_years
148 info = cert_public_key_offset_length(cert)
149 params[
'public_key_cert_loc_offset'] = info[
'offset']
150 params[
'public_key_cert_loc_count'] = info[
'length']
152 info = cert_subj_key_id_offset_length(cert)
154 params[
'subj_key_id_cert_loc_offset'] = info[
'offset']
155 params[
'subj_key_id_cert_loc_count'] = info[
'length']
157 params[
'subj_key_id_cert_loc_offset'] = 0
158 params[
'subj_key_id_cert_loc_count'] = 0
160 info = cert_auth_key_id_offset_length(cert)
162 params[
'auth_key_id_cert_loc_offset'] = info[
'offset']
163 params[
'auth_key_id_cert_loc_count'] = info[
'length']
165 params[
'auth_key_id_cert_loc_offset'] = 0
166 params[
'auth_key_id_cert_loc_count'] = 0
168 info = cert_tbs_offset_length(cert)
169 params[
'tbs_cert_loc_offset'] = info[
'offset']
170 params[
'tbs_cert_loc_count'] = info[
'length']
172 info = cert_sig_offset_length(cert)
173 params[
'signature_cert_loc_offset'] = info[
'offset']
174 params[
'signature_cert_loc_count'] = info[
'length']
176 params[
'cert_template'] = bin_to_c_hex(cert_der)
178 return bytearray(string.Template(cert_def_2_device_c).substitute(params))
181 def gen_cert_def_c_device_csr(csr_path):
182 csr_der = pem.readPemFromFile(
184 startMarker=
'-----BEGIN CERTIFICATE REQUEST-----',
185 endMarker=
'-----END CERTIFICATE REQUEST-----')
189 csr = decoder.decode(csr_der, asn1Spec=rfc2314.CertificationRequest())[0]
193 info = csr_public_key_offset_length(csr)
194 params[
'public_key_cert_loc_offset'] = info[
'offset']
195 params[
'public_key_cert_loc_count'] = info[
'length']
197 info = cert_tbs_offset_length(csr)
198 params[
'tbs_cert_loc_offset'] = info[
'offset']
199 params[
'tbs_cert_loc_count'] = info[
'length']
201 info = cert_sig_offset_length(csr)
202 params[
'signature_cert_loc_offset'] = info[
'offset']
203 params[
'signature_cert_loc_count'] = info[
'length']
205 params[
'cert_template'] = bin_to_c_hex(csr_der)
207 return bytearray(string.Template(cert_def_3_device_csr_c).substitute(params))
213 def set_time_params(params, cert, name):
214 if name ==
'notBefore':
215 param_prefix =
'issue_date' 216 elif name ==
'notAfter':
217 param_prefix =
'expire_date' 219 info = cert_time_offset_length(cert, name)
220 params[param_prefix +
'_cert_loc_offset'] = info[
'offset']
221 params[param_prefix +
'_cert_loc_count'] = info[
'length']
223 if info[
'length'] == 13:
224 params[param_prefix +
'_format'] =
'DATEFMT_RFC5280_UTC' 225 time_str = str(cert[
'tbsCertificate'][
'validity'][name][0])
226 dt = datetime.datetime.strptime(time_str,
'%y%m%d%H%M%SZ')
227 elif info[
'length'] == 15:
228 params[param_prefix +
'_format'] =
'DATEFMT_RFC5280_GEN' 229 time_str = str(cert[
'tbsCertificate'][
'validity'][name][1])
230 dt = datetime.datetime.strptime(time_str,
'%Y%m%d%H%M%SZ')
232 raise ValueError(name +
' date has invalid length')
236 def bin_to_c_hex(data):
237 data = bytearray(data)
239 for i
in range(0, len(data)):
250 c_hex +=
'0x%02X' % data[i]
254 def cert_sn_offset_length(cert):
255 sn_der = bytearray(encoder.encode(cert[
'tbsCertificate'][
'serialNumber']))
256 int_info = der_value_offset_length(sn_der)
257 msb_idx = int_info[
'offset']
258 if sn_der[msb_idx] & 0x80:
259 if sn_der[msb_idx] == 0x81:
260 sn_der[msb_idx] = 0x82
262 sn_der[msb_idx] = 0x81
264 if sn_der[msb_idx] == 0x01:
265 sn_der[msb_idx] = 0x02
267 sn_der[msb_idx] = 0x01
268 cert_der = encoder.encode(cert)
269 cert_mod = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
270 cert_mod[
'tbsCertificate'][
'serialNumber'] = decoder.decode(bytes(sn_der))[0]
272 return {
'offset':diff_offset(cert_der, encoder.encode(cert_mod)),
'length':int_info[
'length']}
274 def cert_signer_id_offset_length(cert, name):
275 name_der = bytearray(encoder.encode(cert[
'tbsCertificate'][name]))
276 name_der = name_der.replace(b
'FFFF', b
'0000')
278 cert_der = encoder.encode(cert)
279 cert_mod = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
280 cert_mod[
'tbsCertificate'][name] = decoder.decode(bytes(name_der))[0]
282 return {
'offset':diff_offset(cert_der, encoder.encode(cert_mod)),
'length':4}
284 def cert_time_offset_length(cert, name):
285 cert_der = encoder.encode(cert)
286 cert_mod = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
287 time_str = str(cert_mod[
'tbsCertificate'][
'validity'][name].getComponent())
288 time_str = chr(ord(time_str[0]) + 1) + time_str[1:]
289 cert_mod[
'tbsCertificate'][
'validity'][name] = cert_mod[
'tbsCertificate'][
'validity'][name].getComponent().clone(
292 return {
'offset': diff_offset(cert_der, encoder.encode(cert_mod)),
'length': len(time_str)}
294 def cert_public_key_offset_length(cert):
295 pk_der = bytearray(encoder.encode(cert[
'tbsCertificate'][
'subjectPublicKeyInfo'][
'subjectPublicKey']))
296 pk_info = der_value_offset_length(pk_der)
298 pk_der[pk_info[
'offset']+2] ^= 0xFF
300 cert_der = encoder.encode(cert)
301 cert_mod = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
302 cert_mod[
'tbsCertificate'][
'subjectPublicKeyInfo'][
'subjectPublicKey'] = decoder.decode(bytes(pk_der))[0]
304 return {
'offset':diff_offset(cert_der, encoder.encode(cert_mod)),
'length':pk_info[
'length']-2}
306 def csr_public_key_offset_length(csr):
307 pk_der = bytearray(encoder.encode(csr[
'certificationRequestInfo'][
'subjectPublicKeyInfo'][
'subjectPublicKey']))
308 pk_info = der_value_offset_length(pk_der)
310 pk_der[pk_info[
'offset']+2] ^= 0xFF
312 csr_der = encoder.encode(csr)
313 csr_mod = decoder.decode(csr_der, asn1Spec=rfc2314.CertificationRequest())[0]
314 csr_mod[
'certificationRequestInfo'][
'subjectPublicKeyInfo'][
'subjectPublicKey'] = decoder.decode(bytes(pk_der))[0]
316 return {
'offset':diff_offset(csr_der, encoder.encode(csr_mod)),
'length':pk_info[
'length']-2}
318 def cert_subj_key_id_offset_length(cert):
319 cert_der = encoder.encode(cert)
320 cert_mod = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
321 for ext
in cert_mod[
'tbsCertificate'][
'extensions']:
322 if ext[
'extnID'] == rfc2459.id_ce_subjectKeyIdentifier:
323 extn_value = decoder.decode(ext[
'extnValue'], asn1Spec=rfc2459.SubjectKeyIdentifier())[0]
324 key_id = bytearray(extn_value)
327 extn_value = rfc2459.SubjectKeyIdentifier(key_id)
328 ext[
'extnValue'] = univ.OctetString(encoder.encode(extn_value))
330 return {
'offset':diff_offset(cert_der, encoder.encode(cert_mod)),
'length':len(key_id)}
333 def cert_auth_key_id_offset_length(cert):
334 cert_der = encoder.encode(cert)
335 cert_mod = decoder.decode(cert_der, asn1Spec=rfc2459.Certificate())[0]
336 for ext
in cert_mod[
'tbsCertificate'][
'extensions']:
337 if ext[
'extnID'] == rfc2459.id_ce_authorityKeyIdentifier:
338 extn_value = decoder.decode(ext[
'extnValue'], asn1Spec=rfc2459.AuthorityKeyIdentifier())[0]
340 key_id = bytearray(extn_value[
'keyIdentifier'])
343 extn_value[
'keyIdentifier'] = extn_value[
'keyIdentifier'].clone(value=key_id)
344 ext[
'extnValue'] = univ.OctetString(encoder.encode(extn_value))
346 return {
'offset':diff_offset(cert_der, encoder.encode(cert_mod)),
'length':len(key_id)}
349 def cert_tbs_offset_length(cert):
350 cert_der = encoder.encode(cert)
351 cert_info = der_value_offset_length(cert_der)
352 tbs_info = der_value_offset_length(cert_der[cert_info[
'offset']:])
354 return {
'offset':cert_info[
'offset'],
'length':(tbs_info[
'offset'] + tbs_info[
'length'])}
356 def cert_sig_offset_length(cert):
357 cert_der = encoder.encode(cert)
359 cert_info = der_value_offset_length(cert_der)
360 offset = cert_info[
'offset']
362 tbs_info = der_value_offset_length(cert_der[offset:])
363 offset += tbs_info[
'offset'] + tbs_info[
'length']
365 alg_info = der_value_offset_length(cert_der[offset:])
366 offset += alg_info[
'offset'] + alg_info[
'length']
368 sig_info = der_value_offset_length(cert_der[offset:])
370 return {
'offset':offset,
'length':(sig_info[
'offset'] + sig_info[
'length'])}
372 def der_value_offset_length(der):
373 """Returns the offset and length of the value part of the DER tag-length-value object.""" 378 if der[tag_len] < 0x80:
384 len_len = (der[tag_len] & 0x7F)
389 len = (der[tag_len+1] << 8) | der[tag_len+2]
391 len = (der[tag_len+1] << 16) | (der[tag_len+2] << 8) | der[tag_len+3]
393 return {
'offset':tag_len+1+len_len,
'length':len}
395 def diff_offset(base, diff):
396 """Return the index where the two parameters differ.""" 397 if len(base) != len(diff):
398 raise ValueError(
'len(base)=%d != len(diff)=%d' % (len(base), len(diff)))
399 for i
in range(0, len(base)):
400 if base[i] != diff[i]:
404 cert_def_1_signer_c =
""" 406 * NOTE: This file was generated. 407 * Use the corresponding Python generation scripts to modify this file. 409 #include "atcacert/atcacert_def.h" 411 uint8_t g_signer_1_ca_public_key[64] = { 415 const atcacert_cert_element_t g_cert_elements_1_signer[] = { 419 .zone = DEVZONE_DATA, 422 .offset = 35-${issue_date_cert_loc_count}, 423 .count = ${issue_date_cert_loc_count} 426 .offset = ${issue_date_cert_loc_offset}, 427 .count = ${issue_date_cert_loc_count} 433 .zone = DEVZONE_DATA, 436 .offset = 50-${expire_date_cert_loc_count}, 437 .count = ${expire_date_cert_loc_count} 440 .offset = ${expire_date_cert_loc_offset}, 441 .count = ${expire_date_cert_loc_count} 446 const uint8_t g_cert_template_1_signer[] = { 450 const atcacert_def_t g_cert_def_1_signer = { 451 .type = CERTTYPE_X509, 454 .private_key_slot = 0, 455 .sn_source = SNSRC_STORED, 457 .zone = DEVZONE_DATA, 460 .offset = 20-${cert_sn_cert_loc_count}, 461 .count = ${cert_sn_cert_loc_count} 463 .issue_date_format = ${issue_date_format}, 464 .expire_date_format = ${expire_date_format}, 466 .offset = ${tbs_cert_loc_offset}, 467 .count = ${tbs_cert_loc_count} 469 .expire_years = ${expire_years}, 470 .public_key_dev_loc = { 471 .zone = DEVZONE_DATA, 477 .comp_cert_dev_loc = { 478 .zone = DEVZONE_DATA, 484 .std_cert_elements = { 485 { // STDCERT_PUBLIC_KEY 486 .offset = ${public_key_cert_loc_offset}, 487 .count = ${public_key_cert_loc_count} 489 { // STDCERT_SIGNATURE 490 .offset = ${signature_cert_loc_offset}, 491 .count = ${signature_cert_loc_count} 493 { // STDCERT_ISSUE_DATE 494 .offset = ${issue_date_cert_loc_offset}, 495 .count = ${issue_date_cert_loc_count} 497 { // STDCERT_EXPIRE_DATE 498 .offset = ${expire_date_cert_loc_offset}, 499 .count = ${expire_date_cert_loc_count} 501 { // STDCERT_SIGNER_ID 502 .offset = ${signer_id_cert_loc_offset}, 503 .count = ${signer_id_cert_loc_count} 506 .offset = ${cert_sn_cert_loc_offset}, 507 .count = ${cert_sn_cert_loc_count} 509 { // STDCERT_AUTH_KEY_ID 510 .offset = ${auth_key_id_cert_loc_offset}, 511 .count = ${auth_key_id_cert_loc_count} 513 { // STDCERT_SUBJ_KEY_ID 514 .offset = ${subj_key_id_cert_loc_offset}, 515 .count = ${subj_key_id_cert_loc_count} 518 .cert_elements = g_cert_elements_1_signer, 519 .cert_elements_count = sizeof(g_cert_elements_1_signer) / sizeof(g_cert_elements_1_signer[0]), 520 .cert_template = g_cert_template_1_signer, 521 .cert_template_size = sizeof(g_cert_template_1_signer) 525 cert_def_2_device_c =
""" 527 * NOTE: This file was generated. 528 * Use the corresponding Python generation scripts to modify this file. 530 #include "atcacert/atcacert_def.h" 532 const uint8_t g_cert_template_2_device[] = { 536 const atcacert_def_t g_cert_def_2_device = { 537 .type = CERTTYPE_X509, 540 .private_key_slot = 0, 541 .sn_source = SNSRC_PUB_KEY_HASH, 543 .zone = DEVZONE_NONE, 549 .issue_date_format = ${issue_date_format}, 550 .expire_date_format = ${expire_date_format}, 552 .offset = ${tbs_cert_loc_offset}, 553 .count = ${tbs_cert_loc_count} 555 .expire_years = ${expire_years}, 556 .public_key_dev_loc = { 557 .zone = DEVZONE_DATA, 563 .comp_cert_dev_loc = { 564 .zone = DEVZONE_DATA, 570 .std_cert_elements = { 571 { // STDCERT_PUBLIC_KEY 572 .offset = ${public_key_cert_loc_offset}, 573 .count = ${public_key_cert_loc_count} 575 { // STDCERT_SIGNATURE 576 .offset = ${signature_cert_loc_offset}, 577 .count = ${signature_cert_loc_count} 579 { // STDCERT_ISSUE_DATE 580 .offset = ${issue_date_cert_loc_offset}, 581 .count = ${issue_date_cert_loc_count} 583 { // STDCERT_EXPIRE_DATE 584 .offset = ${expire_date_cert_loc_offset}, 585 .count = ${expire_date_cert_loc_count} 587 { // STDCERT_SIGNER_ID 588 .offset = ${signer_id_cert_loc_offset}, 589 .count = ${signer_id_cert_loc_count} 592 .offset = ${cert_sn_cert_loc_offset}, 593 .count = ${cert_sn_cert_loc_count} 595 { // STDCERT_AUTH_KEY_ID 596 .offset = ${auth_key_id_cert_loc_offset}, 597 .count = ${auth_key_id_cert_loc_count} 599 { // STDCERT_SUBJ_KEY_ID 600 .offset = ${subj_key_id_cert_loc_offset}, 601 .count = ${subj_key_id_cert_loc_count} 604 .cert_elements = NULL, 605 .cert_elements_count = 0, 606 .cert_template = g_cert_template_2_device, 607 .cert_template_size = sizeof(g_cert_template_2_device) 611 cert_def_3_device_csr_c =
""" 613 * NOTE: This file was generated. 614 * Use the corresponding Python generation scripts to modify this file. 616 #include "atcacert/atcacert_def.h" 618 const uint8_t g_csr_template_3_device[] = { 622 const atcacert_def_t g_csr_def_3_device = { 623 .type = CERTTYPE_X509, 626 .private_key_slot = 0, 627 .sn_source = SNSRC_PUB_KEY_HASH, 629 .zone = DEVZONE_NONE, 635 .issue_date_format = DATEFMT_RFC5280_UTC, 636 .expire_date_format = DATEFMT_RFC5280_UTC, 638 .offset = ${tbs_cert_loc_offset}, 639 .count = ${tbs_cert_loc_count} 642 .public_key_dev_loc = { 643 .zone = DEVZONE_NONE, 649 .comp_cert_dev_loc = { 650 .zone = DEVZONE_NONE, 656 .std_cert_elements = { 657 { // STDCERT_PUBLIC_KEY 658 .offset = ${public_key_cert_loc_offset}, 659 .count = ${public_key_cert_loc_count} 661 { // STDCERT_SIGNATURE 662 .offset = ${signature_cert_loc_offset}, 663 .count = ${signature_cert_loc_count} 665 { // STDCERT_ISSUE_DATE 669 { // STDCERT_EXPIRE_DATE 673 { // STDCERT_SIGNER_ID 681 { // STDCERT_AUTH_KEY_ID 685 { // STDCERT_SUBJ_KEY_ID 690 .cert_elements = NULL, 691 .cert_elements_count = 0, 692 .cert_template = g_csr_template_3_device, 693 .cert_template_size = sizeof(g_csr_template_3_device) 698 if __name__ ==
'__main__':