我已从 openssl 1.1.1 升级到 opessl 3.0.5。我在 i2d_X509_REQ(X509_REQ* req, nullptr) api 中获取 openssl 3.0.5 中内容的长度时遇到错误。我得到的长度错误为-1。谁能指导我解决这个兼容性问题?提前谢谢了。另外,是否可以打印由于 openssl api 导致的错误原因?它将用于查找发生的确切错误。
#include <iostream>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/engine.h>
#include <filesystem>
#include <openssl/x509.h>
using namespace std;
int main()
{
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey = NULL;
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx) {
std::cout<<"ctx error"<<std::endl;
}
/* Error occurred */
if (EVP_PKEY_keygen_init(ctx) <= 0) {
std::cout<<"EVP_PKEY_CTX_new_id error"<<std::endl;
}
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 4096) <= 0) {
std::cout<<"EVP_PKEY_CTX_set_rsa_keygen_bits error"<<std::endl;
}
/* Generate key */
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
std::cout<<"EVP_PKEY_keygen error"<<std::endl;
}
/* Writes the generated key to file*/
FILE *fp;
fp = fopen("/home/tpb1cob/1day/openssl/public_key.txt","w");
if (0 == PEM_write_PUBKEY(fp,pkey)) {
std::cout<<"file write fail"<<std::endl;
}
fclose(fp);
/*Encode the key and write to buffer*/
unsigned char* p;
int ret = -1;
ret = i2d_PublicKey(pkey,&p);
if(ret < 0) {
std::cout<<"i2d_PublicKey returns negative value"<<ret<<std::endl;
}
std::cout<<"i2d_PublicKey returns value "<<ret<<std::endl;
std::cout<<p<<std::endl;
/*Decodes buffer contents and assign to EVP_Key structure*/
EVP_PKEY *pkey1 = NULL;
if(NULL == d2i_PublicKey(EVP_PKEY_RSA,&pkey1,(const unsigned char**)&p,526)) {
std::cout<<"d2i_PrivateKey_fp returns NULL pointer"<<std::endl;
}
/* Writes the decoded key to file*/
FILE *fpq;
fpq = fopen("/home/tpb1cob/1day/openssl/public_key_decoded.txt","w");
if (0 == PEM_write_PUBKEY(fpq,pkey1)) {
std::cout<<"file write fail"<<std::endl;
}
fclose(fpq);
/* checks the parameters of keys pkey and pkey1 for equality */
if(1 == EVP_PKEY_eq(pkey,pkey1)) {
std::cout<<"EVP_PKEY_eq success"<<std::endl;
}
//"C=UK, O=Disorganized Organization, CN=Joe Bloggs"
X509_NAME *nm;
X509_REQ *CR;
nm = X509_NAME_new();
CR = X509_REQ_new();
if (nm == NULL) {
std::cout<<"X509_NAME_new failed"<<std::endl;
}
/* Some error */
int ii = -1;
if (1 == X509_NAME_add_entry_by_txt(nm, "C", MBSTRING_ASC,(const unsigned char*)"UK", -1, -1, 0)) {
std::cout<<"X509_NAME_add_entry_by_txt country success"<<std::endl;
}
/* Error */
if (1 == X509_NAME_add_entry_by_txt(nm, "O", MBSTRING_ASC,(const unsigned char*)"Disorganized Organization", -1, -1, 0)) {
std::cout<<"X509_NAME_add_entry_by_txt organization success"<<std::endl;
}
if (1 == X509_NAME_add_entry_by_txt(nm, "OU", MBSTRING_ASC,(const unsigned char*)"Organization Unit", -1, -1, 0)) {
std::cout<<"X509_NAME_add_entry_by_txt organization unit success"<<std::endl;
}
/* Error */
if (1 == X509_NAME_add_entry_by_txt(nm, "CN", MBSTRING_ASC,(const unsigned char*)"Joe Bloggs", -1, -1, 0)) {
std::cout<<"X509_NAME_add_entry_by_txt common name success"<<std::endl;
}
if (1 == X509_REQ_set_subject_name(CR, nm)) {
std::cout<<"X509_REQ_set_subject_name success"<<std::endl;
}
X509_NAME_free(nm);
if(1 == X509_REQ_set_pubkey(CR, pkey)) {
std::cout<<"X509_REQ_set_pubkey success"<<std::endl;
}
int length = i2d_X509_REQ(CR, NULL);
const char** file;
int* line;
if (length <= 0) {
std::cout<<"i2d_X509_REQ fail"<<length<<std::endl;
}
return 0;
}
我尝试获取证书请求的长度,但它总是返回-1。
反问你的问题:
另外,是否可以打印由于 openssl api 导致的错误原因?
是的。请参阅常见问题解答和手册页。在某些情况下,您可能需要使用更基本的方法更详细地查看代码,但我不会从这里开始。 (但是请注意,下一个常见问题解答 PROG9 已过时;在 OpenSSL 1.1.0 中,错误字符串始终会自动加载,您不再需要为它们编写代码。此外,虽然 libcrypto 例程的所有失败都应提供错误队列信息,libssl 则不同;像
SSL_connect
和 SSL_read
这样的例程在非阻塞模式或 EOF 下可能会“失败”而不会出现任何错误,您应该在查看 SSL_get_error
之前调用
ERR_*
来解决这些问题。)
有人可以指导我解决这个兼容性问题吗?
在代码中调用
ERR_print_errors_fp
失败后执行 i2d_X509_REQ
给出
{thread}:error:068000DE:asn1 encoding routines:(unknown function):illegal zero content:crypto/asn1/tasn_enc.c:374:
虽然不完全明显,但这是因为您没有签署请求,因此签名算法和签名的值(它们是实际 PKCS10 结构的必需部分)丢失了。
X509_REQ_sign[_ctx]
(使用您生成的EVP_PKEY
,其中包含私钥和公钥)。
另请注意,您正在写出密钥对的公共部分(带有
PEM_write_PUBKEY
),而不是私有部分。如果你不将私钥保存在某个地方,你的 CSR 基本上就没用了,因为从该 CSR 获得的任何证书只能与私钥结合使用才能成功使用。
最后,你的“编码然后解码公钥”代码是不安全的;它声明
unsigned char * p
然后使用它而不进行初始化。 可能您在您使用的系统上使用的编译器碰巧以包含 0/null 的方式创建它,这(或多或少)有效,但您不应该依赖于此。