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
print_help(const char * cmd,const struct option * long_opt)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
get_key_alg(const char * key_alg_str)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
parse_fw_enc_status_flag(const char * arg,unsigned short * fw_enc_status)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
main(int argc,char * argv[])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