xref: /rk3399_ARM-atf/tools/encrypt_fw/src/main.c (revision 10ecd58093a34e95e2dfad65b1180610f29397cc)
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