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