rsobies
rsobies

Reputation: 451

EVP_PKEY_verify doesn't work when using EC_KEY

EVP_PKEY_verify() in most cases fails if EVP_PKEY structure contains EC key, but in some cases it succeed.

openssl documentation about EVP_PKEY_verify() shows only example with rsa key. But I can't find any example of verification when the EVP_PKEY contains an EC key

    auto evp = EVP_PKEY_new();
    auto eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
    assert(1 == EC_KEY_generate_key(eckey));
    assert(1 == EC_KEY_check_key(eckey));
    assert(1 == EVP_PKEY_assign_EC_KEY(evp, eckey));

    vector<unsigned char> msg = { 'a', 'd', 'f', 'h', 'k' };

    const int sha256Len = 32;
    unsigned char sha[sha256Len];

    SHA256(&(msg[0]), msg.size(), sha);

    //----signing
    auto evpctx=EVP_PKEY_CTX_new(evp, nullptr);

    assert(1 == EVP_PKEY_sign_init(evpctx));

    assert(1 == EVP_PKEY_CTX_set_signature_md(evpctx, EVP_sha256()));

    size_t signLen = 0;
    assert(1 == EVP_PKEY_sign(evpctx, NULL, &signLen, sha, sha256Len));

    vector<unsigned char> sig(signLen);

    auto ret = EVP_PKEY_sign(evpctx, &(sig[0]), &signLen, sha, sha256Len);

    assert(ret == 1);

    EVP_PKEY_CTX_free(evpctx);

    ///-----veryfication

    auto evpctx1 = EVP_PKEY_CTX_new(evp, nullptr);

    assert(1 == EVP_PKEY_verify_init(evpctx1));

    assert(1 == EVP_PKEY_CTX_set_signature_md(evpctx1, EVP_sha256()));

    ret = EVP_PKEY_verify(evpctx1, &sig[0], sig.size(), sha, sha256Len);

    EVP_PKEY_free(evp);
    EVP_PKEY_CTX_free(evpctx1);
    assert(ret == 1);

The above code, when run in a loop, fails most of times, but not always. Some iterations succeed. If I generate an RSA key instead of an EC key and put it into EVP_PKEY, then it is ok. What I am doing wrong? Can you give me a working example of using EVP_PKEY_verify() with an ec key?

Upvotes: 1

Views: 1841

Answers (1)

Ctx
Ctx

Reputation: 18420

The problem is as follows:

Here, you determine the maximum size of the signature output buffer:

assert(1 == EVP_PKEY_sign(evpctx, NULL, &signLen, sha, sha256Len));

and here you allocate this buffer:

vector<unsigned char> sig(signLen);

This is correct. But you have to be aware, that this is only the maximum needed size. The size, which is indeed used can be less!

So in this line

auto ret = EVP_PKEY_sign(evpctx, &(sig[0]), &signLen, sha, sha256Len);

the actually used output buffer size is written to signLen, which you have to specify here

ret = EVP_PKEY_verify(evpctx1, &sig[0], signLen, sha, sha256Len);

when you verify the signature! With this small modification your code should work as expected.

Upvotes: 4

Related Questions