diff --git a/live_exam_os/.gitignore b/live_exam_os/.gitignore index 13e2528deaca3ca35d47df372b92142538ebc354..906aca118331bd80348ac667bd0d215a2e74d2b3 100644 --- a/live_exam_os/.gitignore +++ b/live_exam_os/.gitignore @@ -2,3 +2,5 @@ .env* cache/ config/02-customisation/etc/NetworkManager/system-connections/wifi.nmconnection +tools/unlocker-advanced.c +config/03-post_install/7000-unlocker-advanced.sh* diff --git a/live_exam_os/Dockerfile b/live_exam_os/Dockerfile index 398bd7aef684d19bcfd54adc86c29412fbf81e21..3ca37d879e9fc4eea6e6a5fc44b2fbdf4a23b693 100644 --- a/live_exam_os/Dockerfile +++ b/live_exam_os/Dockerfile @@ -1,22 +1,50 @@ -ARG DEBIAN_FRONTEND=noninteractive FROM ubuntu:22.04 ENV archive=go1.22.6.linux-amd64.tar.gz ENV PATH=$PATH:/usr/local/go/bin -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y gcc pkg-config git wget make ca-certificates libglfw3-dev libxcursor-dev libxinerama-dev libxi-dev libxxf86vm-dev upx-ucl curl cryptsetup squashfs-tools fakechroot debootstrap xorriso mtools dosfstools gnutls-bin +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive \ + apt-get install -y gcc \ + pkg-config \ + git \ + wget \ + make \ + ca-certificates \ + libglfw3-dev \ + libxcursor-dev \ + libxinerama-dev \ + libxi-dev \ + libxxf86vm-dev \ + upx-ucl \ + curl \ + cryptsetup \ + squashfs-tools \ + fakechroot \ + debootstrap \ + xorriso \ + mtools \ + dosfstools \ + gnutls-bin \ + build-essential \ + unzip \ + libykpers-1-dev \ + libyubikey-dev \ + libcryptsetup-dev \ + libssl-dev \ + && apt-get clean + RUN git clone https://github.com/limine-bootloader/limine.git --branch=v8.x-binary --depth=1 /opt/limine && \ cd /opt/limine && \ make && \ cp /opt/limine/limine /bin/ -RUN git config --global --add safe.directory /data - -RUN wget https://go.dev/dl/$archive && tar -C /usr/local -xzf $archive # This part is used to compile the dependencies so that you don't have to do it every time you run the build.sh script (it saves around 2.5 minutes). WORKDIR /nexus +RUN wget https://go.dev/dl/$archive && tar -C /usr/local -xzf $archive +RUN git config --global --add safe.directory /nexus COPY src src COPY Makefile . @@ -24,3 +52,9 @@ COPY config config RUN cd config/certs && ./gen-cert.sh ca.info nexus-server.info /nexus/certs RUN make build_nexus-exam SERVER='127.0.0.1:1077' CERT='certs/ca-cert.pem' EXAM_USER='user' EXAM_PWD='pwd' + +WORKDIR /tigress + +COPY live_exam_os/tigress_4.0.10-1_all.deb.zip . +RUN unzip tigress_4.0.10-1_all.deb.zip +RUN dpkg --force-architecture -i tigress_4.0.10-1_all.deb diff --git a/live_exam_os/config/01-packages_install/packages b/live_exam_os/config/01-packages_install/packages index 6c3320c7dae5fd3d96e9e5a95803dc668f5f89d8..b309e6bf1972ab2c41aaf0df637bf7410f4bd2b0 100644 --- a/live_exam_os/config/01-packages_install/packages +++ b/live_exam_os/config/01-packages_install/packages @@ -9,7 +9,6 @@ xserver-xorg xserver-xorg-input-libinput xinit xfce4 -xfce4-terminal systemd policykit-1 adwaita-icon-theme @@ -21,6 +20,9 @@ iptables ufw rfkill wpasupplicant -yubikey-personalization shim-signed grub-efi-amd64-signed +build-essential +libykpers-1-dev +libyubikey-dev +libcryptsetup-dev diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/unlock b/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/unlock new file mode 100755 index 0000000000000000000000000000000000000000..ddeed75ff61bf34da4324ab5d62fde44adb260ab --- /dev/null +++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/unlock @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e +. /usr/share/initramfs-tools/hook-functions + +copy_exec /etc/unlock_luks /scripts/unlock_luks +copy_exec /lib/x86_64-linux-gnu/libykpers-1.so.* /lib/x86_64-linux-gnu/ diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/yubikey b/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/yubikey deleted file mode 100755 index 56bc51daadf1fc546c5fe94971d80ff726269b81..0000000000000000000000000000000000000000 --- a/live_exam_os/config/02-customisation/etc/initramfs-tools/hooks/yubikey +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e -. /usr/share/initramfs-tools/hook-functions - -copy_exec /usr/bin/ykchalresp /bin/ykchalresp -copy_exec /etc/challenge /scripts/challenge diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus index 0b2fb417d630e16180f7c963a2c7799148150921..3eba82c00cda688fb2317dd715b455b5f389991d 100755 --- a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus +++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/nexus @@ -24,23 +24,4 @@ if [ ! $exit_code -eq 0 ]; then mount_and_switch /cdrom/squash.rootfs fi - -echo "Waiting for Yubikey." -while true; do - output=$(ykchalresp -2 -i /scripts/challenge 2>&1) - - exit_code=$? - - if read -t 1 -n 1 input && [ "$input" = "p" ]; then - echo "" - decrypt_with_passphrase /cdrom/squash.rootfs - continue - fi - - if [ "$exit_code" -eq 1 ]; then - sleep 1 - continue - fi - - decrypt_with_challenge /cdrom/squash.rootfs $output -done +decrypt_mount_and_switch diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe index d5ed66b68011bbaca5bb671575cb23810de655dd..8077c0256a8e965791c21d0f7f104a1cccc28660 100755 --- a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe +++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/pxe @@ -17,21 +17,4 @@ if [ ! $exit_code -eq 0 ]; then mount_and_switch $SQUASH_FILE fi -echo "Waiting for Yubikey" -while true; do - output=$(ykchalresp -2 -i /scripts/challenge 2>&1) - exit_code=$? - - if read -t 1 -n 1 input && [ "$input" = "p" ]; then - echo "" - decrypt_with_passphrase $SQUASH_FILE - continue - fi - - if [ "$exit_code" -eq 1 ]; then - sleep 1 - continue - fi - - decrypt_with_challenge $SQUASH_FILE $output -done +decrypt_mount_and_switch diff --git a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools index 1f712517796be800b1827df64942f854a0c7cc2e..64b8fa003087c62d436364323d5c4dc129a2cdad 100755 --- a/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools +++ b/live_exam_os/config/02-customisation/etc/initramfs-tools/scripts/tools @@ -14,6 +14,27 @@ mount_and_switch() { exec switch_root /newroot /sbin/init } +decrypt_mount_and_switch() { + echo "Waiting for Yubikey." + while true; do + output=$(/scripts/unlock_luks) + exit_code=$? + + if read -t 1 -n 1 input && [ "$input" = "p" ]; then + echo "" + decrypt_with_passphrase /cdrom/squash.rootfs + continue + fi + + if [ "$exit_code" -eq 1 ]; then + sleep 1 + continue + fi + + mount_and_switch /dev/mapper/data + done +} + decrypt_with_passphrase() { SQUASHFS_LUKS=$1 cryptsetup open $1 data @@ -26,18 +47,6 @@ decrypt_with_passphrase() { echo "Wrong passphrase" } -decrypt_with_challenge() { - SQUASHFS_LUKS=$1 - echo -n "$2" | cryptsetup open $SQUASHFS_LUKS data - exit_code=$? - - if [ "$exit_code" -eq 0 ]; then - mount_and_switch /dev/mapper/data - fi - - echo "Decryption error, possibly wrong Yubikey" -} - mount_fs() { SQUASHFS_PATH=$1 mkdir -p /newroot/{home, run, tmp, var/log, var/tmp} /rw_home /squash @@ -63,7 +72,6 @@ mount_fs() { mount --bind /rw_home /newroot/home } - find_active_interface() { for iface in $(ls /sys/class/net); do if [ "$iface" = "lo" ]; then diff --git a/live_exam_os/config/03-post_install/5000-push_challenge.sh b/live_exam_os/config/03-post_install/5000-push_challenge.sh deleted file mode 100755 index 27bfbe6a91dddc542aee97f2085613a06b442769..0000000000000000000000000000000000000000 --- a/live_exam_os/config/03-post_install/5000-push_challenge.sh +++ /dev/null @@ -1,6 +0,0 @@ -#/bin/bash - -. tools/functions.sh - - echo " [Adding challenge file...]" - echo "$CHALLENGE" > $ROOTFS_DIR/etc/challenge diff --git a/live_exam_os/config/03-post_install/7000-unlocker.sh b/live_exam_os/config/03-post_install/7000-unlocker.sh new file mode 100755 index 0000000000000000000000000000000000000000..628fdb15a260c4ca594a46aaf1ee92bb1bf3aafe --- /dev/null +++ b/live_exam_os/config/03-post_install/7000-unlocker.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +. tools/functions.sh + +echo " [Compile unlocker...]" + +sed "s/DUMMY_CHALLENGE/$CHALLENGE/g" tools/unlocker.c > /tmp/unlocker.c +run_command gcc -o /tmp/unlock_luks /tmp/unlocker.c -I/usr/include/ykpers-1 -lykpers-1 -lyubikey -lcryptsetup +run_command strip /tmp/unlock_luks +run_command cp /tmp/unlock_luks $ROOTFS_DIR/etc/unlock_luks diff --git a/live_exam_os/config/03-post_install/8000-initramfs.sh b/live_exam_os/config/03-post_install/8000-initramfs.sh index 0c5e737be3e3460f5b3b1e5caad49651fab51610..3db26efb3da8cabba3fc687c7d753e06173fcbd3 100755 --- a/live_exam_os/config/03-post_install/8000-initramfs.sh +++ b/live_exam_os/config/03-post_install/8000-initramfs.sh @@ -4,4 +4,3 @@ echo " [Update initramfs...]" run_command_chroot update-initramfs -u -check_exit_code $? "Error during initramfs generation" diff --git a/live_exam_os/tigress_4.0.10-1_all.deb.zip b/live_exam_os/tigress_4.0.10-1_all.deb.zip new file mode 100644 index 0000000000000000000000000000000000000000..3a4c6a2e6a9f57d6a0f9d32d6906c1041766c476 Binary files /dev/null and b/live_exam_os/tigress_4.0.10-1_all.deb.zip differ diff --git a/live_exam_os/tools/functions.sh b/live_exam_os/tools/functions.sh index 1b6745a8455ee0b8d1604255e71c1f0a5229041a..717963aaf2592d354677ba71057faa008158b150 100755 --- a/live_exam_os/tools/functions.sh +++ b/live_exam_os/tools/functions.sh @@ -77,3 +77,20 @@ check_dependencies() { exit 1 fi } + +find_latest_library() { + local library_name=$1 + + local library_files + library_files=$(find /$ROOTFS_DIR -name "$library_name" 2>/dev/null) + + if [ -z "$library_files" ]; then + echo "No version available of $library_name." + return 1 + fi + + local latest_library + latest_library=$(echo "$library_files" | sort -r | head -n 1) + + realpath "$latest_library" +} diff --git a/live_exam_os/tools/unlocker.c b/live_exam_os/tools/unlocker.c new file mode 100644 index 0000000000000000000000000000000000000000..8af2605fd18e217b3c1c6418162c324cc80a40ac --- /dev/null +++ b/live_exam_os/tools/unlocker.c @@ -0,0 +1,85 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ykpers-1/ykpers.h> +#include <yubikey.h> +#include <libcryptsetup.h> + +#define LUKS_DEVICE "/cdrom/squash.rootfs" +#define LUKS_NAME "data" + +int unlock_luks(const char *device, const char *name, const char *key, size_t key_size) { + struct crypt_device *cd; + + if (crypt_init(&cd, device) < 0) { + fprintf(stderr, "Error: Cannot initialize cryptsetup\n"); + return -1; + } + + if (crypt_load(cd, CRYPT_LUKS2, NULL) < 0) { + fprintf(stderr, "Error: Cannot load LUKS header\n"); + crypt_free(cd); + return -1; + } + + if (crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, key, strlen(key), CRYPT_ACTIVATE_ALLOW_DISCARDS) < 0) { + fprintf(stderr, "Error: Cannot decrypt device\n"); + crypt_free(cd); + return -1; + } + + crypt_free(cd); + return 0; +} + +int main() { + YK_KEY *yk = NULL; + unsigned char response[64]; + unsigned int response_len = sizeof(response); + char *hex_response = malloc(41); + unsigned char challenge[64] = "DUMMY_CHALLENGE\n"; + + if (!hex_response) { + fprintf(stderr, "Error: Failed memory allocation\n"); + free(hex_response); + return 1; + } + + if (!yk_init()) { + fprintf(stderr, "Error: Cannot initialize libykpers\n"); + free(hex_response); + return 1; + } + + yk = yk_open_first_key(); + if (!yk) { + yk_release(); + free(hex_response); + return 1; + } + + if (!yk_challenge_response(yk, SLOT_CHAL_HMAC1, YK_FLAG_MAYBLOCK, sizeof(challenge), challenge, response_len, response)) { + fprintf(stderr, "Error: challenge-response issue\n"); + yk_close_key(yk); + yk_release(); + free(hex_response); + return 1; + } + + for (int i = 0; i < 20; i++) { + sprintf(hex_response + (i * 2), "%02x", response[i]); + } + hex_response[40] = '\0'; + + yk_close_key(yk); + yk_release(); + + if (unlock_luks(LUKS_DEVICE, LUKS_NAME, hex_response, strlen(hex_response)) != 0) { + fprintf(stderr, "Error: Cannot decrypt device\n"); + return 1; + } + + free(hex_response); + return 0; +}