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