2 * checksum.c: checksum routines
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
30 #include "svn_checksum.h"
31 #include "svn_error.h"
32 #include "svn_ctype.h"
37 #include "private/svn_subr_private.h"
39 #include "svn_private_config.h"
43 /* 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)
48 /* Check to see if KIND is something we recognize. If not, return
49 * SVN_ERR_BAD_CHECKSUM_KIND */
51 validate_kind(svn_checksum_kind_t kind)
53 if (kind == svn_checksum_md5 || kind == svn_checksum_sha1)
56 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
59 /* Create a svn_checksum_t with everything but the contents of the
61 static svn_checksum_t *
62 checksum_create_without_digest(svn_checksum_kind_t kind,
63 apr_size_t digest_size,
66 /* Use apr_palloc() instead of apr_pcalloc() so that the digest
67 * contents are only set once by the caller. */
68 svn_checksum_t *checksum = apr_palloc(pool, sizeof(*checksum) + digest_size);
69 checksum->digest = (unsigned char *)checksum + sizeof(*checksum);
70 checksum->kind = kind;
74 static svn_checksum_t *
75 checksum_create(svn_checksum_kind_t kind,
76 apr_size_t digest_size,
77 const unsigned char *digest,
80 svn_checksum_t *checksum = checksum_create_without_digest(kind, digest_size,
82 memcpy((unsigned char *)checksum->digest, digest, digest_size);
87 svn_checksum_create(svn_checksum_kind_t kind,
90 svn_checksum_t *checksum;
91 apr_size_t digest_size;
95 case svn_checksum_md5:
96 digest_size = APR_MD5_DIGESTSIZE;
98 case svn_checksum_sha1:
99 digest_size = APR_SHA1_DIGESTSIZE;
105 checksum = checksum_create_without_digest(kind, digest_size, pool);
106 memset((unsigned char *) checksum->digest, 0, digest_size);
111 svn_checksum__from_digest_md5(const unsigned char *digest,
112 apr_pool_t *result_pool)
114 return checksum_create(svn_checksum_md5, APR_MD5_DIGESTSIZE, digest,
119 svn_checksum__from_digest_sha1(const unsigned char *digest,
120 apr_pool_t *result_pool)
122 return checksum_create(svn_checksum_sha1, APR_SHA1_DIGESTSIZE, digest,
127 svn_checksum_clear(svn_checksum_t *checksum)
129 SVN_ERR(validate_kind(checksum->kind));
131 memset((unsigned char *) checksum->digest, 0, DIGESTSIZE(checksum->kind));
136 svn_checksum_match(const svn_checksum_t *checksum1,
137 const svn_checksum_t *checksum2)
139 if (checksum1 == NULL || checksum2 == NULL)
142 if (checksum1->kind != checksum2->kind)
145 switch (checksum1->kind)
147 case svn_checksum_md5:
148 return svn_md5__digests_match(checksum1->digest, checksum2->digest);
149 case svn_checksum_sha1:
150 return svn_sha1__digests_match(checksum1->digest, checksum2->digest);
152 /* We really shouldn't get here, but if we do... */
158 svn_checksum_to_cstring_display(const svn_checksum_t *checksum,
161 switch (checksum->kind)
163 case svn_checksum_md5:
164 return svn_md5__digest_to_cstring_display(checksum->digest, pool);
165 case svn_checksum_sha1:
166 return svn_sha1__digest_to_cstring_display(checksum->digest, pool);
168 /* We really shouldn't get here, but if we do... */
174 svn_checksum_to_cstring(const svn_checksum_t *checksum,
177 if (checksum == NULL)
180 switch (checksum->kind)
182 case svn_checksum_md5:
183 return svn_md5__digest_to_cstring(checksum->digest, pool);
184 case svn_checksum_sha1:
185 return svn_sha1__digest_to_cstring(checksum->digest, pool);
187 /* We really shouldn't get here, but if we do... */
194 svn_checksum_serialize(const svn_checksum_t *checksum,
195 apr_pool_t *result_pool,
196 apr_pool_t *scratch_pool)
198 const char *ckind_str;
200 SVN_ERR_ASSERT_NO_RETURN(checksum->kind == svn_checksum_md5
201 || checksum->kind == svn_checksum_sha1);
202 ckind_str = (checksum->kind == svn_checksum_md5 ? "$md5 $" : "$sha1$");
203 return apr_pstrcat(result_pool,
205 svn_checksum_to_cstring(checksum, scratch_pool),
211 svn_checksum_deserialize(const svn_checksum_t **checksum,
213 apr_pool_t *result_pool,
214 apr_pool_t *scratch_pool)
216 svn_checksum_kind_t ckind;
217 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;
232 svn_checksum_parse_hex(svn_checksum_t **checksum,
233 svn_checksum_kind_t kind,
238 char is_nonzero = '\0';
240 static const char xdigitval[256] =
242 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
243 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
244 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
245 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, /* 0-9 */
246 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A-F */
247 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
248 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* a-f */
249 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
250 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
251 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
252 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
253 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
254 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
255 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
256 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
257 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
266 SVN_ERR(validate_kind(kind));
268 *checksum = svn_checksum_create(kind, pool);
269 digest = (char *)(*checksum)->digest;
270 len = DIGESTSIZE(kind);
272 for (i = 0; i < len; i++)
274 char x1 = xdigitval[(unsigned char)hex[i * 2]];
275 char x2 = xdigitval[(unsigned char)hex[i * 2 + 1]];
276 if (x1 == (char)-1 || x2 == (char)-1)
277 return svn_error_create(SVN_ERR_BAD_CHECKSUM_PARSE, NULL, NULL);
279 digest[i] = (char)((x1 << 4) | x2);
280 is_nonzero |= (char)((x1 << 4) | x2);
290 svn_checksum_dup(const svn_checksum_t *checksum,
293 /* The duplicate of a NULL checksum is a NULL... */
294 if (checksum == NULL)
297 /* Without this check on valid checksum kind a NULL svn_checksum_t
298 * pointer is returned which could cause a core dump at an
299 * indeterminate time in the future because callers are not
300 * expecting a NULL pointer. This commit forces an early abort() so
301 * it's easier to track down where the issue arose. */
302 switch (checksum->kind)
304 case svn_checksum_md5:
305 return svn_checksum__from_digest_md5(checksum->digest, pool);
307 case svn_checksum_sha1:
308 return svn_checksum__from_digest_sha1(checksum->digest, pool);
311 SVN_ERR_MALFUNCTION_NO_RETURN();
317 svn_checksum(svn_checksum_t **checksum,
318 svn_checksum_kind_t kind,
323 apr_sha1_ctx_t sha1_ctx;
325 SVN_ERR(validate_kind(kind));
326 *checksum = svn_checksum_create(kind, pool);
330 case svn_checksum_md5:
331 apr_md5((unsigned char *)(*checksum)->digest, data, len);
334 case svn_checksum_sha1:
335 apr_sha1_init(&sha1_ctx);
336 apr_sha1_update(&sha1_ctx, data, (unsigned int)len);
337 apr_sha1_final((unsigned char *)(*checksum)->digest, &sha1_ctx);
341 /* We really shouldn't get here, but if we do... */
342 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
350 svn_checksum_empty_checksum(svn_checksum_kind_t kind,
355 case svn_checksum_md5:
356 return svn_checksum__from_digest_md5(svn_md5__empty_string_digest(),
359 case svn_checksum_sha1:
360 return svn_checksum__from_digest_sha1(svn_sha1__empty_string_digest(),
364 /* We really shouldn't get here, but if we do... */
365 SVN_ERR_MALFUNCTION_NO_RETURN();
369 struct svn_checksum_ctx_t
372 svn_checksum_kind_t kind;
376 svn_checksum_ctx_create(svn_checksum_kind_t kind,
379 svn_checksum_ctx_t *ctx = apr_palloc(pool, sizeof(*ctx));
384 case svn_checksum_md5:
385 ctx->apr_ctx = apr_palloc(pool, sizeof(apr_md5_ctx_t));
386 apr_md5_init(ctx->apr_ctx);
389 case svn_checksum_sha1:
390 ctx->apr_ctx = apr_palloc(pool, sizeof(apr_sha1_ctx_t));
391 apr_sha1_init(ctx->apr_ctx);
395 SVN_ERR_MALFUNCTION_NO_RETURN();
402 svn_checksum_update(svn_checksum_ctx_t *ctx,
408 case svn_checksum_md5:
409 apr_md5_update(ctx->apr_ctx, data, len);
412 case svn_checksum_sha1:
413 apr_sha1_update(ctx->apr_ctx, data, (unsigned int)len);
417 /* We really shouldn't get here, but if we do... */
418 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
425 svn_checksum_final(svn_checksum_t **checksum,
426 const svn_checksum_ctx_t *ctx,
429 *checksum = svn_checksum_create(ctx->kind, pool);
433 case svn_checksum_md5:
434 apr_md5_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);
437 case svn_checksum_sha1:
438 apr_sha1_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);
442 /* We really shouldn't get here, but if we do... */
443 return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
450 svn_checksum_size(const svn_checksum_t *checksum)
452 return DIGESTSIZE(checksum->kind);
456 svn_checksum_mismatch_err(const svn_checksum_t *expected,
457 const svn_checksum_t *actual,
458 apr_pool_t *scratch_pool,
466 desc = apr_pvsprintf(scratch_pool, fmt, ap);
469 return svn_error_createf(SVN_ERR_CHECKSUM_MISMATCH, NULL,
474 svn_checksum_to_cstring_display(expected, scratch_pool),
475 svn_checksum_to_cstring_display(actual, scratch_pool));
479 svn_checksum_is_empty_checksum(svn_checksum_t *checksum)
481 /* By definition, the NULL checksum matches all others, including the
486 switch (checksum->kind)
488 case svn_checksum_md5:
489 return svn_md5__digests_match(checksum->digest,
490 svn_md5__empty_string_digest());
492 case svn_checksum_sha1:
493 return svn_sha1__digests_match(checksum->digest,
494 svn_sha1__empty_string_digest());
497 /* We really shouldn't get here, but if we do... */
498 SVN_ERR_MALFUNCTION_NO_RETURN();