在OpenSSL中验证RSA公钥?

[英]Verify a RSA public key in OpenSSL?


I have an EVP_PKEY with only the public part of a RSA key. I extracted the public part from a SubjectPublicKeyInfo structure in DER encoding. This is what I have now:

我有一个EVP_PKEY只有RSA密钥的公共部分。我从DER编码中的SubjectPublicKeyInfo结构中提取公共部分。这就是我现在拥有的:

unsigned char publicKey[] = {0x30, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ...}
size_t publicKeyLength = 92;
unsigned char* publicKeyCopy = new unsigned char[publicKeyLength];
memcpy(publicKeyCopy, publicKey, publicKeyLength);

RSA *rsa;
rsa = d2i_RSA_PUBKEY(NULL, (unsigned char const **) &pubKey, pubKeyLen);
EVP_PKEY *pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);

I know that you can use RSA_check_key to verify a RSA private key but the docs say that "It does not work on RSA public keys that have only the modulus and public exponent elements populated".

我知道您可以使用RSA_check_key来验证RSA私钥,但文档说“它不适用于仅填充了模数和公共指数元素的RSA公钥”。

So, is it possible to verify a key without the private part? Because as you can see I have only the public part of the EVP_PKEY. I wonder, is this even possible? What would you verify in a public part of an EVP_PKEY?

那么,是否可以在没有私有部分的情况下验证密钥?因为你可以看到我只有EVP_PKEY的公共部分。我想知道,这甚至可能吗?你会在EVP_PKEY的公共部分验证什么?

You can see the answer for this question Programmatically verify a X509 certificate and private key match but there the full key is validated (private and public parts).

您可以看到此问题的答案以编程方式验证X509证书和私钥匹配,但验证了完整密钥(私有和公共部分)。

Beware The original code posted in this question has a BUG. This is because internally d2i_RSA_PUBKEY uses d2i_PUBKEY and d2i_PUBKEY uses d2i_X509_PUBKEY (in x_pubkey.c). If you read the documentation for d2i_X509 you will see the next "WARNING: The use of temporary variable is mandatory. A common mistake is to attempt to use a buffer directly...". So the corrected code will have to use a temporary copy of publicKeyCopy and after the use you could safely delete publicKeyCopy:

注意这个问题中发布的原始代码有一个BUG。这是因为内部d2i_RSA_PUBKEY使用d2i_PUBKEY而d2i_PUBKEY使用d2i_X509_PUBKEY(在x_pubkey.c中)。如果您阅读d2i_X509的文档,您将看到下一个“警告:必须使用临时变量。常见的错误是尝试直接使用缓冲区......”。因此,更正后的代码必须使用publicKeyCopy的临时副本,使用后您可以安全地删除publicKeyCopy:

2 个解决方案

#1


1  

Beware The original code posted in this question has a BUG...

注意这个问题中发布的原始代码有一个BUG ...

I'm just going to comment on this, and show you how to handle it.

我只想对此发表评论,并向您展示如何处理它。

unsigned char publicKey[] = {0x30, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, ...}
size_t publicKeyLength = sizeof(publicKey);

unsigned char* t = publicKey;
rsa = d2i_RSA_PUBKEY(NULL, &t, pubKeyLen);

Internally, the temporary pointer t is incremented, so its wasted. It will point to some place after the buffer if everything works as expected. What you should find is (size_t)t - (size_t)publicKey == publicKeyLength after the function executes.

在内部,临时指针t递增,因此浪费了它。如果一切按预期工作,它将指向缓冲区之后的某个位置。在函数执行后你应该找到的是(size_t)t - (size_t)publicKey == publicKeyLength。

Because you used a temporary pointer, the original pointer publicKey is still good. And you can use t to parse the next key if there are consecutive keys in memory.

因为您使用了临时指针,所以原始指针publicKey仍然很好。如果内存中有连续的密钥,您可以使用t来解析下一个密钥。

There's no need to copy the data.

无需复制数据。


I think a second option is to use a memory BIO and d2i_RSA_PUBKEY_bio. Something like:

我认为第二种选择是使用内存BIO和d2i_RSA_PUBKEY_bio。就像是:

BIO* bio = BIO_new_mem_buf(publicKey, (int)publicKeyLength);
ASSERT(bio != NULL);

RSA* rsa = d2i_RSA_PUBKEY_bio(bio, NULL);
ASSERT(rsa != NULL);

/* ... */

RSA_free(rsa);
BIO_free(bio);

The get1 bumps the reference count, so you need to call free on both the EVP_PKEY* and RSA*.

get1会破坏引用计数,因此您需要在EVP_PKEY *和RSA *上调用free。

#2


0  

With the help of @jww in this answer https://stackoverflow.com/a/29885771/2692914. I came up with this solution, I hope it is ok:

在这个答案https://stackoverflow.com/a/29885771/2692914的@jww的帮助下。我想出了这个解决方案,我希望它没问题:

bool isValidPublicKeyOnly(EVP_PKEY *pkey) {
    //EVP_PKEY_get_type from https://stackoverflow.com/a/29885771/2692914
    int type = EVP_PKEY_get_type(pkey); //checks nullptr
    if (type != EVP_PKEY_RSA && type != EVP_PKEY_RSA2) {
        //not RSA
        return false;
    }

    RSA *rsa = EVP_PKEY_get1_RSA(pkey);
    if (!rsa) {
        return false;
    }

    bool isValid = isValidRSAPublicKeyOnly(rsa);
    RSA_free(rsa);
    return isValid;
}

bool isValidRSAPublicKeyOnly(RSA *rsa) {
    //from rsa_ameth.c do_rsa_print : has a private key
    //from rsa_chk.c RSA_check_key : doesn't have n (modulus) and e (public exponent)
    if (!rsa || rsa->d || !rsa->n || !rsa->e) {
        return false;
    }
    //from http://rt.openssl.org/Ticket/Display.html?user=guest&pass=guest&id=1454
    //doesnt have a valid public exponent
    return BN_is_odd(rsa->e) && !BN_is_one(rsa->e);
}
智能推荐

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2015/06/09/535e60f82b77d3779982045ae9bccffc.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告