Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/hsm/fido.py
blob: 49f369576806eb35e9466b28678fb5d8eb275a8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import typing
import pathlib
import getpass
import logging
from ..general import SysCommand, SysCommandWorker, clear_vt100_escape_codes
from ..disk.partition import Partition
from ..general import log

def get_fido2_devices() -> typing.Dict[str, typing.Dict[str, str]]:
	"""
	Uses systemd-cryptenroll to list the FIDO2 devices
	connected that supports FIDO2.
	Some devices might show up in udevadm as FIDO2 compliant
	when they are in fact not.

	The drawback of systemd-cryptenroll is that it uses human readable format.
	That means we get this weird table like structure that is of no use.

	So we'll look for `MANUFACTURER` and `PRODUCT`, we take their index
	and we split each line based on those positions.
	"""
	worker = clear_vt100_escape_codes(SysCommand(f"systemd-cryptenroll --fido2-device=list").decode('UTF-8'))

	MANUFACTURER_POS = 0
	PRODUCT_POS = 0
	devices = {}
	for line in worker.split('\r\n'):
		if '/dev' not in line:
			MANUFACTURER_POS = line.find('MANUFACTURER')
			PRODUCT_POS = line.find('PRODUCT')
			continue

		path = line[:MANUFACTURER_POS].rstrip()
		manufacturer = line[MANUFACTURER_POS:PRODUCT_POS].rstrip()
		product = line[PRODUCT_POS:]

		devices[path] = {
			'manufacturer' : manufacturer,
			'product' : product
		}

	return devices

def fido2_enroll(hsm_device_path :pathlib.Path, partition :Partition, password :str) -> bool:
	worker = SysCommandWorker(f"systemd-cryptenroll --fido2-device={hsm_device_path} {partition.real_device}", peak_output=True)
	pw_inputted = False
	pin_inputted = False
	while worker.is_alive():
		if pw_inputted is False and bytes(f"please enter current passphrase for disk {partition.real_device}", 'UTF-8') in worker._trace_log.lower():
			worker.write(bytes(password, 'UTF-8'))
			pw_inputted = True

		elif pin_inputted is False and bytes(f"please enter security token pin", 'UTF-8') in worker._trace_log.lower():
			worker.write(bytes(getpass.getpass(" "), 'UTF-8'))
			pin_inputted = True

			log(f"You might need to touch the FIDO2 device to unlock it if no prompt comes up after 3 seconds.", level=logging.INFO, fg="yellow")