Merge pull request #21 from fdistorted/issue-20

chore: add ec certificate support to pycert_bearssl
This commit is contained in:
Noah Koontz 2020-10-16 13:58:32 -07:00 committed by GitHub
commit a7bcbfba2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 21 deletions

View file

@ -32,6 +32,10 @@ DN_PRE = "TA_DN"
RSA_N_PRE = "TA_RSA_N" RSA_N_PRE = "TA_RSA_N"
# RSA public key exponent prefix # RSA public key exponent prefix
RSA_E_PRE = "TA_RSA_E" RSA_E_PRE = "TA_RSA_E"
# EC public key number prefix
EC_CURVE_PRE = "TA_EC_CURVE"
# EC curve type enum prefix
EC_CURVE_NAME_PRE = "BR_EC_"
# Template that defines the C header output format. # Template that defines the C header output format.
@ -81,7 +85,7 @@ static const {ray_type} {ray_name}[] = {{
{ray_data} {ray_data}
}};""" }};"""
# Template that defines a single root certificate entry in the BearSSL trust # Template that defines a single root RSA certificate entry in the BearSSL trust
# anchor list # anchor list
# This takes in a few named parameters: # This takes in a few named parameters:
# - ta_dn_name: The name of the static byte array containing the distunguished # - ta_dn_name: The name of the static byte array containing the distunguished
@ -101,6 +105,25 @@ CROOTCA_TEMPLATE = """\
}} }}
}},""" }},"""
# Template that defines a single root EC certificate entry in the BearSSL trust
# anchor list
# This takes in a few named parameters:
# - ta_dn_name: The name of the static byte array containing the distunguished
# name of the certificate.
# - ec_number_name: Varible name of the static array containing ec public key
# - ec_curve_name: Varible name of the enum that describes curve type
CROOTCA_EC_TEMPLATE = """\
{{
{{ (unsigned char *){ta_dn_name}, sizeof {ta_dn_name} }},
BR_X509_TA_CA,
{{
BR_KEYTYPE_EC,
{{ .ec = {{{ec_curve_name}, (unsigned char *){ec_number_name}, sizeof {ec_number_name}}}
}}
}}
}},"""
# Template that defines a description of the certificate, so that the header # Template that defines a description of the certificate, so that the header
# file can be slightly more human readable # file can be slightly more human readable
# This takes in a few named parameters: # This takes in a few named parameters:
@ -267,23 +290,43 @@ def x509_to_header(x509Certs, cert_var, cert_length_var, output_file, keep_dupes
# next, the RSA public numbers # next, the RSA public numbers
pubkey = cert.get_pubkey() pubkey = cert.get_pubkey()
numbers = pubkey.to_cryptography_key().public_numbers() numbers = pubkey.to_cryptography_key().public_numbers()
# starting with the modulous numbers_typename = type(numbers).__name__
n_bytes_str = bytes_to_c_data(numbers.n.to_bytes(pubkey.bits() // 8, byteorder="big")) if 'RSA' in numbers_typename:
static_arrays.append(CRAY_TEMPLATE.format( # starting with the modulous
ray_type="unsigned char", n_bytes_str = bytes_to_c_data(numbers.n.to_bytes(pubkey.bits() // 8, byteorder="big"))
ray_name=RSA_N_PRE + str(cert_index), static_arrays.append(CRAY_TEMPLATE.format(
ray_data=n_bytes_str)) ray_type="unsigned char",
# and then the exponent ray_name=RSA_N_PRE + str(cert_index),
e_bytes_str = bytes_to_c_data(numbers.e.to_bytes(math.ceil(numbers.e.bit_length() / 8), byteorder="big")) ray_data=n_bytes_str))
static_arrays.append(CRAY_TEMPLATE.format( # and then the exponent
ray_type="unsigned char", e_bytes_str = bytes_to_c_data(numbers.e.to_bytes(math.ceil(numbers.e.bit_length() / 8), byteorder="big"))
ray_name=RSA_E_PRE + str(cert_index), static_arrays.append(CRAY_TEMPLATE.format(
ray_data=e_bytes_str)) ray_type="unsigned char",
# format the root certificate entry ray_name=RSA_E_PRE + str(cert_index),
CAs.append(CROOTCA_TEMPLATE.format( ray_data=e_bytes_str))
ta_dn_name=DN_PRE + str(cert_index), # format the root certificate entry
rsa_number_name=RSA_N_PRE + str(cert_index), CAs.append(CROOTCA_TEMPLATE.format(
rsa_exp_name=RSA_E_PRE + str(cert_index))) ta_dn_name=DN_PRE + str(cert_index),
rsa_number_name=RSA_N_PRE + str(cert_index),
rsa_exp_name=RSA_E_PRE + str(cert_index)))
elif 'Elliptic' in numbers_typename:
# starting with the modulous
curve_bytes = b'\x04' + numbers.x.to_bytes(pubkey.bits() // 8, byteorder="big") + numbers.y.to_bytes(
pubkey.bits() // 8, byteorder="big")
curve_str = bytes_to_c_data(curve_bytes)
curve_name = numbers.curve.name
static_arrays.append(CRAY_TEMPLATE.format(
ray_type="unsigned char",
ray_name=EC_CURVE_PRE + str(cert_index),
ray_data=curve_str))
# and then the exponent
CAs.append(CROOTCA_EC_TEMPLATE.format(
ta_dn_name=DN_PRE + str(cert_index),
ec_number_name=EC_CURVE_PRE + str(cert_index),
ec_curve_name=EC_CURVE_NAME_PRE + curve_name
))
else:
raise Exception(f'Unknown public key type {numbers_typename}')
# concatonate it all into the big header file template # concatonate it all into the big header file template
# cert descriptions # cert descriptions
cert_desc_out = '\n * \n'.join(cert_desc) cert_desc_out = '\n * \n'.join(cert_desc)

View file

@ -86,7 +86,11 @@ def download(port, cert_var, cert_length_var, output, use_store, keep_dupes, dom
# append cert to array # append cert to array
down_certs.append(cert) down_certs.append(cert)
# Combine PEMs and write output header. # Combine PEMs and write output header.
cert_util.x509_to_header(down_certs, cert_var, cert_length_var, output, keep_dupes, domains=domain) try:
cert_util.x509_to_header(down_certs, cert_var, cert_length_var, output, keep_dupes, domains=domain)
except Exception as E:
click.echo(f'Recieved error when converting certificate to header: {E}')
exit(1)
@pycert_bearssl.command(short_help='Convert PEM certs into a C header.') @pycert_bearssl.command(short_help='Convert PEM certs into a C header.')
@ -144,8 +148,11 @@ def convert(cert_var, cert_length_var, output, use_store, keep_dupes, no_search,
else: else:
root_certs.append(cert_dict[cn_hash]) root_certs.append(cert_dict[cn_hash])
# Combine PEMs and write output header. # Combine PEMs and write output header.
cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes) try:
cert_util.x509_to_header(root_certs, cert_var, cert_length_var, output, keep_dupes)
except Exception as E:
click.echo(f'Recieved error when converting certificate to header: {E}')
exit(1)
if __name__ == '__main__': if __name__ == '__main__':
pycert_bearssl() pycert_bearssl()