302 lines
11 KiB
C
Executable File
302 lines
11 KiB
C
Executable File
/*
|
|
* vault.c -- Crypto Security Token Vault Gateway
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*
|
|
* Full PIN auth module with rotary entry, lockout, and dual identity modes.
|
|
* Dual wired/wired identity modes backed by non-volatile failure
|
|
* limits, roll-count PIN security, and automatic device state
|
|
* enforcement. Wired mode enables USB composite gadget via
|
|
* enable_vault_usb.sh; wireless mode tears down USB and brings
|
|
* up BLE via enable_vault_ble.sh.
|
|
*
|
|
* Manifest ref: Asset IV -- Crypto Security Token Vault Gateway
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <linux/input.h>
|
|
#include "h2_ui.h"
|
|
#include "log_manager.h"
|
|
|
|
#define STATE_FILE "/data/vault/failures.dat"
|
|
#define MAX_FAILURES 3
|
|
#define LOCKOUT_SEC 300
|
|
|
|
/* PIN: 4 digits, default 4-2-9-1 as per manifest */
|
|
static int master_pin[4] = {4, 2, 9, 1};
|
|
static int entered_pin[4] = {0, 0, 0, 0};
|
|
static int current_digit_idx = 0;
|
|
|
|
typedef enum { MODE_NONE, MODE_WIRED, MODE_WIRELESS } VaultMode;
|
|
static VaultMode current_mode = MODE_NONE;
|
|
|
|
/* UI objects */
|
|
static lv_obj_t *pin_label = NULL;
|
|
static lv_obj_t *warning_label = NULL;
|
|
static lv_obj_t *digit_labels[4] = {NULL};
|
|
static lv_obj_t *cursor_label = NULL;
|
|
static lv_obj_t *status_label = NULL;
|
|
static lv_obj_t *mode_label = NULL;
|
|
|
|
static int get_failure_count(void) {
|
|
FILE *f = fopen(STATE_FILE, "r");
|
|
if (!f) return 0;
|
|
int count = 0;
|
|
if (fscanf(f, "%d", &count) <= 0) count = 0;
|
|
fclose(f);
|
|
return count;
|
|
}
|
|
|
|
static void set_failure_count(int count) {
|
|
FILE *f = fopen(STATE_FILE, "w");
|
|
if (f) { fprintf(f, "%d", count); fclose(f); }
|
|
}
|
|
|
|
static int is_usb_plugged_in(void) {
|
|
int fd = open("/sys/class/power_supply/usb/online", O_RDONLY);
|
|
if (fd == -1) return 0;
|
|
char status = '0';
|
|
if (read(fd, &status, 1) <= 0) status = '0';
|
|
close(fd);
|
|
return (status == '1');
|
|
}
|
|
|
|
static void render_pin_screen(int attempts_left) {
|
|
char buf[64];
|
|
|
|
/* Warning */
|
|
snprintf(buf, sizeof(buf), "Attempts before lockdown: %d", attempts_left);
|
|
lv_label_set_text(warning_label, buf);
|
|
lv_obj_set_style_text_color(warning_label, lv_color_make(253, 32, 32), LV_PART_MAIN);
|
|
|
|
/* Digit boxes */
|
|
for (int i = 0; i < 4; i++) {
|
|
char digit_str[16];
|
|
snprintf(digit_str, sizeof(digit_str), "%d", entered_pin[i]);
|
|
lv_label_set_text(digit_labels[i], digit_str);
|
|
|
|
if (i == current_digit_idx) {
|
|
lv_obj_set_style_text_color(digit_labels[i], COLOR_ACCENT, LV_PART_MAIN);
|
|
lv_obj_set_style_border_color(digit_labels[i],
|
|
lv_color_make(0, 224, 0), LV_PART_MAIN);
|
|
lv_obj_set_style_border_width(digit_labels[i], 2, LV_PART_MAIN);
|
|
} else {
|
|
lv_obj_set_style_text_color(digit_labels[i], COLOR_PRIMARY, LV_PART_MAIN);
|
|
lv_obj_set_style_border_width(digit_labels[i], 1, LV_PART_MAIN);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int enforce_pin_authorization(int input_fd) {
|
|
int failures = get_failure_count();
|
|
|
|
/* Lockout check */
|
|
if (failures >= MAX_FAILURES) {
|
|
char log_msg[128];
|
|
snprintf(log_msg, sizeof(log_msg),
|
|
"PIN lockout triggered. %d failures recorded. Enforcing %ds cooldown.",
|
|
failures, LOCKOUT_SEC);
|
|
LOG_ERR("%s", log_msg);
|
|
|
|
for (int penalty_sec = LOCKOUT_SEC; penalty_sec > 0; penalty_sec--) {
|
|
char countdown[64];
|
|
snprintf(countdown, sizeof(countdown),
|
|
"DEVICE LOCKED DOWN\nRetry in: %d s", penalty_sec);
|
|
lv_label_set_text(status_label, countdown);
|
|
lv_obj_set_style_text_color(status_label,
|
|
lv_color_make(255, 0, 0), LV_PART_MAIN);
|
|
lv_timer_handler();
|
|
|
|
/* Check for back key during lockout to allow early exit */
|
|
struct input_event ev;
|
|
if (input_fd >= 0) {
|
|
int flags = fcntl(input_fd, F_GETFL, 0);
|
|
fcntl(input_fd, F_SETFL, flags | O_NONBLOCK);
|
|
if (read(input_fd, &ev, sizeof(struct input_event)) > 0) {
|
|
if (ev.type == EV_KEY && ev.code == H2_KEY_BACK && ev.value == 1) {
|
|
fcntl(input_fd, F_SETFL, flags);
|
|
return -1;
|
|
}
|
|
}
|
|
fcntl(input_fd, F_SETFL, flags);
|
|
}
|
|
sleep(1);
|
|
}
|
|
set_failure_count(0);
|
|
failures = 0;
|
|
}
|
|
|
|
render_pin_screen(MAX_FAILURES - failures);
|
|
|
|
/* PIN entry loop */
|
|
struct input_event ev;
|
|
while (current_digit_idx < 4) {
|
|
lv_timer_handler();
|
|
if (input_fd >= 0 && read(input_fd, &ev, sizeof(struct input_event)) > 0) {
|
|
if (ev.type == EV_REL && ev.code == H2_ROTARY_REL) {
|
|
if (ev.value > 0)
|
|
entered_pin[current_digit_idx] = (entered_pin[current_digit_idx] + 1) % 10;
|
|
else
|
|
entered_pin[current_digit_idx] = (entered_pin[current_digit_idx] - 1 + 10) % 10;
|
|
render_pin_screen(MAX_FAILURES - failures);
|
|
} else if (ev.type == EV_KEY && ev.code == H2_KEY_PLAY && ev.value == 1) {
|
|
current_digit_idx++;
|
|
if (current_digit_idx < 4) render_pin_screen(MAX_FAILURES - failures);
|
|
} else if (ev.type == EV_KEY && ev.code == H2_KEY_BACK && ev.value == 1) {
|
|
if (current_digit_idx > 0) {
|
|
current_digit_idx--;
|
|
render_pin_screen(MAX_FAILURES - failures);
|
|
}
|
|
}
|
|
}
|
|
usleep(5000);
|
|
}
|
|
|
|
/* Verify PIN */
|
|
if (memcmp(master_pin, entered_pin, sizeof(master_pin)) == 0) {
|
|
set_failure_count(0);
|
|
LOG_INF("PIN verified. Authorization granted.");
|
|
lv_label_set_text(status_label, "ACCESS GRANTED\nKEY INJECTED");
|
|
lv_obj_set_style_text_color(status_label, COLOR_ACCENT, LV_PART_MAIN);
|
|
lv_timer_handler();
|
|
sleep(2);
|
|
return 0;
|
|
} else {
|
|
failures++;
|
|
set_failure_count(failures);
|
|
char log_msg[128];
|
|
snprintf(log_msg, sizeof(log_msg),
|
|
"Invalid PIN attempt logged. Failure level: %d/%d",
|
|
failures, MAX_FAILURES);
|
|
LOG_ERR("%s", log_msg);
|
|
|
|
lv_label_set_text(status_label, "INVALID PIN\nATTEMPT LOGGED");
|
|
lv_obj_set_style_text_color(status_label,
|
|
lv_color_make(255, 0, 0), LV_PART_MAIN);
|
|
lv_timer_handler();
|
|
sleep(2);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int main(void) {
|
|
init_h2_graphics_runtime("CRYPTO VAULT GUARD");
|
|
LOG_INF("vault module started (full PIN auth mode)");
|
|
|
|
lv_obj_t *scr = lv_scr_act();
|
|
|
|
/* Title */
|
|
lv_obj_t *title = lv_label_create(scr);
|
|
lv_label_set_text(title, "SECURITY TOKEN VAULT");
|
|
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10);
|
|
lv_obj_set_style_text_color(title, COLOR_PRIMARY, LV_PART_MAIN);
|
|
lv_obj_set_style_text_font(title, &lv_font_montserrat_14, LV_PART_MAIN);
|
|
|
|
/* PIN entry card */
|
|
lv_obj_t *pin_card = lv_obj_create(scr);
|
|
lv_obj_set_size(pin_card, 280, 140);
|
|
lv_obj_align(pin_card, LV_ALIGN_CENTER, 0, -5);
|
|
|
|
lv_obj_t *pin_title = lv_label_create(pin_card);
|
|
lv_label_set_text(pin_title, "ENTER PIN");
|
|
lv_obj_align(pin_title, LV_ALIGN_TOP_MID, 0, 5);
|
|
lv_obj_set_style_text_color(pin_title, COLOR_MUTED, LV_PART_MAIN);
|
|
|
|
warning_label = lv_label_create(pin_card);
|
|
lv_obj_align(warning_label, LV_ALIGN_TOP_MID, 0, 22);
|
|
lv_obj_set_style_text_font(warning_label, &lv_font_montserrat_10, LV_PART_MAIN);
|
|
|
|
/* Four digit display boxes */
|
|
for (int i = 0; i < 4; i++) {
|
|
digit_labels[i] = lv_label_create(pin_card);
|
|
lv_label_set_text(digit_labels[i], "0");
|
|
lv_obj_set_style_text_font(digit_labels[i], &lv_font_montserrat_22, LV_PART_MAIN);
|
|
lv_obj_set_style_border_side(digit_labels[i],
|
|
LV_BORDER_SIDE_FULL, LV_PART_MAIN);
|
|
lv_obj_set_style_border_color(digit_labels[i], COLOR_MUTED, LV_PART_MAIN);
|
|
lv_obj_set_style_border_width(digit_labels[i], 1, LV_PART_MAIN);
|
|
lv_obj_set_style_pad_all(digit_labels[i], 8, LV_PART_MAIN);
|
|
lv_obj_align(digit_labels[i], LV_ALIGN_CENTER, -60 + (i * 40), -5);
|
|
}
|
|
|
|
/* Status area (used for lockout / result) */
|
|
status_label = lv_label_create(scr);
|
|
lv_label_set_text(status_label, "");
|
|
lv_obj_set_style_text_font(status_label, &lv_font_montserrat_12, LV_PART_MAIN);
|
|
lv_obj_align(status_label, LV_ALIGN_BOTTOM_MID, 0, -30);
|
|
|
|
/* Mode indicator */
|
|
mode_label = lv_label_create(scr);
|
|
lv_obj_align(mode_label, LV_ALIGN_BOTTOM_LEFT, 8, -8);
|
|
lv_obj_set_style_text_color(mode_label, COLOR_MUTED, LV_PART_MAIN);
|
|
lv_obj_set_style_text_font(mode_label, &lv_font_montserrat_10, LV_PART_MAIN);
|
|
lv_label_set_text(mode_label, "[WHEEL] Digit [PLAY] Next [BACK] Exit");
|
|
|
|
/* Open input */
|
|
int input_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK);
|
|
if (input_fd < 0) {
|
|
LOG_ERR("cannot open input device");
|
|
return 1;
|
|
}
|
|
|
|
/* Run PIN authorization */
|
|
int auth_result = enforce_pin_authorization(input_fd);
|
|
if (auth_result != 0) {
|
|
close(input_fd);
|
|
LOG_INF("vault module exited (auth failed)");
|
|
return 0;
|
|
}
|
|
|
|
/* Authorized: enter runtime mode loop */
|
|
while (1) {
|
|
lv_timer_handler();
|
|
|
|
int usb_active = is_usb_plugged_in();
|
|
|
|
if (usb_active) {
|
|
if (current_mode != MODE_WIRED) {
|
|
LOG_INF("switching to WIRED mode");
|
|
system("hciconfig hci0 down 2>/dev/null");
|
|
system("/usr/bin/enable_vault_usb.sh 2>/dev/null");
|
|
current_mode = MODE_WIRED;
|
|
}
|
|
lv_label_set_text(status_label, "MODE: SECURE WIRED SMARTCARD\nUSB Token: Operational (CCID)");
|
|
lv_obj_set_style_text_color(status_label,
|
|
lv_color_make(0, 68, 136), LV_PART_MAIN);
|
|
} else {
|
|
if (current_mode != MODE_WIRELESS) {
|
|
LOG_INF("switching to WIRELESS BLE mode");
|
|
system("echo \"\" > /sys/kernel/config/usb_gadget/wh_tool/UDC 2>/dev/null");
|
|
system("/usr/bin/enable_vault_ble.sh 2>/dev/null");
|
|
current_mode = MODE_WIRELESS;
|
|
}
|
|
lv_label_set_text(status_label, "MODE: WIRELESS BLE SMARTCARD\nBLE Identity: Active");
|
|
lv_obj_set_style_text_color(status_label,
|
|
lv_color_make(0, 204, 68), LV_PART_MAIN);
|
|
}
|
|
|
|
/* Check for BACK to exit and purge */
|
|
struct input_event ev;
|
|
if (input_fd >= 0 && read(input_fd, &ev, sizeof(struct input_event)) > 0) {
|
|
if (ev.type == EV_KEY && ev.code == H2_KEY_BACK && ev.value == 1) {
|
|
lv_label_set_text(status_label, "Purging keys from RAM... Locking.");
|
|
lv_obj_set_style_text_color(status_label,
|
|
lv_color_make(255, 0, 0), LV_PART_MAIN);
|
|
lv_timer_handler();
|
|
LOG_INF("vault key purge triggered by user");
|
|
sleep(1);
|
|
break;
|
|
}
|
|
}
|
|
usleep(200000);
|
|
}
|
|
|
|
close(input_fd);
|
|
LOG_INF("vault module exited");
|
|
return 0;
|
|
} |