def public_key_digest(nonce, public_key): config_data = bytearray(128) assert Status.ATCA_SUCCESS == atcab_read_config_zone(config_data) config = Atecc608Config.from_buffer(config_data) nonce = calc_nonce(mode=0x03, zero=0x0000, num_in=nonce) pubkey_digest = calc_genkey_pubkey_digest(mode=0x10, key_id=rotating_key_slot, public_key=public_key, temp_key=nonce, sn=ctypes_to_bytes(config.SN03) + ctypes_to_bytes(config.SN48), other_data=b'\x00' * 3) msg_digest, other_data = calc_sign_internal_digest( mode=0x00, key_id=authority_key_slot, temp_key=pubkey_digest, temp_key_key_id=rotating_key_slot, temp_key_source_flag= 1, # Device nonce in internally generated random number temp_key_gendig_data=False, temp_key_genkey_data=True, temp_key_no_mac=False, config=config, for_invalidate=False) return msg_digest
def public_key_validate_invalidate(validation_status,perform_on_device=True): is_verified = AtcaReference(False) config_data = bytearray(128) nonce = os.urandom(32) public_key = bytearray(64) if(perform_on_device == True): assert atcab_read_pubkey(rotating_key_slot,public_key) == ATCA_SUCCESS else: rotating_private_key = get_rotating_key() public_key = rotating_private_key.public_key().public_bytes(encoding=Encoding.X962, format=PublicFormat.UncompressedPoint)[1:] validation_authority_key = get_validating_authority_key() assert ATCA_SUCCESS == atcab_read_config_zone(config_data) config = Atecc608Config.from_buffer(config_data) if(perform_on_device == True): assert ATCA_SUCCESS == atcab_nonce(nonce) nonce = calc_nonce(mode=0x03, zero=0x0000, num_in=nonce) pubkey_digest = calc_genkey_pubkey_digest( mode=0x10, key_id=rotating_key_slot, public_key=public_key, temp_key=nonce, sn=ctypes_to_bytes(config.SN03) + ctypes_to_bytes(config.SN48), other_data=b'\x00'*3 ) msg_digest,other_data = calc_sign_internal_digest( mode=0x00, key_id=authority_key_slot, temp_key=pubkey_digest, temp_key_key_id=rotating_key_slot, temp_key_source_flag=1, # Device nonce in internally generated random number temp_key_gendig_data=False, temp_key_genkey_data=True, temp_key_no_mac=False, config=config, for_invalidate=validation_status ) # Note that other_data is ignored and not required for this mode public_key = bytearray(64) if(perform_on_device == True): atcab_genkey_base(mode=0x10, key_id=rotating_key_slot, other_data=b'\x00'*3, public_key=public_key) signature = sign_host(msg_digest,validation_authority_key) if(perform_on_device == True): if(validation_status == True): assert atcab_verify_invalidate(rotating_key_slot,signature, other_data, is_verified) == ATCA_SUCCESS else: assert atcab_verify_validate(rotating_key_slot,signature, other_data, is_verified) == ATCA_SUCCESS else: is_verified = True return is_verified,nonce,signature
def calc_sign_internal_digest(mode, key_id, temp_key, temp_key_key_id, temp_key_source_flag, temp_key_gendig_data, temp_key_genkey_data, temp_key_no_mac, config, for_invalidate=False): """ Replicate the internal message digest calculations of the Sign command in sign internal mode. """ # TODO: Doesn't work for ATECC108A if mode & 0x80: raise ValueError('Invalid mode, not internal sign') if len(temp_key) != 32: raise ValueError('temp_key must be 32 bytes') msg = b'' msg += temp_key msg += b'\x41' # Sign Opcode msg += struct.pack('B', mode) msg += struct.pack('<H', key_id) msg += ctypes_to_bytes(config.SlotConfig[temp_key_key_id]) msg += ctypes_to_bytes(config.KeyConfig[temp_key_key_id]) temp_key_flags = 0 if temp_key_key_id < 0 or temp_key_key_id > 15: raise ValueError('temp_key_key_id must be 0 to 15') if temp_key_gendig_data and temp_key_genkey_data: raise ValueError( 'temp_key_gendig_data and temp_key_genkey_data are mutually exclusive and both can not be true' ) temp_key_flags += temp_key_key_id temp_key_flags += (1 << 4) if temp_key_source_flag else 0 temp_key_flags += (1 << 5) if temp_key_gendig_data else 0 temp_key_flags += (1 << 6) if temp_key_genkey_data else 0 temp_key_flags += (1 << 7) if temp_key_no_mac else 0 msg += struct.pack('B', temp_key_flags) msg += b'\x00' * 2 is_full_sn = bool(mode & 0x40) sn = ctypes_to_bytes(config.SN03) + ctypes_to_bytes(config.SN48) msg += sn[8:9] msg += sn[4:8] if is_full_sn else b'\x00' * 4 msg += sn[0:2] msg += sn[2:4] if is_full_sn else b'\x00' * 2 msg += b'\x01' if config.SlotLocked & (1 << temp_key_key_id) else b'\x00' msg += b'\x01' if for_invalidate else b'\x00' msg += b'\x00' other_data = bytearray() other_data.extend(msg[33:43]) other_data.extend(msg[44:48]) other_data.extend(msg[50:55]) return sha256(msg).digest(), other_data
def key_attestation(dev_name, attestation_key_slot, key_slot): """Demo the key attestation flow""" print('Setup: Establish Trust with Attestation Key') wrapper = TextWrapper(width=70, initial_indent=' ', subsequent_indent=' ') print( wrapper.fill( 'The verifier (entity requesting key attestation) needs to trust the' ' attestation key in the device for this process to work. This could' ' be as simple as reading and storing the attestation public keys in' ' a trusted environment (e.g. during manufacturing). The verifier also' ' needs to know the expected configuration and state of the key/slot' ' being attested.')) print('\n Reading attestation public key from slot {}:'.format( attestation_key_slot)) attestation_public_key = bytearray(64) assert ATCA_SUCCESS == atcab_get_pubkey(key_id=attestation_key_slot, public_key=attestation_public_key) print(convert_ec_pub_to_pem(attestation_public_key)) print('\n Read configuration:') config = read_config(dev_name) print(pretty_print_hex(ctypes_to_bytes(config), indent=' ')) if config.LockConfig == 0x55: raise RuntimeError( 'Config zone must be locked for this example to run') if config.LockValue == 0x55: raise RuntimeError('Data zone muct be locked for this example to run') print('\nVERIFIER: Send key attestation request') print(' Generate verifier challenge/nonce:') verifier_nonce = os.urandom(20) print(pretty_print_hex(verifier_nonce, indent=' ')) print('\nDEVICE: Generate key attestation signature') print( wrapper.fill( 'Generate attestation nonce in TempKey from verifier and internal' ' device nonces.')) device_nonce = bytearray(32) assert ATCA_SUCCESS == atcab_nonce_rand(num_in=verifier_nonce, rand_out=device_nonce) print('\n Device nonce:') print(pretty_print_hex(device_nonce, indent=' ')) print('\n' + wrapper.fill( 'Create a PubKey digest using the GenKey command with the Digest mode' ' (0x08). This special mode combines TempKey (attestation nonce) with' ' the public key being attested using SHA256 and stores the resulting' ' digest back into TempKey.')) # Note that other_data is ignored and not required for this mode public_key = bytearray(64) assert ATCA_SUCCESS == atcab_genkey_base(mode=0x08, key_id=key_slot, other_data=b'\x00' * 3, public_key=public_key) print('\n Public key being attested from slot {}:'.format(key_slot)) print(convert_ec_pub_to_pem(public_key)) print('\n' + wrapper.fill( 'Use attestation key to sign (Sign command in internal mode) a message' ' including the PubKey digest in TempKey with additional slot/key' ' configuration and state information.')) signature = bytearray(64) assert ATCA_SUCCESS == atcab_sign_internal(key_id=attestation_key_slot, is_invalidate=False, is_full_sn=False, signature=signature) print('\n Key attestation signature:') print(pretty_print_hex(signature, indent=' ')) print('\nVERIFIER: Validate key attestation signature') print( wrapper.fill( 'The verifier has now has the data from the device required to' ' perform key attestation. This includes the public key being' ' attested, device nonce, key/slot configuration and state, and' ' attestation signature. The verifier will need to build the' ' attestation message from this information and verify it against the' ' signature and the trusted attestation public key.')) print('\n Calculate attestation nonce from verifier and device nonces:') nonce = calc_nonce(mode=0x00, zero=0x0000, num_in=verifier_nonce, rand_out=device_nonce) print(pretty_print_hex(nonce, indent=' ')) print('\n Calculate PubKey digest:') pubkey_digest = calc_genkey_pubkey_digest(mode=0x08, key_id=key_slot, public_key=public_key, temp_key=nonce, sn=ctypes_to_bytes(config.SN03) + ctypes_to_bytes(config.SN48)) print(pretty_print_hex(pubkey_digest, indent=' ')) print('\n Calculate the internal sign message digest:') msg_digest = calc_sign_internal_digest( mode=0x00, key_id=attestation_key_slot, temp_key=pubkey_digest, temp_key_key_id=key_slot, temp_key_source_flag= 0, # Device nonce in internally generated random number temp_key_gendig_data=False, temp_key_genkey_data=True, temp_key_no_mac=False, config=config) print(pretty_print_hex(msg_digest, indent=' ')) print('\n Verifying signature:') attestation_public_key = ec.EllipticCurvePublicNumbers( curve=ec.SECP256R1(), x=int_from_bytes(attestation_public_key[0:32], byteorder='big'), y=int_from_bytes(attestation_public_key[32:64], byteorder='big'), ).public_key(default_backend()) r = int_from_bytes(signature[0:32], byteorder='big', signed=False) s = int_from_bytes(signature[32:64], byteorder='big', signed=False) attestation_public_key.verify(signature=utils.encode_dss_signature(r, s), data=msg_digest, signature_algorithm=ec.ECDSA( utils.Prehashed(hashes.SHA256()))) print(' SUCCESS! Key has been attested.')
def test_device_serial_number_from_def(config, definition, vector): config = config(**definition) sernum = ctypes_to_bytes(config.SN03) + ctypes_to_bytes(config.SN48) assert sernum == bytes(vector)
def test_device_config_from_vector(config, vector): assert ctypes_to_bytes(config.from_buffer(vector)) == bytes(vector)
def test_device_config_from_def(config, definition, vector): assert ctypes_to_bytes(config(**definition)) == bytes(vector)