#include #include #include #include #include #include #include #include #include #include #include #include #include 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; }