1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Check a file including a preload header including a signature
4  *
5  * Copyright (c) 2025 Paul HENRYS <paul.henrys_ext@softathome.com>
6  *
7  * Binman makes it possible to generate a preload header signing part or the
8  * complete file. The tool preload_check_sign allows to verify and authenticate
9  * a file starting with a preload header.
10  */
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <openssl/pem.h>
14 #include <openssl/evp.h>
15 #include <openssl/err.h>
16 #include <image.h>
17 
18 extern void image_pre_load_sig_set_info(struct image_sig_info *info);
19 extern int image_pre_load_sig(ulong addr);
20 
usage(char * cmdname)21 static void usage(char *cmdname)
22 {
23 	fprintf(stderr, "Usage: %s -f file -k PEM key file\n"
24 			"          -f ==> set file which should be checked\n"
25 			"          -k ==> PEM key file\n"
26 			"          -a ==> algo (default: sha256,rsa2048)\n"
27 			"          -p ==> padding (default: pkcs-1.5)\n"
28 			"          -h ==> help\n",
29 		cmdname);
30 	exit(EXIT_FAILURE);
31 }
32 
main(int argc,char ** argv)33 int main(int argc, char **argv)
34 {
35 	int ret = 0;
36 	char cmdname[256];
37 	char *file = NULL;
38 	char *keyfile = NULL;
39 	int c;
40 	FILE *fp = NULL;
41 	FILE *fp_key = NULL;
42 	size_t bytes;
43 	long filesize;
44 	void *buffer = NULL;
45 	EVP_PKEY *pkey = NULL;
46 	char *algo = "sha256,rsa2048";
47 	char *padding = "pkcs-1.5";
48 	struct image_sig_info info = {0};
49 
50 	strncpy(cmdname, *argv, sizeof(cmdname) - 1);
51 	cmdname[sizeof(cmdname) - 1] = '\0';
52 	while ((c = getopt(argc, argv, "f:k:a:p:h")) != -1)
53 		switch (c) {
54 		case 'f':
55 			file = optarg;
56 			break;
57 		case 'k':
58 			keyfile = optarg;
59 			break;
60 		case 'a':
61 			algo = optarg;
62 			break;
63 		case 'p':
64 			padding = optarg;
65 			break;
66 		default:
67 			usage(cmdname);
68 			break;
69 	}
70 
71 	if (!file) {
72 		fprintf(stderr, "%s: Missing file\n", *argv);
73 		usage(*argv);
74 	}
75 
76 	if (!keyfile) {
77 		fprintf(stderr, "%s: Missing key file\n", *argv);
78 		usage(*argv);
79 	}
80 
81 	fp = fopen(file, "r");
82 	if (!fp) {
83 		fprintf(stderr, "Error opening file: %s\n", file);
84 		ret = EXIT_FAILURE;
85 		goto out;
86 	}
87 
88 	fseek(fp, 0, SEEK_END);
89 	filesize = ftell(fp);
90 	rewind(fp);
91 
92 	buffer = malloc(filesize);
93 	if (!buffer) {
94 		fprintf(stderr, "Memory allocation failed");
95 		ret = EXIT_FAILURE;
96 		goto out;
97 	}
98 
99 	bytes = fread(buffer, 1, filesize, fp);
100 	if (bytes != filesize) {
101 		fprintf(stderr, "Error reading file\n");
102 		ret = EXIT_FAILURE;
103 		goto out;
104 	}
105 
106 	fp_key = fopen(keyfile, "r");
107 	if (!fp_key) {
108 		fprintf(stderr, "Error opening file: %s\n", keyfile);
109 		ret = EXIT_FAILURE;
110 		goto out;
111 	}
112 
113 	/* Attempt to read the private key */
114 	pkey = PEM_read_PrivateKey(fp_key, NULL, NULL, NULL);
115 	if (!pkey) {
116 		/* If private key reading fails, try reading as a public key */
117 		fseek(fp_key, 0, SEEK_SET);
118 		pkey = PEM_read_PUBKEY(fp_key, NULL, NULL, NULL);
119 	}
120 	if (!pkey) {
121 		fprintf(stderr, "Unable to retrieve the public key: %s\n",
122 			ERR_error_string(ERR_get_error(), NULL));
123 		ret = EXIT_FAILURE;
124 		goto out;
125 	}
126 
127 	info.algo_name = algo;
128 	info.padding_name = padding;
129 	info.key = (uint8_t *)pkey;
130 	info.mandatory = 1;
131 	info.sig_size = EVP_PKEY_size(pkey);
132 	if (info.sig_size < 0) {
133 		fprintf(stderr, "Fail to retrieve the signature size: %s\n",
134 			ERR_error_string(ERR_get_error(), NULL));
135 		ret = EXIT_FAILURE;
136 		goto out;
137 	}
138 
139 	/* Compute signature information */
140 	info.sig_info.name     = info.algo_name;
141 	info.sig_info.padding  = image_get_padding_algo(info.padding_name);
142 	info.sig_info.checksum = image_get_checksum_algo(info.sig_info.name);
143 	info.sig_info.crypto   = image_get_crypto_algo(info.sig_info.name);
144 	info.sig_info.key      = info.key;
145 	info.sig_info.keylen   = info.key_len;
146 
147 	/* Check the signature */
148 	image_pre_load_sig_set_info(&info);
149 	ret = image_pre_load_sig((ulong)buffer);
150 out:
151 	if (fp)
152 		fclose(fp);
153 	if (fp_key)
154 		fclose(fp_key);
155 	if (info.key)
156 		EVP_PKEY_free(pkey);
157 	free(buffer);
158 
159 	exit(ret);
160 }
161