1 /*
2 * Copyright 2018 Jonathan Dieter <jdieter@gmail.com>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <stdbool.h>
31 #include <string.h>
32 #include <zck.h>
33
34 #include "zck_private.h"
35
36 /***** If we're not using OpenSSL, use bundled sha libraries *****/
37 #ifndef ZCHUNK_OPENSSL
38 #include "sha1/sha1.h"
39 #include "sha2/sha2.h"
40 #define SHA256_CTX sha256_ctx
41 #define SHA256_Init sha256_init
42 #define SHA256_Update sha256_update
SHA256_Final(unsigned char * md,SHA256_CTX * c)43 static void SHA256_Final(unsigned char *md, SHA256_CTX *c) {
44 sha256_final(c, md);
45 }
46 #define SHA512_CTX sha512_ctx
47 #define SHA512_Init sha512_init
48 #define SHA512_Update sha512_update
SHA512_Final(unsigned char * md,SHA512_CTX * c)49 static void SHA512_Final(unsigned char *md, SHA512_CTX *c) {
50 sha512_final(c, md);
51 }
52 /***** If we are using OpenSSL, set the defines accordingly *****/
53 #else
54 #include <openssl/sha.h>
55 #define SHA512_DIGEST_SIZE SHA512_DIGEST_LENGTH
56 #define SHA256_DIGEST_SIZE SHA256_DIGEST_LENGTH
57 #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
58 #define sha1_byte void
59 #endif
60
61 /* This needs to be updated to the largest hash size every time a new hash type
62 * is added */
get_max_hash_size()63 int get_max_hash_size() {
64 return SHA512_DIGEST_SIZE;
65 }
66
67 static char unknown[] = "Unknown(\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
68
69 const static char *HASH_NAME[] = {
70 "SHA-1",
71 "SHA-256",
72 "SHA-512",
73 "SHA-512/128"
74 };
75
validate_checksums(zckCtx * zck,zck_log_type bad_checksums)76 static int validate_checksums(zckCtx *zck, zck_log_type bad_checksums) {
77 VALIDATE_READ_BOOL(zck);
78 char buf[BUF_SIZE] = {0};
79
80 if(zck->data_offset == 0) {
81 set_error(zck, "Header hasn't been read yet");
82 return 0;
83 }
84
85 if(!hash_init(zck, &(zck->check_full_hash), &(zck->hash_type)))
86 return 0;
87
88 if(!seek_data(zck, zck->data_offset, SEEK_SET))
89 return 0;
90
91 /* Check each chunk checksum */
92 bool all_good = true;
93 for(zckChunk *idx = zck->index.first; idx; idx = idx->next) {
94 if(idx == zck->index.first && idx->length == 0) {
95 idx->valid = 1;
96 continue;
97 }
98
99 if(!hash_init(zck, &(zck->check_chunk_hash), &(zck->chunk_hash_type)))
100 return 0;
101
102 size_t rlen = 0;
103 while(rlen < idx->comp_length) {
104 size_t rsize = BUF_SIZE;
105 if(BUF_SIZE > idx->comp_length - rlen)
106 rsize = idx->comp_length - rlen;
107 if(read_data(zck, buf, rsize) != rsize)
108 zck_log(ZCK_LOG_DEBUG, "No more data");
109 if(!hash_update(zck, &(zck->check_chunk_hash), buf, rsize))
110 return 0;
111 if(!hash_update(zck, &(zck->check_full_hash), buf, rsize))
112 return 0;
113 rlen += rsize;
114 }
115 int valid_chunk = validate_chunk(idx, bad_checksums);
116 if(!valid_chunk)
117 return 0;
118 idx->valid = valid_chunk;
119 if(all_good && valid_chunk != 1)
120 all_good = false;
121 }
122 int valid_file = -1;
123 if(all_good) {
124 /* Check data checksum */
125 valid_file = validate_file(zck, bad_checksums);
126 if(!valid_file)
127 return 0;
128
129 /* If data checksum failed, invalidate *all* chunks */
130 if(valid_file == -1)
131 for(zckChunk *idx = zck->index.first; idx; idx = idx->next)
132 idx->valid = -1;
133 }
134
135 /* Go back to beginning of data section */
136 if(!seek_data(zck, zck->data_offset, SEEK_SET))
137 return 0;
138
139 /* Reinitialize data checksum */
140 if(!hash_init(zck, &(zck->check_full_hash), &(zck->hash_type)))
141 return 0;
142
143 return valid_file;
144 }
145
get_digest_string(const char * digest,int size)146 char *get_digest_string(const char *digest, int size) {
147 char *str = zmalloc(size*2+1);
148
149 for(int i=0; i<size; i++)
150 snprintf(str + i*2, 3, "%02x", (unsigned char)digest[i]);
151 return str;
152 }
153
hash_setup(zckCtx * zck,zckHashType * ht,int h)154 bool hash_setup(zckCtx *zck, zckHashType *ht, int h) {
155 if(!ht) {
156 set_error(zck, "zckHashType is null");
157 return false;
158 }
159 if(h == ZCK_HASH_SHA1) {
160 memset(ht, 0, sizeof(zckHashType));
161 ht->type = ZCK_HASH_SHA1;
162 ht->digest_size = SHA1_DIGEST_LENGTH;
163 zck_log(ZCK_LOG_DEBUG, "Setting up hash type %s",
164 zck_hash_name_from_type(ht->type));
165 return true;
166 } else if(h == ZCK_HASH_SHA256) {
167 memset(ht, 0, sizeof(zckHashType));
168 ht->type = ZCK_HASH_SHA256;
169 ht->digest_size = SHA256_DIGEST_SIZE;
170 zck_log(ZCK_LOG_DEBUG, "Setting up hash type %s",
171 zck_hash_name_from_type(ht->type));
172 return true;
173 } else if(h >= ZCK_HASH_SHA512 &&
174 h <= ZCK_HASH_SHA512_128) {
175 memset(ht, 0, sizeof(zckHashType));
176 ht->type = h;
177 if(h == ZCK_HASH_SHA512)
178 ht->digest_size = SHA512_DIGEST_SIZE;
179 else if(h == ZCK_HASH_SHA512_128)
180 ht->digest_size = 16;
181 zck_log(ZCK_LOG_DEBUG, "Setting up hash type %s",
182 zck_hash_name_from_type(ht->type));
183 return true;
184 }
185 set_error(zck, "Unsupported hash type: %s", zck_hash_name_from_type(h));
186 return false;
187 }
188
hash_close(zckHash * hash)189 void hash_close(zckHash *hash) {
190 if(!hash)
191 return;
192
193 if(hash->ctx) {
194 free(hash->ctx);
195 hash->ctx = NULL;
196 }
197 hash->type = NULL;
198 return;
199 }
200
hash_reset(zckHashType * ht)201 void hash_reset(zckHashType *ht) {
202 memset(ht, 0, sizeof(zckHashType));
203 return;
204 }
205
hash_init(zckCtx * zck,zckHash * hash,zckHashType * hash_type)206 bool hash_init(zckCtx *zck, zckHash *hash, zckHashType *hash_type) {
207 hash_close(hash);
208 if(hash == NULL || hash_type == NULL) {
209 set_error(zck, "Either zckHash or zckHashType struct is null");
210 return false;
211 }
212 if(hash_type->type == ZCK_HASH_SHA1) {
213 zck_log(ZCK_LOG_DDEBUG, "Initializing SHA-1 hash");
214 hash->ctx = zmalloc(sizeof(SHA_CTX));
215 hash->type = hash_type;
216 SHA1_Init((SHA_CTX *) hash->ctx);
217 return true;
218 } else if(hash_type->type == ZCK_HASH_SHA256) {
219 zck_log(ZCK_LOG_DDEBUG, "Initializing SHA-256 hash");
220 hash->ctx = zmalloc(sizeof(SHA256_CTX));
221 hash->type = hash_type;
222 SHA256_Init((SHA256_CTX *) hash->ctx);
223 return true;
224 } else if(hash_type->type >= ZCK_HASH_SHA512 &&
225 hash_type->type <= ZCK_HASH_SHA512_128) {
226 zck_log(ZCK_LOG_DDEBUG, "Initializing SHA-512 hash");
227 hash->ctx = zmalloc(sizeof(SHA512_CTX));
228 hash->type = hash_type;
229 SHA512_Init((SHA512_CTX *) hash->ctx);
230 return true;
231 }
232 set_error(zck, "Unsupported hash type: %s",
233 zck_hash_name_from_type(hash_type->type));
234 return false;
235 }
236
hash_update(zckCtx * zck,zckHash * hash,const char * message,const size_t size)237 bool hash_update(zckCtx *zck, zckHash *hash, const char *message,
238 const size_t size) {
239 if(message == NULL && size == 0)
240 return true;
241 if(message == NULL) {
242 set_error(zck,
243 "Hash data is supposed to have %lu bytes, but is NULL", size);
244 return false;
245 }
246 if(size == 0) {
247 set_error(zck,
248 "Hash data is supposed to be 0-length, but is not NULL");
249 return false;
250 }
251 if(hash && hash->ctx && hash->type) {
252 if(hash->type->type == ZCK_HASH_SHA1) {
253 SHA1_Update((SHA_CTX *)hash->ctx, (const sha1_byte *)message, size);
254 return true;
255 } else if(hash->type->type == ZCK_HASH_SHA256) {
256 SHA256_Update((SHA256_CTX *)hash->ctx,
257 (const unsigned char *)message, size);
258 return true;
259 } else if(hash->type->type >= ZCK_HASH_SHA512 &&
260 hash->type->type <= ZCK_HASH_SHA512_128) {
261 SHA512_Update((SHA512_CTX *)hash->ctx,
262 (const unsigned char *)message, size);
263 return true;
264 }
265 set_error(zck, "Unsupported hash type: %s",
266 zck_hash_name_from_type(hash->type->type));
267
268 return false;
269 }
270 set_error(zck, "Hash hasn't been initialized");
271 return false;
272 }
273
hash_finalize(zckCtx * zck,zckHash * hash)274 char *hash_finalize(zckCtx *zck, zckHash *hash) {
275 if(!hash || !hash->ctx || !hash->type) {
276 set_error(zck, "Hash hasn't been initialized");
277 hash_close(hash);
278 return NULL;
279 }
280 if(hash->type->type == ZCK_HASH_SHA1) {
281 unsigned char *digest = zmalloc(SHA1_DIGEST_LENGTH);
282 SHA1_Final((sha1_byte*)digest, (SHA_CTX *)hash->ctx);
283 hash_close(hash);
284 return (char *)digest;
285 } else if(hash->type->type == ZCK_HASH_SHA256) {
286 unsigned char *digest = zmalloc(SHA256_DIGEST_SIZE);
287 SHA256_Final(digest, (SHA256_CTX *)hash->ctx);
288 hash_close(hash);
289 return (char *)digest;
290 } else if(hash->type->type >= ZCK_HASH_SHA512 &&
291 hash->type->type <= ZCK_HASH_SHA512_128) {
292 unsigned char *digest = zmalloc(SHA512_DIGEST_SIZE);
293 SHA512_Final(digest, (SHA512_CTX *)hash->ctx);
294 hash_close(hash);
295 return (char *)digest;
296 }
297 set_error(zck, "Unsupported hash type: %s",
298 zck_hash_name_from_type(hash->type->type));
299 hash_close(hash);
300 return NULL;
301 }
302
set_full_hash_type(zckCtx * zck,int hash_type)303 bool set_full_hash_type(zckCtx *zck, int hash_type) {
304 VALIDATE_BOOL(zck);
305
306 zck_log(ZCK_LOG_INFO, "Setting full hash to %s",
307 zck_hash_name_from_type(hash_type));
308 if(!hash_setup(zck, &(zck->hash_type), hash_type)) {
309 set_error(zck, "Unable to set full hash");
310 return false;
311 }
312 if(!hash_init(zck, &(zck->full_hash), &(zck->hash_type))) {
313 set_error(zck, "Unable initialize full hash");
314 return false;
315 }
316 return true;
317 }
318
set_chunk_hash_type(zckCtx * zck,int hash_type)319 bool set_chunk_hash_type(zckCtx *zck, int hash_type) {
320 VALIDATE_BOOL(zck);
321
322 memset(&(zck->chunk_hash_type), 0, sizeof(zckHashType));
323 zck_log(ZCK_LOG_DEBUG, "Setting chunk hash to %s",
324 zck_hash_name_from_type(hash_type));
325 if(!hash_setup(zck, &(zck->chunk_hash_type), hash_type)) {
326 set_error(zck, "Unable to set chunk hash");
327 return false;
328 }
329 zck->index.hash_type = zck->chunk_hash_type.type;
330 zck->index.digest_size = zck->chunk_hash_type.digest_size;
331 return true;
332 }
333
334 /* Validate chunk, returning -1 if checksum fails, 1 if good, 0 if error */
validate_chunk(zckChunk * idx,zck_log_type bad_checksum)335 int validate_chunk(zckChunk *idx, zck_log_type bad_checksum) {
336 zckCtx *zck = NULL;
337 if(idx && idx->zck) {
338 VALIDATE_INT(idx->zck);
339 zck = idx->zck;
340 }
341 ALLOCD_INT(zck, idx);
342
343 char *digest = hash_finalize(zck, &(zck->check_chunk_hash));
344 if(digest == NULL) {
345 set_error(zck, "Unable to calculate chunk checksum");
346 idx->valid = 0;
347 return 0;
348 }
349 if(idx->comp_length == 0)
350 memset(digest, 0, idx->digest_size);
351 char *pdigest = zck_get_chunk_digest(idx);
352 zck_log(ZCK_LOG_DDEBUG, "Expected chunk checksum: %s", pdigest);
353 free(pdigest);
354 pdigest = get_digest_string(digest, idx->digest_size);
355 zck_log(ZCK_LOG_DDEBUG, "Calculated chunk checksum: %s", pdigest);
356 free(pdigest);
357 if(memcmp(digest, idx->digest, idx->digest_size) != 0) {
358 free(digest);
359 if(idx->number == -1)
360 zck_log(bad_checksum, "Chunk checksum: FAILED!");
361 else
362 zck_log(bad_checksum, "Chunk %i's checksum: FAILED",
363 idx->number);
364 idx->valid = -1;
365 return -1;
366 }
367 if(idx->number == -1)
368 zck_log(ZCK_LOG_DEBUG, "Chunk checksum: valid");
369 else
370 zck_log(ZCK_LOG_DEBUG, "Chunk %i's checksum: valid", idx->number);
371 free(digest);
372 idx->valid = 1;
373 return 1;
374 }
375
validate_current_chunk(zckCtx * zck)376 int validate_current_chunk(zckCtx *zck) {
377 VALIDATE_BOOL(zck);
378
379 return validate_chunk(zck->comp.data_idx, ZCK_LOG_ERROR);
380 }
381
validate_file(zckCtx * zck,zck_log_type bad_checksums)382 int validate_file(zckCtx *zck, zck_log_type bad_checksums) {
383 VALIDATE_BOOL(zck);
384 char *digest = hash_finalize(zck, &(zck->check_full_hash));
385 if(digest == NULL) {
386 set_error(zck, "Unable to calculate full file checksum");
387 return 0;
388 }
389 zck_log(ZCK_LOG_DEBUG, "Checking data checksum");
390 char *cks = get_digest_string(zck->full_hash_digest,
391 zck->hash_type.digest_size);
392 zck_log(ZCK_LOG_DEBUG, "Expected data checksum: %s", cks);
393 free(cks);
394 cks = get_digest_string(digest, zck->hash_type.digest_size);
395 zck_log(ZCK_LOG_DEBUG, "Calculated data checksum: %s", cks);
396 free(cks);
397 if(memcmp(digest, zck->full_hash_digest, zck->hash_type.digest_size) != 0) {
398 free(digest);
399 zck_log(bad_checksums, "Data checksum failed!");
400 return -1;
401 }
402 zck_log(ZCK_LOG_DEBUG, "Data checksum valid");
403 free(digest);
404 return 1;
405 }
406
validate_header(zckCtx * zck)407 int validate_header(zckCtx *zck) {
408 VALIDATE_BOOL(zck);
409
410 char *digest = hash_finalize(zck, &(zck->check_full_hash));
411 if(digest == NULL) {
412 set_error(zck, "Unable to calculate header checksum");
413 return 0;
414 }
415 zck_log(ZCK_LOG_DEBUG, "Checking header checksum");
416 char *cks = get_digest_string(zck->header_digest,
417 zck->hash_type.digest_size);
418 zck_log(ZCK_LOG_DEBUG, "Expected header checksum: %s", cks);
419 free(cks);
420 cks = get_digest_string(digest, zck->hash_type.digest_size);
421 zck_log(ZCK_LOG_DEBUG, "Calculated header checksum: %s", cks);
422 free(cks);
423 if(memcmp(digest, zck->header_digest, zck->hash_type.digest_size) != 0) {
424 free(digest);
425 zck_log(ZCK_LOG_INFO, "Header checksum failed!");
426 return -1;
427 }
428 zck_log(ZCK_LOG_DEBUG, "Header checksum valid");
429 free(digest);
430
431 if(!hash_init(zck, &(zck->check_full_hash), &(zck->hash_type)))
432 return 0;
433
434 return 1;
435 }
436
437 /* Returns 1 if data hash matches, -1 if it doesn't and 0 if error */
zck_validate_data_checksum(zckCtx * zck)438 int PUBLIC zck_validate_data_checksum(zckCtx *zck) {
439 VALIDATE_READ_BOOL(zck);
440
441 if(!seek_data(zck, zck->data_offset, SEEK_SET))
442 return 0;
443 if(!hash_init(zck, &(zck->check_full_hash), &(zck->hash_type)))
444 return 0;
445 char buf[BUF_SIZE] = {0};
446 zckChunk *idx = zck->index.first;
447 zck_log(ZCK_LOG_DEBUG, "Checking full hash");
448 while(idx) {
449 size_t to_read = idx->comp_length;
450 while(to_read > 0) {
451 size_t rb = BUF_SIZE;
452 if(rb > to_read)
453 rb = to_read;
454 if(!read_data(zck, buf, rb))
455 return 0;
456 if(!hash_update(zck, &(zck->check_full_hash), buf, rb))
457 return 0;
458 to_read -= rb;
459 }
460 idx = idx->next;
461 }
462 int ret = validate_file(zck, ZCK_LOG_WARNING);
463 if(!seek_data(zck, zck->data_offset, SEEK_SET))
464 return 0;
465 if(!hash_init(zck, &(zck->check_full_hash), &(zck->hash_type)))
466 return 0;
467 return ret;
468 }
469
zck_hash_name_from_type(int hash_type)470 const char PUBLIC *zck_hash_name_from_type(int hash_type) {
471 if(hash_type >= ZCK_HASH_UNKNOWN || hash_type < 0) {
472 snprintf(unknown+8, 21, "%i)", hash_type);
473 return unknown;
474 }
475 return HASH_NAME[hash_type];
476 }
477
zck_get_full_hash_type(zckCtx * zck)478 int PUBLIC zck_get_full_hash_type(zckCtx *zck) {
479 VALIDATE_INT(zck);
480
481 return zck->hash_type.type;
482 }
483
zck_get_full_digest_size(zckCtx * zck)484 ssize_t PUBLIC zck_get_full_digest_size(zckCtx *zck) {
485 VALIDATE_INT(zck);
486
487 return zck->hash_type.digest_size;
488 }
489
zck_get_chunk_hash_type(zckCtx * zck)490 int PUBLIC zck_get_chunk_hash_type(zckCtx *zck) {
491 VALIDATE_INT(zck);
492
493 return zck->index.hash_type;
494 }
495
zck_get_chunk_digest_size(zckCtx * zck)496 ssize_t PUBLIC zck_get_chunk_digest_size(zckCtx *zck) {
497 VALIDATE_INT(zck);
498
499 return zck->index.digest_size;
500 }
501
zck_get_header_digest(zckCtx * zck)502 char PUBLIC *zck_get_header_digest(zckCtx *zck) {
503 VALIDATE_PTR(zck);
504
505 return get_digest_string(zck->header_digest, zck->hash_type.digest_size);
506 }
507
zck_get_data_digest(zckCtx * zck)508 char PUBLIC *zck_get_data_digest(zckCtx *zck) {
509 VALIDATE_PTR(zck);
510
511 return get_digest_string(zck->full_hash_digest, zck->hash_type.digest_size);
512 }
513
zck_get_chunk_digest(zckChunk * item)514 char PUBLIC *zck_get_chunk_digest(zckChunk *item) {
515 if(item == NULL)
516 return NULL;
517 return get_digest_string(item->digest, item->digest_size);
518 }
519
520 /* Returns 1 if all chunks are valid, -1 if even one isn't and 0 if error */
zck_find_valid_chunks(zckCtx * zck)521 int PUBLIC zck_find_valid_chunks(zckCtx *zck) {
522 VALIDATE_READ_BOOL(zck);
523
524 return validate_checksums(zck, ZCK_LOG_DEBUG);
525 }
526
527 /* Returns 1 if all checksums matched, -1 if even one doesn't and 0 if error */
zck_validate_checksums(zckCtx * zck)528 int PUBLIC zck_validate_checksums(zckCtx *zck) {
529 VALIDATE_READ_BOOL(zck);
530
531 return validate_checksums(zck, ZCK_LOG_WARNING);
532 }
533