Skip to content

Commit

Permalink
Merge branch 'tb/weak-sha1-for-tail-sum'
Browse files Browse the repository at this point in the history
The checksum at the tail of files are now computed without
collision detection protection.  This is safe as the consumer of
the information to protect itself from replay attacks checks for
hash collisions independently.

* tb/weak-sha1-for-tail-sum:
  csum-file.c: use unsafe SHA-1 implementation when available
  Makefile: allow specifying a SHA-1 for non-cryptographic uses
  hash.h: scaffolding for _unsafe hashing variants
  sha1: do not redefine `platform_SHA_CTX` and friends
  pack-objects: use finalize_object_file() to rename pack/idx/etc
  finalize_object_file(): implement collision check
  finalize_object_file(): refactor unlink_or_warn() placement
  finalize_object_file(): check for name collision before renaming
  • Loading branch information
gitster committed Oct 2, 2024
2 parents 59ee4f7 + 1b9e9be commit ead0a05
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 26 deletions.
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,10 @@ include shared.mak
# Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
# SHA-1.
#
# Define the same Makefile knobs as above, but suffixed with _UNSAFE to
# use the corresponding implementations for unsafe SHA-1 hashing for
# non-cryptographic purposes.
#
# If don't enable any of the *_SHA1 settings in this section, Git will
# default to its built-in sha1collisiondetection library, which is a
# collision-detecting sha1 This is slower, but may detect attempted
Expand Down Expand Up @@ -1997,6 +2001,27 @@ endif
endif
endif

ifdef OPENSSL_SHA1_UNSAFE
ifndef OPENSSL_SHA1
EXTLIBS += $(LIB_4_CRYPTO)
BASIC_CFLAGS += -DSHA1_OPENSSL_UNSAFE
endif
else
ifdef BLK_SHA1_UNSAFE
ifndef BLK_SHA1
LIB_OBJS += block-sha1/sha1.o
BASIC_CFLAGS += -DSHA1_BLK_UNSAFE
endif
else
ifdef APPLE_COMMON_CRYPTO_SHA1_UNSAFE
ifndef APPLE_COMMON_CRYPTO_SHA1
COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
BASIC_CFLAGS += -DSHA1_APPLE_UNSAFE
endif
endif
endif
endif

ifdef OPENSSL_SHA256
EXTLIBS += $(LIB_4_CRYPTO)
BASIC_CFLAGS += -DSHA256_OPENSSL
Expand Down
2 changes: 2 additions & 0 deletions block-sha1/sha1.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ void blk_SHA1_Init(blk_SHA_CTX *ctx);
void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, size_t len);
void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);

#ifndef platform_SHA_CTX
#define platform_SHA_CTX blk_SHA_CTX
#define platform_SHA1_Init blk_SHA1_Init
#define platform_SHA1_Update blk_SHA1_Update
#define platform_SHA1_Final blk_SHA1_Final
#endif
18 changes: 9 additions & 9 deletions csum-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void hashflush(struct hashfile *f)

if (offset) {
if (!f->skip_hash)
the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
the_hash_algo->unsafe_update_fn(&f->ctx, f->buffer, offset);
flush(f, f->buffer, offset);
f->offset = 0;
}
Expand All @@ -73,7 +73,7 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
if (f->skip_hash)
hashclr(f->buffer, the_repository->hash_algo);
else
the_hash_algo->final_fn(f->buffer, &f->ctx);
the_hash_algo->unsafe_final_fn(f->buffer, &f->ctx);

if (result)
hashcpy(result, f->buffer, the_repository->hash_algo);
Expand Down Expand Up @@ -128,7 +128,7 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
* f->offset is necessarily zero.
*/
if (!f->skip_hash)
the_hash_algo->update_fn(&f->ctx, buf, nr);
the_hash_algo->unsafe_update_fn(&f->ctx, buf, nr);
flush(f, buf, nr);
} else {
/*
Expand Down Expand Up @@ -174,7 +174,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
f->name = name;
f->do_crc = 0;
f->skip_hash = 0;
the_hash_algo->init_fn(&f->ctx);
the_hash_algo->unsafe_init_fn(&f->ctx);

f->buffer_len = buffer_len;
f->buffer = xmalloc(buffer_len);
Expand Down Expand Up @@ -208,7 +208,7 @@ void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpo
{
hashflush(f);
checkpoint->offset = f->total;
the_hash_algo->clone_fn(&checkpoint->ctx, &f->ctx);
the_hash_algo->unsafe_clone_fn(&checkpoint->ctx, &f->ctx);
}

int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
Expand All @@ -219,7 +219,7 @@ int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint
lseek(f->fd, offset, SEEK_SET) != offset)
return -1;
f->total = offset;
the_hash_algo->clone_fn(&f->ctx, &checkpoint->ctx);
the_hash_algo->unsafe_clone_fn(&f->ctx, &checkpoint->ctx);
f->offset = 0; /* hashflush() was called in checkpoint */
return 0;
}
Expand All @@ -245,9 +245,9 @@ int hashfile_checksum_valid(const unsigned char *data, size_t total_len)
if (total_len < the_hash_algo->rawsz)
return 0; /* say "too short"? */

the_hash_algo->init_fn(&ctx);
the_hash_algo->update_fn(&ctx, data, data_len);
the_hash_algo->final_fn(got, &ctx);
the_hash_algo->unsafe_init_fn(&ctx);
the_hash_algo->unsafe_update_fn(&ctx, data, data_len);
the_hash_algo->unsafe_final_fn(got, &ctx);

return hasheq(got, data + data_len, the_repository->hash_algo);
}
72 changes: 72 additions & 0 deletions hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,36 @@
#include "block-sha1/sha1.h"
#endif

#if defined(SHA1_APPLE_UNSAFE)
# include <CommonCrypto/CommonDigest.h>
# define platform_SHA_CTX_unsafe CC_SHA1_CTX
# define platform_SHA1_Init_unsafe CC_SHA1_Init
# define platform_SHA1_Update_unsafe CC_SHA1_Update
# define platform_SHA1_Final_unsafe CC_SHA1_Final
#elif defined(SHA1_OPENSSL_UNSAFE)
# include <openssl/sha.h>
# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
# define SHA1_NEEDS_CLONE_HELPER_UNSAFE
# include "sha1/openssl.h"
# define platform_SHA_CTX_unsafe openssl_SHA1_CTX
# define platform_SHA1_Init_unsafe openssl_SHA1_Init
# define platform_SHA1_Clone_unsafe openssl_SHA1_Clone
# define platform_SHA1_Update_unsafe openssl_SHA1_Update
# define platform_SHA1_Final_unsafe openssl_SHA1_Final
# else
# define platform_SHA_CTX_unsafe SHA_CTX
# define platform_SHA1_Init_unsafe SHA1_Init
# define platform_SHA1_Update_unsafe SHA1_Update
# define platform_SHA1_Final_unsafe SHA1_Final
# endif
#elif defined(SHA1_BLK_UNSAFE)
# include "block-sha1/sha1.h"
# define platform_SHA_CTX_unsafe blk_SHA_CTX
# define platform_SHA1_Init_unsafe blk_SHA1_Init
# define platform_SHA1_Update_unsafe blk_SHA1_Update
# define platform_SHA1_Final_unsafe blk_SHA1_Final
#endif

#if defined(SHA256_NETTLE)
#include "sha256/nettle.h"
#elif defined(SHA256_GCRYPT)
Expand Down Expand Up @@ -44,14 +74,32 @@
#define platform_SHA1_Final SHA1_Final
#endif

#ifndef platform_SHA_CTX_unsafe
# define platform_SHA_CTX_unsafe platform_SHA_CTX
# define platform_SHA1_Init_unsafe platform_SHA1_Init
# define platform_SHA1_Update_unsafe platform_SHA1_Update
# define platform_SHA1_Final_unsafe platform_SHA1_Final
# ifdef platform_SHA1_Clone
# define platform_SHA1_Clone_unsafe platform_SHA1_Clone
# endif
#endif

#define git_SHA_CTX platform_SHA_CTX
#define git_SHA1_Init platform_SHA1_Init
#define git_SHA1_Update platform_SHA1_Update
#define git_SHA1_Final platform_SHA1_Final

#define git_SHA_CTX_unsafe platform_SHA_CTX_unsafe
#define git_SHA1_Init_unsafe platform_SHA1_Init_unsafe
#define git_SHA1_Update_unsafe platform_SHA1_Update_unsafe
#define git_SHA1_Final_unsafe platform_SHA1_Final_unsafe

#ifdef platform_SHA1_Clone
#define git_SHA1_Clone platform_SHA1_Clone
#endif
#ifdef platform_SHA1_Clone_unsafe
# define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe
#endif

#ifndef platform_SHA256_CTX
#define platform_SHA256_CTX SHA256_CTX
Expand Down Expand Up @@ -81,6 +129,13 @@ static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
memcpy(dst, src, sizeof(*dst));
}
#endif
#ifndef SHA1_NEEDS_CLONE_HELPER_UNSAFE
static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst,
const git_SHA_CTX_unsafe *src)
{
memcpy(dst, src, sizeof(*dst));
}
#endif

#ifndef SHA256_NEEDS_CLONE_HELPER
static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
Expand Down Expand Up @@ -178,6 +233,8 @@ enum get_oid_result {
/* A suitably aligned type for stack allocations of hash contexts. */
union git_hash_ctx {
git_SHA_CTX sha1;
git_SHA_CTX_unsafe sha1_unsafe;

git_SHA256_CTX sha256;
};
typedef union git_hash_ctx git_hash_ctx;
Expand Down Expand Up @@ -222,6 +279,21 @@ struct git_hash_algo {
/* The hash finalization function for object IDs. */
git_hash_final_oid_fn final_oid_fn;

/* The non-cryptographic hash initialization function. */
git_hash_init_fn unsafe_init_fn;

/* The non-cryptographic hash context cloning function. */
git_hash_clone_fn unsafe_clone_fn;

/* The non-cryptographic hash update function. */
git_hash_update_fn unsafe_update_fn;

/* The non-cryptographic hash finalization function. */
git_hash_final_fn unsafe_final_fn;

/* The non-cryptographic hash finalization function. */
git_hash_final_oid_fn unsafe_final_oid_fn;

/* The OID of the empty tree. */
const struct object_id *empty_tree;

Expand Down
Loading

0 comments on commit ead0a05

Please sign in to comment.