hash: introduce source files to break include circles

The hash source files have circular include dependencies right
now, which shows by our broken generic hash implementation. The
"hash.h" header declares two functions and the `git_hash_ctx`
typedef before actually including the hash backend header and can
only declare the remaining hash functions after the include due
to possibly static function declarations inside of the
implementation includes.

Let's break this cycle and help maintainability by creating a
real implementation file for each of the hash implementations.
Instead of relying on the exact include order, we now especially
avoid the use of `GIT_INLINE` for function declarations.
This commit is contained in:
Patrick Steinhardt
2019-06-14 14:21:32 +02:00
parent bbf034ab93
commit bd48bf3fb9
14 changed files with 217 additions and 161 deletions

View File

@@ -40,8 +40,10 @@ ELSEIF(SHA1_BACKEND STREQUAL "OpenSSL")
ELSE()
LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
ENDIF()
FILE(GLOB SRC_SHA1 hash/hash_openssl.c)
ELSEIF(SHA1_BACKEND STREQUAL "CommonCrypto")
SET(GIT_SHA1_COMMON_CRYPTO 1)
FILE(GLOB SRC_SHA1 hash/hash_common_crypto.c)
ELSEIF(SHA1_BACKEND STREQUAL "mbedTLS")
SET(GIT_SHA1_MBEDTLS 1)
FILE(GLOB SRC_SHA1 hash/hash_mbedtls.c)

View File

@@ -13,8 +13,10 @@
typedef struct git_hash_ctx git_hash_ctx;
int git_hash_ctx_init(git_hash_ctx *ctx);
void git_hash_ctx_cleanup(git_hash_ctx *ctx);
typedef struct {
void *data;
size_t len;
} git_buf_vec;
#if defined(GIT_SHA1_COLLISIONDETECT)
# include "hash/hash_collisiondetect.h"
@@ -30,10 +32,10 @@ void git_hash_ctx_cleanup(git_hash_ctx *ctx);
# include "hash/hash_generic.h"
#endif
typedef struct {
void *data;
size_t len;
} git_buf_vec;
int git_hash_global_init(void);
int git_hash_ctx_init(git_hash_ctx *ctx);
void git_hash_ctx_cleanup(git_hash_ctx *ctx);
int git_hash_init(git_hash_ctx *c);
int git_hash_update(git_hash_ctx *c, const void *data, size_t len);

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "hash_collisiondetect.h"
int git_hash_global_init(void)
{
return 0;
}
int git_hash_ctx_init(git_hash_ctx *ctx)
{
return git_hash_init(ctx);
}
void git_hash_ctx_cleanup(git_hash_ctx *ctx)
{
GIT_UNUSED(ctx);
}
int git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
SHA1DCInit(&ctx->c);
return 0;
}
int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
{
assert(ctx);
SHA1DCUpdate(&ctx->c, data, len);
return 0;
}
int git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
if (SHA1DCFinal(out->id, &ctx->c)) {
git_error_set(GIT_ERROR_SHA1, "SHA1 collision attack detected");
return -1;
}
return 0;
}

View File

@@ -9,43 +9,11 @@
#define INCLUDE_hash_hash_collisiondetect_h__
#include "hash.h"
#include "sha1dc/sha1.h"
struct git_hash_ctx {
SHA1_CTX c;
};
#define git_hash_ctx_init(ctx) git_hash_init(ctx)
#define git_hash_ctx_cleanup(ctx)
GIT_INLINE(int) git_hash_global_init(void)
{
return 0;
}
GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
SHA1DCInit(&ctx->c);
return 0;
}
GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
{
assert(ctx);
SHA1DCUpdate(&ctx->c, data, len);
return 0;
}
GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
if (SHA1DCFinal(out->id, &ctx->c)) {
git_error_set(GIT_ERROR_SHA1, "SHA1 collision attack detected");
return -1;
}
return 0;
}
#endif

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "hash_common_crypto.h"
#define CC_LONG_MAX ((CC_LONG)-1)
int git_hash_global_init(void)
{
return 0;
}
int git_hash_ctx_init(git_hash_ctx *ctx)
{
return git_hash_init(ctx);
}
void git_hash_ctx_cleanup(git_hash_ctx *ctx)
{
GIT_UNUSED(ctx);
}
int git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
CC_SHA1_Init(&ctx->c);
return 0;
}
int git_hash_update(git_hash_ctx *ctx, const void *_data, size_t len)
{
const unsigned char *data = _data;
assert(ctx);
while (len > 0) {
CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len;
CC_SHA1_Update(&ctx->c, data, chunk);
data += chunk;
len -= chunk;
}
return 0;
}
int git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
CC_SHA1_Final(out->id, &ctx->c);
return 0;
}

View File

@@ -16,46 +16,4 @@ struct git_hash_ctx {
CC_SHA1_CTX c;
};
#define CC_LONG_MAX ((CC_LONG)-1)
#define git_hash_ctx_init(ctx) git_hash_init(ctx)
#define git_hash_ctx_cleanup(ctx)
GIT_INLINE(int) git_hash_global_init(void)
{
return 0;
}
GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
CC_SHA1_Init(&ctx->c);
return 0;
}
GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *_data, size_t len)
{
const unsigned char *data = _data;
assert(ctx);
while (len > 0) {
CC_LONG chunk = (len > CC_LONG_MAX) ? CC_LONG_MAX : (CC_LONG)len;
CC_SHA1_Update(&ctx->c, data, chunk);
data += chunk;
len -= chunk;
}
return 0;
}
GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
CC_SHA1_Final(out->id, &ctx->c);
return 0;
}
#endif

View File

@@ -7,8 +7,6 @@
#include "hash_generic.h"
#include "hash.h"
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
/*
@@ -221,6 +219,21 @@ static void hash__block(git_hash_ctx *ctx, const unsigned int *data)
ctx->H[4] += E;
}
int git_hash_global_init(void)
{
return 0;
}
int git_hash_ctx_init(git_hash_ctx *ctx)
{
return git_hash_init(ctx);
}
void git_hash_ctx_cleanup(git_hash_ctx *ctx)
{
GIT_UNUSED(ctx);
}
int git_hash_init(git_hash_ctx *ctx)
{
ctx->size = 0;
@@ -285,4 +298,3 @@ int git_hash_final(git_oid *out, git_hash_ctx *ctx)
return 0;
}

View File

@@ -8,8 +8,6 @@
#ifndef INCLUDE_hash_hash_generic_h__
#define INCLUDE_hash_hash_generic_h__
#include "common.h"
#include "hash.h"
struct git_hash_ctx {
@@ -18,12 +16,4 @@ struct git_hash_ctx {
unsigned int W[16];
};
#define git_hash_ctx_init(ctx) git_hash_init(ctx)
#define git_hash_ctx_cleanup(ctx)
GIT_INLINE(int) git_hash_global_init(void)
{
return 0;
}
#endif

View File

@@ -9,6 +9,16 @@
#include "hash.h"
#include "hash/hash_mbedtls.h"
int git_hash_global_init(void)
{
return 0;
}
int git_hash_ctx_init(git_hash_ctx *ctx)
{
return git_hash_init(ctx);
}
void git_hash_ctx_cleanup(git_hash_ctx *ctx)
{
assert(ctx);

View File

@@ -8,17 +8,12 @@
#ifndef INCLUDE_hash_mbedtld_h__
#define INCLUDE_hash_mbedtld_h__
#include "hash.h"
#include <mbedtls/sha1.h>
struct git_hash_ctx {
mbedtls_sha1_context c;
};
#define git_hash_ctx_init(ctx) git_hash_init(ctx)
GIT_INLINE(int) git_hash_global_init(void)
{
return 0;
}
#endif /* INCLUDE_hash_mbedtld_h__ */

59
src/hash/hash_openssl.c Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "hash_openssl.h"
int git_hash_global_init(void)
{
return 0;
}
int git_hash_ctx_init(git_hash_ctx *ctx)
{
return git_hash_init(ctx);
}
void git_hash_ctx_cleanup(git_hash_ctx *ctx)
{
GIT_UNUSED(ctx);
}
int git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
if (SHA1_Init(&ctx->c) != 1) {
git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to initialize hash context");
return -1;
}
return 0;
}
int git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
{
assert(ctx);
if (SHA1_Update(&ctx->c, data, len) != 1) {
git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to update hash");
return -1;
}
return 0;
}
int git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
if (SHA1_Final(out->id, &ctx->c) != 1) {
git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to finalize hash");
return -1;
}
return 0;
}

View File

@@ -8,6 +8,8 @@
#ifndef INCLUDE_hash_hash_openssl_h__
#define INCLUDE_hash_hash_openssl_h__
#include "common.h"
#include "hash.h"
#include <openssl/sha.h>
@@ -16,48 +18,4 @@ struct git_hash_ctx {
SHA_CTX c;
};
#define git_hash_ctx_init(ctx) git_hash_init(ctx)
#define git_hash_ctx_cleanup(ctx)
GIT_INLINE(int) git_hash_global_init(void)
{
return 0;
}
GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
{
assert(ctx);
if (SHA1_Init(&ctx->c) != 1) {
git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to initialize hash context");
return -1;
}
return 0;
}
GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
{
assert(ctx);
if (SHA1_Update(&ctx->c, data, len) != 1) {
git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to update hash");
return -1;
}
return 0;
}
GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
{
assert(ctx);
if (SHA1_Final(out->id, &ctx->c) != 1) {
git_error_set(GIT_ERROR_SHA1, "hash_openssl: failed to finalize hash");
return -1;
}
return 0;
}
#endif

View File

@@ -8,11 +8,21 @@
#include "hash_win32.h"
#include "global.h"
#include "hash.h"
#include <wincrypt.h>
#include <strsafe.h>
#define GIT_HASH_CNG_DLL_NAME "bcrypt.dll"
/* BCRYPT_SHA1_ALGORITHM */
#define GIT_HASH_CNG_HASH_TYPE L"SHA1"
/* BCRYPT_OBJECT_LENGTH */
#define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength"
/* BCRYPT_HASH_REUSEABLE_FLAGS */
#define GIT_HASH_CNG_HASH_REUSABLE 0x00000020
static struct git_hash_prov hash_prov = {0};
/* Hash initialization */
@@ -101,7 +111,7 @@ GIT_INLINE(void) hash_cryptoapi_prov_shutdown(void)
hash_prov.type = INVALID;
}
static void git_hash_global_shutdown(void)
static void sha1_shutdown(void)
{
if (hash_prov.type == CNG)
hash_cng_prov_shutdown();
@@ -119,7 +129,7 @@ int git_hash_global_init(void)
if ((error = hash_cng_prov_init()) < 0)
error = hash_cryptoapi_prov_init();
git__on_shutdown(git_hash_global_shutdown);
git__on_shutdown(sha1_shutdown);
return error;
}

View File

@@ -36,17 +36,6 @@ struct hash_cryptoapi_prov {
* would not exist when building in pre-Windows 2008 environments.
*/
#define GIT_HASH_CNG_DLL_NAME "bcrypt.dll"
/* BCRYPT_SHA1_ALGORITHM */
#define GIT_HASH_CNG_HASH_TYPE L"SHA1"
/* BCRYPT_OBJECT_LENGTH */
#define GIT_HASH_CNG_HASH_OBJECT_LEN L"ObjectLength"
/* BCRYPT_HASH_REUSEABLE_FLAGS */
#define GIT_HASH_CNG_HASH_REUSABLE 0x00000020
/* Function declarations for CNG */
typedef NTSTATUS (WINAPI *hash_win32_cng_open_algorithm_provider_fn)(
HANDLE /* BCRYPT_ALG_HANDLE */ *phAlgorithm,
@@ -138,6 +127,4 @@ struct git_hash_ctx {
} ctx;
};
extern int git_hash_global_init(void);
#endif