[英]Verify a RSA public key in OpenSSL?
I have an EVP_PKEY with only the public part of a RSA key.我有一个 EVP_PKEY,只有 RSA 密钥的公共部分。 I extracted the public part from a SubjectPublicKeyInfo structure in DER encoding.
我从 DER 编码的 SubjectPublicKeyInfo 结构中提取了公共部分。 This is what I have now:
这就是我现在所拥有的:
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.
因为如您所见,我只有EVP_PKEY 的公共部分。 I wonder, is this even possible?
我想知道,这甚至可能吗? What would you verify in a public part of an 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 .当心这个问题中发布的原始代码有一个 BUG 。 This is because internally
d2i_RSA_PUBKEY
uses d2i_PUBKEY
and d2i_PUBKEY
uses d2i_X509_PUBKEY
(in x_pubkey.c ).这是因为内部
d2i_RSA_PUBKEY
使用d2i_PUBKEY
并且d2i_PUBKEY
使用d2i_X509_PUBKEY
(在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..." .如果您阅读d2i_X509的文档,您将看到下一个“警告:临时变量的使用是强制性的。一个常见的错误是尝试直接使用缓冲区...” 。 So the corrected code will have to use a temporary copy of
publicKeyCopy
and after the use you could safely delete publicKeyCopy
:因此,更正后的代码必须使用
publicKeyCopy
的临时副本,使用后您可以安全地删除publicKeyCopy
:
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.在内部,临时指针
t
递增,因此它被浪费了。 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.你应该找到的是
(size_t)t - (size_t)publicKey == publicKeyLength
在函数执行后。
Because you used a temporary pointer, the original pointer publicKey
is still good.因为你用的是临时指针,原来的指针
publicKey
还是好的。 And you can use t
to parse the next key if there are consecutive keys in memory.如果内存中有连续的键,您可以使用
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
.我认为第二个选择是使用内存
BIO
和d2i_RSA_PUBKEY_bio
。 Something like:就像是:
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
。
With the help of @jww in this answer https://stackoverflow.com/a/29885771/2692914 .在@jww 的帮助下,这个答案https://stackoverflow.com/a/29885771/2692914 。 I came up with this solution, I hope it is ok:
我想出了这个解决方案,希望没问题:
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);
}
I had a similiar problem and I thought it may be prudent to display my solution to this issue.我有一个类似的问题,我认为展示我对这个问题的解决方案可能是明智的。 Unlike lmiguelmh's solution, this one does work in C.
与 lmiguelmh 的解决方案不同,这个解决方案在 C 中确实有效。
int checkRsaPublic(RSA *rsa, int debug) {
if (!rsa) {
printf("ERROR: RSA key not defined!\n");
return 0;
}
//key
const BIGNUM *n;
const BIGNUM *e;
const BIGNUM *d;
//factors
const BIGNUM *p;
const BIGNUM *q;
//crt_params
const BIGNUM *dmp1;
const BIGNUM *dmq1;
const BIGNUM *iqmp;
RSA_get0_key(rsa, &n, &e, &d);
RSA_get0_factors(rsa, &p, &q);
RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
if (debug) {
if (n) {
printf("n is %s\n", BN_bn2hex(n));
}
if (e) {
printf("e is %s\n", BN_bn2hex(e));
}
if (d) {
printf("d is %s\n", BN_bn2hex(d));
}
if (p) {
printf("p is %s\n", BN_bn2hex(p));
}
if (q) {
printf("q is %s\n", BN_bn2hex(q));
}
if (dmp1) {
printf("dmp1 is %s\n", BN_bn2hex(dmp1));
}
if (dmq1) {
printf("dmq1 is %s\n", BN_bn2hex(dmq1));
}
if (iqmp) {
printf("iqmp is %s\n", BN_bn2hex(iqmp));
}
}
//RSA_check_key : doesn't have n (modulus) and e (public exponent)
if (d || !n || !e) {
printf("ERROR: RSA public key not well defined!\n");
return 0;
}
if (BN_is_odd(e) && !BN_is_one(e)) {
return 1;
}
printf("ERROR: Invalid public exponent.");
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.