/*
 * NAME:
 *	printkeyid - simple routine to print the ima keyid
 */
/*
 * RCSid:
 *	$Id: printimakeyid.c,v 1.2 2019/12/11 20:27:44 sjg Exp $
 *
 *      Copyright (c) 2014, Juniper Networks, Inc.
 *
 *	This file is provided in the hope that it will
 *	be of use.  There is absolutely NO WARRANTY.
 *	Permission to copy, redistribute or otherwise
 *	use this file is hereby granted provided that 
 *	the above copyright notice and this notice are
 *	left intact. 
 *      
 *	Please send copies of changes and bug-fixes to:
 *	sjg@crufty.net
 */

#include <stdio.h>
#include <err.h>

#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/pem.h>


/*
 * IMA/EVM uses low order octets SHA1 of the ASN1 encoded public key
 * as the keyid. For IMA v1 signatures, it uses eight octets, for IMA
 * v2 signatures, it uses four otets. The key must be in normalized
 * form (a leading zero byte if it would otherwise be a negative
 * number).
 * ASN1 (30) ASN1 (82) (len=0x018a) ASN1(20) ASN1 (82) (len=0x0181)
 * [0x00 modulus n] ASN1(02) (length=0x03) [exponent=0x010001]
 * (where 0x181 is 0x180 (3072-bit key length bytes + 1 for leading 0x00 byte)
 */

int
main(int argc, char *argv[])
{
    X509 *x;
    RSA *rsa;
    BIO *f;
    int len, i;
    EVP_PKEY *key = NULL;
    unsigned char *keyvalue = NULL;
    unsigned char keyid[SHA_DIGEST_LENGTH];

    OpenSSL_add_all_algorithms();
    if (argc < 2)
	errx(1, "usage: %s x509_public_key.pem\n", argv[0]);
    else if (argc > 2)
	errx(1, "too many arguments. usage: %s x509_public_key.pem\n", argv[0]);

    f = BIO_new(BIO_s_file());
    if (f == NULL)
	errx(1, "Bio_new(BIO_s_file()) failed\n");
    if (BIO_read_filename(f, argv[1]) > 0) {
	x = PEM_read_bio_X509_AUX(f, NULL, NULL, NULL);
	if (x)
	    key = X509_get_pubkey(x);
	if (!key)
	    errx(2, "cannot load: %s", argv[1]);
	if ((i = EVP_PKEY_id(key)) != EVP_PKEY_RSA)
	    errx(1, "EVP_PKEY_id (%d) is not EVP_PKEY_RSA (%d)\n",
		 i, EVP_PKEY_RSA);
    } else
	errx(1, "BIO_read_filename(f, \"%s\") failed.\n", argv[1]);
    BIO_free(f);

    /* Fetch the RSA keyid */
    rsa = EVP_PKEY_get1_RSA(key);

    /* Encode a PKCS#1 RSAPublicKey Structure as a stream of bytes */
    len = i2d_RSAPublicKey(rsa, &keyvalue);

    /* Create a SHA1 of the encoded structure */
    SHA1(keyvalue, len, keyid);

    /* Cleanup */
    RSA_free(rsa); rsa = NULL;
    free(keyvalue); keyvalue = NULL;
    EVP_PKEY_free(key); key = NULL;

    /*
     * IMA key identifier-not X509/PGP specific. For a V2 key
     * it is only the last four octets of the SHA1 hash.
     */
    printf("SetKnobs= IMAv2Keyid=%02x%02x%02x%02x\n",
           keyid[16], keyid[17], keyid[18], keyid[19]);

    return 0;
}
