mercredi 29 septembre 2021

How to set only public key in OpenSSL 3.0 EVP_PKEY api

I am able to extract public and private keys from OSSL_PARAM array with these functions (i tried using special functions to get parameter by name, but they can't find actual parameters by that names)

std::vector<unsigned char> RSAKeyPair::GetNamedParam(EVP_PKEY *key, const std::string& name) {
    OSSL_PARAM *param_array;
    if (EVP_PKEY_todata(key, EVP_PKEY_PUBLIC_KEY, &param_array) == 0)
        throw std::runtime_error("cannot read parameters");

    OSSL_PARAM *cur_param;
    int i = 0;
    do {
        cur_param = &param_array[i++];
        if (std::string(cur_param->key) == name) {
            auto data = GetParameterData(cur_param);
            OSSL_PARAM_free(param_array);
            return data;
        }
    } while (cur_param->key != nullptr);

    throw std::runtime_error("cannot find parameter with name \"" + name + '"');
}

std::vector<unsigned char> RSAKeyPair::GetParameterData(OSSL_PARAM *param) {
    BIGNUM *bignum{nullptr};
    if(OSSL_PARAM_get_BN(param, &bignum) == 0)
        throw std::runtime_error("cannot read bignum");

    std::vector<unsigned char> bytes;
    int new_size = BN_num_bytes(bignum);
    bytes.resize(new_size);
    BN_bn2bin(bignum, bytes.data());

    return bytes;
}

The problem is when I try to build new key from raw bytes using the same approach

void RSAKeyPair::SetPublicKey(const std::vector<unsigned char> &key) {
    OSSL_PARAM *parameters = GetKeyParameters({key}, std::nullopt);
    SetKeyFromParameters(parameters);
    OSSL_PARAM_free(parameters);
}

void RSAKeyPair::SetKeyFromParameters(OSSL_PARAM *parameters) {
    auto ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
    if (EVP_PKEY_fromdata_init(ctx) <= 0)
        throw std::runtime_error("cannot init create key");

    EVP_PKEY_free(keys_);
    if (EVP_PKEY_fromdata(ctx, &keys_, EVP_PKEY_KEYPAIR, parameters) <= 0)
        throw std::runtime_error("cannot create key");
}

OSSL_PARAM *RSAKeyPair::GetKeyParameters(std::optional<std::reference_wrapper<const std::vector<unsigned char>>> public_key,
                                         std::optional<std::reference_wrapper<const std::vector<unsigned char>>> private_key) {
    auto param_bld = OSSL_PARAM_BLD_new();

    if (public_key.has_value()) {
        auto public_data = public_key.value().get();
        PushParamBuildBignum(param_bld, "n", public_data);
    }

    if (private_key.has_value()) {
        auto private_data = private_key.value().get();
        PushParamBuildBignum(param_bld, "d", private_data);
    }

    // default rsa exponent
    OSSL_PARAM_BLD_push_long(param_bld, "e", RSA_F4);

    auto parameters = OSSL_PARAM_BLD_to_param(param_bld);
    OSSL_PARAM_BLD_free(param_bld);

    return parameters;
}

void RSAKeyPair::PushParamBuildBignum(OSSL_PARAM_BLD *param_bld, const char *key, std::vector<unsigned char> &bytes) {
    BIGNUM *bignum = BN_bin2bn(bytes.data(), (int)bytes.size(), nullptr);
    OSSL_PARAM_BLD_push_BN(param_bld, key, bignum);
}

for some reason, function EVP_PKEY_fromdata() fails to create new key using my OSSL_PARAM array. What am I supposed to do to initialize ONLY public key on signature verifying end (where I cannot build full keypair with all parameters) ?

you can see full source code for this class at https://github.com/Valemos/course_work_inverted_index/blob/master/src/session/RSAKeyPair.cpp

Aucun commentaire:

Enregistrer un commentaire