:: commit 2a4cbcecc04a0d9b476c9adb99f02ecebaf55d0a

czapek1337 <czapek1337@gmail.com> — 2022-09-11 18:47

parents: 5a6cc57773

uri: Add checksum validation

diff --git a/common/lib/misc.h b/common/lib/misc.h
index 17ce04d2..a85e89fc 100644
--- a/common/lib/misc.h
+++ b/common/lib/misc.h
@@ -33,7 +33,7 @@ extern struct volume *boot_volume;
 extern bool stage3_loaded;
 #endif
 
-extern bool quiet, serial, editor_enabled;
+extern bool quiet, serial, editor_enabled, hash_mismatch_panic;
 
 bool parse_resolution(size_t *width, size_t *height, size_t *bpp, const char *buf);
 
diff --git a/common/lib/misc.s2.c b/common/lib/misc.s2.c
index 9c69e0cc..da5c7e8a 100644
--- a/common/lib/misc.s2.c
+++ b/common/lib/misc.s2.c
@@ -6,6 +6,7 @@
 bool verbose = false;
 bool quiet = false;
 bool serial = false;
+bool hash_mismatch_panic = false;
 
 uint8_t bcd_to_int(uint8_t val) {
     return (val & 0x0f) + ((val & 0xf0) >> 4) * 10;
diff --git a/common/lib/uri.c b/common/lib/uri.c
index e3517fff..3d6e177a 100644
--- a/common/lib/uri.c
+++ b/common/lib/uri.c
@@ -9,10 +9,13 @@
 #include <lib/print.h>
 #include <pxe/tftp.h>
 #include <tinf.h>
+#include <menu.h>
+#include <lib/readline.h>
+#include <crypt/blake2b.h>
 
-// A URI takes the form of: resource://root/path
+// A URI takes the form of: resource://root/path#hash
 // The following function splits up a URI into its componenets
-bool uri_resolve(char *uri, char **resource, char **root, char **path) {
+bool uri_resolve(char *uri, char **resource, char **root, char **path, char **hash) {
     size_t length = strlen(uri) + 1;
     char *buf = ext_mem_alloc(length);
     memcpy(buf, uri, length);
@@ -51,6 +54,31 @@ bool uri_resolve(char *uri, char **resource, char **root, char **path) {
         return false;
     *path = uri;
 
+    // Get hash
+    for (int i = (int)strlen(uri) - 1; i >= 0; i--) {
+        if (uri[i] != '#') {
+            continue;
+        }
+
+        uri[i++] = 0;
+
+        if (hash != NULL) {
+            *hash = uri + i;
+        }
+
+        if (strlen(uri + i) != 128) {
+            panic(true, "Blake2b hash must be 128 characters long");
+            return false;
+        }
+
+        break;
+    }
+
+    for (size_t i = 0; ; i++) {
+        if (uri[i] == 0)
+            break;
+    }
+
     return true;
 }
 
@@ -190,8 +218,10 @@ static struct file_handle *uri_boot_dispatch(char *s_part, char *path) {
 struct file_handle *uri_open(char *uri) {
     struct file_handle *ret;
 
-    char *resource, *root, *path;
-    uri_resolve(uri, &resource, &root, &path);
+    char *resource = NULL, *root = NULL, *path = NULL, *hash = NULL;
+    if (!uri_resolve(uri, &resource, &root, &path, &hash)) {
+        return NULL;
+    }
 
     if (resource == NULL) {
         panic(true, "No resource specified for URI `%#`.", uri);
@@ -225,6 +255,32 @@ struct file_handle *uri_open(char *uri) {
         panic(true, "Resource `%s` not valid.", resource);
     }
 
+    if (hash != NULL && ret != NULL) {
+        uint8_t out_buf[BLAKE2B_OUT_BYTES];
+        void *file_buf = freadall(ret, MEMMAP_BOOTLOADER_RECLAIMABLE);
+        blake2b(out_buf, file_buf, ret->size);
+        uint8_t hash_buf[BLAKE2B_OUT_BYTES];
+
+        for (size_t i = 0; i < sizeof(hash_buf); i++) {
+            hash_buf[i] = digit_to_int(hash[i * 2]) << 4 | digit_to_int(hash[i * 2 + 1]);
+        }
+
+        if (memcmp(hash_buf, out_buf, sizeof(out_buf)) != 0) {
+            if (hash_mismatch_panic) {
+                panic(true, "Blake2b hash for URI `%#` does not match!", uri);
+            } else {
+                print("WARNING: Blake2b hash for URI `%#` does not match!\n"
+                        "         Press Y to continue, press any other key otherwise...", uri);
+
+                char ch = getchar();
+                if (ch != 'Y' && ch != 'y') {
+                    menu(false);
+                }
+                print("\n");
+            }
+        }
+    }
+
     if (compressed && ret != NULL) {
         struct file_handle *compressed_fd = ext_mem_alloc(sizeof(struct file_handle));
         fread(ret, &compressed_fd->size, ret->size - 4, sizeof(uint32_t));
diff --git a/common/lib/uri.h b/common/lib/uri.h
index a883a53a..4f15907a 100644
--- a/common/lib/uri.h
+++ b/common/lib/uri.h
@@ -4,7 +4,7 @@
 #include <stdbool.h>
 #include <fs/file.h>
 
-bool uri_resolve(char *uri, char **resource, char **root, char **path);
+bool uri_resolve(char *uri, char **resource, char **root, char **path, char **hash);
 struct file_handle *uri_open(char *uri);
 
 #endif
diff --git a/common/menu.c b/common/menu.c
index 4977c33c..6fcbad26 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -653,6 +653,9 @@ noreturn void _menu(bool first_run) {
     char *serial_str = config_get_value(NULL, 0, "SERIAL");
     serial = serial_str != NULL && strcmp(serial_str, "yes") == 0;
 
+    char *hash_mismatch_panic_str = config_get_value(NULL, 0, "HASH_MISMATCH_PANIC");
+    hash_mismatch_panic = hash_mismatch_panic_str == NULL || strcmp(hash_mismatch_panic_str, "yes") == 0;
+
     char *randomise_mem_str = config_get_value(NULL, 0, "RANDOMISE_MEMORY");
     if (randomise_mem_str == NULL)
         randomise_mem_str = config_get_value(NULL, 0, "RANDOMIZE_MEMORY");
tab: 248 wrap: offon