diff --git a/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/include/recovery.h b/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/include/recovery.h index 4f7dfddb3..329193542 100644 --- a/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/include/recovery.h +++ b/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/include/recovery.h @@ -47,4 +47,14 @@ int reboot_recovery(unsigned int reboot_timeout); */ int wipe_update_partition(void); +/* + * Configure recovery commands to set a file system encryption key. + * + * Params: + * 'key' (input) Encryption key to use, NULL or empty to generate a random one + * + * Return: 0 on sucess, -1 on failure + */ +int set_fs_encryption_key(char *key); + #endif /* RECOVERY_H */ diff --git a/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/lib/recovery.c b/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/lib/recovery.c index 6f0e232b5..59b46a98d 100644 --- a/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/lib/recovery.c +++ b/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/lib/recovery.c @@ -19,6 +19,7 @@ #define _GNU_SOURCE /* For GNU version of basename */ +#include #include #include #include @@ -29,6 +30,18 @@ #define FILE_PREFIX "file://" +#define OTP_CLOSED_BIT 2 + +/* Plain key size */ +#define KEYSIZE_BYTES 32 /* 256 bits */ + +/* + * Base64 encoded string size + * + * https://en.wikipedia.org/wiki/Base64#Padding + */ +#define BASE64_SIZE_BYTES(x) (4 * ((x + (3 - 1)) / 3)) + /* * Function: append_recovery_command * Description: append configuration to the 'recovery_command' variable @@ -75,6 +88,41 @@ err: return ret ? -1 : 0; } +/* + * Function: is_device_closed + * Description: check if the device is closed + */ +static int is_device_closed(void) +{ + const char *path = "/sys/fsl_otp/HW_OCOTP_CFG5"; + FILE *fd = NULL; + unsigned int value = 0; + long open = 0; + + if ((fd = fopen(path, "r")) == NULL) { + fprintf(stderr, "Cannot check device status. Assuming closed...\n"); + return 1; + } + + open = (fscanf(fd, "%x", &value) == 1) && (value & OTP_CLOSED_BIT); + + fclose(fd); + + return open; +} + +/* + * Function: secure_memzero + * Description: secure memzero that is not optimized out by the compiler + */ +void secure_memzero(void *buf, size_t len) +{ + volatile uint8_t *p = (volatile uint8_t *)buf; + + while (len--) + *p++ = 0; +} + /* * Function: update_firmware * Description: configure recovery commands to update the firmware @@ -153,3 +201,52 @@ int wipe_update_partition(void) { return append_recovery_command("wipe_update"); } + +/* + * Function: set_fs_encryption_key + * Description: configure recovery commands to set a file system encryption key + */ +int set_fs_encryption_key(char *key) +{ + char *key_cmd = NULL; + int generate_random_key = 0; + int ret = -1; + + generate_random_key = (!key || strlen(key) == 0); + + if (!generate_random_key && + BASE64_SIZE_BYTES(KEYSIZE_BYTES) != strlen(key)) { + fprintf(stderr, "Error: invalid key size\n"); + goto err; + } + + if (!is_device_closed()) { + printf("\n" + " *****************************************************************\n" + " * Warning: Use filesystem encryption only on CLOSED devices. *\n" + " * Filesystem encryption on open devices is not secure. *\n" + " *****************************************************************\n"); + } + + key_cmd = + calloc(1, + strlen("encryption_key=") + + (generate_random_key ? 0 : strlen(key)) + 1); + if (!key_cmd) { + fprintf(stderr, "Error: calloc 'key_cmd'\n"); + goto err; + } + + sprintf(key_cmd, "encryption_key=%s", generate_random_key ? "" : key); + + ret = append_recovery_command(key_cmd); + + free(key_cmd); + +err: + /* Secure delete the key buffers */ + if (!generate_random_key) + secure_memzero(key, strlen(key)); + + return ret ? -1 : 0; +} diff --git a/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/recovery-reboot/recovery-reboot.c b/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/recovery-reboot/recovery-reboot.c index d1e49bd44..f14b80368 100644 --- a/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/recovery-reboot/recovery-reboot.c +++ b/meta-digi-dey/recipes-core/recovery/recovery-utils/recovery-utils/recovery-reboot/recovery-reboot.c @@ -26,7 +26,7 @@ #include -#define VERSION "0.1" GIT_REVISION +#define VERSION "0.2" GIT_REVISION #define REBOOT_TIMEOUT 10 @@ -40,10 +40,13 @@ "Version: %s\n" \ "\n" \ "Usage: %s [options] []\n\n" \ - " -u --update-firmware Perform firmware update\n" \ - " -w --wipe-update-partition Wipe 'update' partition\n" \ - " -T --reboot-timeout= Reboot after N seconds (default %d)\n" \ - " --help Print help and exit\n" \ + " -u --update-firmware Perform firmware update\n" \ + " -k[] --encryption-key[=] Set as file system encryption key.\n" \ + " Empty to generate a random key.\n" \ + " Use this option along with update firmware option (-u).\n" \ + " -w --wipe-update-partition Wipe 'update' partition\n" \ + " -T --reboot-timeout= Reboot after N seconds (default %d)\n" \ + " --help Print help and exit\n" \ "\n" \ " Absolute path to the firmware update package\n" \ "\n" @@ -55,8 +58,10 @@ "Version: %s\n" \ "\n" \ "Usage: %s [options] \n\n" \ - " -T --reboot-timeout= Reboot after N seconds (default %d)\n" \ - " --help Print help and exit\n" \ + " -k[] --encryption-key[=] Set as file system encryption key.\n" \ + " Empty to generate a random key.\n" \ + " -T --reboot-timeout= Reboot after N seconds (default %d)\n" \ + " --help Print help and exit\n" \ "\n" \ " Absolute path to the firmware update package\n" \ "\n" @@ -69,8 +74,10 @@ static char *cmd_name; /* Command line options */ static char *swu_package; +static char *key = NULL; static int wipe_update; static int update_fw; +static int set_key; static int reboot_timeout = REBOOT_TIMEOUT; /* @@ -96,9 +103,10 @@ static void usage_and_exit(int exitval) static void parse_options(int argc, char *argv[]) { static int opt_index, opt; - static const char *short_options = "uwT:"; + static const char *short_options = "uk::wT:"; static const struct option long_options[] = { {"update-firmware", no_argument, NULL, 'u'}, + {"encryption-key", optional_argument, NULL, 'k'}, {"wipe-update-partition", no_argument, NULL, 'w'}, {"reboot-timeout", required_argument, NULL, 'T'}, {"help", no_argument, NULL, 'h'}, @@ -123,6 +131,11 @@ static void parse_options(int argc, char *argv[]) case 'w': wipe_update = 1; break; + case 'k': + set_key = 1; + if (optarg) + key = optarg; + break; case 'T': reboot_timeout = (int)strtol(optarg, &endptr, 10); if (*endptr) { @@ -152,6 +165,10 @@ static void parse_options(int argc, char *argv[]) printf("Error: missing SWU package argument\n"); exit(EXIT_FAILURE); } + } else if (set_key) { + /* Always need to update firmware when setting a new key */ + printf("Error: encryption key can only be set while performing a firmware update\n"); + exit(EXIT_FAILURE); } } @@ -168,6 +185,15 @@ int main(int argc, char *argv[]) /* Read and parse command line */ parse_options(argc, argv); + if (set_key) { + /* Configure recovery commands to set a fs encryption key */ + ret = set_fs_encryption_key(key); + if (ret) { + printf("Error: set_fs_encryption_key\n"); + goto out; + } + } + if (swu_package) { /* Configure recovery commands to update the firmware */ ret = update_firmware(swu_package);