1
0
mirror of https://github.com/gryf/mkinitramfs.git synced 2025-12-19 04:20:19 +01:00

Added basic challenge-responce with YubiKey

This commit is contained in:
2022-09-26 17:35:37 +02:00
parent 9146707f97
commit 9ea18fa68b
2 changed files with 59 additions and 20 deletions

View File

@@ -70,5 +70,14 @@ plain USB pendrive. Currently support for the keys is limited to 4096 bytes,
and assumption that key is unencrypted - it helps with booting system and assumption that key is unencrypted - it helps with booting system
non-interactively. non-interactively.
Yubikey
-------
There is possibility for using key which is encrypted using response from
challenge response using `ykchalresp`_ command. The challenge here could be
any string, so the name of the device from config is used.
.. _ccrypt: https://sourceforge.net/projects/ccrypt/ .. _ccrypt: https://sourceforge.net/projects/ccrypt/
.. _cryptsetup: https://gitlab.com/cryptsetup/cryptsetup/blob/master/README.md .. _cryptsetup: https://gitlab.com/cryptsetup/cryptsetup/blob/master/README.md
.. _ykchalresp: https://github.com/Yubico/yubikey-personalization

View File

@@ -24,6 +24,7 @@ DEPS=(
/usr/bin/ccrypt /usr/bin/ccrypt
/sbin/cryptsetup /sbin/cryptsetup
%(lvm)s %(lvm)s
%(yubikey)s
) )
""" """
# /usr/sbin/dropbear # /usr/sbin/dropbear
@@ -187,8 +188,21 @@ if [[ ${ret} -ne 0 && ! -f ${KEY} ]]; then
fi fi
""" """
DECRYPT_YUBICP = """
for i in 1 2 3 4 5 6; do
pass=$(ykchalresp %(disk)s 2>/dev/null)
if [ -n "$pass" ]; then
ccrypt -K $pass -c "$KEY.yk" | \
cryptsetup open --allow-discards $DEVICE root
break
fi
sleep .5
done
"""
DECRYPT_PASSWORD = """ DECRYPT_PASSWORD = """
if [[ -z "${KEYDEV}" || ${ret} -ne 0 ]]; then if [ ! -b /dev/mapper/root ]; then
for i in 0 1 2 ; do for i in 0 1 2 ; do
ccrypt -c $KEY | cryptsetup open --allow-discards $DEVICE root ccrypt -c $KEY | cryptsetup open --allow-discards $DEVICE root
ret=$? ret=$?
@@ -215,7 +229,16 @@ exec switch_root /new-root /sbin/init
class Initramfs(object): class Initramfs(object):
def __init__(self, args, disks): def __init__(self, args, disks):
self._args = args self.lvm = args.lvm
self.yk = args.yubikey
self.name = args.disk
self.modules = args.copy_modules
self.key_path = args.key_path
self.disk_label = args.disk_label
self.sdcard = args.sdcard
self.install = args.install
self.no_key = args.no_key
self.dirname = None self.dirname = None
self.kernel_ver = os.readlink('/usr/src/linux').replace('linux-', '') self.kernel_ver = os.readlink('/usr/src/linux').replace('linux-', '')
self._make_tmp() self._make_tmp()
@@ -242,9 +265,10 @@ class Initramfs(object):
_fd, fname = tempfile.mkstemp(dir=self.dirname, suffix='.sh') _fd, fname = tempfile.mkstemp(dir=self.dirname, suffix='.sh')
os.close(_fd) os.close(_fd)
with open(fname, 'w') as fobj: with open(fname, 'w') as fobj:
lvm = '/sbin/lvscan\n/sbin/vgchange' if self._args.lvm else '' lvm = '/sbin/lvscan\n/sbin/vgchange' if self.lvm else ''
yubikey = '/usr/bin/ykchalresp' if self.yk else ''
fobj.write(SHEBANG) fobj.write(SHEBANG)
fobj.write(DEPS % {'lvm': lvm}) fobj.write(DEPS % {'lvm': lvm, 'yubikey': yubikey})
fobj.write(COPY_DEPS) fobj.write(COPY_DEPS)
# extra crap, which seems to be needed, but is not direct dependency # extra crap, which seems to be needed, but is not direct dependency
@@ -263,7 +287,7 @@ class Initramfs(object):
os.chdir(self.curdir) os.chdir(self.curdir)
def _copy_modules(self): def _copy_modules(self):
if not self._args.copy_modules: if not self.modules:
return return
os.chdir(self.dirname) os.chdir(self.dirname)
os.mkdir(os.path.join('lib', 'modules')) os.mkdir(os.path.join('lib', 'modules'))
@@ -293,16 +317,15 @@ class Initramfs(object):
continue continue
os.symlink('busybox', command) os.symlink('busybox', command)
def _copy_key(self): def _copy_key(self, suffix=''):
key_path = self._disks[self._args.disk]['key'] key_path = self._disks[self.name]['key'] + suffix
if not os.path.exists(key_path): if not os.path.exists(key_path):
key_path = os.path.join(self._args.key_path, key_path = os.path.join(self.key_path,
self._disks[self._args.disk]['key']) self._disks[self.name]['key'] + suffix)
if not os.path.exists(key_path): if not os.path.exists(key_path):
self._cleanup() self._cleanup()
sys.stderr.write('Cannot find key file for %s.\n' % sys.stderr.write(f'Cannot find key(s) file for {self.name}.\n')
self._args.disk)
sys.exit(2) sys.exit(2)
key_path = os.path.abspath(key_path) key_path = os.path.abspath(key_path)
@@ -314,19 +337,22 @@ class Initramfs(object):
os.chdir(self.dirname) os.chdir(self.dirname)
with open('init', 'w') as fobj: with open('init', 'w') as fobj:
fobj.write(SHEBANG_ASH) fobj.write(SHEBANG_ASH)
fobj.write(f"UUID='{self._disks[self._args.disk]['uuid']}'\n") fobj.write(f"UUID='{self._disks[self.name]['uuid']}'\n")
fobj.write(f"KEY='/keys/{self._disks[self._args.disk]['key']}'\n") fobj.write(f"KEY='/keys/{self._disks[self.name]['key']}'\n")
fobj.write(INIT) fobj.write(INIT)
fobj.write(INIT_CMD) fobj.write(INIT_CMD)
if self._args.disk_label: if self.disk_label:
fobj.write(INIT_LABELED % {'label': self._args.disk_label}) fobj.write(INIT_LABELED % {'label': self.disk_label})
if self._args.sdcard: if self.sdcard:
fobj.write(INIT_SD) fobj.write(INIT_SD)
fobj.write(INIT_OPEN) fobj.write(INIT_OPEN)
if self._args.disk_label or self._args.sdcard: if self.disk_label or self.sdcard:
fobj.write(DECRYPT_KEYDEV) fobj.write(DECRYPT_KEYDEV)
if self.yk:
fobj.write(DECRYPT_YUBICP % {'disk': self.name})
fobj.write(DECRYPT_PASSWORD) fobj.write(DECRYPT_PASSWORD)
fobj.write(SWROOT) fobj.write(SWROOT)
os.chmod('init', 0b111101101) os.chmod('init', 0b111101101)
os.chdir(self.curdir) os.chdir(self.curdir)
@@ -346,7 +372,7 @@ class Initramfs(object):
os.chmod(self.cpio_arch, 0b110100100) os.chmod(self.cpio_arch, 0b110100100)
if self._args.install: if self.install:
self._make_boot_links() self._make_boot_links()
else: else:
shutil.move(self.cpio_arch, 'initramfs.cpio') shutil.move(self.cpio_arch, 'initramfs.cpio')
@@ -386,8 +412,10 @@ class Initramfs(object):
self._copy_modules() self._copy_modules()
# self._copy_wlan_modules() # self._copy_wlan_modules()
self._populate_busybox() self._populate_busybox()
if not self._args.no_key: if not self.no_key:
self._copy_key() self._copy_key()
if self.yk:
self._copy_key('.yk')
self._generate_init() self._generate_init()
self._mkcpio_arch() self._mkcpio_arch()
self._cleanup() self._cleanup()
@@ -439,11 +467,13 @@ def main():
parser.add_argument('-k', '--key-path', help='path to the location where ' parser.add_argument('-k', '--key-path', help='path to the location where '
'keys are stored', default=KEYS_PATH) 'keys are stored', default=KEYS_PATH)
parser.add_argument('-d', '--disk-label', help='Provide disk label ' parser.add_argument('-d', '--disk-label', help='Provide disk label '
'to be read decritpion key from.') 'to be read decription key from.')
parser.add_argument('-s', '--sdcard', help='Use built in sdcard reader to ' parser.add_argument('-s', '--sdcard', help='Use built in sdcard reader to '
'read from (hopefully) inserted card') 'read from (hopefully) inserted card')
parser.add_argument('-l', '--lvm', action='store_true', parser.add_argument('-l', '--lvm', action='store_true',
help='Enable LVM in init.') help='Enable LVM in init.')
parser.add_argument('-y', '--yubikey', action='store_true',
help='Enable Yubikey challenge-response in init.')
parser.add_argument('disk', choices=disks.keys(), help='Disk name') parser.add_argument('disk', choices=disks.keys(), help='Disk name')
args = parser.parse_args() args = parser.parse_args()