我想更新一个函数,它应该生成一个 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 手册页也没什么用,有人可以帮我吗?