blob: ebead459273f5e6b4d2bcf60d8d509439c6a7265 [file] [log] [blame]
Paul HENRYS99940082025-02-24 22:20:53 +01001// 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
18extern void image_pre_load_sig_set_info(struct image_sig_info *info);
19extern int image_pre_load_sig(ulong addr);
20
21static 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
33int 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);
150out:
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}