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
Decouple digest and MAC provider logic from
EVP_MD*APIsSummary
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_CTXas an intermediate layer:Current flow:
This creates several issues:
Dependencies
*_directmethod variants that operate on internal contextsRequired Changes
1. Update provider digest context structure (gost_prov_digest.c)
Before:
After:
2. Replace EVP_MD_CTX operations with direct calls
Update all provider OSSL_FUNC implementations:
digest_newctx:digest_freectx:digest_dupctx:digest_init:digest_update:digest_final: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
digest_get_paramshelper if it relies on EVP_MDFiles to Modify
Acceptance Criteria
EVP_MD_CTX_new(),EVP_MD_CTX_free(),EVP_MD_CTX_copy()EVP_DigestInit_ex(),EVP_DigestUpdate(),EVP_DigestFinal_ex()Testing
make test TESTS=test_digest_providermake test TESTS=test_mac_provider