Skip to content

Commit ead0a05

Browse files
committed
Merge branch 'tb/weak-sha1-for-tail-sum'
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
2 parents 59ee4f7 + 1b9e9be commit ead0a05

File tree

11 files changed

+266
-26
lines changed

11 files changed

+266
-26
lines changed

Makefile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,10 @@ include shared.mak
521521
# Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
522522
# SHA-1.
523523
#
524+
# Define the same Makefile knobs as above, but suffixed with _UNSAFE to
525+
# use the corresponding implementations for unsafe SHA-1 hashing for
526+
# non-cryptographic purposes.
527+
#
524528
# If don't enable any of the *_SHA1 settings in this section, Git will
525529
# default to its built-in sha1collisiondetection library, which is a
526530
# collision-detecting sha1 This is slower, but may detect attempted
@@ -1997,6 +2001,27 @@ endif
19972001
endif
19982002
endif
19992003

2004+
ifdef OPENSSL_SHA1_UNSAFE
2005+
ifndef OPENSSL_SHA1
2006+
EXTLIBS += $(LIB_4_CRYPTO)
2007+
BASIC_CFLAGS += -DSHA1_OPENSSL_UNSAFE
2008+
endif
2009+
else
2010+
ifdef BLK_SHA1_UNSAFE
2011+
ifndef BLK_SHA1
2012+
LIB_OBJS += block-sha1/sha1.o
2013+
BASIC_CFLAGS += -DSHA1_BLK_UNSAFE
2014+
endif
2015+
else
2016+
ifdef APPLE_COMMON_CRYPTO_SHA1_UNSAFE
2017+
ifndef APPLE_COMMON_CRYPTO_SHA1
2018+
COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
2019+
BASIC_CFLAGS += -DSHA1_APPLE_UNSAFE
2020+
endif
2021+
endif
2022+
endif
2023+
endif
2024+
20002025
ifdef OPENSSL_SHA256
20012026
EXTLIBS += $(LIB_4_CRYPTO)
20022027
BASIC_CFLAGS += -DSHA256_OPENSSL

block-sha1/sha1.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ void blk_SHA1_Init(blk_SHA_CTX *ctx);
1616
void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, size_t len);
1717
void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);
1818

19+
#ifndef platform_SHA_CTX
1920
#define platform_SHA_CTX blk_SHA_CTX
2021
#define platform_SHA1_Init blk_SHA1_Init
2122
#define platform_SHA1_Update blk_SHA1_Update
2223
#define platform_SHA1_Final blk_SHA1_Final
24+
#endif

csum-file.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void hashflush(struct hashfile *f)
5050

5151
if (offset) {
5252
if (!f->skip_hash)
53-
the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
53+
the_hash_algo->unsafe_update_fn(&f->ctx, f->buffer, offset);
5454
flush(f, f->buffer, offset);
5555
f->offset = 0;
5656
}
@@ -73,7 +73,7 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
7373
if (f->skip_hash)
7474
hashclr(f->buffer, the_repository->hash_algo);
7575
else
76-
the_hash_algo->final_fn(f->buffer, &f->ctx);
76+
the_hash_algo->unsafe_final_fn(f->buffer, &f->ctx);
7777

7878
if (result)
7979
hashcpy(result, f->buffer, the_repository->hash_algo);
@@ -128,7 +128,7 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
128128
* f->offset is necessarily zero.
129129
*/
130130
if (!f->skip_hash)
131-
the_hash_algo->update_fn(&f->ctx, buf, nr);
131+
the_hash_algo->unsafe_update_fn(&f->ctx, buf, nr);
132132
flush(f, buf, nr);
133133
} else {
134134
/*
@@ -174,7 +174,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
174174
f->name = name;
175175
f->do_crc = 0;
176176
f->skip_hash = 0;
177-
the_hash_algo->init_fn(&f->ctx);
177+
the_hash_algo->unsafe_init_fn(&f->ctx);
178178

179179
f->buffer_len = buffer_len;
180180
f->buffer = xmalloc(buffer_len);
@@ -208,7 +208,7 @@ void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpo
208208
{
209209
hashflush(f);
210210
checkpoint->offset = f->total;
211-
the_hash_algo->clone_fn(&checkpoint->ctx, &f->ctx);
211+
the_hash_algo->unsafe_clone_fn(&checkpoint->ctx, &f->ctx);
212212
}
213213

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

248-
the_hash_algo->init_fn(&ctx);
249-
the_hash_algo->update_fn(&ctx, data, data_len);
250-
the_hash_algo->final_fn(got, &ctx);
248+
the_hash_algo->unsafe_init_fn(&ctx);
249+
the_hash_algo->unsafe_update_fn(&ctx, data, data_len);
250+
the_hash_algo->unsafe_final_fn(got, &ctx);
251251

252252
return hasheq(got, data + data_len, the_repository->hash_algo);
253253
}

hash.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,36 @@
1515
#include "block-sha1/sha1.h"
1616
#endif
1717

18+
#if defined(SHA1_APPLE_UNSAFE)
19+
# include <CommonCrypto/CommonDigest.h>
20+
# define platform_SHA_CTX_unsafe CC_SHA1_CTX
21+
# define platform_SHA1_Init_unsafe CC_SHA1_Init
22+
# define platform_SHA1_Update_unsafe CC_SHA1_Update
23+
# define platform_SHA1_Final_unsafe CC_SHA1_Final
24+
#elif defined(SHA1_OPENSSL_UNSAFE)
25+
# include <openssl/sha.h>
26+
# if defined(OPENSSL_API_LEVEL) && OPENSSL_API_LEVEL >= 3
27+
# define SHA1_NEEDS_CLONE_HELPER_UNSAFE
28+
# include "sha1/openssl.h"
29+
# define platform_SHA_CTX_unsafe openssl_SHA1_CTX
30+
# define platform_SHA1_Init_unsafe openssl_SHA1_Init
31+
# define platform_SHA1_Clone_unsafe openssl_SHA1_Clone
32+
# define platform_SHA1_Update_unsafe openssl_SHA1_Update
33+
# define platform_SHA1_Final_unsafe openssl_SHA1_Final
34+
# else
35+
# define platform_SHA_CTX_unsafe SHA_CTX
36+
# define platform_SHA1_Init_unsafe SHA1_Init
37+
# define platform_SHA1_Update_unsafe SHA1_Update
38+
# define platform_SHA1_Final_unsafe SHA1_Final
39+
# endif
40+
#elif defined(SHA1_BLK_UNSAFE)
41+
# include "block-sha1/sha1.h"
42+
# define platform_SHA_CTX_unsafe blk_SHA_CTX
43+
# define platform_SHA1_Init_unsafe blk_SHA1_Init
44+
# define platform_SHA1_Update_unsafe blk_SHA1_Update
45+
# define platform_SHA1_Final_unsafe blk_SHA1_Final
46+
#endif
47+
1848
#if defined(SHA256_NETTLE)
1949
#include "sha256/nettle.h"
2050
#elif defined(SHA256_GCRYPT)
@@ -44,14 +74,32 @@
4474
#define platform_SHA1_Final SHA1_Final
4575
#endif
4676

77+
#ifndef platform_SHA_CTX_unsafe
78+
# define platform_SHA_CTX_unsafe platform_SHA_CTX
79+
# define platform_SHA1_Init_unsafe platform_SHA1_Init
80+
# define platform_SHA1_Update_unsafe platform_SHA1_Update
81+
# define platform_SHA1_Final_unsafe platform_SHA1_Final
82+
# ifdef platform_SHA1_Clone
83+
# define platform_SHA1_Clone_unsafe platform_SHA1_Clone
84+
# endif
85+
#endif
86+
4787
#define git_SHA_CTX platform_SHA_CTX
4888
#define git_SHA1_Init platform_SHA1_Init
4989
#define git_SHA1_Update platform_SHA1_Update
5090
#define git_SHA1_Final platform_SHA1_Final
5191

92+
#define git_SHA_CTX_unsafe platform_SHA_CTX_unsafe
93+
#define git_SHA1_Init_unsafe platform_SHA1_Init_unsafe
94+
#define git_SHA1_Update_unsafe platform_SHA1_Update_unsafe
95+
#define git_SHA1_Final_unsafe platform_SHA1_Final_unsafe
96+
5297
#ifdef platform_SHA1_Clone
5398
#define git_SHA1_Clone platform_SHA1_Clone
5499
#endif
100+
#ifdef platform_SHA1_Clone_unsafe
101+
# define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe
102+
#endif
55103

56104
#ifndef platform_SHA256_CTX
57105
#define platform_SHA256_CTX SHA256_CTX
@@ -81,6 +129,13 @@ static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
81129
memcpy(dst, src, sizeof(*dst));
82130
}
83131
#endif
132+
#ifndef SHA1_NEEDS_CLONE_HELPER_UNSAFE
133+
static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst,
134+
const git_SHA_CTX_unsafe *src)
135+
{
136+
memcpy(dst, src, sizeof(*dst));
137+
}
138+
#endif
84139

85140
#ifndef SHA256_NEEDS_CLONE_HELPER
86141
static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
@@ -178,6 +233,8 @@ enum get_oid_result {
178233
/* A suitably aligned type for stack allocations of hash contexts. */
179234
union git_hash_ctx {
180235
git_SHA_CTX sha1;
236+
git_SHA_CTX_unsafe sha1_unsafe;
237+
181238
git_SHA256_CTX sha256;
182239
};
183240
typedef union git_hash_ctx git_hash_ctx;
@@ -222,6 +279,21 @@ struct git_hash_algo {
222279
/* The hash finalization function for object IDs. */
223280
git_hash_final_oid_fn final_oid_fn;
224281

282+
/* The non-cryptographic hash initialization function. */
283+
git_hash_init_fn unsafe_init_fn;
284+
285+
/* The non-cryptographic hash context cloning function. */
286+
git_hash_clone_fn unsafe_clone_fn;
287+
288+
/* The non-cryptographic hash update function. */
289+
git_hash_update_fn unsafe_update_fn;
290+
291+
/* The non-cryptographic hash finalization function. */
292+
git_hash_final_fn unsafe_final_fn;
293+
294+
/* The non-cryptographic hash finalization function. */
295+
git_hash_final_oid_fn unsafe_final_oid_fn;
296+
225297
/* The OID of the empty tree. */
226298
const struct object_id *empty_tree;
227299

0 commit comments

Comments
 (0)