]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_subr/checksum.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_subr / checksum.c
1 /*
2  * checksum.c:   checksum routines
3  *
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
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
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
20  *    under the License.
21  * ====================================================================
22  */
23
24
25 #include <ctype.h>
26
27 #include <apr_md5.h>
28 #include <apr_sha1.h>
29
30 #include "svn_checksum.h"
31 #include "svn_error.h"
32 #include "svn_ctype.h"
33
34 #include "sha1.h"
35 #include "md5.h"
36
37 #include "private/svn_subr_private.h"
38
39 #include "svn_private_config.h"
40
41 \f
42
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)
46
47
48 /* Check to see if KIND is something we recognize.  If not, return
49  * SVN_ERR_BAD_CHECKSUM_KIND */
50 static svn_error_t *
51 validate_kind(svn_checksum_kind_t kind)
52 {
53   if (kind == svn_checksum_md5 || kind == svn_checksum_sha1)
54     return SVN_NO_ERROR;
55   else
56     return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
57 }
58
59 /* Create a svn_checksum_t with everything but the contents of the
60    digest populated. */
61 static svn_checksum_t *
62 checksum_create_without_digest(svn_checksum_kind_t kind,
63                                apr_size_t digest_size,
64                                apr_pool_t *pool)
65 {
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;
71   return checksum;
72 }
73
74 static svn_checksum_t *
75 checksum_create(svn_checksum_kind_t kind,
76                 apr_size_t digest_size,
77                 const unsigned char *digest,
78                 apr_pool_t *pool)
79 {
80   svn_checksum_t *checksum = checksum_create_without_digest(kind, digest_size,
81                                                             pool);
82   memcpy((unsigned char *)checksum->digest, digest, digest_size);
83   return checksum;
84 }
85
86 svn_checksum_t *
87 svn_checksum_create(svn_checksum_kind_t kind,
88                     apr_pool_t *pool)
89 {
90   svn_checksum_t *checksum;
91   apr_size_t digest_size;
92
93   switch (kind)
94     {
95       case svn_checksum_md5:
96         digest_size = APR_MD5_DIGESTSIZE;
97         break;
98       case svn_checksum_sha1:
99         digest_size = APR_SHA1_DIGESTSIZE;
100         break;
101       default:
102         return NULL;
103     }
104
105   checksum = checksum_create_without_digest(kind, digest_size, pool);
106   memset((unsigned char *) checksum->digest, 0, digest_size);
107   return checksum;
108 }
109
110 svn_checksum_t *
111 svn_checksum__from_digest_md5(const unsigned char *digest,
112                               apr_pool_t *result_pool)
113 {
114   return checksum_create(svn_checksum_md5, APR_MD5_DIGESTSIZE, digest,
115                          result_pool);
116 }
117
118 svn_checksum_t *
119 svn_checksum__from_digest_sha1(const unsigned char *digest,
120                                apr_pool_t *result_pool)
121 {
122   return checksum_create(svn_checksum_sha1, APR_SHA1_DIGESTSIZE, digest,
123                          result_pool);
124 }
125
126 svn_error_t *
127 svn_checksum_clear(svn_checksum_t *checksum)
128 {
129   SVN_ERR(validate_kind(checksum->kind));
130
131   memset((unsigned char *) checksum->digest, 0, DIGESTSIZE(checksum->kind));
132   return SVN_NO_ERROR;
133 }
134
135 svn_boolean_t
136 svn_checksum_match(const svn_checksum_t *checksum1,
137                    const svn_checksum_t *checksum2)
138 {
139   if (checksum1 == NULL || checksum2 == NULL)
140     return TRUE;
141
142   if (checksum1->kind != checksum2->kind)
143     return FALSE;
144
145   switch (checksum1->kind)
146     {
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);
151       default:
152         /* We really shouldn't get here, but if we do... */
153         return FALSE;
154     }
155 }
156
157 const char *
158 svn_checksum_to_cstring_display(const svn_checksum_t *checksum,
159                                 apr_pool_t *pool)
160 {
161   switch (checksum->kind)
162     {
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);
167       default:
168         /* We really shouldn't get here, but if we do... */
169         return NULL;
170     }
171 }
172
173 const char *
174 svn_checksum_to_cstring(const svn_checksum_t *checksum,
175                         apr_pool_t *pool)
176 {
177   if (checksum == NULL)
178     return NULL;
179
180   switch (checksum->kind)
181     {
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);
186       default:
187         /* We really shouldn't get here, but if we do... */
188         return NULL;
189     }
190 }
191
192
193 const char *
194 svn_checksum_serialize(const svn_checksum_t *checksum,
195                        apr_pool_t *result_pool,
196                        apr_pool_t *scratch_pool)
197 {
198   const char *ckind_str;
199
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,
204                      ckind_str,
205                      svn_checksum_to_cstring(checksum, scratch_pool),
206                      (char *)NULL);
207 }
208
209
210 svn_error_t *
211 svn_checksum_deserialize(const svn_checksum_t **checksum,
212                          const char *data,
213                          apr_pool_t *result_pool,
214                          apr_pool_t *scratch_pool)
215 {
216   svn_checksum_kind_t ckind;
217   svn_checksum_t *parsed_checksum;
218
219   /* "$md5 $..." or "$sha1$..." */
220   SVN_ERR_ASSERT(strlen(data) > 6);
221
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;
226
227   return SVN_NO_ERROR;
228 }
229
230
231 svn_error_t *
232 svn_checksum_parse_hex(svn_checksum_t **checksum,
233                        svn_checksum_kind_t kind,
234                        const char *hex,
235                        apr_pool_t *pool)
236 {
237   int i, len;
238   char is_nonzero = '\0';
239   char *digest;
240   static const char xdigitval[256] =
241     {
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,
258     };
259
260   if (hex == NULL)
261     {
262       *checksum = NULL;
263       return SVN_NO_ERROR;
264     }
265
266   SVN_ERR(validate_kind(kind));
267
268   *checksum = svn_checksum_create(kind, pool);
269   digest = (char *)(*checksum)->digest;
270   len = DIGESTSIZE(kind);
271
272   for (i = 0; i < len; i++)
273     {
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);
278
279       digest[i] = (char)((x1 << 4) | x2);
280       is_nonzero |= (char)((x1 << 4) | x2);
281     }
282
283   if (!is_nonzero)
284     *checksum = NULL;
285
286   return SVN_NO_ERROR;
287 }
288
289 svn_checksum_t *
290 svn_checksum_dup(const svn_checksum_t *checksum,
291                  apr_pool_t *pool)
292 {
293   /* The duplicate of a NULL checksum is a NULL... */
294   if (checksum == NULL)
295     return NULL;
296
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)
303     {
304       case svn_checksum_md5:
305         return svn_checksum__from_digest_md5(checksum->digest, pool);
306         break;
307       case svn_checksum_sha1:
308         return svn_checksum__from_digest_sha1(checksum->digest, pool);
309         break;
310       default:
311         SVN_ERR_MALFUNCTION_NO_RETURN();
312         break;
313     }
314 }
315
316 svn_error_t *
317 svn_checksum(svn_checksum_t **checksum,
318              svn_checksum_kind_t kind,
319              const void *data,
320              apr_size_t len,
321              apr_pool_t *pool)
322 {
323   apr_sha1_ctx_t sha1_ctx;
324
325   SVN_ERR(validate_kind(kind));
326   *checksum = svn_checksum_create(kind, pool);
327
328   switch (kind)
329     {
330       case svn_checksum_md5:
331         apr_md5((unsigned char *)(*checksum)->digest, data, len);
332         break;
333
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);
338         break;
339
340       default:
341         /* We really shouldn't get here, but if we do... */
342         return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
343     }
344
345   return SVN_NO_ERROR;
346 }
347
348
349 svn_checksum_t *
350 svn_checksum_empty_checksum(svn_checksum_kind_t kind,
351                             apr_pool_t *pool)
352 {
353   switch (kind)
354     {
355       case svn_checksum_md5:
356         return svn_checksum__from_digest_md5(svn_md5__empty_string_digest(),
357                                              pool);
358
359       case svn_checksum_sha1:
360         return svn_checksum__from_digest_sha1(svn_sha1__empty_string_digest(),
361                                               pool);
362
363       default:
364         /* We really shouldn't get here, but if we do... */
365         SVN_ERR_MALFUNCTION_NO_RETURN();
366     }
367 }
368
369 struct svn_checksum_ctx_t
370 {
371   void *apr_ctx;
372   svn_checksum_kind_t kind;
373 };
374
375 svn_checksum_ctx_t *
376 svn_checksum_ctx_create(svn_checksum_kind_t kind,
377                         apr_pool_t *pool)
378 {
379   svn_checksum_ctx_t *ctx = apr_palloc(pool, sizeof(*ctx));
380
381   ctx->kind = kind;
382   switch (kind)
383     {
384       case svn_checksum_md5:
385         ctx->apr_ctx = apr_palloc(pool, sizeof(apr_md5_ctx_t));
386         apr_md5_init(ctx->apr_ctx);
387         break;
388
389       case svn_checksum_sha1:
390         ctx->apr_ctx = apr_palloc(pool, sizeof(apr_sha1_ctx_t));
391         apr_sha1_init(ctx->apr_ctx);
392         break;
393
394       default:
395         SVN_ERR_MALFUNCTION_NO_RETURN();
396     }
397
398   return ctx;
399 }
400
401 svn_error_t *
402 svn_checksum_update(svn_checksum_ctx_t *ctx,
403                     const void *data,
404                     apr_size_t len)
405 {
406   switch (ctx->kind)
407     {
408       case svn_checksum_md5:
409         apr_md5_update(ctx->apr_ctx, data, len);
410         break;
411
412       case svn_checksum_sha1:
413         apr_sha1_update(ctx->apr_ctx, data, (unsigned int)len);
414         break;
415
416       default:
417         /* We really shouldn't get here, but if we do... */
418         return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
419     }
420
421   return SVN_NO_ERROR;
422 }
423
424 svn_error_t *
425 svn_checksum_final(svn_checksum_t **checksum,
426                    const svn_checksum_ctx_t *ctx,
427                    apr_pool_t *pool)
428 {
429   *checksum = svn_checksum_create(ctx->kind, pool);
430
431   switch (ctx->kind)
432     {
433       case svn_checksum_md5:
434         apr_md5_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);
435         break;
436
437       case svn_checksum_sha1:
438         apr_sha1_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);
439         break;
440
441       default:
442         /* We really shouldn't get here, but if we do... */
443         return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
444     }
445
446   return SVN_NO_ERROR;
447 }
448
449 apr_size_t
450 svn_checksum_size(const svn_checksum_t *checksum)
451 {
452   return DIGESTSIZE(checksum->kind);
453 }
454
455 svn_error_t *
456 svn_checksum_mismatch_err(const svn_checksum_t *expected,
457                           const svn_checksum_t *actual,
458                           apr_pool_t *scratch_pool,
459                           const char *fmt,
460                           ...)
461 {
462   va_list ap;
463   const char *desc;
464
465   va_start(ap, fmt);
466   desc = apr_pvsprintf(scratch_pool, fmt, ap);
467   va_end(ap);
468
469   return svn_error_createf(SVN_ERR_CHECKSUM_MISMATCH, NULL,
470                            _("%s:\n"
471                              "   expected:  %s\n"
472                              "     actual:  %s\n"),
473                 desc,
474                 svn_checksum_to_cstring_display(expected, scratch_pool),
475                 svn_checksum_to_cstring_display(actual, scratch_pool));
476 }
477
478 svn_boolean_t
479 svn_checksum_is_empty_checksum(svn_checksum_t *checksum)
480 {
481   /* By definition, the NULL checksum matches all others, including the
482      empty one. */
483   if (!checksum)
484     return TRUE;
485
486   switch (checksum->kind)
487     {
488       case svn_checksum_md5:
489         return svn_md5__digests_match(checksum->digest,
490                                       svn_md5__empty_string_digest());
491
492       case svn_checksum_sha1:
493         return svn_sha1__digests_match(checksum->digest,
494                                        svn_sha1__empty_string_digest());
495
496       default:
497         /* We really shouldn't get here, but if we do... */
498         SVN_ERR_MALFUNCTION_NO_RETURN();
499     }
500 }