allows silent certificate checks (#410)

This commit is contained in:
kaczmarczyck
2021-11-18 17:09:40 +01:00
committed by GitHub
parent ae4e32ba4a
commit 5cf988c7fa
3 changed files with 72 additions and 27 deletions

View File

@@ -26,6 +26,7 @@ import os
import shutil import shutil
import subprocess import subprocess
import sys import sys
import time
from typing import Dict, List, Tuple from typing import Dict, List, Tuple
import colorama import colorama
@@ -36,6 +37,7 @@ from tockloader import tbfh
from tockloader import tockloader as loader from tockloader import tockloader as loader
from tockloader.exceptions import TockLoaderException from tockloader.exceptions import TockLoaderException
import tools.configure
from tools.deploy_partition import create_metadata, pad_to from tools.deploy_partition import create_metadata, pad_to
PROGRAMMERS = frozenset(("jlink", "openocd", "pyocd", "nordicdfu", "none")) PROGRAMMERS = frozenset(("jlink", "openocd", "pyocd", "nordicdfu", "none"))
@@ -706,6 +708,19 @@ class OpenSKInstaller:
if self.args.programmer == "none": if self.args.programmer == "none":
assert_python_library("intelhex") assert_python_library("intelhex")
def configure_device(self):
"""Checks the device configuration, and sets it according to args."""
configure_response = tools.configure.main(
argparse.Namespace(
batch=False,
certificate=self.args.config_cert,
priv_key=self.args.config_pkey,
lock=self.args.lock_device,
))
if not configure_response:
return None
return configure_response[0]
def run(self) -> int: def run(self) -> int:
"""Reads args to decide and run all required tasks.""" """Reads args to decide and run all required tasks."""
self.check_prerequisites() self.check_prerequisites()
@@ -746,17 +761,13 @@ class OpenSKInstaller:
self.install_padding() self.install_padding()
self.install_tab_file(f"target/tab/{self.args.application}.tab") self.install_tab_file(f"target/tab/{self.args.application}.tab")
self.install_metadata() self.install_metadata()
if self.verify_flashed_app(self.args.application): if not self.verify_flashed_app(self.args.application):
info("You're all set!") error(("It seems that something went wrong. App/example not found "
return 0 "on your board. Ensure the connections between the programmer "
error( "and the board are correct."))
("It seems that something went wrong. App/example not found "
"on your board. Ensure the connections between the programmer and "
"the board are correct."))
return 1 return 1
return 0
if self.args.programmer in ("pyocd", "nordicdfu", "none"): elif self.args.programmer in ("pyocd", "nordicdfu", "none"):
dest_file = f"target/{self.args.board}_merged.hex" dest_file = f"target/{self.args.board}_merged.hex"
os.makedirs("target", exist_ok=True) os.makedirs("target", exist_ok=True)
self.create_hex_file(dest_file) self.create_hex_file(dest_file)
@@ -793,7 +804,7 @@ class OpenSKInstaller:
fatal("Multiple DFU devices are detected. Please only connect one.") fatal("Multiple DFU devices are detected. Please only connect one.")
# Run the command without capturing stdout so that we show progress # Run the command without capturing stdout so that we show progress
info("Flashing device using DFU...") info("Flashing device using DFU...")
return subprocess.run( dfu_return_code = subprocess.run(
[ [
"nrfutil", "dfu", "usb-serial", f"--package={dfu_pkg_file}", "nrfutil", "dfu", "usb-serial", f"--package={dfu_pkg_file}",
f"--serial-number={serial_number[0]}" f"--serial-number={serial_number[0]}"
@@ -801,22 +812,49 @@ class OpenSKInstaller:
check=False, check=False,
timeout=None, timeout=None,
).returncode ).returncode
if dfu_return_code != 0:
return dfu_return_code
# Configure OpenSK through vendor specific command if needed # Configure OpenSK through vendor specific command if needed
if self.args.programmer == "none":
if any([ if any([
self.args.lock_device, self.args.lock_device,
self.args.config_cert, self.args.config_cert,
self.args.config_pkey, self.args.config_pkey,
]): ]):
# pylint: disable=g-import-not-at-top,import-outside-toplevel fatal("Unexpected arguments to configure your device. Since you "
import tools.configure "selected the programmer \"none\", the device is not ready to be "
tools.configure.main( "configured yet.")
argparse.Namespace( return 0
batch=False,
certificate=self.args.config_cert, # Perform checks if OpenSK was flashed.
priv_key=self.args.config_pkey, if self.args.application != "ctap2":
lock=self.args.lock_device, return 0
))
# Trying to check or configure the device. Booting might take some time.
for i in range(5):
# Increasing wait time, total of 10 seconds.
time.sleep(i)
devices = tools.configure.get_opensk_devices(False)
if devices:
break
if not devices:
fatal("No device to configure found.")
status = self.configure_device()
if not status:
fatal("Could not read device configuration.")
if status["cert"] and status["pkey"]:
info("You're all set!")
else:
info("Your device is not yet configured, and lacks some functionality. "
"If you run into issues, this command might help:\n\n"
"./tools/configure.py \\\n"
" --certificate=crypto_data/opensk_cert.pem \\\n"
" --private-key=crypto_data/opensk.key\n\n"
"Please read the Certificate considerations in docs/customization.md"
" to understand the privacy trade-off.")
return 0 return 0

View File

@@ -1192,7 +1192,9 @@ where
params: AuthenticatorVendorConfigureParameters, params: AuthenticatorVendorConfigureParameters,
cid: ChannelID, cid: ChannelID,
) -> Result<ResponseData, Ctap2StatusCode> { ) -> Result<ResponseData, Ctap2StatusCode> {
if params.attestation_material.is_some() || params.lockdown {
(self.check_user_presence)(cid)?; (self.check_user_presence)(cid)?;
}
// Sanity checks // Sanity checks
let current_priv_key = self.persistent_store.attestation_private_key()?; let current_priv_key = self.persistent_store.attestation_private_key()?;

View File

@@ -125,6 +125,7 @@ def main(args):
} }
devices = get_opensk_devices(args.batch) devices = get_opensk_devices(args.batch)
responses = []
if not devices: if not devices:
fatal("No devices found.") fatal("No devices found.")
for authenticator in tqdm(devices): for authenticator in tqdm(devices):
@@ -134,12 +135,15 @@ def main(args):
authenticator.device.wink() authenticator.device.wink()
aaguid = uuid.UUID(bytes=authenticator.get_info().aaguid) aaguid = uuid.UUID(bytes=authenticator.get_info().aaguid)
info(f"Programming OpenSK device AAGUID {aaguid} ({authenticator.device}).") info(f"Programming OpenSK device AAGUID {aaguid} ({authenticator.device}).")
if args.lock or args.priv_key:
info("Please touch the device to confirm...") info("Please touch the device to confirm...")
try: try:
result = authenticator.send_cbor( result = authenticator.send_cbor(
OPENSK_VENDOR_CONFIGURE, OPENSK_VENDOR_CONFIGURE,
data=cbor_data, data=cbor_data,
) )
status = {"cert": result[1], "pkey": result[2]}
responses.append(status)
info(f"Certificate: {'Present' if result[1] else 'Missing'}") info(f"Certificate: {'Present' if result[1] else 'Missing'}")
info(f"Private Key: {'Present' if result[2] else 'Missing'}") info(f"Private Key: {'Present' if result[2] else 'Missing'}")
if args.lock: if args.lock:
@@ -156,6 +160,7 @@ def main(args):
"the given cert/key don't match the ones currently programmed).")) "the given cert/key don't match the ones currently programmed)."))
else: else:
error(f"Failed to configure OpenSK (unknown error: {ex}") error(f"Failed to configure OpenSK (unknown error: {ex}")
return responses
if __name__ == "__main__": if __name__ == "__main__":