xref: /freebsd/sys/contrib/openzfs/module/icp/io/sha2_mod.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1*61145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy  * CDDL HEADER START
4eda14cbcSMatt Macy  *
5eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
6eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
7eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
8eda14cbcSMatt Macy  *
9eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
11eda14cbcSMatt Macy  * See the License for the specific language governing permissions
12eda14cbcSMatt Macy  * and limitations under the License.
13eda14cbcSMatt Macy  *
14eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
15eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
17eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
18eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
19eda14cbcSMatt Macy  *
20eda14cbcSMatt Macy  * CDDL HEADER END
21eda14cbcSMatt Macy  */
22eda14cbcSMatt Macy 
23eda14cbcSMatt Macy /*
24eda14cbcSMatt Macy  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
25eda14cbcSMatt Macy  * Use is subject to license terms.
26eda14cbcSMatt Macy  */
27eda14cbcSMatt Macy 
28eda14cbcSMatt Macy #include <sys/zfs_context.h>
29eda14cbcSMatt Macy #include <sys/crypto/common.h>
30eda14cbcSMatt Macy #include <sys/crypto/spi.h>
31eda14cbcSMatt Macy #include <sys/crypto/icp.h>
32eda14cbcSMatt Macy #include <sys/sha2.h>
33eda14cbcSMatt Macy #include <sha2/sha2_impl.h>
34eda14cbcSMatt Macy 
35eda14cbcSMatt Macy /*
36eda14cbcSMatt Macy  * Macros to access the SHA2 or SHA2-HMAC contexts from a context passed
37eda14cbcSMatt Macy  * by KCF to one of the entry points.
38eda14cbcSMatt Macy  */
39eda14cbcSMatt Macy 
40eda14cbcSMatt Macy #define	PROV_SHA2_CTX(ctx)	((sha2_ctx_t *)(ctx)->cc_provider_private)
41eda14cbcSMatt Macy #define	PROV_SHA2_HMAC_CTX(ctx)	((sha2_hmac_ctx_t *)(ctx)->cc_provider_private)
42eda14cbcSMatt Macy 
43eda14cbcSMatt Macy /* to extract the digest length passed as mechanism parameter */
44eda14cbcSMatt Macy #define	PROV_SHA2_GET_DIGEST_LEN(m, len) {				\
45eda14cbcSMatt Macy 	if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t)))		\
46eda14cbcSMatt Macy 		(len) = (uint32_t)*((ulong_t *)(m)->cm_param);	\
47eda14cbcSMatt Macy 	else {								\
48eda14cbcSMatt Macy 		ulong_t tmp_ulong;					\
49da5137abSMartin Matuska 		memcpy(&tmp_ulong, (m)->cm_param, sizeof (ulong_t));	\
50eda14cbcSMatt Macy 		(len) = (uint32_t)tmp_ulong;				\
51eda14cbcSMatt Macy 	}								\
52eda14cbcSMatt Macy }
53eda14cbcSMatt Macy 
54eda14cbcSMatt Macy #define	PROV_SHA2_DIGEST_KEY(mech, ctx, key, len, digest) {	\
55eda14cbcSMatt Macy 	SHA2Init(mech, ctx);				\
56eda14cbcSMatt Macy 	SHA2Update(ctx, key, len);			\
57eda14cbcSMatt Macy 	SHA2Final(digest, ctx);				\
58eda14cbcSMatt Macy }
59eda14cbcSMatt Macy 
60eda14cbcSMatt Macy /*
61eda14cbcSMatt Macy  * Mechanism info structure passed to KCF during registration.
62eda14cbcSMatt Macy  */
63e92ffd9bSMartin Matuska static const crypto_mech_info_t sha2_mech_info_tab[] = {
64eda14cbcSMatt Macy 	/* SHA512-HMAC */
65eda14cbcSMatt Macy 	{SUN_CKM_SHA512_HMAC, SHA512_HMAC_MECH_INFO_TYPE,
66c03c5b1cSMartin Matuska 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC},
67eda14cbcSMatt Macy };
68eda14cbcSMatt Macy 
69eda14cbcSMatt Macy static int sha2_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
70c03c5b1cSMartin Matuska     crypto_spi_ctx_template_t);
71c03c5b1cSMartin Matuska static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *);
72c03c5b1cSMartin Matuska static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *);
73c03c5b1cSMartin Matuska static int sha2_mac_atomic(crypto_mechanism_t *, crypto_key_t *,
74c03c5b1cSMartin Matuska     crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
75c03c5b1cSMartin Matuska static int sha2_mac_verify_atomic(crypto_mechanism_t *, crypto_key_t *,
76c03c5b1cSMartin Matuska     crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t);
77eda14cbcSMatt Macy 
78e92ffd9bSMartin Matuska static const crypto_mac_ops_t sha2_mac_ops = {
79eda14cbcSMatt Macy 	.mac_init = sha2_mac_init,
80eda14cbcSMatt Macy 	.mac = NULL,
81eda14cbcSMatt Macy 	.mac_update = sha2_mac_update,
82eda14cbcSMatt Macy 	.mac_final = sha2_mac_final,
83eda14cbcSMatt Macy 	.mac_atomic = sha2_mac_atomic,
84eda14cbcSMatt Macy 	.mac_verify_atomic = sha2_mac_verify_atomic
85eda14cbcSMatt Macy };
86eda14cbcSMatt Macy 
87c03c5b1cSMartin Matuska static int sha2_create_ctx_template(crypto_mechanism_t *, crypto_key_t *,
88c03c5b1cSMartin Matuska     crypto_spi_ctx_template_t *, size_t *);
89eda14cbcSMatt Macy static int sha2_free_context(crypto_ctx_t *);
90eda14cbcSMatt Macy 
91e92ffd9bSMartin Matuska static const crypto_ctx_ops_t sha2_ctx_ops = {
92eda14cbcSMatt Macy 	.create_ctx_template = sha2_create_ctx_template,
93eda14cbcSMatt Macy 	.free_context = sha2_free_context
94eda14cbcSMatt Macy };
95eda14cbcSMatt Macy 
96c03c5b1cSMartin Matuska static const crypto_ops_t sha2_crypto_ops = {
97eda14cbcSMatt Macy 	NULL,
98eda14cbcSMatt Macy 	&sha2_mac_ops,
99c03c5b1cSMartin Matuska 	&sha2_ctx_ops,
100c03c5b1cSMartin Matuska };
101eda14cbcSMatt Macy 
102c03c5b1cSMartin Matuska static const crypto_provider_info_t sha2_prov_info = {
103eda14cbcSMatt Macy 	"SHA2 Software Provider",
104eda14cbcSMatt Macy 	&sha2_crypto_ops,
105eda14cbcSMatt Macy 	sizeof (sha2_mech_info_tab) / sizeof (crypto_mech_info_t),
106eda14cbcSMatt Macy 	sha2_mech_info_tab
107c03c5b1cSMartin Matuska };
108eda14cbcSMatt Macy 
109eda14cbcSMatt Macy static crypto_kcf_provider_handle_t sha2_prov_handle = 0;
110eda14cbcSMatt Macy 
111eda14cbcSMatt Macy int
sha2_mod_init(void)112eda14cbcSMatt Macy sha2_mod_init(void)
113eda14cbcSMatt Macy {
114eda14cbcSMatt Macy 	int ret;
115eda14cbcSMatt Macy 
116eda14cbcSMatt Macy 	/*
117eda14cbcSMatt Macy 	 * Register with KCF. If the registration fails, log an
118eda14cbcSMatt Macy 	 * error but do not uninstall the module, since the functionality
119eda14cbcSMatt Macy 	 * provided by misc/sha2 should still be available.
120eda14cbcSMatt Macy 	 */
121eda14cbcSMatt Macy 	if ((ret = crypto_register_provider(&sha2_prov_info,
122eda14cbcSMatt Macy 	    &sha2_prov_handle)) != CRYPTO_SUCCESS)
123eda14cbcSMatt Macy 		cmn_err(CE_WARN, "sha2 _init: "
124eda14cbcSMatt Macy 		    "crypto_register_provider() failed (0x%x)", ret);
125eda14cbcSMatt Macy 
126eda14cbcSMatt Macy 	return (0);
127eda14cbcSMatt Macy }
128eda14cbcSMatt Macy 
129eda14cbcSMatt Macy int
sha2_mod_fini(void)130eda14cbcSMatt Macy sha2_mod_fini(void)
131eda14cbcSMatt Macy {
132e92ffd9bSMartin Matuska 	int ret = 0;
133eda14cbcSMatt Macy 
134eda14cbcSMatt Macy 	if (sha2_prov_handle != 0) {
135eda14cbcSMatt Macy 		if ((ret = crypto_unregister_provider(sha2_prov_handle)) !=
136eda14cbcSMatt Macy 		    CRYPTO_SUCCESS) {
137eda14cbcSMatt Macy 			cmn_err(CE_WARN,
138eda14cbcSMatt Macy 			    "sha2 _fini: crypto_unregister_provider() "
139eda14cbcSMatt Macy 			    "failed (0x%x)", ret);
140eda14cbcSMatt Macy 			return (EBUSY);
141eda14cbcSMatt Macy 		}
142eda14cbcSMatt Macy 		sha2_prov_handle = 0;
143eda14cbcSMatt Macy 	}
144eda14cbcSMatt Macy 
145e92ffd9bSMartin Matuska 	return (ret);
146eda14cbcSMatt Macy }
147eda14cbcSMatt Macy 
148eda14cbcSMatt Macy /*
149eda14cbcSMatt Macy  * Helper SHA2 digest update function for uio data.
150eda14cbcSMatt Macy  */
151eda14cbcSMatt Macy static int
sha2_digest_update_uio(SHA2_CTX * sha2_ctx,crypto_data_t * data)152eda14cbcSMatt Macy sha2_digest_update_uio(SHA2_CTX *sha2_ctx, crypto_data_t *data)
153eda14cbcSMatt Macy {
154eda14cbcSMatt Macy 	off_t offset = data->cd_offset;
155eda14cbcSMatt Macy 	size_t length = data->cd_length;
156eda14cbcSMatt Macy 	uint_t vec_idx = 0;
157eda14cbcSMatt Macy 	size_t cur_len;
158eda14cbcSMatt Macy 
159eda14cbcSMatt Macy 	/* we support only kernel buffer */
160184c1b94SMartin Matuska 	if (zfs_uio_segflg(data->cd_uio) != UIO_SYSSPACE)
161eda14cbcSMatt Macy 		return (CRYPTO_ARGUMENTS_BAD);
162eda14cbcSMatt Macy 
163eda14cbcSMatt Macy 	/*
164eda14cbcSMatt Macy 	 * Jump to the first iovec containing data to be
165eda14cbcSMatt Macy 	 * digested.
166eda14cbcSMatt Macy 	 */
167184c1b94SMartin Matuska 	offset = zfs_uio_index_at_offset(data->cd_uio, offset, &vec_idx);
168184c1b94SMartin Matuska 	if (vec_idx == zfs_uio_iovcnt(data->cd_uio)) {
169eda14cbcSMatt Macy 		/*
170eda14cbcSMatt Macy 		 * The caller specified an offset that is larger than the
171eda14cbcSMatt Macy 		 * total size of the buffers it provided.
172eda14cbcSMatt Macy 		 */
173eda14cbcSMatt Macy 		return (CRYPTO_DATA_LEN_RANGE);
174eda14cbcSMatt Macy 	}
175eda14cbcSMatt Macy 
176eda14cbcSMatt Macy 	/*
177eda14cbcSMatt Macy 	 * Now do the digesting on the iovecs.
178eda14cbcSMatt Macy 	 */
179184c1b94SMartin Matuska 	while (vec_idx < zfs_uio_iovcnt(data->cd_uio) && length > 0) {
180184c1b94SMartin Matuska 		cur_len = MIN(zfs_uio_iovlen(data->cd_uio, vec_idx) -
181eda14cbcSMatt Macy 		    offset, length);
182eda14cbcSMatt Macy 
183184c1b94SMartin Matuska 		SHA2Update(sha2_ctx, (uint8_t *)zfs_uio_iovbase(data->cd_uio,
184eda14cbcSMatt Macy 		    vec_idx) + offset, cur_len);
185eda14cbcSMatt Macy 		length -= cur_len;
186eda14cbcSMatt Macy 		vec_idx++;
187eda14cbcSMatt Macy 		offset = 0;
188eda14cbcSMatt Macy 	}
189eda14cbcSMatt Macy 
190184c1b94SMartin Matuska 	if (vec_idx == zfs_uio_iovcnt(data->cd_uio) && length > 0) {
191eda14cbcSMatt Macy 		/*
192eda14cbcSMatt Macy 		 * The end of the specified iovec's was reached but
193eda14cbcSMatt Macy 		 * the length requested could not be processed, i.e.
194eda14cbcSMatt Macy 		 * The caller requested to digest more data than it provided.
195eda14cbcSMatt Macy 		 */
196eda14cbcSMatt Macy 		return (CRYPTO_DATA_LEN_RANGE);
197eda14cbcSMatt Macy 	}
198eda14cbcSMatt Macy 
199eda14cbcSMatt Macy 	return (CRYPTO_SUCCESS);
200eda14cbcSMatt Macy }
201eda14cbcSMatt Macy 
202eda14cbcSMatt Macy /*
203eda14cbcSMatt Macy  * Helper SHA2 digest final function for uio data.
204eda14cbcSMatt Macy  * digest_len is the length of the desired digest. If digest_len
205eda14cbcSMatt Macy  * is smaller than the default SHA2 digest length, the caller
206eda14cbcSMatt Macy  * must pass a scratch buffer, digest_scratch, which must
207eda14cbcSMatt Macy  * be at least the algorithm's digest length bytes.
208eda14cbcSMatt Macy  */
209eda14cbcSMatt Macy static int
sha2_digest_final_uio(SHA2_CTX * sha2_ctx,crypto_data_t * digest,ulong_t digest_len,uchar_t * digest_scratch)210eda14cbcSMatt Macy sha2_digest_final_uio(SHA2_CTX *sha2_ctx, crypto_data_t *digest,
211eda14cbcSMatt Macy     ulong_t digest_len, uchar_t *digest_scratch)
212eda14cbcSMatt Macy {
213eda14cbcSMatt Macy 	off_t offset = digest->cd_offset;
214eda14cbcSMatt Macy 	uint_t vec_idx = 0;
215eda14cbcSMatt Macy 
216eda14cbcSMatt Macy 	/* we support only kernel buffer */
217184c1b94SMartin Matuska 	if (zfs_uio_segflg(digest->cd_uio) != UIO_SYSSPACE)
218eda14cbcSMatt Macy 		return (CRYPTO_ARGUMENTS_BAD);
219eda14cbcSMatt Macy 
220eda14cbcSMatt Macy 	/*
221eda14cbcSMatt Macy 	 * Jump to the first iovec containing ptr to the digest to
222eda14cbcSMatt Macy 	 * be returned.
223eda14cbcSMatt Macy 	 */
224184c1b94SMartin Matuska 	offset = zfs_uio_index_at_offset(digest->cd_uio, offset, &vec_idx);
225184c1b94SMartin Matuska 	if (vec_idx == zfs_uio_iovcnt(digest->cd_uio)) {
226eda14cbcSMatt Macy 		/*
227eda14cbcSMatt Macy 		 * The caller specified an offset that is
228eda14cbcSMatt Macy 		 * larger than the total size of the buffers
229eda14cbcSMatt Macy 		 * it provided.
230eda14cbcSMatt Macy 		 */
231eda14cbcSMatt Macy 		return (CRYPTO_DATA_LEN_RANGE);
232eda14cbcSMatt Macy 	}
233eda14cbcSMatt Macy 
234eda14cbcSMatt Macy 	if (offset + digest_len <=
235184c1b94SMartin Matuska 	    zfs_uio_iovlen(digest->cd_uio, vec_idx)) {
236eda14cbcSMatt Macy 		/*
237eda14cbcSMatt Macy 		 * The computed SHA2 digest will fit in the current
238eda14cbcSMatt Macy 		 * iovec.
239eda14cbcSMatt Macy 		 */
24075e1fea6SMartin Matuska 		ASSERT3U(sha2_ctx->algotype, ==, SHA512_HMAC_MECH_INFO_TYPE);
24175e1fea6SMartin Matuska 		if (digest_len != SHA512_DIGEST_LENGTH) {
242eda14cbcSMatt Macy 			/*
243eda14cbcSMatt Macy 			 * The caller requested a short digest. Digest
244eda14cbcSMatt Macy 			 * into a scratch buffer and return to
245eda14cbcSMatt Macy 			 * the user only what was requested.
246eda14cbcSMatt Macy 			 */
247eda14cbcSMatt Macy 			SHA2Final(digest_scratch, sha2_ctx);
248eda14cbcSMatt Macy 
249da5137abSMartin Matuska 			memcpy((uchar_t *)
250184c1b94SMartin Matuska 			    zfs_uio_iovbase(digest->cd_uio, vec_idx) + offset,
251da5137abSMartin Matuska 			    digest_scratch, digest_len);
252eda14cbcSMatt Macy 		} else {
253184c1b94SMartin Matuska 			SHA2Final((uchar_t *)zfs_uio_iovbase(digest->
254eda14cbcSMatt Macy 			    cd_uio, vec_idx) + offset,
255eda14cbcSMatt Macy 			    sha2_ctx);
256eda14cbcSMatt Macy 
257eda14cbcSMatt Macy 		}
258eda14cbcSMatt Macy 	} else {
259eda14cbcSMatt Macy 		/*
260eda14cbcSMatt Macy 		 * The computed digest will be crossing one or more iovec's.
261eda14cbcSMatt Macy 		 * This is bad performance-wise but we need to support it.
262eda14cbcSMatt Macy 		 * Allocate a small scratch buffer on the stack and
263eda14cbcSMatt Macy 		 * copy it piece meal to the specified digest iovec's.
264eda14cbcSMatt Macy 		 */
265eda14cbcSMatt Macy 		uchar_t digest_tmp[SHA512_DIGEST_LENGTH];
266eda14cbcSMatt Macy 		off_t scratch_offset = 0;
267eda14cbcSMatt Macy 		size_t length = digest_len;
268eda14cbcSMatt Macy 		size_t cur_len;
269eda14cbcSMatt Macy 
270eda14cbcSMatt Macy 		SHA2Final(digest_tmp, sha2_ctx);
271eda14cbcSMatt Macy 
272184c1b94SMartin Matuska 		while (vec_idx < zfs_uio_iovcnt(digest->cd_uio) && length > 0) {
273eda14cbcSMatt Macy 			cur_len =
274184c1b94SMartin Matuska 			    MIN(zfs_uio_iovlen(digest->cd_uio, vec_idx) -
275eda14cbcSMatt Macy 			    offset, length);
276da5137abSMartin Matuska 			memcpy(
277184c1b94SMartin Matuska 			    zfs_uio_iovbase(digest->cd_uio, vec_idx) + offset,
278da5137abSMartin Matuska 			    digest_tmp + scratch_offset,
279eda14cbcSMatt Macy 			    cur_len);
280eda14cbcSMatt Macy 
281eda14cbcSMatt Macy 			length -= cur_len;
282eda14cbcSMatt Macy 			vec_idx++;
283eda14cbcSMatt Macy 			scratch_offset += cur_len;
284eda14cbcSMatt Macy 			offset = 0;
285eda14cbcSMatt Macy 		}
286eda14cbcSMatt Macy 
287184c1b94SMartin Matuska 		if (vec_idx == zfs_uio_iovcnt(digest->cd_uio) && length > 0) {
288eda14cbcSMatt Macy 			/*
289eda14cbcSMatt Macy 			 * The end of the specified iovec's was reached but
290eda14cbcSMatt Macy 			 * the length requested could not be processed, i.e.
291eda14cbcSMatt Macy 			 * The caller requested to digest more data than it
292eda14cbcSMatt Macy 			 * provided.
293eda14cbcSMatt Macy 			 */
294eda14cbcSMatt Macy 			return (CRYPTO_DATA_LEN_RANGE);
295eda14cbcSMatt Macy 		}
296eda14cbcSMatt Macy 	}
297eda14cbcSMatt Macy 
298eda14cbcSMatt Macy 	return (CRYPTO_SUCCESS);
299eda14cbcSMatt Macy }
300eda14cbcSMatt Macy 
301eda14cbcSMatt Macy /*
302eda14cbcSMatt Macy  * KCF software provider mac entry points.
303eda14cbcSMatt Macy  *
304eda14cbcSMatt Macy  * SHA2 HMAC is: SHA2(key XOR opad, SHA2(key XOR ipad, text))
305eda14cbcSMatt Macy  *
306eda14cbcSMatt Macy  * Init:
307eda14cbcSMatt Macy  * The initialization routine initializes what we denote
308eda14cbcSMatt Macy  * as the inner and outer contexts by doing
309eda14cbcSMatt Macy  * - for inner context: SHA2(key XOR ipad)
310eda14cbcSMatt Macy  * - for outer context: SHA2(key XOR opad)
311eda14cbcSMatt Macy  *
312eda14cbcSMatt Macy  * Update:
313eda14cbcSMatt Macy  * Each subsequent SHA2 HMAC update will result in an
314eda14cbcSMatt Macy  * update of the inner context with the specified data.
315eda14cbcSMatt Macy  *
316eda14cbcSMatt Macy  * Final:
317eda14cbcSMatt Macy  * The SHA2 HMAC final will do a SHA2 final operation on the
318eda14cbcSMatt Macy  * inner context, and the resulting digest will be used
319eda14cbcSMatt Macy  * as the data for an update on the outer context. Last
320eda14cbcSMatt Macy  * but not least, a SHA2 final on the outer context will
321eda14cbcSMatt Macy  * be performed to obtain the SHA2 HMAC digest to return
322eda14cbcSMatt Macy  * to the user.
323eda14cbcSMatt Macy  */
324eda14cbcSMatt Macy 
325eda14cbcSMatt Macy /*
326eda14cbcSMatt Macy  * Initialize a SHA2-HMAC context.
327eda14cbcSMatt Macy  */
328eda14cbcSMatt Macy static void
sha2_mac_init_ctx(sha2_hmac_ctx_t * ctx,void * keyval,uint_t length_in_bytes)329eda14cbcSMatt Macy sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
330eda14cbcSMatt Macy {
331da5137abSMartin Matuska 	uint64_t ipad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)] = {0};
332da5137abSMartin Matuska 	uint64_t opad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)] = {0};
333eda14cbcSMatt Macy 	int i, block_size, blocks_per_int64;
334eda14cbcSMatt Macy 
335eda14cbcSMatt Macy 	/* Determine the block size */
33675e1fea6SMartin Matuska 	ASSERT3U(ctx->hc_mech_type, ==, SHA512_HMAC_MECH_INFO_TYPE);
337eda14cbcSMatt Macy 	block_size = SHA512_HMAC_BLOCK_SIZE;
338eda14cbcSMatt Macy 	blocks_per_int64 = SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t);
339eda14cbcSMatt Macy 
340da5137abSMartin Matuska 	(void) memset(ipad, 0, block_size);
341da5137abSMartin Matuska 	(void) memset(opad, 0, block_size);
342c03c5b1cSMartin Matuska 
343c03c5b1cSMartin Matuska 	if (keyval != NULL) {
344da5137abSMartin Matuska 		(void) memcpy(ipad, keyval, length_in_bytes);
345da5137abSMartin Matuska 		(void) memcpy(opad, keyval, length_in_bytes);
346c03c5b1cSMartin Matuska 	} else {
347c03c5b1cSMartin Matuska 		ASSERT0(length_in_bytes);
348c03c5b1cSMartin Matuska 	}
349eda14cbcSMatt Macy 
350eda14cbcSMatt Macy 	/* XOR key with ipad (0x36) and opad (0x5c) */
351eda14cbcSMatt Macy 	for (i = 0; i < blocks_per_int64; i ++) {
352eda14cbcSMatt Macy 		ipad[i] ^= 0x3636363636363636;
353eda14cbcSMatt Macy 		opad[i] ^= 0x5c5c5c5c5c5c5c5c;
354eda14cbcSMatt Macy 	}
355eda14cbcSMatt Macy 
356eda14cbcSMatt Macy 	/* perform SHA2 on ipad */
357eda14cbcSMatt Macy 	SHA2Init(ctx->hc_mech_type, &ctx->hc_icontext);
358eda14cbcSMatt Macy 	SHA2Update(&ctx->hc_icontext, (uint8_t *)ipad, block_size);
359eda14cbcSMatt Macy 
360eda14cbcSMatt Macy 	/* perform SHA2 on opad */
361eda14cbcSMatt Macy 	SHA2Init(ctx->hc_mech_type, &ctx->hc_ocontext);
362eda14cbcSMatt Macy 	SHA2Update(&ctx->hc_ocontext, (uint8_t *)opad, block_size);
363eda14cbcSMatt Macy }
364eda14cbcSMatt Macy 
365eda14cbcSMatt Macy /*
366eda14cbcSMatt Macy  */
367eda14cbcSMatt Macy static int
sha2_mac_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template)368eda14cbcSMatt Macy sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
369c03c5b1cSMartin Matuska     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template)
370eda14cbcSMatt Macy {
371eda14cbcSMatt Macy 	int ret = CRYPTO_SUCCESS;
372eda14cbcSMatt Macy 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
373eda14cbcSMatt Macy 	uint_t sha_digest_len, sha_hmac_block_size;
374eda14cbcSMatt Macy 
375eda14cbcSMatt Macy 	/*
376eda14cbcSMatt Macy 	 * Set the digest length and block size to values appropriate to the
377eda14cbcSMatt Macy 	 * mechanism
378eda14cbcSMatt Macy 	 */
379eda14cbcSMatt Macy 	switch (mechanism->cm_type) {
380eda14cbcSMatt Macy 	case SHA512_HMAC_MECH_INFO_TYPE:
381eda14cbcSMatt Macy 		sha_digest_len = SHA512_DIGEST_LENGTH;
382eda14cbcSMatt Macy 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
383eda14cbcSMatt Macy 		break;
384eda14cbcSMatt Macy 	default:
385eda14cbcSMatt Macy 		return (CRYPTO_MECHANISM_INVALID);
386eda14cbcSMatt Macy 	}
387eda14cbcSMatt Macy 
388c03c5b1cSMartin Matuska 	ctx->cc_provider_private =
389c03c5b1cSMartin Matuska 	    kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP);
390eda14cbcSMatt Macy 	if (ctx->cc_provider_private == NULL)
391eda14cbcSMatt Macy 		return (CRYPTO_HOST_MEMORY);
392eda14cbcSMatt Macy 
393eda14cbcSMatt Macy 	PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
394eda14cbcSMatt Macy 	if (ctx_template != NULL) {
395eda14cbcSMatt Macy 		/* reuse context template */
396da5137abSMartin Matuska 		memcpy(PROV_SHA2_HMAC_CTX(ctx), ctx_template,
397eda14cbcSMatt Macy 		    sizeof (sha2_hmac_ctx_t));
398eda14cbcSMatt Macy 	} else {
399eda14cbcSMatt Macy 		/* no context template, compute context */
400eda14cbcSMatt Macy 		if (keylen_in_bytes > sha_hmac_block_size) {
401eda14cbcSMatt Macy 			uchar_t digested_key[SHA512_DIGEST_LENGTH];
402eda14cbcSMatt Macy 			sha2_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
403eda14cbcSMatt Macy 
404eda14cbcSMatt Macy 			/*
405eda14cbcSMatt Macy 			 * Hash the passed-in key to get a smaller key.
406eda14cbcSMatt Macy 			 * The inner context is used since it hasn't been
407eda14cbcSMatt Macy 			 * initialized yet.
408eda14cbcSMatt Macy 			 */
409eda14cbcSMatt Macy 			PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
410eda14cbcSMatt Macy 			    &hmac_ctx->hc_icontext,
411eda14cbcSMatt Macy 			    key->ck_data, keylen_in_bytes, digested_key);
412eda14cbcSMatt Macy 			sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),
413eda14cbcSMatt Macy 			    digested_key, sha_digest_len);
414eda14cbcSMatt Macy 		} else {
415eda14cbcSMatt Macy 			sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),
416eda14cbcSMatt Macy 			    key->ck_data, keylen_in_bytes);
417eda14cbcSMatt Macy 		}
418eda14cbcSMatt Macy 	}
419eda14cbcSMatt Macy 
420eda14cbcSMatt Macy 	if (ret != CRYPTO_SUCCESS) {
421da5137abSMartin Matuska 		memset(ctx->cc_provider_private, 0, sizeof (sha2_hmac_ctx_t));
422eda14cbcSMatt Macy 		kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
423eda14cbcSMatt Macy 		ctx->cc_provider_private = NULL;
424eda14cbcSMatt Macy 	}
425eda14cbcSMatt Macy 
426eda14cbcSMatt Macy 	return (ret);
427eda14cbcSMatt Macy }
428eda14cbcSMatt Macy 
429eda14cbcSMatt Macy static int
sha2_mac_update(crypto_ctx_t * ctx,crypto_data_t * data)430c03c5b1cSMartin Matuska sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data)
431eda14cbcSMatt Macy {
432eda14cbcSMatt Macy 	int ret = CRYPTO_SUCCESS;
433eda14cbcSMatt Macy 
434eda14cbcSMatt Macy 	ASSERT(ctx->cc_provider_private != NULL);
435eda14cbcSMatt Macy 
436eda14cbcSMatt Macy 	/*
437eda14cbcSMatt Macy 	 * Do a SHA2 update of the inner context using the specified
438eda14cbcSMatt Macy 	 * data.
439eda14cbcSMatt Macy 	 */
440eda14cbcSMatt Macy 	switch (data->cd_format) {
441eda14cbcSMatt Macy 	case CRYPTO_DATA_RAW:
442eda14cbcSMatt Macy 		SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_icontext,
443eda14cbcSMatt Macy 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
444eda14cbcSMatt Macy 		    data->cd_length);
445eda14cbcSMatt Macy 		break;
446eda14cbcSMatt Macy 	case CRYPTO_DATA_UIO:
447eda14cbcSMatt Macy 		ret = sha2_digest_update_uio(
448eda14cbcSMatt Macy 		    &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data);
449eda14cbcSMatt Macy 		break;
450eda14cbcSMatt Macy 	default:
451eda14cbcSMatt Macy 		ret = CRYPTO_ARGUMENTS_BAD;
452eda14cbcSMatt Macy 	}
453eda14cbcSMatt Macy 
454eda14cbcSMatt Macy 	return (ret);
455eda14cbcSMatt Macy }
456eda14cbcSMatt Macy 
457eda14cbcSMatt Macy static int
sha2_mac_final(crypto_ctx_t * ctx,crypto_data_t * mac)458c03c5b1cSMartin Matuska sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac)
459eda14cbcSMatt Macy {
460eda14cbcSMatt Macy 	int ret = CRYPTO_SUCCESS;
461eda14cbcSMatt Macy 	uchar_t digest[SHA512_DIGEST_LENGTH];
462eda14cbcSMatt Macy 	uint32_t digest_len, sha_digest_len;
463eda14cbcSMatt Macy 
464eda14cbcSMatt Macy 	ASSERT(ctx->cc_provider_private != NULL);
465eda14cbcSMatt Macy 
466eda14cbcSMatt Macy 	/* Set the digest lengths to values appropriate to the mechanism */
467eda14cbcSMatt Macy 	switch (PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type) {
468eda14cbcSMatt Macy 	case SHA512_HMAC_MECH_INFO_TYPE:
469eda14cbcSMatt Macy 		sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
470eda14cbcSMatt Macy 		break;
471eda14cbcSMatt Macy 	default:
472eda14cbcSMatt Macy 		return (CRYPTO_ARGUMENTS_BAD);
473eda14cbcSMatt Macy 	}
474eda14cbcSMatt Macy 
475eda14cbcSMatt Macy 	/*
476eda14cbcSMatt Macy 	 * We need to just return the length needed to store the output.
477eda14cbcSMatt Macy 	 * We should not destroy the context for the following cases.
478eda14cbcSMatt Macy 	 */
479eda14cbcSMatt Macy 	if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
480eda14cbcSMatt Macy 		mac->cd_length = digest_len;
481eda14cbcSMatt Macy 		return (CRYPTO_BUFFER_TOO_SMALL);
482eda14cbcSMatt Macy 	}
483eda14cbcSMatt Macy 
484eda14cbcSMatt Macy 	/*
485eda14cbcSMatt Macy 	 * Do a SHA2 final on the inner context.
486eda14cbcSMatt Macy 	 */
487eda14cbcSMatt Macy 	SHA2Final(digest, &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext);
488eda14cbcSMatt Macy 
489eda14cbcSMatt Macy 	/*
490eda14cbcSMatt Macy 	 * Do a SHA2 update on the outer context, feeding the inner
491eda14cbcSMatt Macy 	 * digest as data.
492eda14cbcSMatt Macy 	 */
493eda14cbcSMatt Macy 	SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, digest,
494eda14cbcSMatt Macy 	    sha_digest_len);
495eda14cbcSMatt Macy 
496eda14cbcSMatt Macy 	/*
497eda14cbcSMatt Macy 	 * Do a SHA2 final on the outer context, storing the computing
498eda14cbcSMatt Macy 	 * digest in the users buffer.
499eda14cbcSMatt Macy 	 */
500eda14cbcSMatt Macy 	switch (mac->cd_format) {
501eda14cbcSMatt Macy 	case CRYPTO_DATA_RAW:
502eda14cbcSMatt Macy 		if (digest_len != sha_digest_len) {
503eda14cbcSMatt Macy 			/*
504eda14cbcSMatt Macy 			 * The caller requested a short digest. Digest
505eda14cbcSMatt Macy 			 * into a scratch buffer and return to
506eda14cbcSMatt Macy 			 * the user only what was requested.
507eda14cbcSMatt Macy 			 */
508eda14cbcSMatt Macy 			SHA2Final(digest,
509eda14cbcSMatt Macy 			    &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);
510da5137abSMartin Matuska 			memcpy((unsigned char *)mac->cd_raw.iov_base +
511da5137abSMartin Matuska 			    mac->cd_offset, digest, digest_len);
512eda14cbcSMatt Macy 		} else {
513eda14cbcSMatt Macy 			SHA2Final((unsigned char *)mac->cd_raw.iov_base +
514eda14cbcSMatt Macy 			    mac->cd_offset,
515eda14cbcSMatt Macy 			    &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);
516eda14cbcSMatt Macy 		}
517eda14cbcSMatt Macy 		break;
518eda14cbcSMatt Macy 	case CRYPTO_DATA_UIO:
519eda14cbcSMatt Macy 		ret = sha2_digest_final_uio(
520eda14cbcSMatt Macy 		    &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac,
521eda14cbcSMatt Macy 		    digest_len, digest);
522eda14cbcSMatt Macy 		break;
523eda14cbcSMatt Macy 	default:
524eda14cbcSMatt Macy 		ret = CRYPTO_ARGUMENTS_BAD;
525eda14cbcSMatt Macy 	}
526eda14cbcSMatt Macy 
527eda14cbcSMatt Macy 	if (ret == CRYPTO_SUCCESS)
528eda14cbcSMatt Macy 		mac->cd_length = digest_len;
529eda14cbcSMatt Macy 	else
530eda14cbcSMatt Macy 		mac->cd_length = 0;
531eda14cbcSMatt Macy 
532da5137abSMartin Matuska 	memset(ctx->cc_provider_private, 0, sizeof (sha2_hmac_ctx_t));
533eda14cbcSMatt Macy 	kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
534eda14cbcSMatt Macy 	ctx->cc_provider_private = NULL;
535eda14cbcSMatt Macy 
536eda14cbcSMatt Macy 	return (ret);
537eda14cbcSMatt Macy }
538eda14cbcSMatt Macy 
539eda14cbcSMatt Macy #define	SHA2_MAC_UPDATE(data, ctx, ret) {				\
540eda14cbcSMatt Macy 	switch (data->cd_format) {					\
541eda14cbcSMatt Macy 	case CRYPTO_DATA_RAW:						\
542eda14cbcSMatt Macy 		SHA2Update(&(ctx).hc_icontext,				\
543eda14cbcSMatt Macy 		    (uint8_t *)data->cd_raw.iov_base +			\
544eda14cbcSMatt Macy 		    data->cd_offset, data->cd_length);			\
545eda14cbcSMatt Macy 		break;							\
546eda14cbcSMatt Macy 	case CRYPTO_DATA_UIO:						\
547eda14cbcSMatt Macy 		ret = sha2_digest_update_uio(&(ctx).hc_icontext, data);	\
548eda14cbcSMatt Macy 		break;							\
549eda14cbcSMatt Macy 	default:							\
550eda14cbcSMatt Macy 		ret = CRYPTO_ARGUMENTS_BAD;				\
551eda14cbcSMatt Macy 	}								\
552eda14cbcSMatt Macy }
553eda14cbcSMatt Macy 
554eda14cbcSMatt Macy static int
sha2_mac_atomic(crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * mac,crypto_spi_ctx_template_t ctx_template)555c03c5b1cSMartin Matuska sha2_mac_atomic(crypto_mechanism_t *mechanism,
556eda14cbcSMatt Macy     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
557c03c5b1cSMartin Matuska     crypto_spi_ctx_template_t ctx_template)
558eda14cbcSMatt Macy {
559eda14cbcSMatt Macy 	int ret = CRYPTO_SUCCESS;
560eda14cbcSMatt Macy 	uchar_t digest[SHA512_DIGEST_LENGTH];
561eda14cbcSMatt Macy 	sha2_hmac_ctx_t sha2_hmac_ctx;
562eda14cbcSMatt Macy 	uint32_t sha_digest_len, digest_len, sha_hmac_block_size;
563eda14cbcSMatt Macy 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
564eda14cbcSMatt Macy 
565eda14cbcSMatt Macy 	/*
566eda14cbcSMatt Macy 	 * Set the digest length and block size to values appropriate to the
567eda14cbcSMatt Macy 	 * mechanism
568eda14cbcSMatt Macy 	 */
569eda14cbcSMatt Macy 	switch (mechanism->cm_type) {
570eda14cbcSMatt Macy 	case SHA512_HMAC_MECH_INFO_TYPE:
571eda14cbcSMatt Macy 		sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
572eda14cbcSMatt Macy 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
573eda14cbcSMatt Macy 		break;
574eda14cbcSMatt Macy 	default:
575eda14cbcSMatt Macy 		return (CRYPTO_MECHANISM_INVALID);
576eda14cbcSMatt Macy 	}
577eda14cbcSMatt Macy 
578eda14cbcSMatt Macy 	if (ctx_template != NULL) {
579eda14cbcSMatt Macy 		/* reuse context template */
580da5137abSMartin Matuska 		memcpy(&sha2_hmac_ctx, ctx_template, sizeof (sha2_hmac_ctx_t));
581eda14cbcSMatt Macy 	} else {
582eda14cbcSMatt Macy 		sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;
583eda14cbcSMatt Macy 		/* no context template, initialize context */
584eda14cbcSMatt Macy 		if (keylen_in_bytes > sha_hmac_block_size) {
585eda14cbcSMatt Macy 			/*
586eda14cbcSMatt Macy 			 * Hash the passed-in key to get a smaller key.
587eda14cbcSMatt Macy 			 * The inner context is used since it hasn't been
588eda14cbcSMatt Macy 			 * initialized yet.
589eda14cbcSMatt Macy 			 */
590eda14cbcSMatt Macy 			PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
591eda14cbcSMatt Macy 			    &sha2_hmac_ctx.hc_icontext,
592eda14cbcSMatt Macy 			    key->ck_data, keylen_in_bytes, digest);
593eda14cbcSMatt Macy 			sha2_mac_init_ctx(&sha2_hmac_ctx, digest,
594eda14cbcSMatt Macy 			    sha_digest_len);
595eda14cbcSMatt Macy 		} else {
596eda14cbcSMatt Macy 			sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,
597eda14cbcSMatt Macy 			    keylen_in_bytes);
598eda14cbcSMatt Macy 		}
599eda14cbcSMatt Macy 	}
600eda14cbcSMatt Macy 
601eda14cbcSMatt Macy 	/* do a SHA2 update of the inner context using the specified data */
602eda14cbcSMatt Macy 	SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);
603eda14cbcSMatt Macy 	if (ret != CRYPTO_SUCCESS)
604eda14cbcSMatt Macy 		/* the update failed, free context and bail */
605eda14cbcSMatt Macy 		goto bail;
606eda14cbcSMatt Macy 
607eda14cbcSMatt Macy 	/*
608eda14cbcSMatt Macy 	 * Do a SHA2 final on the inner context.
609eda14cbcSMatt Macy 	 */
610eda14cbcSMatt Macy 	SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);
611eda14cbcSMatt Macy 
612eda14cbcSMatt Macy 	/*
613eda14cbcSMatt Macy 	 * Do an SHA2 update on the outer context, feeding the inner
614eda14cbcSMatt Macy 	 * digest as data.
615eda14cbcSMatt Macy 	 */
61675e1fea6SMartin Matuska 	ASSERT3U(mechanism->cm_type, ==, SHA512_HMAC_MECH_INFO_TYPE);
617eda14cbcSMatt Macy 	SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);
618eda14cbcSMatt Macy 
619eda14cbcSMatt Macy 	/*
620eda14cbcSMatt Macy 	 * Do a SHA2 final on the outer context, storing the computed
621eda14cbcSMatt Macy 	 * digest in the users buffer.
622eda14cbcSMatt Macy 	 */
623eda14cbcSMatt Macy 	switch (mac->cd_format) {
624eda14cbcSMatt Macy 	case CRYPTO_DATA_RAW:
625eda14cbcSMatt Macy 		if (digest_len != sha_digest_len) {
626eda14cbcSMatt Macy 			/*
627eda14cbcSMatt Macy 			 * The caller requested a short digest. Digest
628eda14cbcSMatt Macy 			 * into a scratch buffer and return to
629eda14cbcSMatt Macy 			 * the user only what was requested.
630eda14cbcSMatt Macy 			 */
631eda14cbcSMatt Macy 			SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);
632da5137abSMartin Matuska 			memcpy((unsigned char *)mac->cd_raw.iov_base +
633da5137abSMartin Matuska 			    mac->cd_offset, digest, digest_len);
634eda14cbcSMatt Macy 		} else {
635eda14cbcSMatt Macy 			SHA2Final((unsigned char *)mac->cd_raw.iov_base +
636eda14cbcSMatt Macy 			    mac->cd_offset, &sha2_hmac_ctx.hc_ocontext);
637eda14cbcSMatt Macy 		}
638eda14cbcSMatt Macy 		break;
639eda14cbcSMatt Macy 	case CRYPTO_DATA_UIO:
640eda14cbcSMatt Macy 		ret = sha2_digest_final_uio(&sha2_hmac_ctx.hc_ocontext, mac,
641eda14cbcSMatt Macy 		    digest_len, digest);
642eda14cbcSMatt Macy 		break;
643eda14cbcSMatt Macy 	default:
644eda14cbcSMatt Macy 		ret = CRYPTO_ARGUMENTS_BAD;
645eda14cbcSMatt Macy 	}
646eda14cbcSMatt Macy 
647eda14cbcSMatt Macy 	if (ret == CRYPTO_SUCCESS) {
648eda14cbcSMatt Macy 		mac->cd_length = digest_len;
649eda14cbcSMatt Macy 		return (CRYPTO_SUCCESS);
650eda14cbcSMatt Macy 	}
651eda14cbcSMatt Macy bail:
652da5137abSMartin Matuska 	memset(&sha2_hmac_ctx, 0, sizeof (sha2_hmac_ctx_t));
653eda14cbcSMatt Macy 	mac->cd_length = 0;
654eda14cbcSMatt Macy 	return (ret);
655eda14cbcSMatt Macy }
656eda14cbcSMatt Macy 
657eda14cbcSMatt Macy static int
sha2_mac_verify_atomic(crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * mac,crypto_spi_ctx_template_t ctx_template)658c03c5b1cSMartin Matuska sha2_mac_verify_atomic(crypto_mechanism_t *mechanism,
659eda14cbcSMatt Macy     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
660c03c5b1cSMartin Matuska     crypto_spi_ctx_template_t ctx_template)
661eda14cbcSMatt Macy {
662eda14cbcSMatt Macy 	int ret = CRYPTO_SUCCESS;
663eda14cbcSMatt Macy 	uchar_t digest[SHA512_DIGEST_LENGTH];
664eda14cbcSMatt Macy 	sha2_hmac_ctx_t sha2_hmac_ctx;
665eda14cbcSMatt Macy 	uint32_t sha_digest_len, digest_len, sha_hmac_block_size;
666eda14cbcSMatt Macy 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
667eda14cbcSMatt Macy 
668eda14cbcSMatt Macy 	/*
669eda14cbcSMatt Macy 	 * Set the digest length and block size to values appropriate to the
670eda14cbcSMatt Macy 	 * mechanism
671eda14cbcSMatt Macy 	 */
672eda14cbcSMatt Macy 	switch (mechanism->cm_type) {
673eda14cbcSMatt Macy 	case SHA512_HMAC_MECH_INFO_TYPE:
674eda14cbcSMatt Macy 		sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
675eda14cbcSMatt Macy 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
676eda14cbcSMatt Macy 		break;
677eda14cbcSMatt Macy 	default:
678eda14cbcSMatt Macy 		return (CRYPTO_MECHANISM_INVALID);
679eda14cbcSMatt Macy 	}
680eda14cbcSMatt Macy 
681eda14cbcSMatt Macy 	if (ctx_template != NULL) {
682eda14cbcSMatt Macy 		/* reuse context template */
683da5137abSMartin Matuska 		memcpy(&sha2_hmac_ctx, ctx_template, sizeof (sha2_hmac_ctx_t));
684eda14cbcSMatt Macy 	} else {
685eda14cbcSMatt Macy 		sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;
686eda14cbcSMatt Macy 		/* no context template, initialize context */
687eda14cbcSMatt Macy 		if (keylen_in_bytes > sha_hmac_block_size) {
688eda14cbcSMatt Macy 			/*
689eda14cbcSMatt Macy 			 * Hash the passed-in key to get a smaller key.
690eda14cbcSMatt Macy 			 * The inner context is used since it hasn't been
691eda14cbcSMatt Macy 			 * initialized yet.
692eda14cbcSMatt Macy 			 */
693eda14cbcSMatt Macy 			PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
694eda14cbcSMatt Macy 			    &sha2_hmac_ctx.hc_icontext,
695eda14cbcSMatt Macy 			    key->ck_data, keylen_in_bytes, digest);
696eda14cbcSMatt Macy 			sha2_mac_init_ctx(&sha2_hmac_ctx, digest,
697eda14cbcSMatt Macy 			    sha_digest_len);
698eda14cbcSMatt Macy 		} else {
699eda14cbcSMatt Macy 			sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,
700eda14cbcSMatt Macy 			    keylen_in_bytes);
701eda14cbcSMatt Macy 		}
702eda14cbcSMatt Macy 	}
703eda14cbcSMatt Macy 
704eda14cbcSMatt Macy 	if (mac->cd_length != digest_len) {
705eda14cbcSMatt Macy 		ret = CRYPTO_INVALID_MAC;
706eda14cbcSMatt Macy 		goto bail;
707eda14cbcSMatt Macy 	}
708eda14cbcSMatt Macy 
709eda14cbcSMatt Macy 	/* do a SHA2 update of the inner context using the specified data */
710eda14cbcSMatt Macy 	SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);
711eda14cbcSMatt Macy 	if (ret != CRYPTO_SUCCESS)
712eda14cbcSMatt Macy 		/* the update failed, free context and bail */
713eda14cbcSMatt Macy 		goto bail;
714eda14cbcSMatt Macy 
715eda14cbcSMatt Macy 	/* do a SHA2 final on the inner context */
716eda14cbcSMatt Macy 	SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);
717eda14cbcSMatt Macy 
718eda14cbcSMatt Macy 	/*
719eda14cbcSMatt Macy 	 * Do an SHA2 update on the outer context, feeding the inner
720eda14cbcSMatt Macy 	 * digest as data.
721eda14cbcSMatt Macy 	 */
72275e1fea6SMartin Matuska 	ASSERT3U(mechanism->cm_type, ==, SHA512_HMAC_MECH_INFO_TYPE);
723eda14cbcSMatt Macy 	SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);
724eda14cbcSMatt Macy 
725eda14cbcSMatt Macy 	/*
726eda14cbcSMatt Macy 	 * Do a SHA2 final on the outer context, storing the computed
727eda14cbcSMatt Macy 	 * digest in the users buffer.
728eda14cbcSMatt Macy 	 */
729eda14cbcSMatt Macy 	SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);
730eda14cbcSMatt Macy 
731eda14cbcSMatt Macy 	/*
732eda14cbcSMatt Macy 	 * Compare the computed digest against the expected digest passed
733eda14cbcSMatt Macy 	 * as argument.
734eda14cbcSMatt Macy 	 */
735eda14cbcSMatt Macy 
736eda14cbcSMatt Macy 	switch (mac->cd_format) {
737eda14cbcSMatt Macy 
738eda14cbcSMatt Macy 	case CRYPTO_DATA_RAW:
739da5137abSMartin Matuska 		if (memcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
740eda14cbcSMatt Macy 		    mac->cd_offset, digest_len) != 0)
741eda14cbcSMatt Macy 			ret = CRYPTO_INVALID_MAC;
742eda14cbcSMatt Macy 		break;
743eda14cbcSMatt Macy 
744eda14cbcSMatt Macy 	case CRYPTO_DATA_UIO: {
745eda14cbcSMatt Macy 		off_t offset = mac->cd_offset;
746eda14cbcSMatt Macy 		uint_t vec_idx = 0;
747eda14cbcSMatt Macy 		off_t scratch_offset = 0;
748eda14cbcSMatt Macy 		size_t length = digest_len;
749eda14cbcSMatt Macy 		size_t cur_len;
750eda14cbcSMatt Macy 
751eda14cbcSMatt Macy 		/* we support only kernel buffer */
752184c1b94SMartin Matuska 		if (zfs_uio_segflg(mac->cd_uio) != UIO_SYSSPACE)
753eda14cbcSMatt Macy 			return (CRYPTO_ARGUMENTS_BAD);
754eda14cbcSMatt Macy 
755eda14cbcSMatt Macy 		/* jump to the first iovec containing the expected digest */
756184c1b94SMartin Matuska 		offset = zfs_uio_index_at_offset(mac->cd_uio, offset, &vec_idx);
757184c1b94SMartin Matuska 		if (vec_idx == zfs_uio_iovcnt(mac->cd_uio)) {
758eda14cbcSMatt Macy 			/*
759eda14cbcSMatt Macy 			 * The caller specified an offset that is
760eda14cbcSMatt Macy 			 * larger than the total size of the buffers
761eda14cbcSMatt Macy 			 * it provided.
762eda14cbcSMatt Macy 			 */
763eda14cbcSMatt Macy 			ret = CRYPTO_DATA_LEN_RANGE;
764eda14cbcSMatt Macy 			break;
765eda14cbcSMatt Macy 		}
766eda14cbcSMatt Macy 
767eda14cbcSMatt Macy 		/* do the comparison of computed digest vs specified one */
768184c1b94SMartin Matuska 		while (vec_idx < zfs_uio_iovcnt(mac->cd_uio) && length > 0) {
769184c1b94SMartin Matuska 			cur_len = MIN(zfs_uio_iovlen(mac->cd_uio, vec_idx) -
770eda14cbcSMatt Macy 			    offset, length);
771eda14cbcSMatt Macy 
772da5137abSMartin Matuska 			if (memcmp(digest + scratch_offset,
773184c1b94SMartin Matuska 			    zfs_uio_iovbase(mac->cd_uio, vec_idx) + offset,
774eda14cbcSMatt Macy 			    cur_len) != 0) {
775eda14cbcSMatt Macy 				ret = CRYPTO_INVALID_MAC;
776eda14cbcSMatt Macy 				break;
777eda14cbcSMatt Macy 			}
778eda14cbcSMatt Macy 
779eda14cbcSMatt Macy 			length -= cur_len;
780eda14cbcSMatt Macy 			vec_idx++;
781eda14cbcSMatt Macy 			scratch_offset += cur_len;
782eda14cbcSMatt Macy 			offset = 0;
783eda14cbcSMatt Macy 		}
784eda14cbcSMatt Macy 		break;
785eda14cbcSMatt Macy 	}
786eda14cbcSMatt Macy 
787eda14cbcSMatt Macy 	default:
788eda14cbcSMatt Macy 		ret = CRYPTO_ARGUMENTS_BAD;
789eda14cbcSMatt Macy 	}
790eda14cbcSMatt Macy 
791eda14cbcSMatt Macy 	return (ret);
792eda14cbcSMatt Macy bail:
793da5137abSMartin Matuska 	memset(&sha2_hmac_ctx, 0, sizeof (sha2_hmac_ctx_t));
794eda14cbcSMatt Macy 	mac->cd_length = 0;
795eda14cbcSMatt Macy 	return (ret);
796eda14cbcSMatt Macy }
797eda14cbcSMatt Macy 
798eda14cbcSMatt Macy /*
799eda14cbcSMatt Macy  * KCF software provider context management entry points.
800eda14cbcSMatt Macy  */
801eda14cbcSMatt Macy 
802eda14cbcSMatt Macy static int
sha2_create_ctx_template(crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t * ctx_template,size_t * ctx_template_size)803c03c5b1cSMartin Matuska sha2_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key,
804c03c5b1cSMartin Matuska     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size)
805eda14cbcSMatt Macy {
806eda14cbcSMatt Macy 	sha2_hmac_ctx_t *sha2_hmac_ctx_tmpl;
807eda14cbcSMatt Macy 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
808eda14cbcSMatt Macy 	uint32_t sha_digest_len, sha_hmac_block_size;
809eda14cbcSMatt Macy 
810eda14cbcSMatt Macy 	/*
811eda14cbcSMatt Macy 	 * Set the digest length and block size to values appropriate to the
812eda14cbcSMatt Macy 	 * mechanism
813eda14cbcSMatt Macy 	 */
814eda14cbcSMatt Macy 	switch (mechanism->cm_type) {
815eda14cbcSMatt Macy 	case SHA512_HMAC_MECH_INFO_TYPE:
816eda14cbcSMatt Macy 		sha_digest_len = SHA512_DIGEST_LENGTH;
817eda14cbcSMatt Macy 		sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
818eda14cbcSMatt Macy 		break;
819eda14cbcSMatt Macy 	default:
820eda14cbcSMatt Macy 		return (CRYPTO_MECHANISM_INVALID);
821eda14cbcSMatt Macy 	}
822eda14cbcSMatt Macy 
823eda14cbcSMatt Macy 	/*
824eda14cbcSMatt Macy 	 * Allocate and initialize SHA2 context.
825eda14cbcSMatt Macy 	 */
826c03c5b1cSMartin Matuska 	sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t), KM_SLEEP);
827eda14cbcSMatt Macy 	if (sha2_hmac_ctx_tmpl == NULL)
828eda14cbcSMatt Macy 		return (CRYPTO_HOST_MEMORY);
829eda14cbcSMatt Macy 
830eda14cbcSMatt Macy 	sha2_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
831eda14cbcSMatt Macy 
832eda14cbcSMatt Macy 	if (keylen_in_bytes > sha_hmac_block_size) {
833eda14cbcSMatt Macy 		uchar_t digested_key[SHA512_DIGEST_LENGTH];
834eda14cbcSMatt Macy 
835eda14cbcSMatt Macy 		/*
836eda14cbcSMatt Macy 		 * Hash the passed-in key to get a smaller key.
837eda14cbcSMatt Macy 		 * The inner context is used since it hasn't been
838eda14cbcSMatt Macy 		 * initialized yet.
839eda14cbcSMatt Macy 		 */
840eda14cbcSMatt Macy 		PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
841eda14cbcSMatt Macy 		    &sha2_hmac_ctx_tmpl->hc_icontext,
842eda14cbcSMatt Macy 		    key->ck_data, keylen_in_bytes, digested_key);
843eda14cbcSMatt Macy 		sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, digested_key,
844eda14cbcSMatt Macy 		    sha_digest_len);
845eda14cbcSMatt Macy 	} else {
846eda14cbcSMatt Macy 		sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, key->ck_data,
847eda14cbcSMatt Macy 		    keylen_in_bytes);
848eda14cbcSMatt Macy 	}
849eda14cbcSMatt Macy 
850eda14cbcSMatt Macy 	*ctx_template = (crypto_spi_ctx_template_t)sha2_hmac_ctx_tmpl;
851eda14cbcSMatt Macy 	*ctx_template_size = sizeof (sha2_hmac_ctx_t);
852eda14cbcSMatt Macy 
853eda14cbcSMatt Macy 	return (CRYPTO_SUCCESS);
854eda14cbcSMatt Macy }
855eda14cbcSMatt Macy 
856eda14cbcSMatt Macy static int
sha2_free_context(crypto_ctx_t * ctx)857eda14cbcSMatt Macy sha2_free_context(crypto_ctx_t *ctx)
858eda14cbcSMatt Macy {
859eda14cbcSMatt Macy 	uint_t ctx_len;
860eda14cbcSMatt Macy 
861eda14cbcSMatt Macy 	if (ctx->cc_provider_private == NULL)
862eda14cbcSMatt Macy 		return (CRYPTO_SUCCESS);
863eda14cbcSMatt Macy 
86475e1fea6SMartin Matuska 	ASSERT3U(PROV_SHA2_CTX(ctx)->sc_mech_type, ==,
86575e1fea6SMartin Matuska 	    SHA512_HMAC_MECH_INFO_TYPE);
866eda14cbcSMatt Macy 	ctx_len = sizeof (sha2_hmac_ctx_t);
867eda14cbcSMatt Macy 
868da5137abSMartin Matuska 	memset(ctx->cc_provider_private, 0, ctx_len);
869eda14cbcSMatt Macy 	kmem_free(ctx->cc_provider_private, ctx_len);
870eda14cbcSMatt Macy 	ctx->cc_provider_private = NULL;
871eda14cbcSMatt Macy 
872eda14cbcSMatt Macy 	return (CRYPTO_SUCCESS);
873eda14cbcSMatt Macy }
874