recovery-utils: add partition encryption support

Add a new function to the recovery library to be able to encrypt/unencrypt any
partition on the internal storage media. Since it's a destructive operation,
add a warning message and a confirmation prompt that can be skipped if needed.

Reflect this new functionality in the recovery-reboot app. Change the logic so
that an encryption key can be set even if there's no update package, because
now it's possible to encrypt other partitions while leaving the rootfs intact.
Also change the logic so that the app doesn't reboot into recovery mode if
there's no recovery command set.

Implement the same blacklist as the one in the recovery script.

https://onedigi.atlassian.net/browse/DEL-7174

Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
This commit is contained in:
Gabriel Valcazar 2021-05-03 11:56:37 +02:00
parent deaeef6c6d
commit d54510766a
4 changed files with 717 additions and 40 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Digi International Inc.
* Copyright (c) 2017-2021, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -48,13 +48,25 @@ int reboot_recovery(unsigned int reboot_timeout);
int wipe_update_partition(void);
/*
* Configure recovery commands to set a file system encryption key.
* Configure recovery commands to set a partition 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);
int set_encryption_key(char *key);
/*
* Configure recovery commands to encrypt/un-encrypt provided partitions.
*
* Params:
* 'to_encrypt' (input) Comma-separated list of partitions to be encrypted
* 'to_unencrypt' (input) Comma-separated list of partition names to be un-encrypted
* 'force' (input) Skips warning and confirmation prompt if non-zero
*
* Return: 0 on sucess, -1 on failure and 1 on success with no recovery command set
*/
int encrypt_partitions(char *to_encrypt, char *to_unencrypt, unsigned char force);
#endif /* RECOVERY_H */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Digi International Inc.
* Copyright (c) 2017-2021, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -42,6 +42,34 @@
*/
#define BASE64_SIZE_BYTES(x) (4 * ((x + (3 - 1)) / 3))
/* 20 partitions + 1 NULL array terminator */
#define MAX_PARTITIONS (20 + 1)
#define MAX_LIST_LEN 2048
/* Shell command used to obtain the eMMC partition list */
#define EMMC_FDISK_CMD "fdisk -l /dev/mmcblk0 | grep '^ *' | rev | cut -d ' ' -f1 | rev"
#define MAX_PART_NAME_LENGTH 64
#define PARTS_BLACKLIST is_device_nand() ? nand_parts_blacklist : emmc_parts_blacklist
#define PARSE_PARTITION_INFO(x, y, z) \
is_device_nand() ? parse_nand_partition_info(x, y, z) : parse_emmc_partition_info(x, y, z)
static char *nand_parts_blacklist[] = {
"bootloader",
"environment",
"linux",
"recovery",
"safe",
NULL
};
static char *emmc_parts_blacklist[] = {
"linux",
"recovery",
"safe",
NULL
};
/*
* Function: append_recovery_command
* Description: append configuration to the 'recovery_command' variable
@ -105,6 +133,417 @@ static int is_device_closed(void)
return 0;
}
/*
* Function: is_device_nand
* Description: check if the device's storage is NAND/MTD
*/
static int is_device_nand(void)
{
const char *path_mtd = "/proc/mtd";
if (access(path_mtd, F_OK) != -1)
return 1;
return 0;
}
/*
* Function: print_open_device_warning
* Description: print a warning if device isn't closed
*/
static void print_open_device_warning(void)
{
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");
}
}
/*
* Function: remove_entry
* Description: remove a specific entry from a NULL-terminated array
*/
static void remove_entry(char **array, unsigned char index)
{
free(array[index]);
array[index] = array[index+1];
while (array[index++])
array[index] = array[index+1];
}
/*
* Function: subtract_array
* Description: remove the entries of a NULL-terminated array from another NULL-terminated array
*/
static void subtract_array(char **subtract, char **from)
{
unsigned char i, j;
i = 0;
while (from[i]) {
j = 0;
while(subtract[j]) {
if (!strcmp(subtract[j], from[i])) {
remove_entry(from, i);
break;
}
j++;
}
if (subtract[j])
continue;
i++;
}
}
/*
* Function: add_array
* Description: add the entries of a NULL-terminated array to the end of another NULL-terminated array
*/
static int add_array(char **add, char **to, unsigned char limit)
{
unsigned char i = 0, j = 0;
/* Get to the end of 'to' */
while (to[i])
i++;
/* Add all 'add' entries to the end of 'to' */
while (add[j] && i < (limit - 1)) {
to[i] = strdup(add[j++]);
if (!to[i++])
return -1;
}
to[i] = NULL;
if (i == (limit - 1) && add[j])
return -1;
return 0;
}
/*
* Function: modify_array
* Description: add and remove NULL-terminated array entries from another NULL-terminated array
*/
static int modify_array(char **target, char **to_add, char **to_remove, unsigned char limit)
{
/* Remove the entries in 'to_add' that are already in 'target' */
subtract_array(target, to_add);
/* Remove the 'to_remove' entries from 'target' */
subtract_array(to_remove, target);
/* Add 'to_add' to 'target' while respecting the limit */
return add_array(to_add, target, limit);
}
/*
* Function: entry_exists
* Description: check if a string is an entry in a NULL-terminated array
*/
static int entry_exists(char *entry, char **array)
{
unsigned char i = 0;
while (array[i]) {
if (!strcmp(entry, array[i++]))
return 1;
}
return 0;
}
/*
* Function: is_subset
* Description: check if a NULL-terminated array is a subset of another NULL-terminated array
*/
static int is_subset(char **subset, char **set)
{
unsigned char i = 0;
/* Return 1 if and only if all subset entries are in set */
while (subset[i]) {
if (!entry_exists(subset[i++], set))
return 0;
}
return 1;
}
/*
* Function: list_to_array
* Description: convert a list into a NULL-terminated string array, while checking against a blacklist and a superset
*/
static int list_to_array(char *list, char **array, char **blacklist,
char **superset, const char *delim, unsigned char limit)
{
char *tmp = NULL;
char *entry = NULL;
int ret = -1;
unsigned char i = 0;
unsigned char j;
if (!list)
return 0;
tmp = strdup(list);
if (!tmp)
return -1;
/* Tokenize the list and iterate through it to build the array */
entry = strtok(tmp, delim);
while (entry && i < (limit - 1)) {
/* If entry is in the blacklist, print a warning and discard it */
if (blacklist && entry_exists(entry, blacklist)) {
printf("Warning: encryption of partition '%s' is forbidden, skipping\n",
entry);
entry = strtok(NULL, delim);
continue;
}
/* If entry isn't a part of the superset, exit with an error */
if (superset && !entry_exists(entry, superset)) {
fprintf(stderr, "Error: partition '%s' doesn't exist\n", entry);
goto err;
}
array[i] = strdup(entry);
if (!array[i++])
goto err;
entry = strtok(NULL, delim);
}
/* Return an error if the number of entries surpasses the limit */
if (entry && i == (limit - 1))
goto err;
array[i] = NULL;
ret = 0;
/* Remove duplicate entries */
i = 0;
while (array[i]) {
j = i+1;
while (array[j]) {
if (!strcmp(array[j], array[i])) {
remove_entry(array, j);
continue;
}
j++;
}
i++;
}
err:
array[i] = NULL;
free(tmp);
return ret;
}
/*
* Function: array_to_list
* Description: convert a non-empty NULL-terminated string array to a list
*/
static char *array_to_list(char **array, const char delim, unsigned int limit)
{
char *list;
char *tmp;
unsigned char i = 0;
unsigned int len;
/* Obtain the total length of the list to allocate the exact string size */
len = 0;
while (array[i])
len += strlen(array[i++]) + 1;
/* Make sure that we don't surpass the character limit */
if (len > limit)
return NULL;
list = calloc(1, len);
if (!list)
return NULL;
/* Iterate through the array to build the list */
i = 0;
tmp = list;
while (array[i]) {
len = strlen(array[i]);
memcpy(tmp, array[i], len);
tmp += len;
if (array[++i]) {
*tmp = delim;
tmp++;
}
}
*tmp = '\0';
return list;
}
/*
* Function: free_array
* Description: free all entries in a NULL-terminated string array
*/
static inline void free_array(char **array)
{
unsigned char i = 0;
while (array[i])
free(array[i++]);
}
/*
* Function: parse_nand_partition_info
* Description: puts the NAND partition and encrypted partition lists into NULL-terminated arrays
*/
static int parse_nand_partition_info(char **parts, char **encrypted, unsigned char limit)
{
const char *var;
char *tmp;
char *entry;
char *start;
char *end;
int ret;
unsigned char i = 0, j = 0;
/* Parse mtdparts for all partition info */
ret = uboot_getenv("mtdparts", &var);
if (ret) {
fprintf(stderr, "Error: getenv 'mtdparts'\n");
return ret;
}
tmp = strdup(var);
if (!tmp)
return -1;
ret = -1;
/* Discard first part of mtdparts to get the partition list */
entry = strtok(tmp, ":");
/*
* Parse the partition names from each mtdparts entry.
* Expected entry format is:
*
* <size>(<name>)[enc]
*/
entry = strtok(NULL, ",");
while (entry && i < (limit - 1)) {
start = strchr(entry, '(');
if (!start)
goto err;
start++;
end = strchr(entry, ')');
if (!end)
goto err;
parts[i] = calloc(1, (end - start) + 1);
if (!parts[i])
goto err;
strncpy(parts[i], start, end - start);
parts[i++][end - start] = '\0';
/* If the encryption flag is found, add the part to the encrypted list */
if (strstr(entry, ")enc")) {
encrypted[j] = strdup(parts[i-1]);
if (!encrypted[j++])
goto err;
}
entry = strtok(NULL, ",");
}
/* Return an error if the number of entries surpasses the limit */
if (entry && i == (limit - 1))
goto err;
ret = 0;
err:
if (tmp)
free(tmp);
/* NULL-terminate the arrays */
parts[i] = NULL;
encrypted[j] = NULL;
return ret ? -1 : 0;
}
/*
* Function: parse_emmc_partition_info
* Description: puts the eMMC partition and encrypted partition lists into NULL-terminated arrays
*/
static int parse_emmc_partition_info(char **parts, char **encrypted, unsigned char limit)
{
FILE *fp = NULL;
const char *var;
char *tmp;
char *end;
int ret;
unsigned char i = 0;
/*
* For now, obtain eMMC partition list via the
* "fdisk -l" command, just like we do in the recovery
* script.
*/
fp = popen(EMMC_FDISK_CMD, "r");
if (!fp)
return -1;
ret = -1;
tmp = calloc(1, MAX_PART_NAME_LENGTH);
if (!tmp)
goto err;
/* Entries have a newline character at the end, make sure to remove it */
while (i < (limit - 1) && fgets(tmp, MAX_PART_NAME_LENGTH, fp) != NULL) {
end = strchr(tmp, '\n');
parts[i] = calloc(1, (end - tmp) + 1);
if (!parts[i])
goto err;
strncpy(parts[i], tmp, (end - tmp));
parts[i++][end - tmp] = '\0';
}
/* Return an error if the number of partitions surpasses the limit */
if (i == (limit - 1) && fgets(tmp, MAX_PART_NAME_LENGTH, fp) != NULL)
goto err;
/* Obtain encrypted partition list from the environment */
ret = uboot_getenv("encrypted_parts_list", &var);
if (ret) {
fprintf(stderr, "Error: getenv 'encrypted_parts_list'\n");
goto err;
}
/*
* If non-existing partitions have been added by hand to
* encrypted_parts_list, the process will fail at this point.
*/
ret = list_to_array(var, encrypted, emmc_parts_blacklist, parts, " ", limit);
err:
if (fp)
pclose(fp);
if (tmp)
free(tmp);
/* NULL-terminate the parts array */
parts[i] = NULL;
return ret ? -1 : 0;
}
/*
* Function: secure_memzero
* Description: secure memzero that is not optimized out by the compiler
@ -198,10 +637,10 @@ int wipe_update_partition(void)
}
/*
* Function: set_fs_encryption_key
* Description: configure recovery commands to set a file system encryption key
* Function: set_encryption_key
* Description: configure recovery commands to set a partition encryption key
*/
int set_fs_encryption_key(char *key)
int set_encryption_key(char *key)
{
char *key_cmd = NULL;
int generate_random_key = 0;
@ -215,13 +654,7 @@ int set_fs_encryption_key(char *key)
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");
}
print_open_device_warning();
key_cmd =
calloc(1,
@ -245,3 +678,169 @@ err:
return ret ? -1 : 0;
}
/*
* Function: encrypt_partitions
* Description: configure recovery commands to encrypt/un-encrypt provided partitions
*/
int encrypt_partitions(char *to_encrypt, char *to_unencrypt, unsigned char force)
{
char *parts[MAX_PARTITIONS];
char *encrypted[MAX_PARTITIONS];
char *new_encrypted[MAX_PARTITIONS];
char *enc_diff[MAX_PARTITIONS];
char *unenc_diff[MAX_PARTITIONS];
char *true_unenc_diff[MAX_PARTITIONS];
char *new_list = NULL;
char *cmd = NULL;
char confirmation;
unsigned char i = 0;
int ret;
/* If both lists are empty, we have nothing to do */
if (!to_encrypt && !to_unencrypt)
return 1;
/* Initialize arrays */
parts[0] = NULL;
encrypted[0] = NULL;
enc_diff[0] = NULL;
unenc_diff[0] = NULL;
true_unenc_diff[0] = NULL;
new_encrypted[0] = NULL;
/* Get current partition info */
ret = PARSE_PARTITION_INFO(parts, encrypted, MAX_PARTITIONS);
if (ret) {
fprintf(stderr, "Error: parse_partition_info\n");
goto err;
}
/* Transform the lists into arrays for easier processing */
ret = list_to_array(to_encrypt, enc_diff, PARTS_BLACKLIST, parts, ",", MAX_PARTITIONS);
if (ret) {
fprintf(stderr, "Error: list_to_array 'to_encrypt'\n");
goto err;
}
ret = list_to_array(to_unencrypt, unenc_diff, NULL, parts, ",", MAX_PARTITIONS);
if (ret) {
fprintf(stderr, "Error: list_to_array 'to_unencrypt'\n");
goto err;
}
/* If both diffs are empty, return immediately. */
if (!enc_diff[0] && !unenc_diff[0]) {
ret = 1;
goto err;
}
/*
* Create a copy of the encrypted parts array. We know the copy won't
* surpass the limit, but check the return code in case of a strdup()
* failure.
*/
ret = add_array(encrypted, new_encrypted, MAX_PARTITIONS);
if (ret) {
fprintf(stderr, "Error: add_array 'new_encrypted'\n");
goto err;
}
/* Build the new array of encrypted parts using the diffs */
ret = modify_array(new_encrypted, enc_diff, unenc_diff, MAX_PARTITIONS);
if (ret) {
fprintf(stderr, "Error: modify_array\n");
goto err;
}
/*
* If the new encrypted parts array is equal to the old one, there's
* no need to set the recovery command, so return immediately.
*/
if (is_subset(encrypted, new_encrypted) && is_subset(new_encrypted, encrypted)) {
ret = 1;
goto err;
}
print_open_device_warning();
/*
* At this point, we know that we have at least one partition to
* (un)encrypt, so ask for confirmation before continuing.
*/
if (!force) {
/*
* Even though the unenc_diff list is sanitized at this
* point, it might contain partitions that are already
* unencrypted. Calculate the true diff between the current
* list and the new one.
*/
ret = add_array(encrypted, true_unenc_diff, MAX_PARTITIONS);
if (ret) {
fprintf(stderr, "Error: add_array 'true_unenc_diff'\n");
goto err;
}
subtract_array(new_encrypted, true_unenc_diff);
printf("\n"
" *****************************************************************\n"
" * Warning: Partition (un)encryption is a destructive operation. *\n"
" * The affected partitions' contents will be erased in *\n"
" * the process. *\n"
" *****************************************************************\n"
" Affected partitions:\n");
while (enc_diff[i])
printf(" %s\n", enc_diff[i++]);
i = 0;
while (true_unenc_diff[i])
printf(" %s\n", true_unenc_diff[i++]);
printf("\n Continue? (y/n): ");
confirmation = getchar();
if (confirmation != 'y' && confirmation != 'Y') {
printf("\nSkipping (un)encryption of partitions\n");
ret = 1;
goto err;
}
}
ret = -1;
/* Create comma-separated list from the encrypted parts array */
if (new_encrypted[0]) {
new_list = array_to_list(new_encrypted, ',', MAX_LIST_LEN);
if (!new_list) {
fprintf(stderr, "Error: array_to_list\n");
goto err;
}
}
cmd = calloc(1,
strlen("encrypt_partitions=") +
(new_list ? strlen(new_list) : 0) + 1);
if (!cmd) {
fprintf(stderr, "Error: calloc 'cmd'\n");
goto err_cmd;
}
sprintf(cmd, "encrypt_partitions=%s", new_list ? new_list : "");
ret = append_recovery_command(cmd);
free(cmd);
err_cmd:
if (new_list)
free(new_list);
err:
free_array(enc_diff);
free_array(unenc_diff);
free_array(true_unenc_diff);
free_array(new_encrypted);
free_array(encrypted);
free_array(parts);
return ret < 0 ? -1 : ret;
}

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, Digi International Inc.
# Copyright (c) 2017-2021, Digi International Inc.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
@ -41,6 +41,7 @@ install: $(PROGRAM)
install -d $(DESTDIR)/usr/bin
install -m 0755 $(PROGRAM) $(DESTDIR)/usr/bin/
ln -sf $(PROGRAM) $(DESTDIR)/usr/bin/update-firmware
ln -sf $(PROGRAM) $(DESTDIR)/usr/bin/encrypt-partitions
.PHONY: clean
clean:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Digi International Inc.
* Copyright (c) 2017-2021, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -26,12 +26,13 @@
#include <recovery.h>
#define VERSION "0.2" GIT_REVISION
#define VERSION "0.3" GIT_REVISION
#define REBOOT_TIMEOUT 10
#define CMD_RECOVERY "recovery-reboot"
#define CMD_UPDATEFW "update-firmware"
#define CMD_ENCRYPT "encrypt-partitions"
#define RECOVERY_USAGE \
"Reboot into recovery mode setting recovery commands.\n" \
@ -40,13 +41,15 @@
"Version: %s\n" \
"\n" \
"Usage: %s [options] [<SWU-package-path>]\n\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" \
" -u --update-firmware Perform firmware update\n" \
" -e <partitions> --encrypt=<partitions> Encrypt the list of provided partitions.\n" \
" -d <partitions> --unencrypt=<partitions> Un-encrypt the list of provided partitions.\n" \
" -k [<key>] --encryption-key[=<key>] Set <key> as file system encryption key.\n" \
" Empty to generate a random key.\n" \
" -w --wipe-update-partition Wipe 'update' partition\n" \
" -T <N> --reboot-timeout=<N> Reboot after N seconds (default %d)\n" \
" -f --force Force (un)encryption operations.\n" \
" --help Print help and exit\n" \
"\n" \
"<SWU-package-path> Absolute path to the firmware update package\n" \
"\n"
@ -58,16 +61,33 @@
"Version: %s\n" \
"\n" \
"Usage: %s [options] <SWU-package-path>\n\n" \
" -k[<key>] --encryption-key[=<key>] Set <key> as file system encryption key.\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" \
" -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"
/* Check if application was called as update-firmware */
#define ENCRYPT_USAGE \
"Encrypt/unencrypt partitions using the recovery reboot.\n" \
"Copyright(c) Digi International Inc.\n" \
"\n" \
"Version: %s\n" \
"\n" \
"Usage: %s [-e <partitions>] [-d <partitions>] [options]\n\n" \
" -e <partitions> --encrypt=<partitions> Encrypt the list of provided partitions.\n" \
" -d <partitions> --unencrypt=<partitions> Un-encrypt the list of provided partitions.\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" \
" -f --force Force (un)encryption operations.\n" \
" --help Print help and exit\n" \
"\n"
/* Check if application was called as update-firmware or encrypt-partitions */
#define IS_UPDATEFW(cmd) (!strcmp(cmd, CMD_UPDATEFW))
#define IS_ENCRYPT(cmd) (!strcmp(cmd, CMD_ENCRYPT))
/* Actual command name */
static char *cmd_name;
@ -75,9 +95,12 @@ static char *cmd_name;
/* Command line options */
static char *swu_package;
static char *key = NULL;
static char *to_encrypt = NULL;
static char *to_unencrypt = NULL;
static int wipe_update;
static int update_fw;
static int set_key;
static int force;
static int reboot_timeout = REBOOT_TIMEOUT;
/*
@ -89,6 +112,9 @@ static void usage_and_exit(int exitval)
if (IS_UPDATEFW(cmd_name))
fprintf(stdout, UPDATEFW_USAGE, VERSION, CMD_UPDATEFW,
REBOOT_TIMEOUT);
else if (IS_ENCRYPT(cmd_name))
fprintf(stdout, ENCRYPT_USAGE, VERSION, CMD_ENCRYPT,
REBOOT_TIMEOUT);
else
fprintf(stdout, RECOVERY_USAGE, VERSION, CMD_RECOVERY,
REBOOT_TIMEOUT);
@ -103,12 +129,15 @@ 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 = "uk::wT:";
static const char *short_options = "uk::wT:e:d:f";
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'},
{"encrypt", required_argument, NULL, 'e'},
{"unencrypt", required_argument, NULL, 'd'},
{"force", no_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
@ -143,6 +172,15 @@ static void parse_options(int argc, char *argv[])
exit(EXIT_FAILURE);
}
break;
case 'e':
to_encrypt = optarg;
break;
case 'd':
to_unencrypt = optarg;
break;
case 'f':
force = 1;
break;
case 'h':
usage_and_exit(EXIT_SUCCESS);
break;
@ -152,10 +190,15 @@ static void parse_options(int argc, char *argv[])
}
}
/* If command is 'update-firmware' reset the options */
/* If command is 'update-firmware' or 'encrypt-partitions' reset the options */
if (IS_UPDATEFW(cmd_name)) {
update_fw = 1;
wipe_update = 0;
to_encrypt = NULL;
to_unencrypt = NULL;
} else if (IS_ENCRYPT(cmd_name)) {
update_fw = 0;
wipe_update = 0;
}
if (update_fw) {
@ -165,16 +208,13 @@ 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);
}
}
int main(int argc, char *argv[])
{
int ret = 0;
unsigned char need_reboot = 0;
cmd_name = basename(argv[0]);
if (!cmd_name) {
@ -187,11 +227,12 @@ int main(int argc, char *argv[])
if (set_key) {
/* Configure recovery commands to set a fs encryption key */
ret = set_fs_encryption_key(key);
ret = set_encryption_key(key);
if (ret) {
printf("Error: set_fs_encryption_key\n");
printf("Error: set_encryption_key\n");
goto out;
}
need_reboot++;
}
if (swu_package) {
@ -201,6 +242,7 @@ int main(int argc, char *argv[])
printf("Error: update_firmware\n");
goto out;
}
need_reboot++;
}
if (wipe_update) {
@ -210,15 +252,38 @@ int main(int argc, char *argv[])
printf("Error: wipe_update_partition\n");
goto out;
}
need_reboot++;
}
/* Reboot to recovery */
ret = reboot_recovery(reboot_timeout);
if (ret) {
printf("Error: reboot_recovery\n");
goto out;
if (to_encrypt || to_unencrypt) {
/* Configure recovery commands to encrypt/unencrypt partitions */
ret = encrypt_partitions(to_encrypt, to_unencrypt, force);
if (ret < 0) {
printf("Error: encrypt_partitions\n");
goto out;
} else if (ret == 0) {
/*
* Only reboot if strictly necessary, since the function
* might succeed without setting a recovery command
* (for example, if you try to encrypt partitions that
* are already encrypted).
*/
need_reboot++;
} else {
ret = 0;
}
}
if (need_reboot > 0) {
/* Reboot to recovery */
ret = reboot_recovery(reboot_timeout);
if (ret) {
printf("Error: reboot_recovery\n");
goto out;
}
}
printf("\nNo recovery commands configured.\n");
out:
return ret;
}