Signing using EVP_PKEY_encrypt when using pkcs11 engine

Martin Townsend mtownsend1973 at gmail.com
Mon Jun 3 15:35:58 UTC 2019


Hi,

I'm trying to modify the evm/ima utility so that it can use a HSM to
perform signing.  I've setup SoftHSM and used this to create a
certificate with an RSA public key pair.  The evmctl code creates the
hash and then calls a function to perform the sign operation which
ends up calling
len = RSA_private_encrypt(size + asn1->size, buf, hdr->sig,
  key, RSA_PKCS1_PADDING);

My idea was to keep the hash calculation as is, and replace the
RSA_private_encrypt with code that uses the private key in the HSM to
encrypt the hash buffer that has been calculated.

My initialisation looks like this
    /* Load the configuration using OPENSSL_CONF environment variable */
    OPENSSL_config(NULL);
    /* Try and load PKCS11 engine */
    const char* s = getenv("OPENSSL_CONF");
    printf("Trying to load pkcs#11 engine\n");
    printf("OPENSSL_CONF=%s\n", s);
    pkcs_engine = ENGINE_by_id("pkcs11");
    if (!pkcs_engine) {
        printf("PKCS#11 engine not found, not using HSM\n");
    } else {
        int rv = ENGINE_init(pkcs_engine);

        if (!rv) {
            fprintf(stderr, "PKCS#11 could not be initialised\n");
            ENGINE_free(pkcs_engine);
            pkcs_engine = NULL;
        }

        ENGINE_set_default(pkcs_engine, ENGINE_METHOD_ALL);
    }

    OpenSSL_add_all_algorithms();
    OpenSSL_add_all_digests();
    ERR_load_crypto_strings();

and then I load the private key with

    key = ENGINE_load_private_key(pkcs_engine, keyid, UI_OpenSSL(), NULL);
    if (!key) {
        log_err("%s: Failed to load private key with id: %s\n", keyid,
__func__);
        ERR_print_errors_fp(stderr);
    }


and then use the following to perform the encryption

        /* Create context */
        hsm_key_ctx = EVP_PKEY_CTX_new(hsm_key, NULL);
        if (hsm_key_ctx == NULL) {
            log_err("sign_hash_v2: failed to create context\n");
            ERR_print_errors_fp(stderr);
            return -1;
        }
        rv = EVP_PKEY_encrypt_init(hsm_key_ctx);
        if (rv <= 0) {
            log_err("sign_hash_v2: failed to init encrypt (rv=%d\n", rv);
            ERR_print_errors_fp(stderr);
            EVP_PKEY_CTX_free(hsm_key_ctx);
            return -1;
        }
        /* TODO: What padding??? RSA_PKCS1_PSS_PADDING?? */
        rv = EVP_PKEY_CTX_set_rsa_padding(hsm_key_ctx, RSA_PKCS1_PADDING);
        if (rv <= 0) {
            log_err("sign_hash_v2: failed to set RSA_PKCS1_PADDING
(rv=%d\n", rv);
            ERR_print_errors_fp(stderr);
            EVP_PKEY_CTX_free(hsm_key_ctx);
            return -1;
        }
        if (rv <= 0) {
            log_err("sign_hash_v2: failed to set RSA_PKCS1_PADDING
(rv=%d\n", rv);
            ERR_print_errors_fp(stderr);
            EVP_PKEY_CTX_free(hsm_key_ctx);
            return -1;
        }

        /* Create signature */
        outlen = 0;
        rv = EVP_PKEY_encrypt(hsm_key_ctx, NULL, &outlen, buf, size +
asn1->size);
        if ((rv <= 0) || (outlen == 0)) {
            log_err("sign_hash_v2: failed to learn needed output buf
len (rv=%d)\n", rv);
            ERR_print_errors_fp(stderr);
            EVP_PKEY_CTX_free(hsm_key_ctx);
            return -1;
        }
        /*outlen = 256;*/
        log_info("EVP_PKEY_encrypt: outlen: %lu\n", outlen);
        rv = EVP_PKEY_encrypt(hsm_key_ctx, hdr->sig, &outlen, buf,
size + asn1->size);
        if (rv <= 0) {
            log_err("sign_hash_v2: EVP_PKEY_encrypt() failed (rv=%d)\n", rv);
            ERR_print_errors_fp(stderr);
            EVP_PKEY_CTX_free(hsm_key_ctx);
            return -1;
        }

But I find that when I create a signature for a particular file it's
always different with each invocation of the utility. If I try and
verify it using the associated public key I get:

RSA_public_decrypt() failed: -1
errno: No data available (61)
error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01
error:04067072:rsa routines:RSA_EAY_PUBLIC_DECRYPT:padding check failed

Is there something I am missing in my code above?  I tried setting the
Engine in EVP_PKEY_CTX_new but get:
sign_hash_v2: failed to create context
140174165591744:error:260C0065:engine
routines:ENGINE_get_pkey_meth:unimplemented public key
method:tb_pkmeth.c:128:
140174165591744:error:0609D09C:digital envelope
routines:INT_CTX_NEW:unsupported algorithm:pmeth_lib.c:166:
errno: Invalid argument (22)

Any help appreciated,
Martin.


More information about the openssl-users mailing list