hast_checksum.c revision 219351
1184610Salfred/*- 2184610Salfred * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net> 3184610Salfred * All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27194677Sthompsa#include <sys/cdefs.h> 28194677Sthompsa__FBSDID("$FreeBSD: head/sbin/hastd/hast_checksum.c 219351 2011-03-06 22:56:14Z pjd $"); 29194677Sthompsa 30194677Sthompsa#include <errno.h> 31194677Sthompsa#include <string.h> 32194677Sthompsa#include <strings.h> 33194677Sthompsa 34194677Sthompsa#ifdef HAVE_CRYPTO 35194677Sthompsa#include <openssl/sha.h> 36194677Sthompsa#endif 37194677Sthompsa 38194677Sthompsa#include <crc32.h> 39194677Sthompsa#include <hast.h> 40194677Sthompsa#include <nv.h> 41194677Sthompsa#include <pjdlog.h> 42194677Sthompsa 43194677Sthompsa#include "hast_checksum.h" 44194677Sthompsa 45194677Sthompsa#ifdef HAVE_CRYPTO 46194677Sthompsa#define MAX_HASH_SIZE SHA256_DIGEST_LENGTH 47194677Sthompsa#else 48188942Sthompsa#define MAX_HASH_SIZE 4 49188942Sthompsa#endif 50194677Sthompsa 51194677Sthompsastatic int 52184610Salfredhast_crc32_checksum(const unsigned char *data, size_t size, 53184610Salfred unsigned char *hash, size_t *hsizep) 54184610Salfred{ 55188942Sthompsa uint32_t crc; 56194677Sthompsa 57188942Sthompsa crc = crc32(data, size); 58188942Sthompsa /* XXXPJD: Do we have to use htole32() on crc first? */ 59188942Sthompsa bcopy(&crc, hash, sizeof(crc)); 60188942Sthompsa *hsizep = sizeof(crc); 61188942Sthompsa 62188942Sthompsa return (0); 63188942Sthompsa} 64188942Sthompsa 65188942Sthompsa#ifdef HAVE_CRYPTO 66188942Sthompsastatic int 67184610Salfredhast_sha256_checksum(const unsigned char *data, size_t size, 68188942Sthompsa unsigned char *hash, size_t *hsizep) 69188942Sthompsa{ 70184610Salfred SHA256_CTX ctx; 71190191Sthompsa 72190191Sthompsa SHA256_Init(&ctx); 73184610Salfred SHA256_Update(&ctx, data, size); 74184610Salfred SHA256_Final(hash, &ctx); 75184610Salfred *hsizep = SHA256_DIGEST_LENGTH; 76184610Salfred 77184610Salfred return (0); 78184610Salfred} 79184610Salfred#endif /* HAVE_CRYPTO */ 80184610Salfred 81193045Sthompsaconst char * 82193045Sthompsachecksum_name(int num) 83207080Sthompsa{ 84207080Sthompsa 85193045Sthompsa switch (num) { 86193045Sthompsa case HAST_CHECKSUM_NONE: 87207080Sthompsa return ("none"); 88184610Salfred case HAST_CHECKSUM_CRC32: 89193045Sthompsa return ("crc32"); 90193045Sthompsa case HAST_CHECKSUM_SHA256: 91193045Sthompsa return ("sha256"); 92193045Sthompsa } 93193045Sthompsa return ("unknown"); 94193045Sthompsa} 95193045Sthompsa 96184610Salfredint 97192984Sthompsachecksum_send(const struct hast_resource *res, struct nv *nv, void **datap, 98192984Sthompsa size_t *sizep, bool *freedatap __unused) 99192984Sthompsa{ 100192984Sthompsa unsigned char hash[MAX_HASH_SIZE]; 101192984Sthompsa size_t hsize; 102192984Sthompsa int ret; 103192984Sthompsa 104192984Sthompsa switch (res->hr_checksum) { 105192984Sthompsa case HAST_CHECKSUM_NONE: 106194228Sthompsa return (0); 107192984Sthompsa case HAST_CHECKSUM_CRC32: 108192984Sthompsa ret = hast_crc32_checksum(*datap, *sizep, hash, &hsize); 109192984Sthompsa break; 110192984Sthompsa#ifdef HAVE_CRYPTO 111213432Shselasky case HAST_CHECKSUM_SHA256: 112184610Salfred ret = hast_sha256_checksum(*datap, *sizep, hash, &hsize); 113184610Salfred break; 114184610Salfred#endif 115194228Sthompsa default: 116184610Salfred PJDLOG_ABORT("Invalid checksum: %d.", res->hr_checksum); 117184610Salfred } 118184610Salfred 119185087Salfred if (ret != 0) 120184610Salfred return (ret); 121184610Salfred nv_add_string(nv, checksum_name(res->hr_checksum), "checksum"); 122184610Salfred nv_add_uint8_array(nv, hash, hsize, "hash"); 123184610Salfred if (nv_error(nv) != 0) { 124184610Salfred errno = nv_error(nv); 125184610Salfred return (-1); 126194677Sthompsa } 127184610Salfred return (0); 128184610Salfred} 129248085Smarius 130242775Shselaskyint 131184610Salfredchecksum_recv(const struct hast_resource *res __unused, struct nv *nv, 132199675Sthompsa void **datap, size_t *sizep, bool *freedatap __unused) 133184610Salfred{ 134184610Salfred unsigned char chash[MAX_HASH_SIZE]; 135184610Salfred const unsigned char *rhash; 136184610Salfred size_t chsize, rhsize; 137184610Salfred const char *algo; 138184610Salfred int ret; 139192984Sthompsa 140192984Sthompsa algo = nv_get_string(nv, "checksum"); 141184610Salfred if (algo == NULL) 142194677Sthompsa return (0); /* No checksum. */ 143192984Sthompsa rhash = nv_get_uint8_array(nv, &rhsize, "hash"); 144193644Sthompsa if (rhash == NULL) { 145184610Salfred pjdlog_error("Hash is missing."); 146184610Salfred return (-1); /* Hash not found. */ 147184610Salfred } 148184610Salfred if (strcmp(algo, "crc32") == 0) 149184610Salfred ret = hast_crc32_checksum(*datap, *sizep, chash, &chsize); 150194228Sthompsa#ifdef HAVE_CRYPTO 151184610Salfred else if (strcmp(algo, "sha256") == 0) 152184610Salfred ret = hast_sha256_checksum(*datap, *sizep, chash, &chsize); 153194228Sthompsa#endif 154184610Salfred else { 155184610Salfred pjdlog_error("Unknown checksum algorithm '%s'.", algo); 156184610Salfred return (-1); /* Unknown checksum algorithm. */ 157184610Salfred } 158194228Sthompsa if (rhsize != chsize) { 159184610Salfred pjdlog_error("Invalid hash size (%zu) for %s, should be %zu.", 160184610Salfred rhsize, algo, chsize); 161194228Sthompsa return (-1); /* Different hash size. */ 162184610Salfred } 163184610Salfred if (bcmp(rhash, chash, chsize) != 0) { 164184610Salfred pjdlog_error("Hash mismatch."); 165184610Salfred return (-1); /* Hash mismatch. */ 166194228Sthompsa } 167184610Salfred 168184610Salfred return (0); 169184610Salfred} 170184610Salfred