在OpenSSL中validationRSA公钥?

我有一个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); 

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

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

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

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

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

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

 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); 

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

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

无需复制数据。


我认为第二种选择是使用内存BIOd2i_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); 

EVP_PKEY*引用计数,因此您需要在EVP_PKEY*RSA*上调用free

在这个答案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); }