| // 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); |
| } |