blob: 23ee202c8e523c490417f0853e935fd470fc63be [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Verify pairing between base and lid
During pairing, the base computes it's public key from base_private key
and authenticator is derived from shared secret. For the lid to verify the
challenge, it needs to check whether base_public corresponds to one of
the previously seen bases, and that the returned authenticator matches.
"""
from __future__ import print_function
import ctypes
import sys
import time
import common
import hammerd_api # pylint: disable=import-error
PAIRING_RUNS = 10
INJECTION_RUNS = 10
PUBLIC_KEY_SIZE = 32
# Before this test, please flash staff.bin using servo
def main(argv):
if argv:
sys.exit('Test takes no args!')
updater = hammerd_api.FirmwareUpdater(common.BASE_VENDOR_ID,
common.BASE_PRODUCT_ID,
common.BASE_USB_PATH)
public_key_first = (ctypes.c_ubyte * PUBLIC_KEY_SIZE)()
# Load EC image.
with open(common.IMAGE, 'rb') as f:
ec_image = f.read()
updater.LoadEcImage(ec_image)
common.disable_hammerd()
print('Connect to base EC.')
common.connect_usb(updater)
print('EC information:')
print('PDU Response: %s' % updater.GetFirstResponsePdu().contents)
print('RO: %s' % updater.GetSectionVersion(hammerd_api.SectionName.RO))
print('RW: %s' % updater.GetSectionVersion(hammerd_api.SectionName.RW))
print('Current section : %s' % updater.CurrentSection())
assert updater.CurrentSection() == 1, 'Running section should be 1 (RW)'
# Sends 'Need to inject entropy' message if base is new
pair_manager = hammerd_api.PairManager()
challenge_status = pair_manager.PairChallenge(updater.object,
public_key_first)
print('Challenge status: %d' % challenge_status)
# assert challenge_status == 9, 'Need to inject the entropy'
for iteratn in range(INJECTION_RUNS):
print('Jumping back to RO to inject entropy. Iteratn: %d' % (iteratn + 1))
updater.SendSubcommand(hammerd_api.UpdateExtraCommand.UnlockRollback)
updater.SendSubcommand(hammerd_api.UpdateExtraCommand.ImmediateReset)
updater.CloseUsb()
time.sleep(0.5)
updater.TryConnectUsb()
updater.SendSubcommand(hammerd_api.UpdateExtraCommand.StayInRO)
# Wait for RO to run, else SendFirstPdu() picks up RW
time.sleep(1)
# Verify that we're in RO
assert updater.SendFirstPdu() is True, 'Error sending first PDU'
updater.SendDone()
assert updater.CurrentSection() == 0, 'Not in RO: Cannot inject entropy'
print('Inject entropy and sys jump to RW')
updater.InjectEntropyWithPayload(b'\x87' * hammerd_api.ENTROPY_SIZE)
updater.SendSubcommand(hammerd_api.UpdateExtraCommand.ImmediateReset)
updater.CloseUsb()
time.sleep(0.5)
common.connect_usb(updater)
updater.SendSubcommand(hammerd_api.UpdateExtraCommand.JumpToRW)
# Wait for RW to run
time.sleep(1)
updater.CloseUsb()
time.sleep(0.5)
# Jump to RW resets the base. Need to reconnect
common.connect_usb(updater)
print('PDU Response: %s' % updater.GetFirstResponsePdu().contents)
# Check that RW is running
assert updater.SendFirstPdu() is True, 'Error sending first PDU'
updater.SendDone()
print('Current running section after jumping to RW: %s'
% updater.CurrentSection())
assert updater.CurrentSection() == 1, 'Running section should be 1 (RW)'
# Autheticator should match for each pairing run
for i in range(PAIRING_RUNS):
public_key = (ctypes.c_ubyte * PUBLIC_KEY_SIZE)()
pair_manager = hammerd_api.PairManager()
challenge_status = pair_manager.PairChallenge(updater.object, public_key)
print('Challenge status: %d' % challenge_status)
assert challenge_status == 0, 'Pairing challenge failed!'
if i == 0:
same = True
for j in range(0, PUBLIC_KEY_SIZE-1):
if public_key_first[j] != public_key[j]:
same = False
assert not same, 'The key did not change after entropy injection!'
public_key_first = public_key
else:
for j in range(0, PUBLIC_KEY_SIZE-1):
assert public_key_first[j] == public_key[j], 'Key changed!'
# Reset the base
common.sim_disconnect_connect(updater)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))