1 /* 2 * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved. 3 * Copyright (c) 2019, Linaro Limited. All rights reserved. 4 * Author: Sumit Garg <sumit.garg@linaro.org> 5 * 6 * SPDX-License-Identifier: BSD-3-Clause 7 */ 8 9 #include <assert.h> 10 #include <ctype.h> 11 #include <getopt.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <stdbool.h> 16 17 #include <openssl/conf.h> 18 19 #include "cmd_opt.h" 20 #include "debug.h" 21 #include "encrypt.h" 22 #include "firmware_encrypted.h" 23 24 #define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0]))) 25 #define HELP_OPT_MAX_LEN 128 26 27 /* Global options */ 28 29 #if LOG_LEVEL >= LOG_LEVEL_NOTICE 30 static const char build_msg[] = "Built : " __TIME__ ", " __DATE__; 31 #endif 32 33 static char *key_algs_str[] = { 34 [KEY_ALG_GCM] = "gcm", 35 }; 36 37 static void print_help(const char *cmd, const struct option *long_opt) 38 { 39 int rem, i = 0; 40 const struct option *opt; 41 char line[HELP_OPT_MAX_LEN]; 42 char *p; 43 44 assert(cmd != NULL); 45 assert(long_opt != NULL); 46 47 printf("\n\n"); 48 printf("The firmware encryption tool loads the binary image and\n" 49 "outputs encrypted binary image using an encryption key\n" 50 "provided as an input hex string.\n"); 51 printf("\n"); 52 printf("Usage:\n"); 53 printf("\t%s [OPTIONS]\n\n", cmd); 54 55 printf("Available options:\n"); 56 opt = long_opt; 57 while (opt->name) { 58 p = line; 59 rem = HELP_OPT_MAX_LEN; 60 if (isalpha(opt->val)) { 61 /* Short format */ 62 sprintf(p, "-%c,", (char)opt->val); 63 p += 3; 64 rem -= 3; 65 } 66 snprintf(p, rem, "--%s %s", opt->name, 67 (opt->has_arg == required_argument) ? "<arg>" : ""); 68 printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i)); 69 opt++; 70 i++; 71 } 72 printf("\n"); 73 } 74 75 static int get_key_alg(const char *key_alg_str) 76 { 77 int i; 78 79 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) { 80 if (strcmp(key_alg_str, key_algs_str[i]) == 0) { 81 return i; 82 } 83 } 84 85 return -1; 86 } 87 88 static void parse_fw_enc_status_flag(const char *arg, 89 unsigned short *fw_enc_status) 90 { 91 unsigned long flag; 92 char *endptr; 93 94 flag = strtoul(arg, &endptr, 16); 95 if (*endptr != '\0' || flag > FW_ENC_WITH_BSSK) { 96 ERROR("Invalid fw_enc_status flag '%s'\n", arg); 97 exit(1); 98 } 99 100 *fw_enc_status = flag & FW_ENC_STATUS_FLAG_MASK; 101 } 102 103 /* Common command line options */ 104 static const cmd_opt_t common_cmd_opt[] = { 105 { 106 { "help", no_argument, NULL, 'h' }, 107 "Print this message and exit" 108 }, 109 { 110 { "fw-enc-status", required_argument, NULL, 'f' }, 111 "Firmware encryption status flag (with SSK=0 or BSSK=1)." 112 }, 113 { 114 { "key-alg", required_argument, NULL, 'a' }, 115 "Encryption key algorithm: 'gcm' (default)" 116 }, 117 { 118 { "key", required_argument, NULL, 'k' }, 119 "Encryption key (for supported algorithm)." 120 }, 121 { 122 { "nonce", required_argument, NULL, 'n' }, 123 "Nonce or Initialization Vector (for supported algorithm)." 124 }, 125 { 126 { "in", required_argument, NULL, 'i' }, 127 "Input filename to be encrypted." 128 }, 129 { 130 { "out", required_argument, NULL, 'o' }, 131 "Encrypted output filename." 132 }, 133 }; 134 135 int main(int argc, char *argv[]) 136 { 137 int i, key_alg, ret; 138 int c, opt_idx = 0; 139 const struct option *cmd_opt; 140 char *key = NULL; 141 char *nonce = NULL; 142 char *in_fn = NULL; 143 char *out_fn = NULL; 144 unsigned short fw_enc_status = 0; 145 146 NOTICE("Firmware Encryption Tool: %s\n", build_msg); 147 148 /* Set default options */ 149 key_alg = KEY_ALG_GCM; 150 151 /* Add common command line options */ 152 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) { 153 cmd_opt_add(&common_cmd_opt[i]); 154 } 155 156 /* Get the command line options populated during the initialization */ 157 cmd_opt = cmd_opt_get_array(); 158 159 while (1) { 160 /* getopt_long stores the option index here. */ 161 c = getopt_long(argc, argv, "a:f:hi:k:n:o:", cmd_opt, &opt_idx); 162 163 /* Detect the end of the options. */ 164 if (c == -1) { 165 break; 166 } 167 168 switch (c) { 169 case 'a': 170 key_alg = get_key_alg(optarg); 171 if (key_alg < 0) { 172 ERROR("Invalid key algorithm '%s'\n", optarg); 173 exit(1); 174 } 175 break; 176 case 'f': 177 parse_fw_enc_status_flag(optarg, &fw_enc_status); 178 break; 179 case 'k': 180 key = optarg; 181 break; 182 case 'i': 183 in_fn = optarg; 184 break; 185 case 'o': 186 out_fn = optarg; 187 break; 188 case 'n': 189 nonce = optarg; 190 break; 191 case 'h': 192 print_help(argv[0], cmd_opt); 193 exit(0); 194 case '?': 195 default: 196 print_help(argv[0], cmd_opt); 197 exit(1); 198 } 199 } 200 201 if (!key) { 202 ERROR("Key must not be NULL\n"); 203 exit(1); 204 } 205 206 if (!nonce) { 207 ERROR("Nonce must not be NULL\n"); 208 exit(1); 209 } 210 211 if (!in_fn) { 212 ERROR("Input filename must not be NULL\n"); 213 exit(1); 214 } 215 216 if (!out_fn) { 217 ERROR("Output filename must not be NULL\n"); 218 exit(1); 219 } 220 221 ret = encrypt_file(fw_enc_status, key_alg, key, nonce, in_fn, out_fn); 222 223 CRYPTO_cleanup_all_ex_data(); 224 225 return ret; 226 } 227