我想将一个生成PEM格式的EC私钥的函数更新到OpenSSL 3.0。大多数使用的EC函数现在都被弃用了。下面你可以看到被弃用的函数。
ERR Security_GetECKey(KeyPairECType enKeyPairECType, const unsigned char *puchKey, unsigned int uiLength, char **ppstPEMKey)
{
ERR err;
int iNID;
BIGNUM *pBigNumPrivate;
BN_CTX *pBigNumCtx;
EC_KEY *pEcKey;
EC_POINT *pEcPoint;
const EC_GROUP *pEcGroup;
EVP_PKEY *pEVPPKey;
int iBIOLength;
BIO *pBIOOut;
const unsigned char *puchPEMKey;
err = ERR_NONE;
if((enKeyPairECType > KeyPairECType_Max) ||
(ppstPEMKey == NULL) ||
(uiLength == 0) ||
(puchKey == NULL))
{
err = Err_Code(ERR_INVALID_PARAM);
}
else
{
switch(enKeyPairECType)
{
case KeyPairECType_NID_SECP521r1:
iNID = NID_secp521r1;
break;
default:
iNID = 0;
err = Err_Code(ERR_INVALID_PARAM);
break;
}
if(err == ERR_NONE)
{
THREAD_LOCK_LIB_TOOLS();
/*
* Use length from mpi header + 4. instead of length of whole char array.
* Length of char array (uiLength) could be longer than mpi
*/
pBigNumPrivate = BN_mpi2bn((unsigned char*)puchKey, ((puchKey[0]<<24) | (puchKey[1]<<16) | (puchKey[2]<<8) | puchKey[3]) + 4, NULL);
if(pBigNumPrivate != NULL)
{
pBigNumCtx = BN_CTX_new();
if(pBigNumCtx != NULL)
{
/*
* TODO: The low-level EC_KEY_... API functions are deprecated with OpenSSL 3.0!
* Ignore the warnings for now until the source code is adapted to use
* the appropriate high-level APIs.
*/
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
pEcKey = EC_KEY_new_by_curve_name(iNID);
if(pEcKey != NULL)
{
pEcGroup = EC_KEY_get0_group(pEcKey);
if(pEcGroup != NULL)
{
pEcPoint = EC_POINT_new(pEcGroup);
if(pEcPoint != NULL)
{
if(EC_KEY_set_private_key(pEcKey, pBigNumPrivate) != FALSE)
{
if(EC_POINT_mul(pEcGroup, pEcPoint, pBigNumPrivate, NULL, NULL, pBigNumCtx) != FALSE)
{
if(EC_KEY_set_public_key(pEcKey, pEcPoint) != FALSE)
{
pEVPPKey = EVP_PKEY_new();
if(pEVPPKey != NULL)
{
if(EVP_PKEY_set1_EC_KEY(pEVPPKey, pEcKey) != FALSE)
{
pBIOOut = BIO_new(BIO_s_mem());
if(pBIOOut != NULL)
{
gstPassword = NULL;
if((PEM_write_bio_PrivateKey(pBIOOut, pEVPPKey, NULL, NULL, 0, Security_PEM_Password_CB, NULL)) == 0)
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
else
{
iBIOLength = BIO_get_mem_data(pBIOOut, &puchPEMKey);
if(iBIOLength > 0)
{
err = Mem_AllocEx((void **)ppstPEMKey, (iBIOLength + 1) * sizeof(char));
if(err == ERR_NONE)
{
memcpy(*ppstPEMKey, puchPEMKey, iBIOLength);
(*ppstPEMKey)[iBIOLength] = '\00';
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
BIO_free(pBIOOut);
}
EVP_PKEY_free(pEVPPKey);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
EC_KEY_free(pEcKey);
}
/*
* TODO: Remove end of #pragma above if adapted!
*/
#pragma GCC diagnostic pop
BN_CTX_free(pBigNumCtx);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
BN_free(pBigNumPrivate);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
THREAD_UNLOCK_LIB_TOOLS();
}
}
return err;
}
我曾尝试用OpenSSL 3.0支持的EVP密钥函数替换过时的EC函数。以下是我的最新尝试:
ERR Security_GetECKey(KeyPairECType enKeyPairECType, const unsigned char *puchKey, unsigned int uiLength, char **ppstPEMKey)
{
ERR err;
THREAD_INIT_LOCK_LIB_TOOLS();
err = ERR_NONE;
if((enKeyPairECType > KeyPairECType_Max) ||
(ppstPEMKey == NULL) ||
(uiLength == 0) ||
(puchKey == NULL))
{
err = Err_Code(ERR_INVALID_PARAM);
}
else
{
const char *pstCurveName;
switch(enKeyPairECType)
{
case KeyPairECType_NID_SECP521r1:
pstCurveName = SN_secp521r1;
break;
default:
pstCurveName = NULL;
err = Err_Code(ERR_INVALID_PARAM);
break;
}
if(err == ERR_NONE)
{
BIGNUM *pBigNumPrivate;
THREAD_LOCK_LIB_TOOLS();
/*
* Use length from mpi header + 4. instead of length of whole char array.
* Length of char array (uiLength) could be longer than mpi
*/
pBigNumPrivate = BN_mpi2bn((unsigned char *) puchKey, ((puchKey[0] << 24) | (puchKey[1] << 16) | (puchKey[2] << 8) | puchKey[3]) + 4, NULL);
if(pBigNumPrivate != NULL)
{
int iNid = OBJ_sn2nid(pstCurveName);
if(iNid != NID_undef)
{
EC_GROUP *pEcGroup = EC_GROUP_new_by_curve_name(iNid);
if(pEcGroup != NULL)
{
EC_POINT *pEcPoint = EC_POINT_new(pEcGroup);
BN_CTX *pBigNumCtx = BN_CTX_new();
if((pEcPoint != NULL) && (pBigNumCtx != NULL) && EC_POINT_mul(pEcGroup, pEcPoint, pBigNumPrivate, NULL, NULL, pBigNumCtx))
{
size_t uzPubKeySize = EC_POINT_point2oct(pEcGroup, pEcPoint, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL);
if(uzPubKeySize > 0)
{
unsigned char *puchPubKey = NULL;
err = Mem_AllocEx((void **) &puchPubKey, uzPubKeySize);
if((err == ERR_NONE) && (EC_POINT_point2oct(pEcGroup, pEcPoint, POINT_CONVERSION_COMPRESSED, puchPubKey, uzPubKeySize, NULL)))
{
OSSL_PARAM_BLD *paramBuild = OSSL_PARAM_BLD_new();
if((paramBuild != NULL) &&
OSSL_PARAM_BLD_push_utf8_string(paramBuild, OSSL_PKEY_PARAM_GROUP_NAME, pstCurveName, 0) &&
OSSL_PARAM_BLD_push_BN(paramBuild, OSSL_PKEY_PARAM_PRIV_KEY, pBigNumPrivate) &&
OSSL_PARAM_BLD_push_octet_ptr(paramBuild, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, puchPubKey, uzPubKeySize))
{
EVP_PKEY *pEVPPKey = NULL;
OSSL_PARAM *pParams = OSSL_PARAM_BLD_to_param(paramBuild);
EVP_PKEY_CTX *pKeyCtx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
if((pParams != NULL) &&
(pKeyCtx != NULL) &&
(EVP_PKEY_fromdata_init(pKeyCtx) > 0) &&
((EVP_PKEY_fromdata(pKeyCtx, &pEVPPKey, EVP_PKEY_KEYPAIR, pParams)) > 0))
{
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pEVPPKey, NULL);
if(EVP_PKEY_check(ctx) <= 0)
ERR_print_errors_fp(stderr);
BIO *pBIOOut = BIO_new(BIO_s_mem());
if(pBIOOut != NULL)
{
if((PEM_write_bio_PrivateKey(pBIOOut, pEVPPKey, NULL, NULL, 0, NULL, NULL)) == 0)
{
ERR_print_errors_fp(stderr);
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
else
{
const unsigned char *puchPEMKey;
int iBIOLength = BIO_get_mem_data(pBIOOut, &puchPEMKey);
if(iBIOLength > 0)
{
err = Mem_AllocEx((void **) ppstPEMKey, (iBIOLength + 1) * sizeof(char));
if(err == ERR_NONE)
{
memcpy(*ppstPEMKey, puchPEMKey, iBIOLength);
(*ppstPEMKey)[iBIOLength] = '\00';
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
BIO_free(pBIOOut);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
EVP_PKEY_free(pEVPPKey);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
EVP_PKEY_CTX_free(pKeyCtx);
OSSL_PARAM_free(pParams);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
OSSL_PARAM_BLD_free(paramBuild);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
Mem_Free((void **) &puchPubKey);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
EC_POINT_free(pEcPoint);
BN_CTX_free(pBigNumCtx);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
EC_GROUP_free(pEcGroup);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
BN_free(pBigNumPrivate);
}
else
{
err = Err_Code(ERR_TOOLS_SECURITY_GET_EC_KEY);
}
THREAD_UNLOCK_LIB_TOOLS();
}
return err;
}
看起来我没有创建创建PEM密钥所需的EVP结构的所有参数。密钥生成后的检查返回以下错误:
C01BFCF7FF7F0000:error:080C0102:elliptic curve routines:ossl_ec_key_public_check_quick:passed a null parameter:crypto/ec/ec_key.c:444:
PEM_write_bio_PrivateKey之后,最终输出以下错误:
C01BFCF7FF7F0000:error:080C0102:elliptic curve routines:i2d_ECPrivateKey:passed a null parameter:crypto/ec/ec_asn1.c:1031:
C01BFCF7FF7F0000:error:1C8C0100:Provider routines:key_to_p8info:malloc failure:providers/implementations/encode_decode/encode_key2any.c:94:
我已经没有什么想法了,OpenSSL手册页也没有什么帮助,有人能帮我吗?
1条答案
按热度按时间nx7onnlm1#
据我所知,新的高级接口不能创建一个“密钥对”PKEY,其中的public是从一个原始的private派生出来的,您可以做的是创建一个private-only PKEY并将其写出来--根据RFC 5915(又名SEC 1)和由知道自己在做什么的人编写的软件(如OpenSSL),这是有效的,但不推荐(至少在这种情况下!),* 将 * 阅读它。然而,很多软件不是由这样的人编写的,可能会拒绝或错误处理这样的文件。在这种情况下,或者如果你只是真的想要一个密钥对,你能做的就是把私钥“写出”内存,然后“读回”-- * API * 做的 *(内部)从private派生public,(编辑)导致,但它也将编码标志设置为no-public,因此您必须修复它以获得可以作为密钥对编写的PKEY。
我真的不喜欢“if precondition 1 if precondition 2 if precondition 3......”的风格,这种风格会导致代码中的正常情况,我通常关心的情况,被缩进到最右边,我不得不到邻居家去读它(特别是在像现在这样的冬天),所以我使用了微不足道的abort-on-error;您几乎肯定希望将其更改回适合您的程序设计的内容。