You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
tbm-utils/source/sign.c

204 lines
4.0 KiB

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <getopt.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <image.h>
#include <macros.h>
#include <sign.h>
#include <x509.h>
enum {
OPTION_HELP = 'h',
OPTION_IMAGE = 'i',
OPTION_DIGEST = 'd',
OPTION_KEY = 'k',
OPTION_CERT = 'c',
};
struct args {
const char *image, *digest, *key, *cert;
};
static int parse_args(struct args *args, int argc, char *argv[])
{
struct option options[] = {
{ "help", no_argument, NULL, OPTION_HELP },
{ "image", required_argument, 0, OPTION_IMAGE },
{ "digest", required_argument, 0, OPTION_DIGEST },
{ "key", required_argument, 0, OPTION_KEY },
{ "cert", required_argument, 0, OPTION_CERT },
{ NULL, 0, 0, 0 },
};
int ret;
while ((ret = getopt_long(argc, (char * const *)argv, "hi:d:k:", options,
NULL)) >= 0) {
switch (ret) {
case OPTION_HELP: return -1;
case OPTION_IMAGE: args->image = optarg; break;
case OPTION_DIGEST: args->digest = optarg; break;
case OPTION_KEY: args->key = optarg; break;
case OPTION_CERT: args->cert = optarg; break;
default: break;
}
}
return 0;
}
static EVP_PKEY *open_priv_key(const char *path)
{
EVP_PKEY *key;
FILE *fp;
if (!(fp = fopen(path, "r")))
return NULL;
PEM_read_PrivateKey(fp, &key, NULL, NULL);
fclose(fp);
return key;
}
static int sign(const char *image, const char *name, const char *digest_name,
EVP_PKEY *key)
{
char data[512];
struct rots_hdr hdr;
struct rots_sig_hdr sig_hdr;
const EVP_MD *digest;
FILE *fp;
unsigned char *sig;
EVP_MD_CTX *ctx = NULL;
size_t nbytes, size, sig_len = 0;
if (!image || !digest_name || !key)
return -1;
if (!(fp = fopen(image, "r+b")))
return -1;
if (rots_read_hdr(fp, &hdr) < 0)
goto err_close_image;
size = hdr.size + ftell(fp);
fseek(fp, 0, SEEK_SET);
if (!(ctx = EVP_MD_CTX_create()))
goto err_close_image;
if (!(digest = EVP_get_digestbyname(digest_name)))
goto err_destroy_ctx;
if (!(EVP_DigestSignInit(ctx, NULL, digest, NULL, key)))
goto err_destroy_ctx;
while (size) {
nbytes = fread(data, sizeof *data, min(size, sizeof data), fp);
if (nbytes == 0)
goto err_destroy_ctx;
if (!(EVP_DigestSignUpdate(ctx, data, nbytes)))
goto err_destroy_ctx;
size -= nbytes;
}
sig_hdr.timestamp = (uint64_t)time(NULL);
if (!(EVP_DigestSignUpdate(ctx, &sig_hdr.timestamp,
sizeof sig_hdr.timestamp)))
goto err_destroy_ctx;
if (!(EVP_DigestSignFinal(ctx, NULL, &sig_len)))
goto err_destroy_ctx;
if (!(sig = malloc(sizeof(char) * sig_len)))
goto err_destroy_ctx;
if (!(EVP_DigestSignFinal(ctx, sig, &sig_len)))
goto err_free_sig;
if (fseek(fp, 0, SEEK_END) < 0)
goto err_free_sig;
sig_hdr.name = name;
sig_hdr.digest = digest_name;
sig_hdr.size = sig_len;
if (rots_write_sig_hdr(fp, &sig_hdr) < 0)
goto err_free_sig;
if (fwrite(sig, sizeof *sig, sig_len, fp) < sig_len)
goto err_free_sig;
free(sig);
EVP_MD_CTX_destroy(ctx);
fclose(fp);
return 0;
err_free_sig:
free(sig);
err_destroy_ctx:
EVP_MD_CTX_destroy(ctx);
err_close_image:
fclose(fp);
return -1;
}
int do_sign(int argc, char *argv[])
{
struct args args;
EVP_PKEY *key;
X509 *cert;
char *cn;
if (parse_args(&args, argc, argv) < 0) {
fprintf(stderr, "invalid\n");
return -1;
}
OpenSSL_add_all_algorithms();
if (!(key = open_priv_key(args.key))) {
fprintf(stderr, "error: unable to read the private key.\n");
return -1;
}
if (!(cert = X509_open_cert(args.cert))) {
fprintf(stderr, "error: unable to read the X509 certificate.\n");
OPENSSL_free(key);
return -1;
}
if (!(cn = X509_get_common_name(cert))) {
fprintf(stderr, "error: unable to get the common name.\n");
OPENSSL_free(cert);
OPENSSL_free(key);
return -1;
}
if (sign(args.image, cn, args.digest, key) < 0) {
fprintf(stderr, "error: unable to sign the payload.\n");
OPENSSL_free(cn);
OPENSSL_free(cert);
OPENSSL_free(key);
return -1;
}
OPENSSL_free(cn);
OPENSSL_free(cert);
OPENSSL_free(key);
return 0;
}