简体   繁体   中英

How do I check if an EVP_PKEY contains a private key?

OpenSSL has the higher-level EVP_PKEY_* functions which work across all the pubkey-key cryptography algorithms. However, sometimes a EVP_PKEY* only has a public key. How could I check if a EVP_PKEY* contains a private key? I could use EVP_PKEY_decrypt_init and see if it returns an error, but that seems to be quite heavy-handed for what seems to be a simple check.

I am working with EC keys and had to do just this, but it will not work for the general case. I am not even sure if it is correct to do it this way. I have two files, one with a private key and one with a public key. I load those files, retrieve and verify the EC_KEY , and attempt to get the private key and the public key from the EC_KEY .

A general overview of the process is:

// private key:
PEM_read_PrivateKey      // load private key
EVP_PKEY_get1_EC_KEY     // EVP_PKEY to EC_KEY
EC_KEY_check_key         // validate key (OK)
EC_KEY_get0_private_key  // if result is not NULL: has private key (OK)
EC_KEY_get0_public_key   // if result is not NULL: has public key (OK)

// public key (only thing that changes is LOAD function):
PEM_read_PUBKEY          // load public key
EVP_PKEY_get1_EC_KEY     // EVP_PKEY to EC_KEY
EC_KEY_check_key         // validate key (OK)
EC_KEY_get0_private_key  // if result is not NULL: has private key (false)
EC_KEY_get0_public_key   // if result is not NULL: has public key (OK)

Note that when we read the private key, it appears to populate both the private key and the public key whereas when we read the public key it only populates the public key parameters. I suppose this is has expected.


Validate EVP_PKEY and check whether it has public/private keys

This only works for type EVP_PKEY_EC but can be extended to support others. We would call validate_pkey , the rest would be internal support functions one for each type of key.

static int validate_pkey_ec(EVP_PKEY *pkey)
{
    int result = 0;

    EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pkey);
    if (!ec_key)
        return -1;

    if (1 != EC_KEY_check_key(ec_key)) {
        EC_KEY_free(ec_key);
        return -1;
    }

    if (EC_KEY_get0_private_key(ec_key))
        result = 2;

    if (EC_KEY_get0_public_key(ec_key))
        result++;

    EC_KEY_free(ec_key);

    return result;
}

/**
** Performs sanity checks on the given EVP_PKEY.
**
** Returns 1, 2, or 3 when valid:
**   - Returns 1 if only public key is present.
**   - Returns 2 if only private key is present.
**   - Returns 3 if both public and private keys are present.
**/
int validate_pkey(EVP_PKEY *pkey)
{
    int key_type = EVP_PKEY_type(pkey->type);

    switch (key_type) {
    case EVP_PKEY_RSA:
    case EVP_PKEY_DSA:
    case EVP_PKEY_DH:
        // not implemented
        return -1;
    case EVP_PKEY_EC:
        return validate_pkey_ec(pkey);
    default:
        // unknown type, NID_undef?
        return -2;
    }
}

You can just check if the EVP_PKEY object has the necessary params, like private key exponent.

if (Key->pkey.rsa->d)
 printf("I have a private key");

I'm not sure if a more universal method exists to handle other three algorithms in one line, but it's easy to write your own function based on this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM