You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用OpenSSL获取原始私钥时返回长度为0的问题排查

问题:EVP_PKEY_get_raw_private_key获取私钥长度返回0的解决方法

我通过generate_key()生成EVP_PKEY类型私钥,generate_x509()生成X509证书,成功将证书写入内存BIO,但调用EVP_PKEY_get_raw_private_key获取原始私钥长度时返回0,触发“Private key is 0”错误。GDB调试发现读取证书的buf仅为单个字符“-”,但已确认证书和密钥生成正常,请问该如何正确获取私钥?

EVP_PKEY * privKey = generate_key();

if (privKey == NULL){
   qDebug() << "NULL PRIVATE KEY";
   exit(-1);
}
X509 * certif = generate_x509(privKey);
if (certif == NULL){
   qDebug() << "NULL CERT";
   exit(-1);
}
BIO* bio = BIO_new(BIO_s_mem());

if (!PEM_write_bio_X509(bio, certif)){
   qDebug() << "NULL RETURNED BY PEM_write_bio_x509";
    exit(-1);
}
std::unique_ptr<char[]> buf;
BUF_MEM* biostruct;
BIO_get_mem_ptr(bio, &biostruct);
buf = std::make_unique<char[]>(biostruct->length);
if (static_cast<size_t>(BIO_read(bio, buf.get(), biostruct->length)) != biostruct->length){
   qDebug() << "Houston, we have some problems";
   exit(-1);
}

size_t lengthOfPrivateKey = 0;
//    uint32_t* privkey = new uint32_t[lengthOfPrivateKey];

EVP_PKEY_get_raw_private_key(privKey, NULL, &lengthOfPrivateKey);
if (lengthOfPrivateKey == 0){
   qDebug() << "Private key is 0";
   exit(-1);
}
std::unique_ptr<unsigned char[]> prKey(new unsigned char[lengthOfPrivateKey]);
if (!EVP_PKEY_get_raw_private_key(privKey, prKey.get(), &lengthOfPrivateKey)){
    qDebug() << "Unable to get private key";
    exit(-1);
}
size_t lengthOfPublicKey = 0;
EVP_PKEY_get_raw_public_key(privKey, NULL, &lengthOfPublicKey);
if (lengthOfPublicKey == 0){
   qDebug() << "Public key is 0";
   exit(-1);
}
std::unique_ptr<unsigned char[]> pubKey(new unsigned char[lengthOfPublicKey]);
if (!EVP_PKEY_get_raw_public_key(privKey, pubKey.get(), &lengthOfPublicKey)){
    qDebug() << "Unable to get public key";
    exit(-1);
}

核心问题分析与解决步骤

1. 修复BIO读取证书的错误

PEM_write_bio_X509执行后,BIO的读写指针停留在内容末尾,直接调用BIO_read会读取到空内容或无效字符(比如你看到的“-”)。需要先重置指针到BIO开头:

BIO_get_mem_ptr(bio, &biostruct);
buf = std::make_unique<char[]>(biostruct->length);
// 新增:重置BIO读写指针到起始位置
BIO_reset(bio);
if (static_cast<size_t>(BIO_read(bio, buf.get(), biostruct->length)) != biostruct->length){
   qDebug() << "Houston, we have some problems";
   exit(-1);
}

2. 私钥获取失败的原因与解决

EVP_PKEY_get_raw_private_key仅支持无格式的原始私钥导出,仅适用于EC(椭圆曲线)、Ed25519、X25519等特定密钥类型,对RSA密钥无效——如果你的generate_key()生成的是RSA密钥,这个函数会直接返回0。

情况A:密钥是EC/Ed25519等支持原始私钥的类型

  • 确认generate_key()生成的密钥类型正确,可通过EVP_PKEY_id(privKey)验证:
    • EC密钥对应EVP_PKEY_EC
    • Ed25519对应EVP_PKEY_ED25519
  • 确保使用OpenSSL 1.1.0及以上版本(该函数在1.1.0引入)。

情况B:密钥是RSA类型

改用RSA专用的导出方式,示例如下:

// 获取RSA结构
RSA* rsa = EVP_PKEY_get1_RSA(privKey);
if (!rsa) {
    qDebug() << "Failed to get RSA structure";
    exit(-1);
}

// 导出PEM格式私钥到内存BIO
BIO* rsa_bio = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(rsa_bio, rsa, NULL, NULL, 0, NULL, NULL);

// 读取私钥内容
BUF_MEM* rsa_biostruct;
BIO_get_mem_ptr(rsa_bio, &rsa_biostruct);
std::unique_ptr<char[]> rsa_privkey(new char[rsa_biostruct->length + 1]);
BIO_reset(rsa_bio);
BIO_read(rsa_bio, rsa_privkey.get(), rsa_biostruct->length);
rsa_privkey[rsa_biostruct->length] = '\0'; // 加字符串结束符

// 释放资源
BIO_free(rsa_bio);
RSA_free(rsa);

如果需要原始的RSA私钥参数(如p、q、d等),可直接从RSA结构体中读取对应字段。

3. 公钥获取的对应调整

如果是RSA密钥,EVP_PKEY_get_raw_public_key同样无效,需改用EVP_PKEY_get1_RSA后读取公钥参数,或用PEM_write_bio_RSAPublicKey导出公钥。

内容的提问来源于stack exchange,提问作者user20433177

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 16:16:06