Skip to content

Instantly share code, notes, and snippets.

@pfried
Forked from bryan-hunt/README.md
Created June 13, 2019 05:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfried/456a274af9c74ac2b73bf7abc2070d5d to your computer and use it in GitHub Desktop.
Save pfried/456a274af9c74ac2b73bf7abc2070d5d to your computer and use it in GitHub Desktop.
Example Certificate Provisioning

Microchip Secure Element Tools

These tools are used to set up an example chain of trust ecosystem for use with Microchip ATECC508A and ATECC608A parts. Included are utilities to create the ecosystem keys and certificates.

Dependencies

Python scripts will require python 3 to be installed. Once python is installed install the requirements (from the path of this file):

> pip install -r requirements.txt

The application will have to built by loading the microchip_security_tool.sln project file and building either the x86 or x64 version of the application

Set up a Certificate Ecosystem

The first step is to set up a certificate chain that mirrors how a secure iot ecosystem would be configured. For this we'll create a dummy root certificate authority (normally this would be handled by a third party, or an internal PKI system) and an intermediate certificate authority that mirrors the signing hardware security modules (HSM) that are used in the Microchip facility during manufacturing of security devices.

Create the Root CA

> ca_create_root.py 

Create the Signing CA

> ca_create_signer.py <code_from_aws>

code_from_aws is the registration code required to verify the private key used for the signing certificate. This is obtained where you upload the signer into the AWS IOT cacertificatehub.

  1. In the AWS console navigate to AWS IOT -> Secure -> CAs
  2. Click the "Register" button and then the "Register CA" button
  3. Copy the registration code in "Step 2"
  4. Run ca_create_signer.py with the registration code
  5. Select the CA certificate (default is signer-ca.crt)
  6. Select the Verification certificate (default is verificationCert.crt)
  7. Select Activate CA certificate & Enable auto-registration
  8. Click the "Register CA certificate" button
  9. Make note of the certificate ARN hash for later (the first few digits)

The intermediate signing certificate is now active and allows for automatic registration of new devices when they are created (requires lambda functions). At this time we are not going to configure the lambda functions for automatic registration so we'll upload the devices certificate manually.

Create the Device Certificate

  1. Run the ca_create_device script:
> ca_create_device.py

This step mirrors the production provisioning process where Microchip uses HSMs to sign each device produced and loads the certificate information into them. This performs the certificate creation and signing process but does not load the certificates into the device (provisioning).

If lambda functions have been set up for Just In Time Registration this following step may be skipped, otherwise we have to load the device certificate into the aws certificatehub manually.

  1. In the AWS console navigate to AWS IOT -> Secure -> Certificates
  2. Click the "Create" button
  3. Select "Use my certificate" path by clicking the "Get started" button
  4. Select the CA that was created earlier (see the ARN hash we noted)
  5. Click "Register Certificates"
  6. Select the device certificate (default device.crt)
  7. Click "Register certificates"
  8. Find the newly create "inactive" certificate and select it
  9. Attach Policies and Things to the new certificate
  10. Activate the certificate

Finally provision the device

ca_write_certs.py

import os
import base64
import argparse
import pytz
import binascii
import ctypes
import datetime
import cryptography
from cryptoauthlib import *
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
def pubnums_to_bytes(pub_nums):
try:
pubkey = pub_nums.x.to_bytes(32, byteorder='big', signed=False)
pubkey += pub_nums.y.to_bytes(32, byteorder='big', signed=False)
except AttributeError:
pubkey = bytes(bytearray.fromhex(hex(pub_nums.x)[2:-1] + hex(pub_nums.y)[2:-1]))
return pubkey
def device_cert_sn(size, builder):
"""Cert serial number is the SHA256(Subject public key + Encoded dates)"""
# Get the public key as X and Y integers concatenated
pubkey = pubnums_to_bytes(builder._public_key.public_numbers())
# Get the encoded dates
expire_years = 0
enc_dates = bytearray(b'\x00'*3)
enc_dates[0] = (enc_dates[0] & 0x07) | ((((builder._not_valid_before.year - 2000) & 0x1F) << 3) & 0xFF)
enc_dates[0] = (enc_dates[0] & 0xF8) | ((((builder._not_valid_before.month) & 0x0F) >> 1) & 0xFF)
enc_dates[1] = (enc_dates[1] & 0x7F) | ((((builder._not_valid_before.month) & 0x0F) << 7) & 0xFF)
enc_dates[1] = (enc_dates[1] & 0x83) | (((builder._not_valid_before.day & 0x1F) << 2) & 0xFF)
enc_dates[1] = (enc_dates[1] & 0xFC) | (((builder._not_valid_before.hour & 0x1F) >> 3) & 0xFF)
enc_dates[2] = (enc_dates[2] & 0x1F) | (((builder._not_valid_before.hour & 0x1F) << 5) & 0xFF)
enc_dates[2] = (enc_dates[2] & 0xE0) | ((expire_years & 0x1F) & 0xFF)
enc_dates = bytes(enc_dates)
# SAH256 hash of the public key and encoded dates
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(pubkey)
digest.update(enc_dates)
raw_sn = bytearray(digest.finalize()[:size])
raw_sn[0] = raw_sn[0] & 0x7F # Force MSB bit to 0 to ensure positive integer
raw_sn[0] = raw_sn[0] | 0x40 # Force next bit to 1 to ensure the integer won't be trimmed in ASN.1 DER encoding
try:
return int.from_bytes(raw_sn, byteorder='big', signed=False)
except AttributeError:
return int(binascii.hexlify(raw_sn), 16)
def create_device_cert(signer_file, signer_key_file):
# Make sure files exist
if not (os.path.isfile(signer_file) and os.path.isfile(signer_key_file)):
raise FileNotFoundError('Failed to find {}, {}, or {}'.format(signer_file, signer_key_file))
assert atcab_init(cfg_ateccx08a_kithid_default()) == Status.ATCA_SUCCESS
# Load device public key
public_key = bytearray(64)
assert Status.ATCA_SUCCESS == atcab_get_pubkey(0, public_key)
# Convert to the key to PEM format
public_key_pem = bytearray.fromhex('3059301306072A8648CE3D020106082A8648CE3D03010703420004') + public_key
public_key_pem = '-----BEGIN PUBLIC KEY-----\n' + base64.b64encode(public_key_pem).decode('ascii') + '\n-----END PUBLIC KEY-----'
# Convert the key into the cryptography format
public_key = serialization.load_pem_public_key(public_key_pem.encode('ascii'), default_backend())
# Load the Signing key from the file
with open(signer_key_file, 'rb') as f:
signer_ca_priv_key = serialization.load_pem_private_key(data=f.read(), password=None, backend=default_backend())
signer_ca_pub_key = bytearray(signer_ca_priv_key.public_key().public_bytes(encoding=serialization.Encoding.X962,
format=serialization.PublicFormat.UncompressedPoint)[1:])
# Load the Signing Certificate from the file
with open(signer_file, 'rb') as f:
signer_ca_cert = x509.load_pem_x509_certificate(f.read(), default_backend())
# Build certificate
builder = x509.CertificateBuilder()
builder = builder.issuer_name(signer_ca_cert.subject)
# Device cert must have minutes and seconds set to 0
builder = builder.not_valid_before(datetime.datetime.now(tz=pytz.utc).replace(minute=0,second=0))
# Should be year 9999, but this doesn't work on windows
builder = builder.not_valid_after(datetime.datetime(3000, 12, 31, 23, 59, 59))
builder = builder.subject_name(x509.Name([
x509.NameAttribute(x509.oid.NameOID.ORGANIZATION_NAME, u'Example Inc'),
x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, u'Example Device')]))
builder = builder.public_key(public_key)
# Device certificate is generated from certificate dates and public key
builder = builder.serial_number(device_cert_sn(16, builder))
# Subject Key ID is used as the thing name and MQTT client ID and is required for this demo
builder = builder.add_extension(
x509.SubjectKeyIdentifier.from_public_key(public_key),
critical=False)
issuer_ski = signer_ca_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
builder = builder.add_extension(
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(issuer_ski),
critical=False)
# Sign certificate
device_cert = builder.sign(private_key=signer_ca_priv_key, algorithm=hashes.SHA256(), backend=default_backend())
with open('device.crt', 'wb') as f:
f.write(device_cert.public_bytes(encoding=serialization.Encoding.PEM))
print('Done');
if __name__ == '__main__':
# Create argument parser to document script use
parser = argparse.ArgumentParser(description='Provisions the kit by requesting a CSR and returning signed certificates.')
parser.add_argument('--cert', default='signer-ca.crt', help='Certificate file of the signer')
parser.add_argument('--key', default='signer-ca.key', help='Private Key file of the signer')
args = parser.parse_args()
assert atcab_init(cfg_ateccx08a_kithid_default()) == Status.ATCA_SUCCESS
create_device_cert(args.cert, args.key)
import os
import datetime
import pytz
import cryptography
import argparse
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
crypto_be = cryptography.hazmat.backends.default_backend()
def random_cert_sn(size):
"""Create a positive, non-trimmable serial number for X.509 certificates"""
raw_sn = bytearray(os.urandom(size))
raw_sn[0] = raw_sn[0] & 0x7F # Force MSB bit to 0 to ensure positive integer
raw_sn[0] = raw_sn[0] | 0x40 # Force next bit to 1 to ensure the integer won't be trimmed in ASN.1 DER encoding
return int.from_bytes(raw_sn, byteorder='big', signed=False)
def load_or_create_key(filename):
# Create or load a root CA key pair
priv_key = None
if os.path.isfile(filename):
# Load existing key
with open(filename, 'rb') as f:
priv_key = serialization.load_pem_private_key(
data=f.read(),
password=None,
backend=crypto_be)
if priv_key == None:
# No private key loaded, generate new one
priv_key = ec.generate_private_key(ec.SECP256R1(), crypto_be)
# Save private key to file
with open(filename, 'wb') as f:
pem_key = priv_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption())
f.write(pem_key)
return priv_key
def create_root_cert_key(certfile, keyfile, pubfile):
# Create or load a root CA key pair
print('\nLoading root CA key')
root_ca_priv_key = load_or_create_key(keyfile)
# Create root CA certificate
print('\nGenerating self-signed root CA certificate')
builder = x509.CertificateBuilder()
builder = builder.serial_number(random_cert_sn(16))
# Please note that the name of the root CA is also part of the signer certificate and thus, it's
# part of certificate definition in the firmware (g_cert_elements_1_signer). If this name is
# changed, it will also need to be changed in the firmware.
builder = builder.issuer_name(x509.Name([
x509.NameAttribute(x509.oid.NameOID.ORGANIZATION_NAME, u'Example Inc'),
x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, u'Example Root CA')]))
builder = builder.not_valid_before(datetime.datetime.now(tz=pytz.utc))
builder = builder.not_valid_after(builder._not_valid_before.replace(year=builder._not_valid_before.year + 25))
builder = builder.subject_name(builder._issuer_name)
builder = builder.public_key(root_ca_priv_key.public_key())
builder = builder.add_extension(
x509.SubjectKeyIdentifier.from_public_key(root_ca_priv_key.public_key()),
critical=False)
builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=None),
critical=True)
# Self-sign certificate
root_ca_cert = builder.sign(
private_key=root_ca_priv_key,
algorithm=hashes.SHA256(),
backend=crypto_be)
# Write root CA certificate to file
with open(certfile, 'wb') as f:
print(' Saving to ' + f.name)
f.write(root_ca_cert.public_bytes(encoding=serialization.Encoding.PEM))
# Save root public key
with open(pubfile, 'wb') as f:
f.write(root_ca_cert.public_key().public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo))
print('\nDone')
if __name__ == '__main__':
# Create argument parser to document script use
parser = argparse.ArgumentParser(description='Create a root certificate and key')
parser.add_argument('--out', default='root-ca.crt', help='Device Certificate (PEM)')
parser.add_argument('--key', default='root-ca.key', help='Root public key (PEM)')
parser.add_argument('--pubkey', default='root-pub.pem', help='Root public key (PEM)')
args = parser.parse_args()
create_root_cert_key(args.out, args.key, args.pubkey)
import os
import pytz
import argparse
import datetime
import cryptography
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
crypto_be = cryptography.hazmat.backends.default_backend()
def random_cert_sn(size):
"""Create a positive, non-trimmable serial number for X.509 certificates"""
raw_sn = bytearray(os.urandom(size))
raw_sn[0] = raw_sn[0] & 0x7F # Force MSB bit to 0 to ensure positive integer
raw_sn[0] = raw_sn[0] | 0x40 # Force next bit to 1 to ensure the integer won't be trimmed in ASN.1 DER encoding
return int.from_bytes(raw_sn, byteorder='big', signed=False)
def load_or_create_key(filename):
# Create or load a root CA key pair
priv_key = None
if os.path.isfile(filename):
# Load existing key
with open(filename, 'rb') as f:
priv_key = serialization.load_pem_private_key(
data=f.read(),
password=None,
backend=crypto_be)
if priv_key == None:
# No private key loaded, generate new one
priv_key = ec.generate_private_key(ec.SECP256R1(), crypto_be)
# Save private key to file
with open(filename, 'wb') as f:
pem_key = priv_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption())
f.write(pem_key)
return priv_key
def create_intermediate_cert(reg_code, verifyfile, certfile, keyfile, rootfile, rootkeyfile):
print('\nLoading signer CA key')
signer_ca_priv_key = load_or_create_key(keyfile)
print('\nLoading root CA key')
if not os.path.isfile(rootkeyfile):
raise Exception('Failed to find root CA key file, ' + rootkeyfile + '. Have you run ca_create_root first?')
with open(rootkeyfile, 'rb') as f:
print(' Loading from ' + f.name)
root_ca_priv_key = serialization.load_pem_private_key(
data=f.read(),
password=None,
backend=crypto_be)
print('\nLoading Root CA certificate')
if not os.path.isfile(rootfile):
raise Exception('Failed to find root CA certificate file, ' + rootfile + '. Have you run ca_create_root first?')
with open(rootfile, 'rb') as f:
print(' Loading from ' + f.name)
root_ca_cert = x509.load_pem_x509_certificate(f.read(), crypto_be)
# Create signer CA certificate
print('\nGenerating Signer/Intermediate Certificate')
# Please note that the structure of the signer certificate is part of certificate definition in the firmware
# If any part of it is changed, it will also need to be changed in the firmware.
builder = x509.CertificateBuilder()
builder = builder.serial_number(random_cert_sn(16))
builder = builder.subject_name(x509.Name([
x509.NameAttribute(x509.oid.NameOID.ORGANIZATION_NAME, u'Example Inc'),
x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, u'Example Signer FFFF')]))
builder = builder.issuer_name(root_ca_cert.subject)
builder = builder.not_valid_before(datetime.datetime.now(tz=pytz.utc))
builder = builder.not_valid_after(builder._not_valid_before.replace(year=builder._not_valid_before.year + 10))
builder = builder.public_key(signer_ca_priv_key.public_key())
builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=0),
critical=True)
builder = builder.add_extension(
x509.KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False),
critical=True)
builder = builder.add_extension(
x509.SubjectKeyIdentifier.from_public_key(signer_ca_priv_key.public_key()),
critical=False)
issuer_ski = root_ca_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier)
builder = builder.add_extension(
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(issuer_ski),
critical=False)
# Sign signer certificate with root
signer_ca_cert = builder.sign(
private_key=root_ca_priv_key,
algorithm=hashes.SHA256(),
backend=crypto_be)
# Write signer CA certificate to file
with open(certfile, 'wb') as f:
print(' Saving to ' + f.name)
f.write(signer_ca_cert.public_bytes(encoding=serialization.Encoding.PEM))
# Generate a verification certificate around the registration code (subject common name)
print('\nGenerating signer CA AWS verification certificate')
builder = x509.CertificateBuilder()
builder = builder.serial_number(random_cert_sn(16))
builder = builder.issuer_name(signer_ca_cert.subject)
builder = builder.not_valid_before(datetime.datetime.now(tz=pytz.utc))
builder = builder.not_valid_after(builder._not_valid_before.replace(day=builder._not_valid_before.day + 1))
builder = builder.subject_name(x509.Name([x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, reg_code)]))
builder = builder.public_key(signer_ca_cert.public_key())
signer_ca_ver_cert = builder.sign(
private_key=signer_ca_priv_key,
algorithm=hashes.SHA256(),
backend=crypto_be)
# Write signer CA certificate to file for reference
with open(verifyfile, 'wb') as f:
print(' Saved to ' + f.name)
f.write(signer_ca_ver_cert.public_bytes(encoding=serialization.Encoding.PEM))
print('\nDone')
if __name__ == '__main__':
# Create argument parser to document script use
parser = argparse.ArgumentParser(description='Create a Signer/Intermediate Certificate')
parser.add_argument('code', help='AWS Verification Code')
parser.add_argument('--vcert', default='verificationCert.crt', help='AWS Verification Certificate')
parser.add_argument('--cert', default='signer-ca.crt', help='Certificate file of the signer')
parser.add_argument('--key', default='signer-ca.key', help='Private Key file of the signer')
parser.add_argument('--root', default='root-ca.crt', help='Root Certificate')
parser.add_argument('--rootkey', default='root-ca.key', help='Root Key')
args = parser.parse_args()
create_intermediate_cert(args.code, args.vcert, args.cert, args.key, args.root, args.rootkey)
import os
import base64
import argparse
import pytz
import binascii
import ctypes
import datetime
import cryptography
from cryptoauthlib import *
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
ROOT_PUBKEY_SLOT = 15
ATCACERT_DEF_SIGNER_CONFIG_ELEMENTS = (atcacert_cert_element_t*2)(
atcacert_cert_element_t(
# id='IssueDate',
device_loc = atcacert_device_loc_t(**{
'zone': atcacert_device_zone_t.DEVZONE_DATA,
'slot': 14,
'is_genkey': 0,
'offset': 35-13,
'count': 13}),
cert_loc= atcacert_cert_loc_t(offset=97, count=13)
),
atcacert_cert_element_t(
# id='ExpireDate',
device_loc = atcacert_device_loc_t(**{
'zone': atcacert_device_zone_t.DEVZONE_DATA,
'slot': 14,
'is_genkey': 0,
'offset': 50-13,
'count': 13}),
cert_loc = atcacert_cert_loc_t(offset=112, count=13)
)
)
ATCACERT_DEF_SIGNER_CONFIG = {
'type': atcacert_cert_type_t.CERTTYPE_X509,
'template_id': 1,
'chain_id': 0,
'private_key_slot': 0,
'sn_source': atcacert_cert_sn_src_t.SNSRC_STORED,
'cert_sn_dev_loc': {
'zone': atcacert_device_zone_t.DEVZONE_DATA,
'slot': 14,
'is_genkey': 0,
'offset': 20-16,
'count': 16
},
'issue_date_format': atcacert_date_format_t.DATEFMT_RFC5280_UTC,
'expire_date_format': atcacert_date_format_t.DATEFMT_RFC5280_GEN,
'tbs_cert_loc': {'offset': 4, 'count': 370},
'expire_years': 10,
'public_key_dev_loc': {
'zone': atcacert_device_zone_t.DEVZONE_DATA,
'slot': 11,
'is_genkey': 0,
'offset': 0,
'count': 72
},
'comp_cert_dev_loc': {
'zone': atcacert_device_zone_t.DEVZONE_DATA,
'slot': 12,
'is_genkey': 0,
'offset': 0,
'count': 72
},
'std_cert_elements' : [
{'offset': 206, 'count': 64},
{'offset': 386, 'count': 74},
{'offset': 97, 'count': 13},
{'offset': 112, 'count': 13},
{'offset': 175, 'count': 4},
{'offset': 15, 'count': 16},
{'offset': 354, 'count': 20},
{'offset': 321, 'count': 20},
],
'cert_elements': ctypes.cast(ATCACERT_DEF_SIGNER_CONFIG_ELEMENTS, ctypes.POINTER(atcacert_cert_element_t)),
'cert_elements_count': 2
}
ATCACERT_DEF_DEVICE_CONFIG = {
'type': atcacert_cert_type_t.CERTTYPE_X509,
'template_id': 2,
'chain_id': 0,
'private_key_slot': 0,
'sn_source': atcacert_cert_sn_src_t.SNSRC_PUB_KEY_HASH,
'cert_sn_dev_loc': {
'zone': atcacert_device_zone_t.DEVZONE_NONE,
'slot': 0,
'is_genkey': 0,
'offset': 0,
'count': 0
},
'issue_date_format': atcacert_date_format_t.DATEFMT_RFC5280_UTC,
'expire_date_format': atcacert_date_format_t.DATEFMT_RFC5280_GEN,
'tbs_cert_loc': {'offset': 4, 'count': 335},
'expire_years': 0,
'public_key_dev_loc': {
'zone': atcacert_device_zone_t.DEVZONE_DATA,
'slot': 0,
'is_genkey': 1,
'offset': 0,
'count': 64
},
'comp_cert_dev_loc': {
'zone': atcacert_device_zone_t.DEVZONE_DATA,
'slot': 10,
'is_genkey': 0,
'offset': 0,
'count': 72
},
'std_cert_elements' : [
{'offset': 207, 'count': 64},
{'offset': 351, 'count': 75},
{'offset': 101, 'count': 13},
{'offset': 0, 'count': 0},
{'offset': 93, 'count': 4},
{'offset': 15, 'count': 16},
{'offset': 319, 'count': 20},
{'offset': 286, 'count': 20},
]
}
def write_root(root_file):
# Load the Signing Certificate from the file
with open(root_file, 'rb') as f:
cert = x509.load_pem_x509_certificate(f.read(), default_backend())
root_pubkey = bytearray(cert.public_key().public_bytes(encoding=serialization.Encoding.X962,
format=serialization.PublicFormat.UncompressedPoint)[1:])
assert Status.ATCA_SUCCESS == atcab_write_pubkey(ROOT_PUBKEY_SLOT, root_pubkey)
def write_signer(signer_file):
# Load the Signing Certificate from the file
with open(signer_file, 'rb') as f:
cert = x509.load_pem_x509_certificate(f.read(), default_backend())
cert_def = atcacert_def_t(**ATCACERT_DEF_SIGNER_CONFIG)
cert = cert.public_bytes(encoding=serialization.Encoding.DER)
assert Status.ATCA_SUCCESS == atcacert_write_cert(cert_def, cert, len(cert))
def write_device(device_file):
# Load the Signing Certificate from the file
with open(device_file, 'rb') as f:
cert = x509.load_pem_x509_certificate(f.read(), default_backend())
cert_def = atcacert_def_t(**ATCACERT_DEF_DEVICE_CONFIG)
cert = cert.public_bytes(encoding=serialization.Encoding.DER)
# Write the device certificate
assert Status.ATCA_SUCCESS == atcacert_write_cert(cert_def, cert, len(cert))
if __name__ == '__main__':
# Create argument parser to document script use
parser = argparse.ArgumentParser(description='Programs a certificate chain into a device using the provided definitions')
parser.add_argument('--cert', default='device.crt', help='Certificate file of the device (PEM)')
parser.add_argument('--signer', default='signer-ca.crt', help='Certificate file of the signer (PEM)')
parser.add_argument('--root', default='root-ca.crt', help='Device Certificate (PEM)')
args = parser.parse_args()
assert atcab_init(cfg_ateccx08a_kithid_default()) == Status.ATCA_SUCCESS
write_root(args.root)
write_signer(args.signer)
write_device(args.cert)
#include "atcacert/atcacert_def.h"
#include "atca_cert_chain.h"
const atcacert_def_t g_cert_def_0_root = {
.type = CERTTYPE_X509,
.template_id = 0,
.public_key_dev_loc = {
.zone = DEVZONE_DATA,
.slot = 15,
.is_genkey = 0,
.offset = 0,
.count = 72
}
};
const atcacert_cert_element_t g_cert_elements_1_signer[] = {
{
.id = "IssueDate",
.device_loc = {
.zone = DEVZONE_DATA,
.slot = 14,
.is_genkey = 0,
.offset = 35-13,
.count = 13
},
.cert_loc = {
.offset = 97,
.count = 13
}
},
{
.id = "ExpireDate",
.device_loc = {
.zone = DEVZONE_DATA,
.slot = 14,
.is_genkey = 0,
.offset = 50-13,
.count = 13
},
.cert_loc = {
.offset = 112,
.count = 13
}
}
};
const uint8_t g_cert_template_1_signer[] = {
0x30, 0x82, 0x01, 0xc8, 0x30, 0x82, 0x01, 0x6e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x57,
0x06, 0x2e, 0xf0, 0x05, 0xea, 0x8a, 0x70, 0x44, 0xff, 0x1b, 0x90, 0x00, 0x21, 0x78, 0xd6, 0x30,
0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x30, 0x31, 0x14, 0x30,
0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20,
0x49, 0x6e, 0x63, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x45, 0x78,
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17,
0x0d, 0x31, 0x37, 0x30, 0x36, 0x30, 0x37, 0x31, 0x37, 0x35, 0x36, 0x31, 0x32, 0x5a, 0x17, 0x0d,
0x32, 0x37, 0x30, 0x36, 0x30, 0x37, 0x31, 0x37, 0x35, 0x36, 0x31, 0x32, 0x5a, 0x30, 0x34, 0x31,
0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c,
0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13,
0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x20, 0x46,
0x46, 0x46, 0x46, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xb1, 0xf5,
0x9c, 0xbe, 0x22, 0x11, 0x7f, 0x28, 0x2f, 0x7f, 0x2e, 0xcb, 0xa2, 0x8c, 0x30, 0x3b, 0xae, 0x59,
0x45, 0xb9, 0x5c, 0x0e, 0xba, 0xaa, 0x9b, 0x81, 0x73, 0x52, 0x63, 0x41, 0xbf, 0x37, 0x3c, 0x2e,
0xdd, 0xcd, 0xea, 0x0e, 0x7c, 0x9d, 0x90, 0xea, 0x25, 0x9c, 0x64, 0xeb, 0xc6, 0x54, 0x47, 0x32,
0x81, 0x63, 0xbf, 0x42, 0x5f, 0xdd, 0x5a, 0x3f, 0xd5, 0x71, 0x81, 0x9b, 0x77, 0x44, 0xa3, 0x66,
0x30, 0x64, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06,
0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
0x14, 0x81, 0x1d, 0xc6, 0x7c, 0x0f, 0x18, 0x2b, 0x65, 0x96, 0xeb, 0x22, 0x73, 0xdb, 0xf3, 0x23,
0x63, 0x6d, 0x79, 0x0f, 0xc8, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
0x80, 0x14, 0xdb, 0x2a, 0x0d, 0x06, 0x05, 0xc7, 0x98, 0xbc, 0xda, 0xc0, 0x34, 0x67, 0x66, 0xf4,
0xe2, 0xb0, 0x61, 0xa3, 0xd2, 0xc8, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x49, 0xfe, 0xdf, 0xc9, 0x94, 0xe3, 0x07,
0xdb, 0x08, 0xb3, 0x99, 0x9e, 0x04, 0xe4, 0x78, 0xe5, 0xf8, 0xb9, 0x09, 0xa9, 0xf0, 0x41, 0x66,
0xc6, 0x69, 0x1b, 0x87, 0x30, 0x86, 0x10, 0xaf, 0x64, 0x02, 0x21, 0x00, 0xc8, 0xd6, 0x86, 0x61,
0x94, 0x95, 0xdb, 0x45, 0xb3, 0x40, 0x8e, 0xac, 0x14, 0x9a, 0x19, 0xb6, 0x8c, 0x5c, 0x79, 0x9d,
0x06, 0xcb, 0x52, 0x08, 0xa0, 0x1f, 0x49, 0x8b, 0x22, 0x4e, 0x52, 0x71
};
const atcacert_def_t g_cert_def_1_signer = {
.type = CERTTYPE_X509,
.template_id = 1,
.chain_id = 0,
.private_key_slot = 0,
.sn_source = SNSRC_STORED,
.cert_sn_dev_loc = {
.zone = DEVZONE_DATA,
.slot = 14,
.is_genkey = 0,
.offset = 20-16,
.count = 16
},
.issue_date_format = DATEFMT_RFC5280_UTC,
.expire_date_format = DATEFMT_RFC5280_UTC,
.tbs_cert_loc = {
.offset = 4,
.count = 370
},
.expire_years = 10,
.public_key_dev_loc = {
.zone = DEVZONE_DATA,
.slot = 11,
.is_genkey = 0,
.offset = 0,
.count = 72
},
.comp_cert_dev_loc = {
.zone = DEVZONE_DATA,
.slot = 12,
.is_genkey = 0,
.offset = 0,
.count = 72
},
.std_cert_elements = {
{ // STDCERT_PUBLIC_KEY
.offset = 206,
.count = 64
},
{ // STDCERT_SIGNATURE
.offset = 386,
.count = 74
},
{ // STDCERT_ISSUE_DATE
.offset = 97,
.count = 13
},
{ // STDCERT_EXPIRE_DATE
.offset = 112,
.count = 13
},
{ // STDCERT_SIGNER_ID
.offset = 175,
.count = 4
},
{ // STDCERT_CERT_SN
.offset = 15,
.count = 16
},
{ // STDCERT_AUTH_KEY_ID
.offset = 354,
.count = 20
},
{ // STDCERT_SUBJ_KEY_ID
.offset = 321,
.count = 20
}
},
.cert_elements = g_cert_elements_1_signer,
.cert_elements_count = sizeof(g_cert_elements_1_signer) / sizeof(g_cert_elements_1_signer[0]),
.cert_template = g_cert_template_1_signer,
.cert_template_size = sizeof(g_cert_template_1_signer),
.ca_cert_def = &g_cert_def_0_root,
};
const uint8_t g_cert_template_2_device[] = {
0x30, 0x82, 0x01, 0xa6, 0x30, 0x82, 0x01, 0x4b, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x41,
0xa6, 0x8b, 0xe4, 0x36, 0xdd, 0xc3, 0xd8, 0x39, 0xfa, 0xbd, 0xd7, 0x27, 0xd9, 0x74, 0xe7, 0x30,
0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x34, 0x31, 0x14, 0x30,
0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20,
0x49, 0x6e, 0x63, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x45, 0x78,
0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x20, 0x46, 0x46, 0x46,
0x46, 0x30, 0x20, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x37, 0x31, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30,
0x30, 0x5a, 0x18, 0x0f, 0x33, 0x30, 0x30, 0x30, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39,
0x35, 0x39, 0x5a, 0x30, 0x2f, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b,
0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x17, 0x30, 0x15, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x0e, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x96,
0x27, 0xf1, 0x3e, 0x80, 0xac, 0xf9, 0xd4, 0x12, 0xce, 0x3b, 0x0d, 0x68, 0xf7, 0x4e, 0xb2, 0xc6,
0x07, 0x35, 0x00, 0xb7, 0x78, 0x5b, 0xac, 0xe6, 0x50, 0x30, 0x54, 0x77, 0x7f, 0xc8, 0x62, 0x21,
0xce, 0xf2, 0x5a, 0x9a, 0x9e, 0x86, 0x40, 0xc2, 0x29, 0xd6, 0x4a, 0x32, 0x1e, 0xb9, 0x4a, 0x1b,
0x1c, 0x94, 0xf5, 0x39, 0x88, 0xae, 0xfe, 0x49, 0xcc, 0xfd, 0xbf, 0x8a, 0x0d, 0x34, 0xb8, 0xa3,
0x42, 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x2d, 0xda,
0x6c, 0x36, 0xd5, 0xa5, 0x5a, 0xce, 0x97, 0x10, 0x3d, 0xbb, 0xaf, 0x9c, 0x66, 0x2a, 0xcd, 0x3e,
0xe6, 0xcf, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xc6,
0x70, 0xe0, 0x5e, 0x8a, 0x45, 0x0d, 0xb8, 0x2c, 0x00, 0x2a, 0x40, 0x06, 0x39, 0x4c, 0x19, 0x58,
0x04, 0x35, 0x76, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03,
0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0xe1, 0xfc, 0x00, 0x23, 0xc1, 0x3d, 0x01, 0x3f, 0x22,
0x31, 0x0b, 0xf0, 0xb8, 0xf4, 0xf4, 0x22, 0xfc, 0x95, 0x96, 0x33, 0x9c, 0xb9, 0x62, 0xb1, 0xfc,
0x8a, 0x2d, 0xa8, 0x5c, 0xee, 0x67, 0x72, 0x02, 0x21, 0x00, 0xa1, 0x0d, 0x47, 0xe4, 0xfd, 0x0d,
0x15, 0xd8, 0xde, 0xa1, 0xb5, 0x96, 0x28, 0x4e, 0x7a, 0x0b, 0xbe, 0xcc, 0xec, 0xe8, 0x8e, 0xcc,
0x7a, 0x31, 0xb3, 0x00, 0x8b, 0xc0, 0x2e, 0x4f, 0x99, 0xc5
};
const atcacert_def_t g_cert_def_2_device = {
.type = CERTTYPE_X509,
.template_id = 2,
.chain_id = 0,
.private_key_slot = 0,
.sn_source = SNSRC_PUB_KEY_HASH,
.cert_sn_dev_loc = {
.zone = DEVZONE_NONE,
.slot = 0,
.is_genkey = 0,
.offset = 0,
.count = 0
},
.issue_date_format = DATEFMT_RFC5280_UTC,
.expire_date_format = DATEFMT_RFC5280_GEN,
.tbs_cert_loc = {
.offset = 4,
.count = 335
},
.expire_years = 0,
.public_key_dev_loc = {
.zone = DEVZONE_DATA,
.slot = 0,
.is_genkey = 1,
.offset = 0,
.count = 64
},
.comp_cert_dev_loc = {
.zone = DEVZONE_DATA,
.slot = 10,
.is_genkey = 0,
.offset = 0,
.count = 72
},
.std_cert_elements = {
{ // STDCERT_PUBLIC_KEY
.offset = 207,
.count = 64
},
{ // STDCERT_SIGNATURE
.offset = 351,
.count = 75
},
{ // STDCERT_ISSUE_DATE
.offset = 101,
.count = 13
},
{ // STDCERT_EXPIRE_DATE
.offset = 0,
.count = 0
},
{ // STDCERT_SIGNER_ID
.offset = 93,
.count = 4
},
{ // STDCERT_CERT_SN
.offset = 15,
.count = 16
},
{ // STDCERT_AUTH_KEY_ID
.offset = 319,
.count = 20
},
{ // STDCERT_SUBJ_KEY_ID
.offset = 286,
.count = 20
}
},
.cert_elements = NULL,
.cert_elements_count = 0,
.cert_template = g_cert_template_2_device,
.cert_template_size = sizeof(g_cert_template_2_device),
.ca_cert_def = &g_cert_def_1_signer,
};
cryptoauthlib >= 20190304
cryptography >= 2.5
pytz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment