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