Skip to content

Move all code using EVP_PKEY_assign and EVP_PKEY_get0 into legacy-only modules #508

@VladGud

Description

@VladGud

Move all code using EVP_PKEY_assign and EVP_PKEY_get0 into legacy-only modules

Summary

Extract all functions using deprecated EVP_PKEY internal accessors (EVP_PKEY_assign, EVP_PKEY_get0) into separate legacy-only modules (gost_ameth_legacy.c, gost_pmeth_legacy.c) that are compiled only when GOST_ENABLE_LEGACY is enabled.

Problem Description

The current implementation uses deprecated OpenSSL EVP_PKEY internal accessors scattered throughout multiple files:

  • EVP_PKEY_assign(pkey, nid, key_data) - Directly assigns algorithm-specific key data to an EVP_PKEY without going through proper OpenSSL provider interfaces
  • EVP_PKEY_get0(pkey) - Directly retrieves raw algorithm-specific key data from EVP_PKEY, bypassing encapsulation

These functions are deprecated because they:

  1. Break encapsulation by exposing internal EVP_PKEY structure layout
  2. Are not available in OpenSSL builds with OPENSSL_NO_DEPRECATED flag
  3. Prevent migration to provider-based EVP_PKEY implementations
  4. Create tight coupling to OpenSSL internal APIs

Current usage

These deprecated accessors are used in:

  • gost_ameth.c - ASN1 method implementations
  • gost_pmeth.c - PKEYmethod implementations for key generation, signing, MAC operations

Required Changes

1. Create gost_ameth_legacy.c

Move all functions from gost_ameth.c that call EVP_PKEY_assign or EVP_PKEY_get0:

Functions to extract:

  • All ASN1 key encoding/decoding functions that use EVP_PKEY_get0 to access EC_KEY
  • All functions that use EVP_PKEY_assign to set EC_KEY in pkey

File structure:

/*
 * gost_ameth_legacy.c - Legacy ENGINE-based ASN1 methods
 * Contains all ASN1 method implementations that depend on
 * EVP_PKEY_assign and EVP_PKEY_get0.
 * Only compiled when GOST_ENABLE_LEGACY is enabled.
 */

#include "gost_lcl.h"
#include "e_gost_err.h"


/* Legacy ASN1 implementations using EVP_PKEY internals */
static int gost_ameth_keybuf_to_priv_key(...)
{
    EVP_PKEY *pkey = EVP_PKEY_new();
    if (!pkey)
        return 0;
    
    /* Use EVP_PKEY_get0 / EVP_PKEY_assign here */
    EC_KEY *ec = ECP_KEY_new();
    /* ... */
    if (!EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec)) {
        EC_KEY_free(ec);
        EVP_PKEY_free(pkey);
        return 0;
    }
    
    return 1;
}

/* ... other extracted functions ... */

2. Create gost_pmeth_legacy.c

Move all functions from gost_pmeth.c that call EVP_PKEY_assign or EVP_PKEY_get0:

Functions to extract:

  • pkey_gost2001_paramgen()
  • pkey_gost2012_paramgen()
  • pkey_gost2001cp_keygen()
  • pkey_gost2012cp_keygen()
  • pkey_gost_mac_keygen_base()
  • pkey_gost_mac_keygen_12()
  • pkey_gost_mac_keygen()
  • pkey_gost_magma_mac_keygen()
  • pkey_gost_grasshopper_mac_keygen()
  • pkey_gost_ec_cp_sign() and related
  • pkey_gost_ec_cp_verify() and related

File structure:

/*
 * gost_pmeth_legacy.c - Legacy ENGINE-based PKEY methods
 * Contains all EVP_PKEY_METHOD implementations that depend on
 * EVP_PKEY_assign and EVP_PKEY_get0.
 * Only compiled when GOST_ENABLE_LEGACY is enabled.
 */

#include "gost_lcl.h"
#include "e_gost_err.h"

/* Legacy paramgen implementations using EVP_PKEY internals */
static int pkey_gost2001_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
{
    struct gost_pmeth_data *data = EVP_PKEY_CTX_get_data(ctx);
    EC_KEY *ec = NULL;

    if (!data || data->sign_param_nid == NID_undef) {
        GOSTerr(GOST_F_PKEY_GOST2001_PARAMGEN, GOST_R_NO_PARAMETERS_SET);
        return 0;
    }

    ec = internal_ec_paramgen(data->sign_param_nid);
    if (!ec)
        return 0;

    if (!EVP_PKEY_assign(pkey, NID_id_GostR3410_2001, ec)) {
        EC_KEY_free(ec);
        return 0;
    }
    return 1;
}

/* ... other extracted functions ... */

/* Registration function called from main register_pmeth_gost */
int register_pmeth_gost_legacy(int id, EVP_PKEY_METHOD **pmeth, int flags)
{
    /* Set up methods for legacy-only cases */
    switch (id) {
    case NID_id_GostR3410_2001:
        EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost2001cp_keygen);
        break;
    case NID_id_GostR3410_2012_256:
        EVP_PKEY_meth_set_keygen(*pmeth, NULL, pkey_gost2012cp_keygen);
        break;
    /* ... */
    }
    return 1;
}

3. Update gost_ameth.c

Remove all functions that use EVP_PKEY_assign or EVP_PKEY_get0. Keep only the common infrastructure:

/* gost_ameth.c - ASN1 method implementations (provider-compatible) */

#include "gost_lcl.h"
#include "e_gost_err.h"

/* Common ASN1 infrastructure that doesn't depend on EVP_PKEY internals */
static int gost_ameth_foo() { ... }

/* Conditional inclusion of legacy implementations */
#ifdef GOST_ENABLE_LEGACY
#include "gost_ameth_legacy.c"
#endif

/* For provider-only builds, these return error */
#ifndef GOST_ENABLE_LEGACY
static int gost_ameth_keybuf_to_priv_key_stub(...)
{
    GOSTerr(GOST_F_AMETH, GOST_R_LEGACY_DISABLED);
    return 0;
}
/* ... other stubs ... */
#endif

4. Update gost_pmeth.c

Remove all functions that use EVP_PKEY_assign or EVP_PKEY_get0.

5. Update CMakeLists.txt or build system

Add conditional compilation:

# Legacy support (default: ON for backward compatibility)
option(GOST_ENABLE_LEGACY "Enable legacy ENGINE-based implementations" ON)

if(GOST_ENABLE_LEGACY)
    target_sources(gost_engine PRIVATE
        gost_ameth_legacy.c
        gost_pmeth_legacy.c
    )
    target_compile_definitions(gost_engine PRIVATE GOST_ENABLE_LEGACY)
endif()

target_sources(gost_engine PRIVATE
    gost_ameth.c
    gost_pmeth.c
    # ... other sources ...
)

Files to Create

  • gost_ameth_legacy.c - Legacy ASN1 method implementations
  • gost_pmeth_legacy.c - Legacy PKEY method implementations

Files to Modify

  • gost_ameth.c - Remove legacy functions, keep common code
  • gost_pmeth.c - Remove legacy functions, update registration to delegate to legacy module
  • CMakeLists.txt or build system - Add conditional compilation

Compilation behavior

When GOST_ENABLE_LEGACY=ON (default):

  • gost_ameth_legacy.c and gost_pmeth_legacy.c are compiled
  • Full backward compatibility with existing ENGINE-based code
  • Uses EVP_PKEY_assign and EVP_PKEY_get0

When GOST_ENABLE_LEGACY is not set:

  • gost_ameth_legacy.c and gost_pmeth_legacy.c are NOT compiled
  • Legacy paramgen/keygen operations return error
  • Compatible with OpenSSL builds with OPENSSL_NO_DEPRECATED
  • Provider-only mode (future work will implement provider interfaces)

Acceptance Criteria

  • All EVP_PKEY_assign calls moved to legacy modules
  • All EVP_PKEY_get0 calls moved to legacy modules
  • Code compiles with GOST_ENABLE_LEGACY=ON (default) - all tests pass
  • Code compiles with GOST_ENABLE_LEGACY=OFF - legacy operations fail gracefully with clear error

Testing

  • Compile with -DGOST_ENABLE_LEGACY=ON (default) - all tests pass
  • Compile with -DGOST_ENABLE_LEGACY=OFF - legacy operations fail with GOST_R_LEGACY_DISABLED
  • Test with OpenSSL compiled with OPENSSL_NO_DEPRECATED and GOST_ENABLE_LEGACY=OFF

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions