xref: /freebsd/sbin/hastd/hast_checksum.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
11fee97b0SPawel Jakub Dawidek /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
41fee97b0SPawel Jakub Dawidek  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
51fee97b0SPawel Jakub Dawidek  * All rights reserved.
61fee97b0SPawel Jakub Dawidek  *
71fee97b0SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
81fee97b0SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
91fee97b0SPawel Jakub Dawidek  * are met:
101fee97b0SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
111fee97b0SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
121fee97b0SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
131fee97b0SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
141fee97b0SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
151fee97b0SPawel Jakub Dawidek  *
161fee97b0SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
171fee97b0SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181fee97b0SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191fee97b0SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
201fee97b0SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211fee97b0SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221fee97b0SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231fee97b0SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241fee97b0SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251fee97b0SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261fee97b0SPawel Jakub Dawidek  * SUCH DAMAGE.
271fee97b0SPawel Jakub Dawidek  */
281fee97b0SPawel Jakub Dawidek 
291fee97b0SPawel Jakub Dawidek #include <sys/cdefs.h>
301fee97b0SPawel Jakub Dawidek #include <errno.h>
311fee97b0SPawel Jakub Dawidek #include <string.h>
321fee97b0SPawel Jakub Dawidek #include <strings.h>
331fee97b0SPawel Jakub Dawidek 
341fee97b0SPawel Jakub Dawidek #include <hast.h>
351fee97b0SPawel Jakub Dawidek #include <nv.h>
36c0bde750SAllan Jude #include <sha256.h>
376998572aSXin LI #include <zlib.h>
381fee97b0SPawel Jakub Dawidek #include <pjdlog.h>
391fee97b0SPawel Jakub Dawidek 
401fee97b0SPawel Jakub Dawidek #include "hast_checksum.h"
411fee97b0SPawel Jakub Dawidek 
421fee97b0SPawel Jakub Dawidek #define	MAX_HASH_SIZE	SHA256_DIGEST_LENGTH
431fee97b0SPawel Jakub Dawidek 
448c63ee4fSPawel Jakub Dawidek static void
hast_crc32_checksum(const unsigned char * data,size_t size,unsigned char * hash,size_t * hsizep)451fee97b0SPawel Jakub Dawidek hast_crc32_checksum(const unsigned char *data, size_t size,
461fee97b0SPawel Jakub Dawidek     unsigned char *hash, size_t *hsizep)
471fee97b0SPawel Jakub Dawidek {
481fee97b0SPawel Jakub Dawidek 	uint32_t crc;
491fee97b0SPawel Jakub Dawidek 
506998572aSXin LI 	crc = crc32(0L, Z_NULL, 0);
516998572aSXin LI 	crc = crc32(crc, data, size);
526998572aSXin LI 
531fee97b0SPawel Jakub Dawidek 	/* XXXPJD: Do we have to use htole32() on crc first? */
541fee97b0SPawel Jakub Dawidek 	bcopy(&crc, hash, sizeof(crc));
551fee97b0SPawel Jakub Dawidek 	*hsizep = sizeof(crc);
561fee97b0SPawel Jakub Dawidek }
571fee97b0SPawel Jakub Dawidek 
588c63ee4fSPawel Jakub Dawidek static void
hast_sha256_checksum(const unsigned char * data,size_t size,unsigned char * hash,size_t * hsizep)591fee97b0SPawel Jakub Dawidek hast_sha256_checksum(const unsigned char *data, size_t size,
601fee97b0SPawel Jakub Dawidek     unsigned char *hash, size_t *hsizep)
611fee97b0SPawel Jakub Dawidek {
621fee97b0SPawel Jakub Dawidek 	SHA256_CTX ctx;
631fee97b0SPawel Jakub Dawidek 
641fee97b0SPawel Jakub Dawidek 	SHA256_Init(&ctx);
651fee97b0SPawel Jakub Dawidek 	SHA256_Update(&ctx, data, size);
661fee97b0SPawel Jakub Dawidek 	SHA256_Final(hash, &ctx);
671fee97b0SPawel Jakub Dawidek 	*hsizep = SHA256_DIGEST_LENGTH;
681fee97b0SPawel Jakub Dawidek }
691fee97b0SPawel Jakub Dawidek 
701fee97b0SPawel Jakub Dawidek const char *
checksum_name(int num)711fee97b0SPawel Jakub Dawidek checksum_name(int num)
721fee97b0SPawel Jakub Dawidek {
731fee97b0SPawel Jakub Dawidek 
741fee97b0SPawel Jakub Dawidek 	switch (num) {
751fee97b0SPawel Jakub Dawidek 	case HAST_CHECKSUM_NONE:
761fee97b0SPawel Jakub Dawidek 		return ("none");
771fee97b0SPawel Jakub Dawidek 	case HAST_CHECKSUM_CRC32:
781fee97b0SPawel Jakub Dawidek 		return ("crc32");
791fee97b0SPawel Jakub Dawidek 	case HAST_CHECKSUM_SHA256:
801fee97b0SPawel Jakub Dawidek 		return ("sha256");
811fee97b0SPawel Jakub Dawidek 	}
821fee97b0SPawel Jakub Dawidek 	return ("unknown");
831fee97b0SPawel Jakub Dawidek }
841fee97b0SPawel Jakub Dawidek 
851fee97b0SPawel Jakub Dawidek int
checksum_send(const struct hast_resource * res,struct nv * nv,void ** datap,size_t * sizep,bool * freedatap __unused)861fee97b0SPawel Jakub Dawidek checksum_send(const struct hast_resource *res, struct nv *nv, void **datap,
871fee97b0SPawel Jakub Dawidek     size_t *sizep, bool *freedatap __unused)
881fee97b0SPawel Jakub Dawidek {
891fee97b0SPawel Jakub Dawidek 	unsigned char hash[MAX_HASH_SIZE];
901fee97b0SPawel Jakub Dawidek 	size_t hsize;
911fee97b0SPawel Jakub Dawidek 
921fee97b0SPawel Jakub Dawidek 	switch (res->hr_checksum) {
931fee97b0SPawel Jakub Dawidek 	case HAST_CHECKSUM_NONE:
941fee97b0SPawel Jakub Dawidek 		return (0);
951fee97b0SPawel Jakub Dawidek 	case HAST_CHECKSUM_CRC32:
968c63ee4fSPawel Jakub Dawidek 		hast_crc32_checksum(*datap, *sizep, hash, &hsize);
971fee97b0SPawel Jakub Dawidek 		break;
981fee97b0SPawel Jakub Dawidek 	case HAST_CHECKSUM_SHA256:
998c63ee4fSPawel Jakub Dawidek 		hast_sha256_checksum(*datap, *sizep, hash, &hsize);
1001fee97b0SPawel Jakub Dawidek 		break;
1011fee97b0SPawel Jakub Dawidek 	default:
1021fee97b0SPawel Jakub Dawidek 		PJDLOG_ABORT("Invalid checksum: %d.", res->hr_checksum);
1031fee97b0SPawel Jakub Dawidek 	}
1041fee97b0SPawel Jakub Dawidek 	nv_add_string(nv, checksum_name(res->hr_checksum), "checksum");
1051fee97b0SPawel Jakub Dawidek 	nv_add_uint8_array(nv, hash, hsize, "hash");
1061fee97b0SPawel Jakub Dawidek 	if (nv_error(nv) != 0) {
1071fee97b0SPawel Jakub Dawidek 		errno = nv_error(nv);
1081fee97b0SPawel Jakub Dawidek 		return (-1);
1091fee97b0SPawel Jakub Dawidek 	}
1101fee97b0SPawel Jakub Dawidek 	return (0);
1111fee97b0SPawel Jakub Dawidek }
1121fee97b0SPawel Jakub Dawidek 
1131fee97b0SPawel Jakub Dawidek int
checksum_recv(const struct hast_resource * res __unused,struct nv * nv,void ** datap,size_t * sizep,bool * freedatap __unused)1141fee97b0SPawel Jakub Dawidek checksum_recv(const struct hast_resource *res __unused, struct nv *nv,
1151fee97b0SPawel Jakub Dawidek     void **datap, size_t *sizep, bool *freedatap __unused)
1161fee97b0SPawel Jakub Dawidek {
1171fee97b0SPawel Jakub Dawidek 	unsigned char chash[MAX_HASH_SIZE];
1181fee97b0SPawel Jakub Dawidek 	const unsigned char *rhash;
1191fee97b0SPawel Jakub Dawidek 	size_t chsize, rhsize;
1201fee97b0SPawel Jakub Dawidek 	const char *algo;
1211fee97b0SPawel Jakub Dawidek 
1221fee97b0SPawel Jakub Dawidek 	algo = nv_get_string(nv, "checksum");
1231fee97b0SPawel Jakub Dawidek 	if (algo == NULL)
1241fee97b0SPawel Jakub Dawidek 		return (0);	/* No checksum. */
1251fee97b0SPawel Jakub Dawidek 	rhash = nv_get_uint8_array(nv, &rhsize, "hash");
1261fee97b0SPawel Jakub Dawidek 	if (rhash == NULL) {
1271fee97b0SPawel Jakub Dawidek 		pjdlog_error("Hash is missing.");
1281fee97b0SPawel Jakub Dawidek 		return (-1);	/* Hash not found. */
1291fee97b0SPawel Jakub Dawidek 	}
1301fee97b0SPawel Jakub Dawidek 	if (strcmp(algo, "crc32") == 0)
1318c63ee4fSPawel Jakub Dawidek 		hast_crc32_checksum(*datap, *sizep, chash, &chsize);
1321fee97b0SPawel Jakub Dawidek 	else if (strcmp(algo, "sha256") == 0)
1338c63ee4fSPawel Jakub Dawidek 		hast_sha256_checksum(*datap, *sizep, chash, &chsize);
1341fee97b0SPawel Jakub Dawidek 	else {
1351fee97b0SPawel Jakub Dawidek 		pjdlog_error("Unknown checksum algorithm '%s'.", algo);
1361fee97b0SPawel Jakub Dawidek 		return (-1);	/* Unknown checksum algorithm. */
1371fee97b0SPawel Jakub Dawidek 	}
1381fee97b0SPawel Jakub Dawidek 	if (rhsize != chsize) {
1391fee97b0SPawel Jakub Dawidek 		pjdlog_error("Invalid hash size (%zu) for %s, should be %zu.",
1401fee97b0SPawel Jakub Dawidek 		    rhsize, algo, chsize);
1411fee97b0SPawel Jakub Dawidek 		return (-1);	/* Different hash size. */
1421fee97b0SPawel Jakub Dawidek 	}
1431fee97b0SPawel Jakub Dawidek 	if (bcmp(rhash, chash, chsize) != 0) {
1441fee97b0SPawel Jakub Dawidek 		pjdlog_error("Hash mismatch.");
1451fee97b0SPawel Jakub Dawidek 		return (-1);	/* Hash mismatch. */
1461fee97b0SPawel Jakub Dawidek 	}
1471fee97b0SPawel Jakub Dawidek 
1481fee97b0SPawel Jakub Dawidek 	return (0);
1491fee97b0SPawel Jakub Dawidek }
150