45
/* The MD5 digest for the empty string. */
46
static const unsigned char md5_empty_string_digest_array[] = {
47
0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
48
0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
51
/* The SHA1 digest for the empty string. */
52
static const unsigned char sha1_empty_string_digest_array[] = {
53
0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
54
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09
57
/* The FNV-1a digest for the empty string. */
58
static const unsigned char fnv1a_32_empty_string_digest_array[] = {
59
0x81, 0x1c, 0x9d, 0xc5
62
/* The FNV-1a digest for the empty string. */
63
static const unsigned char fnv1a_32x4_empty_string_digest_array[] = {
64
0xcd, 0x6d, 0x9a, 0x85
67
/* Digests for an empty string, indexed by checksum type */
68
static const unsigned char * empty_string_digests[] = {
69
md5_empty_string_digest_array,
70
sha1_empty_string_digest_array,
71
fnv1a_32_empty_string_digest_array,
72
fnv1a_32x4_empty_string_digest_array
75
/* Digest sizes in bytes, indexed by checksum type */
76
static const apr_size_t digest_sizes[] = {
83
/* Checksum type prefixes used in serialized checksums. */
84
static const char *ckind_str[] = {
43
91
/* Returns the digest size of it's argument. */
44
#define DIGESTSIZE(k) ((k) == svn_checksum_md5 ? APR_MD5_DIGESTSIZE : \
45
(k) == svn_checksum_sha1 ? APR_SHA1_DIGESTSIZE : 0)
92
#define DIGESTSIZE(k) \
93
(((k) < svn_checksum_md5 || (k) > svn_checksum_fnv1a_32x4) ? 0 : digest_sizes[k])
95
/* Largest supported digest size */
96
#define MAX_DIGESTSIZE (MAX(APR_MD5_DIGESTSIZE,APR_SHA1_DIGESTSIZE))
99
svn__empty_string_digest(svn_checksum_kind_t kind)
101
return empty_string_digests[kind];
105
svn__digest_to_cstring_display(const unsigned char digest[],
106
apr_size_t digest_size,
109
static const char *hex = "0123456789abcdef";
110
char *str = apr_palloc(pool, (digest_size * 2) + 1);
113
for (i = 0; i < digest_size; i++)
115
str[i*2] = hex[digest[i] >> 4];
116
str[i*2+1] = hex[digest[i] & 0x0f];
125
svn__digest_to_cstring(const unsigned char digest[],
126
apr_size_t digest_size,
129
static const unsigned char zeros_digest[MAX_DIGESTSIZE] = { 0 };
131
if (memcmp(digest, zeros_digest, digest_size) != 0)
132
return svn__digest_to_cstring_display(digest, digest_size, pool);
139
svn__digests_match(const unsigned char d1[],
140
const unsigned char d2[],
141
apr_size_t digest_size)
143
static const unsigned char zeros[MAX_DIGESTSIZE] = { 0 };
145
return ((memcmp(d1, d2, digest_size) == 0)
146
|| (memcmp(d2, zeros, digest_size) == 0)
147
|| (memcmp(d1, zeros, digest_size) == 0));
48
150
/* Check to see if KIND is something we recognize. If not, return
49
151
* SVN_ERR_BAD_CHECKSUM_KIND */
50
152
static svn_error_t *
51
153
validate_kind(svn_checksum_kind_t kind)
53
if (kind == svn_checksum_md5 || kind == svn_checksum_sha1)
155
if (kind >= svn_checksum_md5 && kind <= svn_checksum_fnv1a_32x4)
54
156
return SVN_NO_ERROR;
56
158
return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
111
217
svn_checksum__from_digest_md5(const unsigned char *digest,
112
218
apr_pool_t *result_pool)
114
return checksum_create(svn_checksum_md5, APR_MD5_DIGESTSIZE, digest,
220
return checksum_create(svn_checksum_md5, digest, result_pool);
119
224
svn_checksum__from_digest_sha1(const unsigned char *digest,
120
225
apr_pool_t *result_pool)
122
return checksum_create(svn_checksum_sha1, APR_SHA1_DIGESTSIZE, digest,
227
return checksum_create(svn_checksum_sha1, digest, result_pool);
231
svn_checksum__from_digest_fnv1a_32(const unsigned char *digest,
232
apr_pool_t *result_pool)
234
return checksum_create(svn_checksum_fnv1a_32, digest, result_pool);
238
svn_checksum__from_digest_fnv1a_32x4(const unsigned char *digest,
239
apr_pool_t *result_pool)
241
return checksum_create(svn_checksum_fnv1a_32x4, digest, result_pool);
213
340
apr_pool_t *result_pool,
214
341
apr_pool_t *scratch_pool)
216
svn_checksum_kind_t ckind;
343
svn_checksum_kind_t kind;
217
344
svn_checksum_t *parsed_checksum;
219
/* "$md5 $..." or "$sha1$..." */
220
SVN_ERR_ASSERT(strlen(data) > 6);
222
ckind = (data[1] == 'm' ? svn_checksum_md5 : svn_checksum_sha1);
223
SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, ckind,
224
data + 6, result_pool));
225
*checksum = parsed_checksum;
346
/* All prefixes have the same length. */
347
apr_size_t prefix_len = strlen(ckind_str[0]);
349
/* "$md5 $...", "$sha1$..." or ... */
350
if (strlen(data) <= prefix_len)
351
return svn_error_createf(SVN_ERR_BAD_CHECKSUM_PARSE, NULL,
352
_("Invalid prefix in checksum '%s'"),
355
for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
356
if (strncmp(ckind_str[kind], data, prefix_len) == 0)
358
SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, kind,
359
data + prefix_len, result_pool));
360
*checksum = parsed_checksum;
364
return svn_error_createf(SVN_ERR_BAD_CHECKSUM_KIND, NULL,
365
"Unknown checksum kind in '%s'", data);
486
658
switch (checksum->kind)
488
660
case svn_checksum_md5:
489
return svn_md5__digests_match(checksum->digest,
490
svn_md5__empty_string_digest());
492
661
case svn_checksum_sha1:
493
return svn_sha1__digests_match(checksum->digest,
494
svn_sha1__empty_string_digest());
662
case svn_checksum_fnv1a_32:
663
case svn_checksum_fnv1a_32x4:
664
return svn__digests_match(checksum->digest,
665
svn__empty_string_digest(checksum->kind),
666
digest_sizes[checksum->kind]);
497
669
/* We really shouldn't get here, but if we do... */
498
670
SVN_ERR_MALFUNCTION_NO_RETURN();
674
/* Checksum calculating stream wrappers.
677
/* Baton used by write_handler and close_handler to calculate the checksum
678
* and return the result to the stream creator. It accommodates the data
679
* needed by svn_checksum__wrap_write_stream_fnv1a_32x4 as well as
680
* svn_checksum__wrap_write_stream.
682
typedef struct stream_baton_t
684
/* Stream we are wrapping. Forward write() and close() operations to it. */
685
svn_stream_t *inner_stream;
687
/* Build the checksum data in here. */
688
svn_checksum_ctx_t *context;
690
/* Write the final checksum here. May be NULL. */
691
svn_checksum_t **checksum;
693
/* Copy the digest of the final checksum. May be NULL. */
694
unsigned char *digest;
696
/* Allocate the resulting checksum here. */
700
/* Implement svn_write_fn_t.
701
* Update checksum and pass data on to inner stream.
704
write_handler(void *baton,
708
stream_baton_t *b = baton;
710
SVN_ERR(svn_checksum_update(b->context, data, *len));
711
SVN_ERR(svn_stream_write(b->inner_stream, data, len));
716
/* Implement svn_close_fn_t.
717
* Finalize checksum calculation and write results. Close inner stream.
720
close_handler(void *baton)
722
stream_baton_t *b = baton;
723
svn_checksum_t *local_checksum;
725
/* Ensure we can always write to *B->CHECKSUM. */
727
b->checksum = &local_checksum;
729
/* Get the final checksum. */
730
SVN_ERR(svn_checksum_final(b->checksum, b->context, b->pool));
732
/* Extract digest, if wanted. */
735
apr_size_t digest_size = DIGESTSIZE((*b->checksum)->kind);
736
memcpy(b->digest, (*b->checksum)->digest, digest_size);
739
/* Done here. Now, close the underlying stream as well. */
740
return svn_error_trace(svn_stream_close(b->inner_stream));
743
/* Common constructor function for svn_checksum__wrap_write_stream and
744
* svn_checksum__wrap_write_stream_fnv1a_32x4, taking the superset of their
745
* respecting parameters.
747
* In the current usage, either CHECKSUM or DIGEST will be NULL but this
748
* function does not enforce any such restriction. Also, the caller must
749
* make sure that DIGEST refers to a buffer of sufficient length.
751
static svn_stream_t *
752
wrap_write_stream(svn_checksum_t **checksum,
753
unsigned char *digest,
754
svn_stream_t *inner_stream,
755
svn_checksum_kind_t kind,
758
svn_stream_t *outer_stream;
760
stream_baton_t *baton = apr_pcalloc(pool, sizeof(*baton));
761
baton->inner_stream = inner_stream;
762
baton->context = svn_checksum_ctx_create(kind, pool);
763
baton->checksum = checksum;
764
baton->digest = digest;
767
outer_stream = svn_stream_create(baton, pool);
768
svn_stream_set_write(outer_stream, write_handler);
769
svn_stream_set_close(outer_stream, close_handler);
775
svn_checksum__wrap_write_stream(svn_checksum_t **checksum,
776
svn_stream_t *inner_stream,
777
svn_checksum_kind_t kind,
780
return wrap_write_stream(checksum, NULL, inner_stream, kind, pool);
783
/* Implement svn_close_fn_t.
784
* For FNV-1a-like checksums, we want the checksum as 32 bit integer instead
785
* of a big endian 4 byte sequence. This simply wraps close_handler adding
786
* the digest conversion.
789
close_handler_fnv1a_32x4(void *baton)
791
stream_baton_t *b = baton;
792
SVN_ERR(close_handler(baton));
794
*(apr_uint32_t *)b->digest = ntohl(*(apr_uint32_t *)b->digest);
799
svn_checksum__wrap_write_stream_fnv1a_32x4(apr_uint32_t *digest,
800
svn_stream_t *inner_stream,
804
= wrap_write_stream(NULL, (unsigned char *)digest, inner_stream,
805
svn_checksum_fnv1a_32x4, pool);
806
svn_stream_set_close(result, close_handler_fnv1a_32x4);