Files
git/sha1/openssl.h
Jeff King 600588d2aa hash: add platform-specific discard functions
Our git_hash_discard() is a bit hacky: it just calls git_hash_final()
into a dummy result buffer, using the side effect that each
implementation's Final() function will also free any resources.

This is probably not too terrible, since generating the final hash is
not that expensive and we'd mostly call discard on unusual or error code
paths. But we can do better by widening the platform API a bit to add an
explicit discard function.

This requires an annoying amount of boilerplate:

  - Each algorithm needs a git_$ALGO_discard() wrapper that dereferences
    the union'd git_hash_ctx into the type-safe field. So sha1 + sha256
    + sha1-unsafe, plus a BUG() for the unknown algo. And then these all
    need to be referenced in the git_hash_algo structs.

  - Platforms which don't do anything special to discard now need a
    fallback function which does nothing. And we need this for each algo
    (sha1, sha256, and sha1-unsafe).

  - Platforms which do need to discard must define their discard
    functions. This includes sha1/openssl, sha256/openssl, and
    sha256/gcrypt (no sha1-unsafe here as it sits atop the sha1/openssl
    functions).

  - Algo selection needs to point platform_*_Discard to the appropriate
    underlying macro, or indicate that the fallback should be used. We
    have a similar situation for the Clone function (where a straight
    memcpy() of the context struct is not enough for some platforms).
    I've tied Discard to the same flag used by Clone here, since they
    are basically the same problem: is the hash context a sequence of
    bytes, or does it need smart copying/discarding?

It's easy to miss a case here since we don't even compile the
implementations we aren't using. I've tested with each of:

  - no flags, which uses our internal sha1/sha256 implementations, both
    of which exercise the noop fallback function

  - OPENSSL_SHA1_UNSAFE=1, which checks that our unsafe macro
    redirections work

  - OPENSSL_SHA1=1, though you should not do that in real life!

  - OPENSSL_SHA256=1, passes tests with GIT_TEST_DEFAULT_HASH=sha256

  - GCRYPT_SHA256=1, which likewise passes

The other implementations do not set the CLONE_HELPER flag, so they
treat the context as bytes and should be fine with the fallback.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-02 09:50:47 -07:00

58 lines
1.4 KiB
C

/* wrappers for the EVP API of OpenSSL 3+ */
#ifndef SHA1_OPENSSL_H
#define SHA1_OPENSSL_H
#include <openssl/evp.h>
struct openssl_SHA1_CTX {
EVP_MD_CTX *ectx;
};
typedef struct openssl_SHA1_CTX openssl_SHA1_CTX;
static inline void openssl_SHA1_Init(struct openssl_SHA1_CTX *ctx)
{
const EVP_MD *type = EVP_sha1();
ctx->ectx = EVP_MD_CTX_new();
if (!ctx->ectx)
die("EVP_MD_CTX_new: out of memory");
EVP_DigestInit_ex(ctx->ectx, type, NULL);
}
static inline void openssl_SHA1_Update(struct openssl_SHA1_CTX *ctx,
const void *data,
size_t len)
{
EVP_DigestUpdate(ctx->ectx, data, len);
}
static inline void openssl_SHA1_Final(unsigned char *digest,
struct openssl_SHA1_CTX *ctx)
{
EVP_DigestFinal_ex(ctx->ectx, digest, NULL);
EVP_MD_CTX_free(ctx->ectx);
}
static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst,
const struct openssl_SHA1_CTX *src)
{
EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
}
static inline void openssl_SHA1_Discard(struct openssl_SHA1_CTX *ctx)
{
EVP_MD_CTX_free(ctx->ectx);
}
#ifndef platform_SHA_CTX
#define platform_SHA_CTX openssl_SHA1_CTX
#define platform_SHA1_Init openssl_SHA1_Init
#define platform_SHA1_Clone openssl_SHA1_Clone
#define platform_SHA1_Update openssl_SHA1_Update
#define platform_SHA1_Final openssl_SHA1_Final
#define platform_SHA1_Discard openssl_SHA1_Discard
#endif
#endif /* SHA1_OPENSSL_H */