hast_checksum.c revision 219351
1238384Sjkim/*- 2238384Sjkim * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 3238384Sjkim * All rights reserved. 4238384Sjkim * 5238384Sjkim * Redistribution and use in source and binary forms, with or without 6238384Sjkim * modification, are permitted provided that the following conditions 7238384Sjkim * are met: 8238384Sjkim * 1. Redistributions of source code must retain the above copyright 9238384Sjkim * notice, this list of conditions and the following disclaimer. 10238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 11238384Sjkim * notice, this list of conditions and the following disclaimer in the 12238384Sjkim * documentation and/or other materials provided with the distribution. 13238384Sjkim * 14238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15238384Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17238384Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18238384Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19238384Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20238384Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22238384Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23238384Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24238384Sjkim * SUCH DAMAGE. 25238384Sjkim */ 26238384Sjkim 27238384Sjkim#include <sys/cdefs.h> 28238384Sjkim__FBSDID("$FreeBSD: head/sbin/hastd/hast_checksum.c 219351 2011-03-06 22:56:14Z pjd $"); 29238384Sjkim 30238384Sjkim#include <errno.h> 31238384Sjkim#include <string.h> 32238384Sjkim#include <strings.h> 33238384Sjkim 34238384Sjkim#ifdef HAVE_CRYPTO 35238384Sjkim#include <openssl/sha.h> 36238384Sjkim#endif 37238384Sjkim 38238384Sjkim#include <crc32.h> 39238384Sjkim#include <hast.h> 40238384Sjkim#include <nv.h> 41238384Sjkim#include <pjdlog.h> 42238384Sjkim 43238384Sjkim#include "hast_checksum.h" 44238384Sjkim 45238384Sjkim#ifdef HAVE_CRYPTO 46238384Sjkim#define MAX_HASH_SIZE SHA256_DIGEST_LENGTH 47238384Sjkim#else 48238384Sjkim#define MAX_HASH_SIZE 4 49238384Sjkim#endif 50238384Sjkim 51238384Sjkimstatic int 52238384Sjkimhast_crc32_checksum(const unsigned char *data, size_t size, 53238384Sjkim unsigned char *hash, size_t *hsizep) 54238384Sjkim{ 55238384Sjkim uint32_t crc; 56238384Sjkim 57238384Sjkim crc = crc32(data, size); 58238384Sjkim /* XXXPJD: Do we have to use htole32() on crc first? */ 59238384Sjkim bcopy(&crc, hash, sizeof(crc)); 60238384Sjkim *hsizep = sizeof(crc); 61238384Sjkim 62238384Sjkim return (0); 63238384Sjkim} 64238384Sjkim 65238384Sjkim#ifdef HAVE_CRYPTO 66238384Sjkimstatic int 67238384Sjkimhast_sha256_checksum(const unsigned char *data, size_t size, 68238384Sjkim unsigned char *hash, size_t *hsizep) 69238384Sjkim{ 70238384Sjkim SHA256_CTX ctx; 71238384Sjkim 72238384Sjkim SHA256_Init(&ctx); 73238384Sjkim SHA256_Update(&ctx, data, size); 74238384Sjkim SHA256_Final(hash, &ctx); 75238384Sjkim *hsizep = SHA256_DIGEST_LENGTH; 76238384Sjkim 77238384Sjkim return (0); 78238384Sjkim} 79238384Sjkim#endif /* HAVE_CRYPTO */ 80238384Sjkim 81238384Sjkimconst char * 82238384Sjkimchecksum_name(int num) 83238384Sjkim{ 84238384Sjkim 85238384Sjkim switch (num) { 86238384Sjkim case HAST_CHECKSUM_NONE: 87238384Sjkim return ("none"); 88238384Sjkim case HAST_CHECKSUM_CRC32: 89238384Sjkim return ("crc32"); 90238384Sjkim case HAST_CHECKSUM_SHA256: 91238384Sjkim return ("sha256"); 92238384Sjkim } 93238384Sjkim return ("unknown"); 94238384Sjkim} 95238384Sjkim 96238384Sjkimint 97238384Sjkimchecksum_send(const struct hast_resource *res, struct nv *nv, void **datap, 98238384Sjkim size_t *sizep, bool *freedatap __unused) 99238384Sjkim{ 100238384Sjkim unsigned char hash[MAX_HASH_SIZE]; 101238384Sjkim size_t hsize; 102238384Sjkim int ret; 103238384Sjkim 104238384Sjkim switch (res->hr_checksum) { 105238384Sjkim case HAST_CHECKSUM_NONE: 106238384Sjkim return (0); 107238384Sjkim case HAST_CHECKSUM_CRC32: 108238384Sjkim ret = hast_crc32_checksum(*datap, *sizep, hash, &hsize); 109238384Sjkim break; 110238384Sjkim#ifdef HAVE_CRYPTO 111238384Sjkim case HAST_CHECKSUM_SHA256: 112238384Sjkim ret = hast_sha256_checksum(*datap, *sizep, hash, &hsize); 113238384Sjkim break; 114238384Sjkim#endif 115238384Sjkim default: 116238384Sjkim PJDLOG_ABORT("Invalid checksum: %d.", res->hr_checksum); 117238384Sjkim } 118238384Sjkim 119238384Sjkim if (ret != 0) 120238384Sjkim return (ret); 121238384Sjkim nv_add_string(nv, checksum_name(res->hr_checksum), "checksum"); 122238384Sjkim nv_add_uint8_array(nv, hash, hsize, "hash"); 123238384Sjkim if (nv_error(nv) != 0) { 124238384Sjkim errno = nv_error(nv); 125238384Sjkim return (-1); 126238384Sjkim } 127238384Sjkim return (0); 128238384Sjkim} 129238384Sjkim 130238384Sjkimint 131238384Sjkimchecksum_recv(const struct hast_resource *res __unused, struct nv *nv, 132238384Sjkim void **datap, size_t *sizep, bool *freedatap __unused) 133238384Sjkim{ 134238384Sjkim unsigned char chash[MAX_HASH_SIZE]; 135238384Sjkim const unsigned char *rhash; 136238384Sjkim size_t chsize, rhsize; 137238384Sjkim const char *algo; 138238384Sjkim int ret; 139238384Sjkim 140238384Sjkim algo = nv_get_string(nv, "checksum"); 141238384Sjkim if (algo == NULL) 142238384Sjkim return (0); /* No checksum. */ 143238384Sjkim rhash = nv_get_uint8_array(nv, &rhsize, "hash"); 144238384Sjkim if (rhash == NULL) { 145238384Sjkim pjdlog_error("Hash is missing."); 146238384Sjkim return (-1); /* Hash not found. */ 147238384Sjkim } 148238384Sjkim if (strcmp(algo, "crc32") == 0) 149238384Sjkim ret = hast_crc32_checksum(*datap, *sizep, chash, &chsize); 150238384Sjkim#ifdef HAVE_CRYPTO 151238384Sjkim else if (strcmp(algo, "sha256") == 0) 152238384Sjkim ret = hast_sha256_checksum(*datap, *sizep, chash, &chsize); 153238384Sjkim#endif 154238384Sjkim else { 155238384Sjkim pjdlog_error("Unknown checksum algorithm '%s'.", algo); 156238384Sjkim return (-1); /* Unknown checksum algorithm. */ 157238384Sjkim } 158238384Sjkim if (rhsize != chsize) { 159238384Sjkim pjdlog_error("Invalid hash size (%zu) for %s, should be %zu.", 160238384Sjkim rhsize, algo, chsize); 161238384Sjkim return (-1); /* Different hash size. */ 162 } 163 if (bcmp(rhash, chash, chsize) != 0) { 164 pjdlog_error("Hash mismatch."); 165 return (-1); /* Hash mismatch. */ 166 } 167 168 return (0); 169} 170