recovery-utils: add support to set the rootfs encryption key

Internal recovery-utils.git SHA1: 283f6e0768c0

https://jira.digi.com/browse/DEL-3857

Signed-off-by: Tatiana Leon <tatiana.leon@digi.com>
This commit is contained in:
Tatiana Leon 2017-03-14 18:01:02 +01:00
parent d7da8794f1
commit c4bd0534e2
3 changed files with 141 additions and 8 deletions

View File

@ -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 */

View File

@ -19,6 +19,7 @@
#define _GNU_SOURCE /* For GNU version of basename */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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;
}

View File

@ -26,7 +26,7 @@
#include <recovery.h>
#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] [<SWU-package-path>]\n\n" \
" -u --update-firmware Perform firmware update\n" \
" -w --wipe-update-partition Wipe 'update' partition\n" \
" -T --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" --help Print help and exit\n" \
" -u --update-firmware Perform firmware update\n" \
" -k[<key>] --encryption-key[=<key>] Set <key> 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<N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" --help Print help and exit\n" \
"\n" \
"<SWU-package-path> Absolute path to the firmware update package\n" \
"\n"
@ -55,8 +58,10 @@
"Version: %s\n" \
"\n" \
"Usage: %s [options] <SWU-package-path>\n\n" \
" -T --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" --help Print help and exit\n" \
" -k[<key>] --encryption-key[=<key>] Set <key> as file system encryption key.\n" \
" Empty to generate a random key.\n" \
" -T<N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" --help Print help and exit\n" \
"\n" \
"<SWU-package-path> 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);