summaryrefslogtreecommitdiff
path: root/tools/preload_check_sign.c
blob: ebead459273f5e6b4d2bcf60d8d509439c6a7265 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// SPDX-License-Identifier: GPL-2.0+
/*
 * Check a file including a preload header including a signature
 *
 * Copyright (c) 2025 Paul HENRYS <paul.henrys_ext@softathome.com>
 *
 * Binman makes it possible to generate a preload header signing part or the
 * complete file. The tool preload_check_sign allows to verify and authenticate
 * a file starting with a preload header.
 */
#include <stdio.h>
#include <unistd.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <image.h>

extern void image_pre_load_sig_set_info(struct image_sig_info *info);
extern int image_pre_load_sig(ulong addr);

static void usage(char *cmdname)
{
	fprintf(stderr, "Usage: %s -f file -k PEM key file\n"
			"          -f ==> set file which should be checked\n"
			"          -k ==> PEM key file\n"
			"          -a ==> algo (default: sha256,rsa2048)\n"
			"          -p ==> padding (default: pkcs-1.5)\n"
			"          -h ==> help\n",
		cmdname);
	exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
	int ret = 0;
	char cmdname[256];
	char *file = NULL;
	char *keyfile = NULL;
	int c;
	FILE *fp = NULL;
	FILE *fp_key = NULL;
	size_t bytes;
	long filesize;
	void *buffer = NULL;
	EVP_PKEY *pkey = NULL;
	char *algo = "sha256,rsa2048";
	char *padding = "pkcs-1.5";
	struct image_sig_info info = {0};

	strncpy(cmdname, *argv, sizeof(cmdname) - 1);
	cmdname[sizeof(cmdname) - 1] = '\0';
	while ((c = getopt(argc, argv, "f:k:a:p:h")) != -1)
		switch (c) {
		case 'f':
			file = optarg;
			break;
		case 'k':
			keyfile = optarg;
			break;
		case 'a':
			algo = optarg;
			break;
		case 'p':
			padding = optarg;
			break;
		default:
			usage(cmdname);
			break;
	}

	if (!file) {
		fprintf(stderr, "%s: Missing file\n", *argv);
		usage(*argv);
	}

	if (!keyfile) {
		fprintf(stderr, "%s: Missing key file\n", *argv);
		usage(*argv);
	}

	fp = fopen(file, "r");
	if (!fp) {
		fprintf(stderr, "Error opening file: %s\n", file);
		ret = EXIT_FAILURE;
		goto out;
	}

	fseek(fp, 0, SEEK_END);
	filesize = ftell(fp);
	rewind(fp);

	buffer = malloc(filesize);
	if (!buffer) {
		fprintf(stderr, "Memory allocation failed");
		ret = EXIT_FAILURE;
		goto out;
	}

	bytes = fread(buffer, 1, filesize, fp);
	if (bytes != filesize) {
		fprintf(stderr, "Error reading file\n");
		ret = EXIT_FAILURE;
		goto out;
	}

	fp_key = fopen(keyfile, "r");
	if (!fp_key) {
		fprintf(stderr, "Error opening file: %s\n", keyfile);
		ret = EXIT_FAILURE;
		goto out;
	}

	/* Attempt to read the private key */
	pkey = PEM_read_PrivateKey(fp_key, NULL, NULL, NULL);
	if (!pkey) {
		/* If private key reading fails, try reading as a public key */
		fseek(fp_key, 0, SEEK_SET);
		pkey = PEM_read_PUBKEY(fp_key, NULL, NULL, NULL);
	}
	if (!pkey) {
		fprintf(stderr, "Unable to retrieve the public key: %s\n",
			ERR_error_string(ERR_get_error(), NULL));
		ret = EXIT_FAILURE;
		goto out;
	}

	info.algo_name = algo;
	info.padding_name = padding;
	info.key = (uint8_t *)pkey;
	info.mandatory = 1;
	info.sig_size = EVP_PKEY_size(pkey);
	if (info.sig_size < 0) {
		fprintf(stderr, "Fail to retrieve the signature size: %s\n",
			ERR_error_string(ERR_get_error(), NULL));
		ret = EXIT_FAILURE;
		goto out;
	}

	/* Compute signature information */
	info.sig_info.name     = info.algo_name;
	info.sig_info.padding  = image_get_padding_algo(info.padding_name);
	info.sig_info.checksum = image_get_checksum_algo(info.sig_info.name);
	info.sig_info.crypto   = image_get_crypto_algo(info.sig_info.name);
	info.sig_info.key      = info.key;
	info.sig_info.keylen   = info.key_len;

	/* Check the signature */
	image_pre_load_sig_set_info(&info);
	ret = image_pre_load_sig((ulong)buffer);
out:
	if (fp)
		fclose(fp);
	if (fp_key)
		fclose(fp_key);
	if (info.key)
		EVP_PKEY_free(pkey);
	free(buffer);

	exit(ret);
}