OpenSSL 3.0 从 mpi 表示中的私钥创建 PEM 格式的 EC 私钥

问题描述 投票:0回答:0

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

c openssl public-key-encryption
© www.soinside.com 2019 - 2024. All rights reserved.