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();