""" Basic Configuration Common Use Cases """ # (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. # # Subject to your compliance with these terms, you may use Microchip software # and any derivatives exclusively with Microchip products. It is your # responsibility to comply with third party license terms applicable to your # use of third party software (including open source software) that may # accompany Microchip software. # # THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER # EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED # WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A # PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, # SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE # OF ANY KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF # MICROCHIP HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE # FORESEEABLE. TO THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL # LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED # THE AMOUNT OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR # THIS SOFTWARE. from cryptoauthlib import * from cryptoauthlib.device import * from common import * import time import ctypes import base64 # Example configuration for ATECC608A minus the first 16 bytes which are fixed by the factory _atecc608_config = bytearray.fromhex( '6C 00 00 01 85 66 82 00 85 20 85 20 85 20 C6 46' '8F 0F 9F 8F 0F 0F 8F 0F 0F 0F 0F 0F 0F 0F 0F 0F' '0D 1F 0F 0F FF FF FF FF 00 00 00 00 FF FF FF FF' '00 00 00 00 00 00 03 F7 00 69 76 00 00 00 00 00' '00 00 00 00 00 00 55 55 FF FF 0E 60 00 00 00 00' '53 00 53 00 73 00 73 00 73 00 38 00 7C 00 1C 00' '3C 00 1A 00 3C 00 30 00 3C 00 30 00 12 00 30 00') _configs = {'ATECC608A': _atecc608_config } # Default IO Encryption key IO_ENC_KEY = bytearray([ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, ]) IO_ENC_KEY_SLOT = 6 # Safe input if using python 2 try: input = raw_input except NameError: pass def configure_device(iface='hid', device='ecc', i2c_addr=None, keygen=True, **kwargs): ATCA_SUCCESS = 0x00 # Loading cryptoauthlib(python specific) load_cryptoauthlib() # Get the target default config cfg = eval('cfg_at{}a_{}_default()'.format(atca_names_map.get(device), atca_names_map.get(iface))) # Set interface parameters if kwargs is not None: for k, v in kwargs.items(): icfg = getattr(cfg.cfg, 'atca{}'.format(iface)) setattr(icfg, k, int(v, 16)) # Basic Raspberry Pi I2C check if 'i2c' == iface and check_if_rpi(): cfg.cfg.atcai2c.bus = 1 # Initialize the stack assert atcab_init(cfg) == ATCA_SUCCESS print('') # Check device type info = bytearray(4) assert atcab_info(info) == ATCA_SUCCESS dev_name = get_device_name(info) dev_type = get_device_type_id(dev_name) # Reinitialize if the device type doesn't match the default if dev_type != cfg.devtype: cfg.dev_type = dev_type assert atcab_release() == ATCA_SUCCESS time.sleep(1) assert atcab_init(cfg) == ATCA_SUCCESS # Request the Serial Number serial_number = bytearray(9) assert atcab_read_serial_number(serial_number) == ATCA_SUCCESS print('\nSerial number: ') print(pretty_print_hex(serial_number, indent=' ')) # Check the zone locks print('\nReading the Lock Status') is_locked = AtcaReference(False) assert ATCA_SUCCESS == atcab_is_locked(0, is_locked) config_zone_lock = bool(is_locked.value) assert ATCA_SUCCESS == atcab_is_locked(1, is_locked) data_zone_lock = bool(is_locked.value) print(' Config Zone: {}'.format('Locked' if config_zone_lock else 'Unlocked')) print(' Data Zone: {}'.format('Locked' if data_zone_lock else 'Unlocked')) # Get Current I2C Address print('\nGetting the I2C Address') response = bytearray(4) assert ATCA_SUCCESS == atcab_read_bytes_zone(0, 0, 16, response, 4) print(' Current Address: {:02X}'.format(response[0])) # Program the configuration zone print('\nProgram Configuration') if not config_zone_lock: config = _configs.get(dev_name) if config is None: raise ValueError('Unknown Device Type: {}'.format(dev_type)) # Update with the target I2C Address if i2c_addr is not None: config[0] = i2c_addr print('\n New Address: {:02X}'.format(config[0])) ck590_i2c_addr = 0xC0 if dev_name != 'ATSHA204A' else 0xC8 if config[0] != ck590_i2c_addr: print(' The AT88CK590 Kit does not support changing the I2C addresses of devices.') print(' If you are not using an AT88CK590 kit you may continue without errors') print(' otherwise exit and specify a compatible (0x{:02X}) address.'.format(ck590_i2c_addr)) if 'Y' != input(' Continue (Y/n): '): exit(0) print(' Programming {} Configuration'.format(dev_name)) # Write configuration assert ATCA_SUCCESS == atcab_write_bytes_zone(0, 0, 16, config, len(config)) print(' Success') # Verify Config Zone print(' Verifying Configuration') config_qa = bytearray(len(config)) atcab_read_bytes_zone(0, 0, 16, config_qa, len(config_qa)) if config_qa != config: raise ValueError('Configuration read from the device does not match') print(' Success') print(' Locking Configuration') assert ATCA_SUCCESS == atcab_lock_config_zone() print(' Locked') else: print(' Locked, skipping') # Check data zone lock print('\nActivating Configuration') if not data_zone_lock: # Generate initial ECC key pairs, if applicable key_gen(dev_name) # Lock the data zone assert ATCA_SUCCESS == atcab_lock_data_zone() print(' Activated') else: print(' Already Active') # Generate new keys if keygen and data_zone_lock: print('\nGenerating New Keys') key_gen(dev_name) assert atcab_write_zone(2, IO_ENC_KEY_SLOT, 0, 0, IO_ENC_KEY, 32) == ATCA_SUCCESS atcab_release() def key_gen(dev_name): """Reviews the configuration of a device and generates new random ECC key pairs for slots that allow it.""" ATCA_SUCCESS = 0x00 if 'ECC' not in dev_name: return # SHA device, no keys to generate # Read the device configuration config_data = bytearray(128) assert ATCA_SUCCESS == atcab_read_config_zone(config_data) if dev_name == 'ATECC508A': config = Atecc508aConfig.from_buffer(config_data) elif dev_name == 'ATECC608A': config = Atecc608aConfig.from_buffer(config_data) else: raise ValueError('Unsupported device {}'.format(dev_name)) # Review all slot configurations and generate keys where possible for slot in range(16): if not config.KeyConfig[slot].Private: continue # Not a private key if config.LockValue != 0x55: # Data zone is already locked, additional conditions apply skip_msg = ' Skipping key pair generation in slot {}: '.format(slot) if not config.SlotConfig[slot].WriteConfig & 0x02: print(skip_msg + 'GenKey is disabled') continue if not config.SlotLocked & (1 << slot): print(skip_msg + 'Slot has ben locked') continue if config.KeyConfig[slot].ReqAuth: print(skip_msg + 'Slot requires authorization') continue if config.KeyConfig[slot].PersistentDisable: print(skip_msg + 'Slot requires persistent latch') continue print(' Generating key pair in slot {}'.format(slot)) public_key = bytearray(64) assert ATCA_SUCCESS == atcab_genkey(slot, public_key) print(convert_ec_pub_to_pem(public_key)) if __name__ == '__main__': parser = setup_example_runner(__file__) parser.add_argument('--i2c', help='I2C Address (in hex)') parser.add_argument('--gen', default=True, help='Generate new keys') args = parser.parse_args() if args.i2c is not None: args.i2c = int(args.i2c, 16) print('\nConfiguring the device with an example configuration') configure_device(args.iface, args.device, args.i2c, args.gen, **parse_interface_params(args.params)) print('\nDevice Successfully Configured')