// SPDX-License-Identifier: GPL-2.0+ /* * Check a file including a preload header including a signature * * Copyright (c) 2025 Paul HENRYS * * 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 #include #include #include #include #include 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); }