diff options
Diffstat (limited to 'subversion/libsvn_subr/checksum.c')
-rw-r--r-- | subversion/libsvn_subr/checksum.c | 127 |
1 files changed, 101 insertions, 26 deletions
diff --git a/subversion/libsvn_subr/checksum.c b/subversion/libsvn_subr/checksum.c index 1732d2e..e5d6a62 100644 --- a/subversion/libsvn_subr/checksum.c +++ b/subversion/libsvn_subr/checksum.c @@ -34,6 +34,8 @@ #include "sha1.h" #include "md5.h" +#include "private/svn_subr_private.h" + #include "svn_private_config.h" @@ -54,36 +56,71 @@ validate_kind(svn_checksum_kind_t kind) return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL); } +/* Create a svn_checksum_t with everything but the contents of the + digest populated. */ +static svn_checksum_t * +checksum_create_without_digest(svn_checksum_kind_t kind, + apr_size_t digest_size, + apr_pool_t *pool) +{ + /* Use apr_palloc() instead of apr_pcalloc() so that the digest + * contents are only set once by the caller. */ + svn_checksum_t *checksum = apr_palloc(pool, sizeof(*checksum) + digest_size); + checksum->digest = (unsigned char *)checksum + sizeof(*checksum); + checksum->kind = kind; + return checksum; +} + +static svn_checksum_t * +checksum_create(svn_checksum_kind_t kind, + apr_size_t digest_size, + const unsigned char *digest, + apr_pool_t *pool) +{ + svn_checksum_t *checksum = checksum_create_without_digest(kind, digest_size, + pool); + memcpy((unsigned char *)checksum->digest, digest, digest_size); + return checksum; +} svn_checksum_t * svn_checksum_create(svn_checksum_kind_t kind, apr_pool_t *pool) { svn_checksum_t *checksum; + apr_size_t digest_size; switch (kind) { case svn_checksum_md5: + digest_size = APR_MD5_DIGESTSIZE; + break; case svn_checksum_sha1: - checksum = apr_pcalloc(pool, sizeof(*checksum) + DIGESTSIZE(kind)); - checksum->digest = (unsigned char *)checksum + sizeof(*checksum); - checksum->kind = kind; - return checksum; - + digest_size = APR_SHA1_DIGESTSIZE; + break; default: return NULL; } + + checksum = checksum_create_without_digest(kind, digest_size, pool); + memset((unsigned char *) checksum->digest, 0, digest_size); + return checksum; } svn_checksum_t * -svn_checksum__from_digest(const unsigned char *digest, - svn_checksum_kind_t kind, - apr_pool_t *result_pool) +svn_checksum__from_digest_md5(const unsigned char *digest, + apr_pool_t *result_pool) { - svn_checksum_t *checksum = svn_checksum_create(kind, result_pool); + return checksum_create(svn_checksum_md5, APR_MD5_DIGESTSIZE, digest, + result_pool); +} - memcpy((unsigned char *)checksum->digest, digest, DIGESTSIZE(kind)); - return checksum; +svn_checksum_t * +svn_checksum__from_digest_sha1(const unsigned char *digest, + apr_pool_t *result_pool) +{ + return checksum_create(svn_checksum_sha1, APR_SHA1_DIGESTSIZE, digest, + result_pool); } svn_error_t * @@ -160,6 +197,8 @@ svn_checksum_serialize(const svn_checksum_t *checksum, { const char *ckind_str; + SVN_ERR_ASSERT_NO_RETURN(checksum->kind == svn_checksum_md5 + || checksum->kind == svn_checksum_sha1); ckind_str = (checksum->kind == svn_checksum_md5 ? "$md5 $" : "$sha1$"); return apr_pstrcat(result_pool, ckind_str, @@ -237,8 +276,8 @@ svn_checksum_parse_hex(svn_checksum_t **checksum, if (x1 == (char)-1 || x2 == (char)-1) return svn_error_create(SVN_ERR_BAD_CHECKSUM_PARSE, NULL, NULL); - digest[i] = (x1 << 4) | x2; - is_nonzero |= (x1 << 4) | x2; + digest[i] = (char)((x1 << 4) | x2); + is_nonzero |= (char)((x1 << 4) | x2); } if (!is_nonzero) @@ -255,7 +294,23 @@ svn_checksum_dup(const svn_checksum_t *checksum, if (checksum == NULL) return NULL; - return svn_checksum__from_digest(checksum->digest, checksum->kind, pool); + /* Without this check on valid checksum kind a NULL svn_checksum_t + * pointer is returned which could cause a core dump at an + * indeterminate time in the future because callers are not + * expecting a NULL pointer. This commit forces an early abort() so + * it's easier to track down where the issue arose. */ + switch (checksum->kind) + { + case svn_checksum_md5: + return svn_checksum__from_digest_md5(checksum->digest, pool); + break; + case svn_checksum_sha1: + return svn_checksum__from_digest_sha1(checksum->digest, pool); + break; + default: + SVN_ERR_MALFUNCTION_NO_RETURN(); + break; + } } svn_error_t * @@ -278,7 +333,7 @@ svn_checksum(svn_checksum_t **checksum, case svn_checksum_sha1: apr_sha1_init(&sha1_ctx); - apr_sha1_update(&sha1_ctx, data, len); + apr_sha1_update(&sha1_ctx, data, (unsigned int)len); apr_sha1_final((unsigned char *)(*checksum)->digest, &sha1_ctx); break; @@ -295,24 +350,20 @@ svn_checksum_t * svn_checksum_empty_checksum(svn_checksum_kind_t kind, apr_pool_t *pool) { - const unsigned char *digest; - switch (kind) { case svn_checksum_md5: - digest = svn_md5__empty_string_digest(); - break; + return svn_checksum__from_digest_md5(svn_md5__empty_string_digest(), + pool); case svn_checksum_sha1: - digest = svn_sha1__empty_string_digest(); - break; + return svn_checksum__from_digest_sha1(svn_sha1__empty_string_digest(), + pool); default: /* We really shouldn't get here, but if we do... */ - return NULL; + SVN_ERR_MALFUNCTION_NO_RETURN(); } - - return svn_checksum__from_digest(digest, kind, pool); } struct svn_checksum_ctx_t @@ -341,7 +392,7 @@ svn_checksum_ctx_create(svn_checksum_kind_t kind, break; default: - return NULL; + SVN_ERR_MALFUNCTION_NO_RETURN(); } return ctx; @@ -359,7 +410,7 @@ svn_checksum_update(svn_checksum_ctx_t *ctx, break; case svn_checksum_sha1: - apr_sha1_update(ctx->apr_ctx, data, len); + apr_sha1_update(ctx->apr_ctx, data, (unsigned int)len); break; default: @@ -423,3 +474,27 @@ svn_checksum_mismatch_err(const svn_checksum_t *expected, svn_checksum_to_cstring_display(expected, scratch_pool), svn_checksum_to_cstring_display(actual, scratch_pool)); } + +svn_boolean_t +svn_checksum_is_empty_checksum(svn_checksum_t *checksum) +{ + /* By definition, the NULL checksum matches all others, including the + empty one. */ + if (!checksum) + return TRUE; + + switch (checksum->kind) + { + case svn_checksum_md5: + return svn_md5__digests_match(checksum->digest, + svn_md5__empty_string_digest()); + + case svn_checksum_sha1: + return svn_sha1__digests_match(checksum->digest, + svn_sha1__empty_string_digest()); + + default: + /* We really shouldn't get here, but if we do... */ + SVN_ERR_MALFUNCTION_NO_RETURN(); + } +} |