Skip to content

Decouple digest and MAC provider logic from EVP_MD* APIs #505

@VladGud

Description

@VladGud

Decouple digest and MAC provider logic from EVP_MD* APIs

Summary

Refactor provider digest and MAC implementations (gost_prov_digest.c and gost_prov_mac.c) to operate on provider-native contexts, without relying on EVP_MD, EVP_MD_CTX, or legacy EVP digest interfaces.

Problem Description

The current provider implementation wraps legacy ENGINE-based digest implementations using EVP_MD_CTX as an intermediate layer:

Current flow:

Provider DIGEST API → EVP_MD_CTX → ENGINE/legacy EVP_MD → struct ossl_gost_digest_ctx → actual digest logic

This creates several issues:

  • Performance overhead: Extra indirection through EVP_MD_CTX with redundant context handling
  • Legacy API dependency: Relies on EVP_MD_CTX_* and EVP_Digest* APIs which are not provider-native
  • Maintenance burden: Requires translating provider calls into EVP calls
  • Future compatibility: Risks incompatibility with future OpenSSL versions moving away from ENGINE

Dependencies

Required Changes

1. Update provider digest context structure (gost_prov_digest.c)

Before:

struct gost_prov_crypt_ctx_st {
    PROV_CTX *provctx;
    const OSSL_PARAM *known_params;
    GOST_digest *descriptor;
    EVP_MD *digest;        // Remove
    EVP_MD_CTX *dctx;      // Remove
};

After:

struct gost_prov_digest_ctx_st {
    PROV_CTX *provctx;
    const OSSL_PARAM *known_params;
    const GOST_digest *descriptor;
    void *md_data;  // Direct internal digest context
};

2. Replace EVP_MD_CTX operations with direct calls

Update all provider OSSL_FUNC implementations:

digest_newctx:

static void *digest_newctx(void *provctx, GOST_digest *descriptor, const OSSL_PARAM *known_params)
{
    GOST_PROV_MD_CTX *gctx = OPENSSL_zalloc(sizeof(*gctx));
    if (gctx == NULL)
        return NULL;
    
    gctx->provctx = provctx;
    gctx->known_params = known_params;
    gctx->descriptor = descriptor;
    
    // Allocate internal digest context directly
    gctx->md_data = OPENSSL_zalloc(descriptor->app_datasize);
    if (gctx->md_data == NULL) {
        OPENSSL_free(gctx);
        return NULL;
    }
    
    return gctx;
}

digest_freectx:

static void digest_freectx(void *vgctx)
{
    GOST_PROV_MD_CTX *gctx = vgctx;
    if (gctx == NULL)
        return;
    
    if (gctx->md_data && gctx->descriptor && gctx->descriptor->cleanup_direct)
        gctx->descriptor->cleanup_direct(gctx->md_data);
    
    OPENSSL_clear_free(gctx->md_data, gctx->descriptor->app_datasize);
    OPENSSL_free(gctx);
}

digest_dupctx:

static void *digest_dupctx(void *vsrc)
{
    GOST_PROV_MD_CTX *src = vsrc;
    GOST_PROV_MD_CTX *dst = digest_newctx(src->provctx, src->descriptor, src->known_params);
    
    if (dst == NULL)
        return NULL;
    
    if (src->descriptor->copy_direct)
        src->descriptor->copy_direct(dst->md_data, src->md_data);
    else
        memcpy(dst->md_data, src->md_data, src->descriptor->app_datasize);
    
    return dst;
}

digest_init:

static int digest_init(void *vgctx, const OSSL_PARAM unused_params[])
{
    GOST_PROV_MD_CTX *gctx = vgctx;
    return gctx->descriptor->init_direct(gctx->md_data);
}

digest_update:

static int digest_update(void *vgctx, const unsigned char *in, size_t inl)
{
    GOST_PROV_MD_CTX *gctx = vgctx;
    return gctx->descriptor->update_direct(gctx->md_data, in, inl);
}

digest_final:

static int digest_final(void *vgctx, unsigned char *out, size_t *outl, size_t outsize)
{
    GOST_PROV_MD_CTX *gctx = vgctx;
    
    if (out == NULL) {
        *outl = gctx->descriptor->result_size;
        return 1;
    }
    
    if (outsize < gctx->descriptor->result_size)
        return 0;
    
    int ret = gctx->descriptor->final_direct(gctx->md_data, out);
    if (ret > 0)
        *outl = gctx->descriptor->result_size;
    
    return ret;
}

3. Update provider MAC context structure (gost_prov_mac.c)

Similar changes for MAC provider, replacing EVP_MD_CTX with direct OMAC context operations.

4. Remove obsolete helper functions

  • Remove digest_get_params helper if it relies on EVP_MD
  • Update to use descriptor fields directly

Files to Modify

  • gost_prov_digest.c: Remove all EVP_MD_CTX usage, use direct dispatch
  • gost_prov_mac.c: Remove all EVP_MD_CTX usage for MAC operations

Acceptance Criteria

  • No calls to EVP_MD_CTX_new(), EVP_MD_CTX_free(), EVP_MD_CTX_copy()
  • No calls to EVP_DigestInit_ex(), EVP_DigestUpdate(), EVP_DigestFinal_ex()
  • Provider digest/MAC operations use direct method dispatch via descriptor
  • All provider digest tests pass
  • All provider MAC tests pass
  • Code is ready for ENGINE-free OpenSSL builds

Testing

  • Run provider digest tests: make test TESTS=test_digest_provider
  • Run provider MAC tests: make test TESTS=test_mac_provider
  • Verify no regressions in digest/MAC functionality

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions