xref: /onnv-gate/usr/src/uts/common/crypto/io/sha1_mod.c (revision 1694:d5b31941a4a5)
1*1694Sdarrenm /*
2*1694Sdarrenm  * CDDL HEADER START
3*1694Sdarrenm  *
4*1694Sdarrenm  * The contents of this file are subject to the terms of the
5*1694Sdarrenm  * Common Development and Distribution License (the "License").
6*1694Sdarrenm  * You may not use this file except in compliance with the License.
7*1694Sdarrenm  *
8*1694Sdarrenm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1694Sdarrenm  * or http://www.opensolaris.org/os/licensing.
10*1694Sdarrenm  * See the License for the specific language governing permissions
11*1694Sdarrenm  * and limitations under the License.
12*1694Sdarrenm  *
13*1694Sdarrenm  * When distributing Covered Code, include this CDDL HEADER in each
14*1694Sdarrenm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1694Sdarrenm  * If applicable, add the following below this CDDL HEADER, with the
16*1694Sdarrenm  * fields enclosed by brackets "[]" replaced with your own identifying
17*1694Sdarrenm  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1694Sdarrenm  *
19*1694Sdarrenm  * CDDL HEADER END
20*1694Sdarrenm  */
21*1694Sdarrenm 
22*1694Sdarrenm /*
23*1694Sdarrenm  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1694Sdarrenm  * Use is subject to license terms.
25*1694Sdarrenm  */
26*1694Sdarrenm 
27*1694Sdarrenm #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1694Sdarrenm 
29*1694Sdarrenm #include <sys/modctl.h>
30*1694Sdarrenm #include <sys/cmn_err.h>
31*1694Sdarrenm #include <sys/note.h>
32*1694Sdarrenm #include <sys/crypto/common.h>
33*1694Sdarrenm #include <sys/crypto/spi.h>
34*1694Sdarrenm #include <sys/strsun.h>
35*1694Sdarrenm #include <sys/systm.h>
36*1694Sdarrenm #include <sys/sysmacros.h>
37*1694Sdarrenm 
38*1694Sdarrenm #include <sys/sha1.h>
39*1694Sdarrenm 
40*1694Sdarrenm /*
41*1694Sdarrenm  * The sha1 module is created with two modlinkages:
42*1694Sdarrenm  * - a modlmisc that allows consumers to directly call the entry points
43*1694Sdarrenm  *   SHA1Init, SHA1Update, and SHA1Final.
44*1694Sdarrenm  * - a modlcrypto that allows the module to register with the Kernel
45*1694Sdarrenm  *   Cryptographic Framework (KCF) as a software provider for the SHA1
46*1694Sdarrenm  *   mechanisms.
47*1694Sdarrenm  */
48*1694Sdarrenm 
49*1694Sdarrenm static struct modlmisc modlmisc = {
50*1694Sdarrenm 	&mod_miscops,
51*1694Sdarrenm 	"SHA1 Message-Digest Algorithm"
52*1694Sdarrenm };
53*1694Sdarrenm 
54*1694Sdarrenm static struct modlcrypto modlcrypto = {
55*1694Sdarrenm 	&mod_cryptoops,
56*1694Sdarrenm 	"SHA1 Kernel SW Provider 1.1"
57*1694Sdarrenm };
58*1694Sdarrenm 
59*1694Sdarrenm static struct modlinkage modlinkage = {
60*1694Sdarrenm 	MODREV_1, &modlmisc, &modlcrypto, NULL
61*1694Sdarrenm };
62*1694Sdarrenm 
63*1694Sdarrenm /*
64*1694Sdarrenm  * CSPI information (entry points, provider info, etc.)
65*1694Sdarrenm  */
66*1694Sdarrenm 
67*1694Sdarrenm typedef enum sha1_mech_type {
68*1694Sdarrenm 	SHA1_MECH_INFO_TYPE,		/* SUN_CKM_SHA1 */
69*1694Sdarrenm 	SHA1_HMAC_MECH_INFO_TYPE,	/* SUN_CKM_SHA1_HMAC */
70*1694Sdarrenm 	SHA1_HMAC_GEN_MECH_INFO_TYPE	/* SUN_CKM_SHA1_HMAC_GENERAL */
71*1694Sdarrenm } sha1_mech_type_t;
72*1694Sdarrenm 
73*1694Sdarrenm #define	SHA1_DIGEST_LENGTH	20	/* SHA1 digest length in bytes */
74*1694Sdarrenm #define	SHA1_HMAC_BLOCK_SIZE	64	/* SHA1-HMAC block size */
75*1694Sdarrenm #define	SHA1_HMAC_MIN_KEY_LEN	8	/* SHA1-HMAC min key length in bits */
76*1694Sdarrenm #define	SHA1_HMAC_MAX_KEY_LEN	INT_MAX /* SHA1-HMAC max key length in bits */
77*1694Sdarrenm #define	SHA1_HMAC_INTS_PER_BLOCK	(SHA1_HMAC_BLOCK_SIZE/sizeof (uint32_t))
78*1694Sdarrenm 
79*1694Sdarrenm /*
80*1694Sdarrenm  * Context for SHA1 mechanism.
81*1694Sdarrenm  */
82*1694Sdarrenm typedef struct sha1_ctx {
83*1694Sdarrenm 	sha1_mech_type_t	sc_mech_type;	/* type of context */
84*1694Sdarrenm 	SHA1_CTX		sc_sha1_ctx;	/* SHA1 context */
85*1694Sdarrenm } sha1_ctx_t;
86*1694Sdarrenm 
87*1694Sdarrenm /*
88*1694Sdarrenm  * Context for SHA1-HMAC and SHA1-HMAC-GENERAL mechanisms.
89*1694Sdarrenm  */
90*1694Sdarrenm typedef struct sha1_hmac_ctx {
91*1694Sdarrenm 	sha1_mech_type_t	hc_mech_type;	/* type of context */
92*1694Sdarrenm 	uint32_t		hc_digest_len;	/* digest len in bytes */
93*1694Sdarrenm 	SHA1_CTX		hc_icontext;	/* inner SHA1 context */
94*1694Sdarrenm 	SHA1_CTX		hc_ocontext;	/* outer SHA1 context */
95*1694Sdarrenm } sha1_hmac_ctx_t;
96*1694Sdarrenm 
97*1694Sdarrenm /*
98*1694Sdarrenm  * Macros to access the SHA1 or SHA1-HMAC contexts from a context passed
99*1694Sdarrenm  * by KCF to one of the entry points.
100*1694Sdarrenm  */
101*1694Sdarrenm 
102*1694Sdarrenm #define	PROV_SHA1_CTX(ctx)	((sha1_ctx_t *)(ctx)->cc_provider_private)
103*1694Sdarrenm #define	PROV_SHA1_HMAC_CTX(ctx)	((sha1_hmac_ctx_t *)(ctx)->cc_provider_private)
104*1694Sdarrenm 
105*1694Sdarrenm /* to extract the digest length passed as mechanism parameter */
106*1694Sdarrenm #define	PROV_SHA1_GET_DIGEST_LEN(m, len) {				\
107*1694Sdarrenm 	if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t)))		\
108*1694Sdarrenm 		(len) = (uint32_t)*((ulong_t *)mechanism->cm_param);	\
109*1694Sdarrenm 	else {								\
110*1694Sdarrenm 		ulong_t tmp_ulong;					\
111*1694Sdarrenm 		bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t));	\
112*1694Sdarrenm 		(len) = (uint32_t)tmp_ulong;				\
113*1694Sdarrenm 	}								\
114*1694Sdarrenm }
115*1694Sdarrenm 
116*1694Sdarrenm #define	PROV_SHA1_DIGEST_KEY(ctx, key, len, digest) {	\
117*1694Sdarrenm 	SHA1Init(ctx);					\
118*1694Sdarrenm 	SHA1Update(ctx, key, len);			\
119*1694Sdarrenm 	SHA1Final(digest, ctx);				\
120*1694Sdarrenm }
121*1694Sdarrenm 
122*1694Sdarrenm /*
123*1694Sdarrenm  * Mechanism info structure passed to KCF during registration.
124*1694Sdarrenm  */
125*1694Sdarrenm static crypto_mech_info_t sha1_mech_info_tab[] = {
126*1694Sdarrenm 	/* SHA1 */
127*1694Sdarrenm 	{SUN_CKM_SHA1, SHA1_MECH_INFO_TYPE,
128*1694Sdarrenm 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
129*1694Sdarrenm 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
130*1694Sdarrenm 	/* SHA1-HMAC */
131*1694Sdarrenm 	{SUN_CKM_SHA1_HMAC, SHA1_HMAC_MECH_INFO_TYPE,
132*1694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
133*1694Sdarrenm 	    SHA1_HMAC_MIN_KEY_LEN, SHA1_HMAC_MAX_KEY_LEN,
134*1694Sdarrenm 	    CRYPTO_KEYSIZE_UNIT_IN_BITS},
135*1694Sdarrenm 	/* SHA1-HMAC GENERAL */
136*1694Sdarrenm 	{SUN_CKM_SHA1_HMAC_GENERAL, SHA1_HMAC_GEN_MECH_INFO_TYPE,
137*1694Sdarrenm 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
138*1694Sdarrenm 	    SHA1_HMAC_MIN_KEY_LEN, SHA1_HMAC_MAX_KEY_LEN,
139*1694Sdarrenm 	    CRYPTO_KEYSIZE_UNIT_IN_BITS}
140*1694Sdarrenm };
141*1694Sdarrenm 
142*1694Sdarrenm static void sha1_provider_status(crypto_provider_handle_t, uint_t *);
143*1694Sdarrenm 
144*1694Sdarrenm static crypto_control_ops_t sha1_control_ops = {
145*1694Sdarrenm 	sha1_provider_status
146*1694Sdarrenm };
147*1694Sdarrenm 
148*1694Sdarrenm static int sha1_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
149*1694Sdarrenm     crypto_req_handle_t);
150*1694Sdarrenm static int sha1_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
151*1694Sdarrenm     crypto_req_handle_t);
152*1694Sdarrenm static int sha1_digest_update(crypto_ctx_t *, crypto_data_t *,
153*1694Sdarrenm     crypto_req_handle_t);
154*1694Sdarrenm static int sha1_digest_final(crypto_ctx_t *, crypto_data_t *,
155*1694Sdarrenm     crypto_req_handle_t);
156*1694Sdarrenm static int sha1_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
157*1694Sdarrenm     crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
158*1694Sdarrenm     crypto_req_handle_t);
159*1694Sdarrenm 
160*1694Sdarrenm static crypto_digest_ops_t sha1_digest_ops = {
161*1694Sdarrenm 	sha1_digest_init,
162*1694Sdarrenm 	sha1_digest,
163*1694Sdarrenm 	sha1_digest_update,
164*1694Sdarrenm 	NULL,
165*1694Sdarrenm 	sha1_digest_final,
166*1694Sdarrenm 	sha1_digest_atomic
167*1694Sdarrenm };
168*1694Sdarrenm 
169*1694Sdarrenm static int sha1_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
170*1694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
171*1694Sdarrenm static int sha1_mac_update(crypto_ctx_t *, crypto_data_t *,
172*1694Sdarrenm     crypto_req_handle_t);
173*1694Sdarrenm static int sha1_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
174*1694Sdarrenm static int sha1_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
175*1694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
176*1694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
177*1694Sdarrenm static int sha1_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
178*1694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
179*1694Sdarrenm     crypto_spi_ctx_template_t, crypto_req_handle_t);
180*1694Sdarrenm 
181*1694Sdarrenm static crypto_mac_ops_t sha1_mac_ops = {
182*1694Sdarrenm 	sha1_mac_init,
183*1694Sdarrenm 	NULL,
184*1694Sdarrenm 	sha1_mac_update,
185*1694Sdarrenm 	sha1_mac_final,
186*1694Sdarrenm 	sha1_mac_atomic,
187*1694Sdarrenm 	sha1_mac_verify_atomic
188*1694Sdarrenm };
189*1694Sdarrenm 
190*1694Sdarrenm static int sha1_create_ctx_template(crypto_provider_handle_t,
191*1694Sdarrenm     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
192*1694Sdarrenm     size_t *, crypto_req_handle_t);
193*1694Sdarrenm static int sha1_free_context(crypto_ctx_t *);
194*1694Sdarrenm 
195*1694Sdarrenm static crypto_ctx_ops_t sha1_ctx_ops = {
196*1694Sdarrenm 	sha1_create_ctx_template,
197*1694Sdarrenm 	sha1_free_context
198*1694Sdarrenm };
199*1694Sdarrenm 
200*1694Sdarrenm static crypto_ops_t sha1_crypto_ops = {
201*1694Sdarrenm 	&sha1_control_ops,
202*1694Sdarrenm 	&sha1_digest_ops,
203*1694Sdarrenm 	NULL,
204*1694Sdarrenm 	&sha1_mac_ops,
205*1694Sdarrenm 	NULL,
206*1694Sdarrenm 	NULL,
207*1694Sdarrenm 	NULL,
208*1694Sdarrenm 	NULL,
209*1694Sdarrenm 	NULL,
210*1694Sdarrenm 	NULL,
211*1694Sdarrenm 	NULL,
212*1694Sdarrenm 	NULL,
213*1694Sdarrenm 	NULL,
214*1694Sdarrenm 	&sha1_ctx_ops
215*1694Sdarrenm };
216*1694Sdarrenm 
217*1694Sdarrenm static crypto_provider_info_t sha1_prov_info = {
218*1694Sdarrenm 	CRYPTO_SPI_VERSION_1,
219*1694Sdarrenm 	"SHA1 Software Provider",
220*1694Sdarrenm 	CRYPTO_SW_PROVIDER,
221*1694Sdarrenm 	{&modlinkage},
222*1694Sdarrenm 	NULL,
223*1694Sdarrenm 	&sha1_crypto_ops,
224*1694Sdarrenm 	sizeof (sha1_mech_info_tab)/sizeof (crypto_mech_info_t),
225*1694Sdarrenm 	sha1_mech_info_tab
226*1694Sdarrenm };
227*1694Sdarrenm 
228*1694Sdarrenm static crypto_kcf_provider_handle_t sha1_prov_handle = NULL;
229*1694Sdarrenm 
230*1694Sdarrenm int
231*1694Sdarrenm _init()
232*1694Sdarrenm {
233*1694Sdarrenm 	int ret;
234*1694Sdarrenm 
235*1694Sdarrenm 	if ((ret = mod_install(&modlinkage)) != 0)
236*1694Sdarrenm 		return (ret);
237*1694Sdarrenm 
238*1694Sdarrenm 	/*
239*1694Sdarrenm 	 * Register with KCF. If the registration fails, log an
240*1694Sdarrenm 	 * error but do not uninstall the module, since the functionality
241*1694Sdarrenm 	 * provided by misc/sha1 should still be available.
242*1694Sdarrenm 	 */
243*1694Sdarrenm 	if ((ret = crypto_register_provider(&sha1_prov_info,
244*1694Sdarrenm 	    &sha1_prov_handle)) != CRYPTO_SUCCESS)
245*1694Sdarrenm 		cmn_err(CE_WARN, "sha1 _init: "
246*1694Sdarrenm 		    "crypto_register_provider() failed (0x%x)", ret);
247*1694Sdarrenm 
248*1694Sdarrenm 	return (0);
249*1694Sdarrenm }
250*1694Sdarrenm 
251*1694Sdarrenm int
252*1694Sdarrenm _info(struct modinfo *modinfop)
253*1694Sdarrenm {
254*1694Sdarrenm 	return (mod_info(&modlinkage, modinfop));
255*1694Sdarrenm }
256*1694Sdarrenm 
257*1694Sdarrenm /*
258*1694Sdarrenm  * KCF software provider control entry points.
259*1694Sdarrenm  */
260*1694Sdarrenm /* ARGSUSED */
261*1694Sdarrenm static void
262*1694Sdarrenm sha1_provider_status(crypto_provider_handle_t provider, uint_t *status)
263*1694Sdarrenm {
264*1694Sdarrenm 	*status = CRYPTO_PROVIDER_READY;
265*1694Sdarrenm }
266*1694Sdarrenm 
267*1694Sdarrenm /*
268*1694Sdarrenm  * KCF software provider digest entry points.
269*1694Sdarrenm  */
270*1694Sdarrenm 
271*1694Sdarrenm static int
272*1694Sdarrenm sha1_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
273*1694Sdarrenm     crypto_req_handle_t req)
274*1694Sdarrenm {
275*1694Sdarrenm 	if (mechanism->cm_type != SHA1_MECH_INFO_TYPE)
276*1694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
277*1694Sdarrenm 
278*1694Sdarrenm 	/*
279*1694Sdarrenm 	 * Allocate and initialize SHA1 context.
280*1694Sdarrenm 	 */
281*1694Sdarrenm 	ctx->cc_provider_private = kmem_alloc(sizeof (sha1_ctx_t),
282*1694Sdarrenm 	    crypto_kmflag(req));
283*1694Sdarrenm 	if (ctx->cc_provider_private == NULL)
284*1694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
285*1694Sdarrenm 
286*1694Sdarrenm 	PROV_SHA1_CTX(ctx)->sc_mech_type = SHA1_MECH_INFO_TYPE;
287*1694Sdarrenm 	SHA1Init(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
288*1694Sdarrenm 
289*1694Sdarrenm 	return (CRYPTO_SUCCESS);
290*1694Sdarrenm }
291*1694Sdarrenm 
292*1694Sdarrenm /*
293*1694Sdarrenm  * Helper SHA1 digest update function for uio data.
294*1694Sdarrenm  */
295*1694Sdarrenm static int
296*1694Sdarrenm sha1_digest_update_uio(SHA1_CTX *sha1_ctx, crypto_data_t *data)
297*1694Sdarrenm {
298*1694Sdarrenm 	off_t offset = data->cd_offset;
299*1694Sdarrenm 	size_t length = data->cd_length;
300*1694Sdarrenm 	uint_t vec_idx;
301*1694Sdarrenm 	size_t cur_len;
302*1694Sdarrenm 
303*1694Sdarrenm 	/* we support only kernel buffer */
304*1694Sdarrenm 	if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
305*1694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
306*1694Sdarrenm 
307*1694Sdarrenm 	/*
308*1694Sdarrenm 	 * Jump to the first iovec containing data to be
309*1694Sdarrenm 	 * digested.
310*1694Sdarrenm 	 */
311*1694Sdarrenm 	for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
312*1694Sdarrenm 	    offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
313*1694Sdarrenm 	    offset -= data->cd_uio->uio_iov[vec_idx++].iov_len);
314*1694Sdarrenm 	if (vec_idx == data->cd_uio->uio_iovcnt) {
315*1694Sdarrenm 		/*
316*1694Sdarrenm 		 * The caller specified an offset that is larger than the
317*1694Sdarrenm 		 * total size of the buffers it provided.
318*1694Sdarrenm 		 */
319*1694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
320*1694Sdarrenm 	}
321*1694Sdarrenm 
322*1694Sdarrenm 	/*
323*1694Sdarrenm 	 * Now do the digesting on the iovecs.
324*1694Sdarrenm 	 */
325*1694Sdarrenm 	while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
326*1694Sdarrenm 		cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
327*1694Sdarrenm 		    offset, length);
328*1694Sdarrenm 
329*1694Sdarrenm 		SHA1Update(sha1_ctx,
330*1694Sdarrenm 		    (uint8_t *)data->cd_uio->uio_iov[vec_idx].iov_base + offset,
331*1694Sdarrenm 		    cur_len);
332*1694Sdarrenm 
333*1694Sdarrenm 		length -= cur_len;
334*1694Sdarrenm 		vec_idx++;
335*1694Sdarrenm 		offset = 0;
336*1694Sdarrenm 	}
337*1694Sdarrenm 
338*1694Sdarrenm 	if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
339*1694Sdarrenm 		/*
340*1694Sdarrenm 		 * The end of the specified iovec's was reached but
341*1694Sdarrenm 		 * the length requested could not be processed, i.e.
342*1694Sdarrenm 		 * The caller requested to digest more data than it provided.
343*1694Sdarrenm 		 */
344*1694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
345*1694Sdarrenm 	}
346*1694Sdarrenm 
347*1694Sdarrenm 	return (CRYPTO_SUCCESS);
348*1694Sdarrenm }
349*1694Sdarrenm 
350*1694Sdarrenm /*
351*1694Sdarrenm  * Helper SHA1 digest final function for uio data.
352*1694Sdarrenm  * digest_len is the length of the desired digest. If digest_len
353*1694Sdarrenm  * is smaller than the default SHA1 digest length, the caller
354*1694Sdarrenm  * must pass a scratch buffer, digest_scratch, which must
355*1694Sdarrenm  * be at least SHA1_DIGEST_LENGTH bytes.
356*1694Sdarrenm  */
357*1694Sdarrenm static int
358*1694Sdarrenm sha1_digest_final_uio(SHA1_CTX *sha1_ctx, crypto_data_t *digest,
359*1694Sdarrenm     ulong_t digest_len, uchar_t *digest_scratch)
360*1694Sdarrenm {
361*1694Sdarrenm 	off_t offset = digest->cd_offset;
362*1694Sdarrenm 	uint_t vec_idx;
363*1694Sdarrenm 
364*1694Sdarrenm 	/* we support only kernel buffer */
365*1694Sdarrenm 	if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
366*1694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
367*1694Sdarrenm 
368*1694Sdarrenm 	/*
369*1694Sdarrenm 	 * Jump to the first iovec containing ptr to the digest to
370*1694Sdarrenm 	 * be returned.
371*1694Sdarrenm 	 */
372*1694Sdarrenm 	for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
373*1694Sdarrenm 	    vec_idx < digest->cd_uio->uio_iovcnt;
374*1694Sdarrenm 	    offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len);
375*1694Sdarrenm 	if (vec_idx == digest->cd_uio->uio_iovcnt) {
376*1694Sdarrenm 		/*
377*1694Sdarrenm 		 * The caller specified an offset that is
378*1694Sdarrenm 		 * larger than the total size of the buffers
379*1694Sdarrenm 		 * it provided.
380*1694Sdarrenm 		 */
381*1694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
382*1694Sdarrenm 	}
383*1694Sdarrenm 
384*1694Sdarrenm 	if (offset + digest_len <=
385*1694Sdarrenm 	    digest->cd_uio->uio_iov[vec_idx].iov_len) {
386*1694Sdarrenm 		/*
387*1694Sdarrenm 		 * The computed SHA1 digest will fit in the current
388*1694Sdarrenm 		 * iovec.
389*1694Sdarrenm 		 */
390*1694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
391*1694Sdarrenm 			/*
392*1694Sdarrenm 			 * The caller requested a short digest. Digest
393*1694Sdarrenm 			 * into a scratch buffer and return to
394*1694Sdarrenm 			 * the user only what was requested.
395*1694Sdarrenm 			 */
396*1694Sdarrenm 			SHA1Final(digest_scratch, sha1_ctx);
397*1694Sdarrenm 			bcopy(digest_scratch, (uchar_t *)digest->
398*1694Sdarrenm 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
399*1694Sdarrenm 			    digest_len);
400*1694Sdarrenm 		} else {
401*1694Sdarrenm 			SHA1Final((uchar_t *)digest->
402*1694Sdarrenm 			    cd_uio->uio_iov[vec_idx].iov_base + offset,
403*1694Sdarrenm 			    sha1_ctx);
404*1694Sdarrenm 		}
405*1694Sdarrenm 	} else {
406*1694Sdarrenm 		/*
407*1694Sdarrenm 		 * The computed digest will be crossing one or more iovec's.
408*1694Sdarrenm 		 * This is bad performance-wise but we need to support it.
409*1694Sdarrenm 		 * Allocate a small scratch buffer on the stack and
410*1694Sdarrenm 		 * copy it piece meal to the specified digest iovec's.
411*1694Sdarrenm 		 */
412*1694Sdarrenm 		uchar_t digest_tmp[SHA1_DIGEST_LENGTH];
413*1694Sdarrenm 		off_t scratch_offset = 0;
414*1694Sdarrenm 		size_t length = digest_len;
415*1694Sdarrenm 		size_t cur_len;
416*1694Sdarrenm 
417*1694Sdarrenm 		SHA1Final(digest_tmp, sha1_ctx);
418*1694Sdarrenm 
419*1694Sdarrenm 		while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
420*1694Sdarrenm 			cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
421*1694Sdarrenm 			    offset, length);
422*1694Sdarrenm 			bcopy(digest_tmp + scratch_offset,
423*1694Sdarrenm 			    digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
424*1694Sdarrenm 			    cur_len);
425*1694Sdarrenm 
426*1694Sdarrenm 			length -= cur_len;
427*1694Sdarrenm 			vec_idx++;
428*1694Sdarrenm 			scratch_offset += cur_len;
429*1694Sdarrenm 			offset = 0;
430*1694Sdarrenm 		}
431*1694Sdarrenm 
432*1694Sdarrenm 		if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
433*1694Sdarrenm 			/*
434*1694Sdarrenm 			 * The end of the specified iovec's was reached but
435*1694Sdarrenm 			 * the length requested could not be processed, i.e.
436*1694Sdarrenm 			 * The caller requested to digest more data than it
437*1694Sdarrenm 			 * provided.
438*1694Sdarrenm 			 */
439*1694Sdarrenm 			return (CRYPTO_DATA_LEN_RANGE);
440*1694Sdarrenm 		}
441*1694Sdarrenm 	}
442*1694Sdarrenm 
443*1694Sdarrenm 	return (CRYPTO_SUCCESS);
444*1694Sdarrenm }
445*1694Sdarrenm 
446*1694Sdarrenm /*
447*1694Sdarrenm  * Helper SHA1 digest update for mblk's.
448*1694Sdarrenm  */
449*1694Sdarrenm static int
450*1694Sdarrenm sha1_digest_update_mblk(SHA1_CTX *sha1_ctx, crypto_data_t *data)
451*1694Sdarrenm {
452*1694Sdarrenm 	off_t offset = data->cd_offset;
453*1694Sdarrenm 	size_t length = data->cd_length;
454*1694Sdarrenm 	mblk_t *mp;
455*1694Sdarrenm 	size_t cur_len;
456*1694Sdarrenm 
457*1694Sdarrenm 	/*
458*1694Sdarrenm 	 * Jump to the first mblk_t containing data to be digested.
459*1694Sdarrenm 	 */
460*1694Sdarrenm 	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
461*1694Sdarrenm 	    offset -= MBLKL(mp), mp = mp->b_cont);
462*1694Sdarrenm 	if (mp == NULL) {
463*1694Sdarrenm 		/*
464*1694Sdarrenm 		 * The caller specified an offset that is larger than the
465*1694Sdarrenm 		 * total size of the buffers it provided.
466*1694Sdarrenm 		 */
467*1694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
468*1694Sdarrenm 	}
469*1694Sdarrenm 
470*1694Sdarrenm 	/*
471*1694Sdarrenm 	 * Now do the digesting on the mblk chain.
472*1694Sdarrenm 	 */
473*1694Sdarrenm 	while (mp != NULL && length > 0) {
474*1694Sdarrenm 		cur_len = MIN(MBLKL(mp) - offset, length);
475*1694Sdarrenm 		SHA1Update(sha1_ctx, mp->b_rptr + offset, cur_len);
476*1694Sdarrenm 		length -= cur_len;
477*1694Sdarrenm 		offset = 0;
478*1694Sdarrenm 		mp = mp->b_cont;
479*1694Sdarrenm 	}
480*1694Sdarrenm 
481*1694Sdarrenm 	if (mp == NULL && length > 0) {
482*1694Sdarrenm 		/*
483*1694Sdarrenm 		 * The end of the mblk was reached but the length requested
484*1694Sdarrenm 		 * could not be processed, i.e. The caller requested
485*1694Sdarrenm 		 * to digest more data than it provided.
486*1694Sdarrenm 		 */
487*1694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
488*1694Sdarrenm 	}
489*1694Sdarrenm 
490*1694Sdarrenm 	return (CRYPTO_SUCCESS);
491*1694Sdarrenm }
492*1694Sdarrenm 
493*1694Sdarrenm /*
494*1694Sdarrenm  * Helper SHA1 digest final for mblk's.
495*1694Sdarrenm  * digest_len is the length of the desired digest. If digest_len
496*1694Sdarrenm  * is smaller than the default SHA1 digest length, the caller
497*1694Sdarrenm  * must pass a scratch buffer, digest_scratch, which must
498*1694Sdarrenm  * be at least SHA1_DIGEST_LENGTH bytes.
499*1694Sdarrenm  */
500*1694Sdarrenm static int
501*1694Sdarrenm sha1_digest_final_mblk(SHA1_CTX *sha1_ctx, crypto_data_t *digest,
502*1694Sdarrenm     ulong_t digest_len, uchar_t *digest_scratch)
503*1694Sdarrenm {
504*1694Sdarrenm 	off_t offset = digest->cd_offset;
505*1694Sdarrenm 	mblk_t *mp;
506*1694Sdarrenm 
507*1694Sdarrenm 	/*
508*1694Sdarrenm 	 * Jump to the first mblk_t that will be used to store the digest.
509*1694Sdarrenm 	 */
510*1694Sdarrenm 	for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
511*1694Sdarrenm 	    offset -= MBLKL(mp), mp = mp->b_cont);
512*1694Sdarrenm 	if (mp == NULL) {
513*1694Sdarrenm 		/*
514*1694Sdarrenm 		 * The caller specified an offset that is larger than the
515*1694Sdarrenm 		 * total size of the buffers it provided.
516*1694Sdarrenm 		 */
517*1694Sdarrenm 		return (CRYPTO_DATA_LEN_RANGE);
518*1694Sdarrenm 	}
519*1694Sdarrenm 
520*1694Sdarrenm 	if (offset + digest_len <= MBLKL(mp)) {
521*1694Sdarrenm 		/*
522*1694Sdarrenm 		 * The computed SHA1 digest will fit in the current mblk.
523*1694Sdarrenm 		 * Do the SHA1Final() in-place.
524*1694Sdarrenm 		 */
525*1694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
526*1694Sdarrenm 			/*
527*1694Sdarrenm 			 * The caller requested a short digest. Digest
528*1694Sdarrenm 			 * into a scratch buffer and return to
529*1694Sdarrenm 			 * the user only what was requested.
530*1694Sdarrenm 			 */
531*1694Sdarrenm 			SHA1Final(digest_scratch, sha1_ctx);
532*1694Sdarrenm 			bcopy(digest_scratch, mp->b_rptr + offset, digest_len);
533*1694Sdarrenm 		} else {
534*1694Sdarrenm 			SHA1Final(mp->b_rptr + offset, sha1_ctx);
535*1694Sdarrenm 		}
536*1694Sdarrenm 	} else {
537*1694Sdarrenm 		/*
538*1694Sdarrenm 		 * The computed digest will be crossing one or more mblk's.
539*1694Sdarrenm 		 * This is bad performance-wise but we need to support it.
540*1694Sdarrenm 		 * Allocate a small scratch buffer on the stack and
541*1694Sdarrenm 		 * copy it piece meal to the specified digest iovec's.
542*1694Sdarrenm 		 */
543*1694Sdarrenm 		uchar_t digest_tmp[SHA1_DIGEST_LENGTH];
544*1694Sdarrenm 		off_t scratch_offset = 0;
545*1694Sdarrenm 		size_t length = digest_len;
546*1694Sdarrenm 		size_t cur_len;
547*1694Sdarrenm 
548*1694Sdarrenm 		SHA1Final(digest_tmp, sha1_ctx);
549*1694Sdarrenm 
550*1694Sdarrenm 		while (mp != NULL && length > 0) {
551*1694Sdarrenm 			cur_len = MIN(MBLKL(mp) - offset, length);
552*1694Sdarrenm 			bcopy(digest_tmp + scratch_offset,
553*1694Sdarrenm 			    mp->b_rptr + offset, cur_len);
554*1694Sdarrenm 
555*1694Sdarrenm 			length -= cur_len;
556*1694Sdarrenm 			mp = mp->b_cont;
557*1694Sdarrenm 			scratch_offset += cur_len;
558*1694Sdarrenm 			offset = 0;
559*1694Sdarrenm 		}
560*1694Sdarrenm 
561*1694Sdarrenm 		if (mp == NULL && length > 0) {
562*1694Sdarrenm 			/*
563*1694Sdarrenm 			 * The end of the specified mblk was reached but
564*1694Sdarrenm 			 * the length requested could not be processed, i.e.
565*1694Sdarrenm 			 * The caller requested to digest more data than it
566*1694Sdarrenm 			 * provided.
567*1694Sdarrenm 			 */
568*1694Sdarrenm 			return (CRYPTO_DATA_LEN_RANGE);
569*1694Sdarrenm 		}
570*1694Sdarrenm 	}
571*1694Sdarrenm 
572*1694Sdarrenm 	return (CRYPTO_SUCCESS);
573*1694Sdarrenm }
574*1694Sdarrenm 
575*1694Sdarrenm /* ARGSUSED */
576*1694Sdarrenm static int
577*1694Sdarrenm sha1_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
578*1694Sdarrenm     crypto_req_handle_t req)
579*1694Sdarrenm {
580*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
581*1694Sdarrenm 
582*1694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
583*1694Sdarrenm 
584*1694Sdarrenm 	/*
585*1694Sdarrenm 	 * We need to just return the length needed to store the output.
586*1694Sdarrenm 	 * We should not destroy the context for the following cases.
587*1694Sdarrenm 	 */
588*1694Sdarrenm 	if ((digest->cd_length == 0) ||
589*1694Sdarrenm 	    (digest->cd_length < SHA1_DIGEST_LENGTH)) {
590*1694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
591*1694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
592*1694Sdarrenm 	}
593*1694Sdarrenm 
594*1694Sdarrenm 	/*
595*1694Sdarrenm 	 * Do the SHA1 update on the specified input data.
596*1694Sdarrenm 	 */
597*1694Sdarrenm 	switch (data->cd_format) {
598*1694Sdarrenm 	case CRYPTO_DATA_RAW:
599*1694Sdarrenm 		SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
600*1694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
601*1694Sdarrenm 		    data->cd_length);
602*1694Sdarrenm 		break;
603*1694Sdarrenm 	case CRYPTO_DATA_UIO:
604*1694Sdarrenm 		ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
605*1694Sdarrenm 		    data);
606*1694Sdarrenm 		break;
607*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
608*1694Sdarrenm 		ret = sha1_digest_update_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
609*1694Sdarrenm 		    data);
610*1694Sdarrenm 		break;
611*1694Sdarrenm 	default:
612*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
613*1694Sdarrenm 	}
614*1694Sdarrenm 
615*1694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
616*1694Sdarrenm 		/* the update failed, free context and bail */
617*1694Sdarrenm 		kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
618*1694Sdarrenm 		ctx->cc_provider_private = NULL;
619*1694Sdarrenm 		digest->cd_length = 0;
620*1694Sdarrenm 		return (ret);
621*1694Sdarrenm 	}
622*1694Sdarrenm 
623*1694Sdarrenm 	/*
624*1694Sdarrenm 	 * Do a SHA1 final, must be done separately since the digest
625*1694Sdarrenm 	 * type can be different than the input data type.
626*1694Sdarrenm 	 */
627*1694Sdarrenm 	switch (digest->cd_format) {
628*1694Sdarrenm 	case CRYPTO_DATA_RAW:
629*1694Sdarrenm 		SHA1Final((unsigned char *)digest->cd_raw.iov_base +
630*1694Sdarrenm 		    digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
631*1694Sdarrenm 		break;
632*1694Sdarrenm 	case CRYPTO_DATA_UIO:
633*1694Sdarrenm 		ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
634*1694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
635*1694Sdarrenm 		break;
636*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
637*1694Sdarrenm 		ret = sha1_digest_final_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
638*1694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
639*1694Sdarrenm 		break;
640*1694Sdarrenm 	default:
641*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
642*1694Sdarrenm 	}
643*1694Sdarrenm 
644*1694Sdarrenm 	/* all done, free context and return */
645*1694Sdarrenm 
646*1694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
647*1694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
648*1694Sdarrenm 	} else {
649*1694Sdarrenm 		digest->cd_length = 0;
650*1694Sdarrenm 	}
651*1694Sdarrenm 
652*1694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
653*1694Sdarrenm 	ctx->cc_provider_private = NULL;
654*1694Sdarrenm 	return (ret);
655*1694Sdarrenm }
656*1694Sdarrenm 
657*1694Sdarrenm /* ARGSUSED */
658*1694Sdarrenm static int
659*1694Sdarrenm sha1_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
660*1694Sdarrenm     crypto_req_handle_t req)
661*1694Sdarrenm {
662*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
663*1694Sdarrenm 
664*1694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
665*1694Sdarrenm 
666*1694Sdarrenm 	/*
667*1694Sdarrenm 	 * Do the SHA1 update on the specified input data.
668*1694Sdarrenm 	 */
669*1694Sdarrenm 	switch (data->cd_format) {
670*1694Sdarrenm 	case CRYPTO_DATA_RAW:
671*1694Sdarrenm 		SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
672*1694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
673*1694Sdarrenm 		    data->cd_length);
674*1694Sdarrenm 		break;
675*1694Sdarrenm 	case CRYPTO_DATA_UIO:
676*1694Sdarrenm 		ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
677*1694Sdarrenm 		    data);
678*1694Sdarrenm 		break;
679*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
680*1694Sdarrenm 		ret = sha1_digest_update_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
681*1694Sdarrenm 		    data);
682*1694Sdarrenm 		break;
683*1694Sdarrenm 	default:
684*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
685*1694Sdarrenm 	}
686*1694Sdarrenm 
687*1694Sdarrenm 	return (ret);
688*1694Sdarrenm }
689*1694Sdarrenm 
690*1694Sdarrenm /* ARGSUSED */
691*1694Sdarrenm static int
692*1694Sdarrenm sha1_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
693*1694Sdarrenm     crypto_req_handle_t req)
694*1694Sdarrenm {
695*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
696*1694Sdarrenm 
697*1694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
698*1694Sdarrenm 
699*1694Sdarrenm 	/*
700*1694Sdarrenm 	 * We need to just return the length needed to store the output.
701*1694Sdarrenm 	 * We should not destroy the context for the following cases.
702*1694Sdarrenm 	 */
703*1694Sdarrenm 	if ((digest->cd_length == 0) ||
704*1694Sdarrenm 	    (digest->cd_length < SHA1_DIGEST_LENGTH)) {
705*1694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
706*1694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
707*1694Sdarrenm 	}
708*1694Sdarrenm 
709*1694Sdarrenm 	/*
710*1694Sdarrenm 	 * Do a SHA1 final.
711*1694Sdarrenm 	 */
712*1694Sdarrenm 	switch (digest->cd_format) {
713*1694Sdarrenm 	case CRYPTO_DATA_RAW:
714*1694Sdarrenm 		SHA1Final((unsigned char *)digest->cd_raw.iov_base +
715*1694Sdarrenm 		    digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
716*1694Sdarrenm 		break;
717*1694Sdarrenm 	case CRYPTO_DATA_UIO:
718*1694Sdarrenm 		ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
719*1694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
720*1694Sdarrenm 		break;
721*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
722*1694Sdarrenm 		ret = sha1_digest_final_mblk(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
723*1694Sdarrenm 		    digest, SHA1_DIGEST_LENGTH, NULL);
724*1694Sdarrenm 		break;
725*1694Sdarrenm 	default:
726*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
727*1694Sdarrenm 	}
728*1694Sdarrenm 
729*1694Sdarrenm 	/* all done, free context and return */
730*1694Sdarrenm 
731*1694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
732*1694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
733*1694Sdarrenm 	} else {
734*1694Sdarrenm 		digest->cd_length = 0;
735*1694Sdarrenm 	}
736*1694Sdarrenm 
737*1694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
738*1694Sdarrenm 	ctx->cc_provider_private = NULL;
739*1694Sdarrenm 
740*1694Sdarrenm 	return (ret);
741*1694Sdarrenm }
742*1694Sdarrenm 
743*1694Sdarrenm /* ARGSUSED */
744*1694Sdarrenm static int
745*1694Sdarrenm sha1_digest_atomic(crypto_provider_handle_t provider,
746*1694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
747*1694Sdarrenm     crypto_data_t *data, crypto_data_t *digest,
748*1694Sdarrenm     crypto_req_handle_t req)
749*1694Sdarrenm {
750*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
751*1694Sdarrenm 	SHA1_CTX sha1_ctx;
752*1694Sdarrenm 
753*1694Sdarrenm 	if (mechanism->cm_type != SHA1_MECH_INFO_TYPE)
754*1694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
755*1694Sdarrenm 
756*1694Sdarrenm 	/*
757*1694Sdarrenm 	 * Do the SHA1 init.
758*1694Sdarrenm 	 */
759*1694Sdarrenm 	SHA1Init(&sha1_ctx);
760*1694Sdarrenm 
761*1694Sdarrenm 	/*
762*1694Sdarrenm 	 * Do the SHA1 update on the specified input data.
763*1694Sdarrenm 	 */
764*1694Sdarrenm 	switch (data->cd_format) {
765*1694Sdarrenm 	case CRYPTO_DATA_RAW:
766*1694Sdarrenm 		SHA1Update(&sha1_ctx,
767*1694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
768*1694Sdarrenm 		    data->cd_length);
769*1694Sdarrenm 		break;
770*1694Sdarrenm 	case CRYPTO_DATA_UIO:
771*1694Sdarrenm 		ret = sha1_digest_update_uio(&sha1_ctx, data);
772*1694Sdarrenm 		break;
773*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
774*1694Sdarrenm 		ret = sha1_digest_update_mblk(&sha1_ctx, data);
775*1694Sdarrenm 		break;
776*1694Sdarrenm 	default:
777*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
778*1694Sdarrenm 	}
779*1694Sdarrenm 
780*1694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
781*1694Sdarrenm 		/* the update failed, bail */
782*1694Sdarrenm 		digest->cd_length = 0;
783*1694Sdarrenm 		return (ret);
784*1694Sdarrenm 	}
785*1694Sdarrenm 
786*1694Sdarrenm 	/*
787*1694Sdarrenm 	 * Do a SHA1 final, must be done separately since the digest
788*1694Sdarrenm 	 * type can be different than the input data type.
789*1694Sdarrenm 	 */
790*1694Sdarrenm 	switch (digest->cd_format) {
791*1694Sdarrenm 	case CRYPTO_DATA_RAW:
792*1694Sdarrenm 		SHA1Final((unsigned char *)digest->cd_raw.iov_base +
793*1694Sdarrenm 		    digest->cd_offset, &sha1_ctx);
794*1694Sdarrenm 		break;
795*1694Sdarrenm 	case CRYPTO_DATA_UIO:
796*1694Sdarrenm 		ret = sha1_digest_final_uio(&sha1_ctx, digest,
797*1694Sdarrenm 		    SHA1_DIGEST_LENGTH, NULL);
798*1694Sdarrenm 		break;
799*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
800*1694Sdarrenm 		ret = sha1_digest_final_mblk(&sha1_ctx, digest,
801*1694Sdarrenm 		    SHA1_DIGEST_LENGTH, NULL);
802*1694Sdarrenm 		break;
803*1694Sdarrenm 	default:
804*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
805*1694Sdarrenm 	}
806*1694Sdarrenm 
807*1694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
808*1694Sdarrenm 		digest->cd_length = SHA1_DIGEST_LENGTH;
809*1694Sdarrenm 	} else {
810*1694Sdarrenm 		digest->cd_length = 0;
811*1694Sdarrenm 	}
812*1694Sdarrenm 
813*1694Sdarrenm 	return (ret);
814*1694Sdarrenm }
815*1694Sdarrenm 
816*1694Sdarrenm /*
817*1694Sdarrenm  * KCF software provider mac entry points.
818*1694Sdarrenm  *
819*1694Sdarrenm  * SHA1 HMAC is: SHA1(key XOR opad, SHA1(key XOR ipad, text))
820*1694Sdarrenm  *
821*1694Sdarrenm  * Init:
822*1694Sdarrenm  * The initialization routine initializes what we denote
823*1694Sdarrenm  * as the inner and outer contexts by doing
824*1694Sdarrenm  * - for inner context: SHA1(key XOR ipad)
825*1694Sdarrenm  * - for outer context: SHA1(key XOR opad)
826*1694Sdarrenm  *
827*1694Sdarrenm  * Update:
828*1694Sdarrenm  * Each subsequent SHA1 HMAC update will result in an
829*1694Sdarrenm  * update of the inner context with the specified data.
830*1694Sdarrenm  *
831*1694Sdarrenm  * Final:
832*1694Sdarrenm  * The SHA1 HMAC final will do a SHA1 final operation on the
833*1694Sdarrenm  * inner context, and the resulting digest will be used
834*1694Sdarrenm  * as the data for an update on the outer context. Last
835*1694Sdarrenm  * but not least, a SHA1 final on the outer context will
836*1694Sdarrenm  * be performed to obtain the SHA1 HMAC digest to return
837*1694Sdarrenm  * to the user.
838*1694Sdarrenm  */
839*1694Sdarrenm 
840*1694Sdarrenm /*
841*1694Sdarrenm  * Initialize a SHA1-HMAC context.
842*1694Sdarrenm  */
843*1694Sdarrenm static void
844*1694Sdarrenm sha1_mac_init_ctx(sha1_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
845*1694Sdarrenm {
846*1694Sdarrenm 	uint32_t ipad[SHA1_HMAC_INTS_PER_BLOCK];
847*1694Sdarrenm 	uint32_t opad[SHA1_HMAC_INTS_PER_BLOCK];
848*1694Sdarrenm 	uint_t i;
849*1694Sdarrenm 
850*1694Sdarrenm 	bzero(ipad, SHA1_HMAC_BLOCK_SIZE);
851*1694Sdarrenm 	bzero(opad, SHA1_HMAC_BLOCK_SIZE);
852*1694Sdarrenm 
853*1694Sdarrenm 	bcopy(keyval, ipad, length_in_bytes);
854*1694Sdarrenm 	bcopy(keyval, opad, length_in_bytes);
855*1694Sdarrenm 
856*1694Sdarrenm 	/* XOR key with ipad (0x36) and opad (0x5c) */
857*1694Sdarrenm 	for (i = 0; i < SHA1_HMAC_INTS_PER_BLOCK; i++) {
858*1694Sdarrenm 		ipad[i] ^= 0x36363636;
859*1694Sdarrenm 		opad[i] ^= 0x5c5c5c5c;
860*1694Sdarrenm 	}
861*1694Sdarrenm 
862*1694Sdarrenm 	/* perform SHA1 on ipad */
863*1694Sdarrenm 	SHA1Init(&ctx->hc_icontext);
864*1694Sdarrenm 	SHA1Update(&ctx->hc_icontext, (uint8_t *)ipad, SHA1_HMAC_BLOCK_SIZE);
865*1694Sdarrenm 
866*1694Sdarrenm 	/* perform SHA1 on opad */
867*1694Sdarrenm 	SHA1Init(&ctx->hc_ocontext);
868*1694Sdarrenm 	SHA1Update(&ctx->hc_ocontext, (uint8_t *)opad, SHA1_HMAC_BLOCK_SIZE);
869*1694Sdarrenm }
870*1694Sdarrenm 
871*1694Sdarrenm /*
872*1694Sdarrenm  */
873*1694Sdarrenm static int
874*1694Sdarrenm sha1_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
875*1694Sdarrenm     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
876*1694Sdarrenm     crypto_req_handle_t req)
877*1694Sdarrenm {
878*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
879*1694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
880*1694Sdarrenm 
881*1694Sdarrenm 	if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
882*1694Sdarrenm 	    mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
883*1694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
884*1694Sdarrenm 
885*1694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
886*1694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
887*1694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
888*1694Sdarrenm 
889*1694Sdarrenm 	ctx->cc_provider_private = kmem_alloc(sizeof (sha1_hmac_ctx_t),
890*1694Sdarrenm 	    crypto_kmflag(req));
891*1694Sdarrenm 	if (ctx->cc_provider_private == NULL)
892*1694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
893*1694Sdarrenm 
894*1694Sdarrenm 	if (ctx_template != NULL) {
895*1694Sdarrenm 		/* reuse context template */
896*1694Sdarrenm 		bcopy(ctx_template, PROV_SHA1_HMAC_CTX(ctx),
897*1694Sdarrenm 		    sizeof (sha1_hmac_ctx_t));
898*1694Sdarrenm 	} else {
899*1694Sdarrenm 		/* no context template, compute context */
900*1694Sdarrenm 		if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
901*1694Sdarrenm 			uchar_t digested_key[SHA1_DIGEST_LENGTH];
902*1694Sdarrenm 			sha1_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
903*1694Sdarrenm 
904*1694Sdarrenm 			/*
905*1694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
906*1694Sdarrenm 			 * The inner context is used since it hasn't been
907*1694Sdarrenm 			 * initialized yet.
908*1694Sdarrenm 			 */
909*1694Sdarrenm 			PROV_SHA1_DIGEST_KEY(&hmac_ctx->hc_icontext,
910*1694Sdarrenm 			    key->ck_data, keylen_in_bytes, digested_key);
911*1694Sdarrenm 			sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx),
912*1694Sdarrenm 			    digested_key, SHA1_DIGEST_LENGTH);
913*1694Sdarrenm 		} else {
914*1694Sdarrenm 			sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx),
915*1694Sdarrenm 			    key->ck_data, keylen_in_bytes);
916*1694Sdarrenm 		}
917*1694Sdarrenm 	}
918*1694Sdarrenm 
919*1694Sdarrenm 	/*
920*1694Sdarrenm 	 * Get the mechanism parameters, if applicable.
921*1694Sdarrenm 	 */
922*1694Sdarrenm 	PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
923*1694Sdarrenm 	if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
924*1694Sdarrenm 		if (mechanism->cm_param == NULL ||
925*1694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t))
926*1694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
927*1694Sdarrenm 		PROV_SHA1_GET_DIGEST_LEN(mechanism,
928*1694Sdarrenm 		    PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len);
929*1694Sdarrenm 		if (PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len >
930*1694Sdarrenm 		    SHA1_DIGEST_LENGTH)
931*1694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
932*1694Sdarrenm 	}
933*1694Sdarrenm 
934*1694Sdarrenm 	if (ret != CRYPTO_SUCCESS) {
935*1694Sdarrenm 		bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
936*1694Sdarrenm 		kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
937*1694Sdarrenm 		ctx->cc_provider_private = NULL;
938*1694Sdarrenm 	}
939*1694Sdarrenm 
940*1694Sdarrenm 	return (ret);
941*1694Sdarrenm }
942*1694Sdarrenm 
943*1694Sdarrenm /* ARGSUSED */
944*1694Sdarrenm static int
945*1694Sdarrenm sha1_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
946*1694Sdarrenm {
947*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
948*1694Sdarrenm 
949*1694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
950*1694Sdarrenm 
951*1694Sdarrenm 	/*
952*1694Sdarrenm 	 * Do a SHA1 update of the inner context using the specified
953*1694Sdarrenm 	 * data.
954*1694Sdarrenm 	 */
955*1694Sdarrenm 	switch (data->cd_format) {
956*1694Sdarrenm 	case CRYPTO_DATA_RAW:
957*1694Sdarrenm 		SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_icontext,
958*1694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
959*1694Sdarrenm 		    data->cd_length);
960*1694Sdarrenm 		break;
961*1694Sdarrenm 	case CRYPTO_DATA_UIO:
962*1694Sdarrenm 		ret = sha1_digest_update_uio(
963*1694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, data);
964*1694Sdarrenm 		break;
965*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
966*1694Sdarrenm 		ret = sha1_digest_update_mblk(
967*1694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, data);
968*1694Sdarrenm 		break;
969*1694Sdarrenm 	default:
970*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
971*1694Sdarrenm 	}
972*1694Sdarrenm 
973*1694Sdarrenm 	return (ret);
974*1694Sdarrenm }
975*1694Sdarrenm 
976*1694Sdarrenm /* ARGSUSED */
977*1694Sdarrenm static int
978*1694Sdarrenm sha1_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
979*1694Sdarrenm {
980*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
981*1694Sdarrenm 	uchar_t digest[SHA1_DIGEST_LENGTH];
982*1694Sdarrenm 	uint32_t digest_len = SHA1_DIGEST_LENGTH;
983*1694Sdarrenm 
984*1694Sdarrenm 	ASSERT(ctx->cc_provider_private != NULL);
985*1694Sdarrenm 
986*1694Sdarrenm 	if (PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type ==
987*1694Sdarrenm 	    SHA1_HMAC_GEN_MECH_INFO_TYPE)
988*1694Sdarrenm 		digest_len = PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len;
989*1694Sdarrenm 
990*1694Sdarrenm 	/*
991*1694Sdarrenm 	 * We need to just return the length needed to store the output.
992*1694Sdarrenm 	 * We should not destroy the context for the following cases.
993*1694Sdarrenm 	 */
994*1694Sdarrenm 	if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
995*1694Sdarrenm 		mac->cd_length = digest_len;
996*1694Sdarrenm 		return (CRYPTO_BUFFER_TOO_SMALL);
997*1694Sdarrenm 	}
998*1694Sdarrenm 
999*1694Sdarrenm 	/*
1000*1694Sdarrenm 	 * Do a SHA1 final on the inner context.
1001*1694Sdarrenm 	 */
1002*1694Sdarrenm 	SHA1Final(digest, &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext);
1003*1694Sdarrenm 
1004*1694Sdarrenm 	/*
1005*1694Sdarrenm 	 * Do a SHA1 update on the outer context, feeding the inner
1006*1694Sdarrenm 	 * digest as data.
1007*1694Sdarrenm 	 */
1008*1694Sdarrenm 	SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, digest,
1009*1694Sdarrenm 	    SHA1_DIGEST_LENGTH);
1010*1694Sdarrenm 
1011*1694Sdarrenm 	/*
1012*1694Sdarrenm 	 * Do a SHA1 final on the outer context, storing the computing
1013*1694Sdarrenm 	 * digest in the users buffer.
1014*1694Sdarrenm 	 */
1015*1694Sdarrenm 	switch (mac->cd_format) {
1016*1694Sdarrenm 	case CRYPTO_DATA_RAW:
1017*1694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
1018*1694Sdarrenm 			/*
1019*1694Sdarrenm 			 * The caller requested a short digest. Digest
1020*1694Sdarrenm 			 * into a scratch buffer and return to
1021*1694Sdarrenm 			 * the user only what was requested.
1022*1694Sdarrenm 			 */
1023*1694Sdarrenm 			SHA1Final(digest,
1024*1694Sdarrenm 			    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext);
1025*1694Sdarrenm 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
1026*1694Sdarrenm 			    mac->cd_offset, digest_len);
1027*1694Sdarrenm 		} else {
1028*1694Sdarrenm 			SHA1Final((unsigned char *)mac->cd_raw.iov_base +
1029*1694Sdarrenm 			    mac->cd_offset,
1030*1694Sdarrenm 			    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext);
1031*1694Sdarrenm 		}
1032*1694Sdarrenm 		break;
1033*1694Sdarrenm 	case CRYPTO_DATA_UIO:
1034*1694Sdarrenm 		ret = sha1_digest_final_uio(
1035*1694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, mac,
1036*1694Sdarrenm 		    digest_len, digest);
1037*1694Sdarrenm 		break;
1038*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
1039*1694Sdarrenm 		ret = sha1_digest_final_mblk(
1040*1694Sdarrenm 		    &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, mac,
1041*1694Sdarrenm 		    digest_len, digest);
1042*1694Sdarrenm 		break;
1043*1694Sdarrenm 	default:
1044*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
1045*1694Sdarrenm 	}
1046*1694Sdarrenm 
1047*1694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
1048*1694Sdarrenm 		mac->cd_length = digest_len;
1049*1694Sdarrenm 	} else {
1050*1694Sdarrenm 		mac->cd_length = 0;
1051*1694Sdarrenm 	}
1052*1694Sdarrenm 
1053*1694Sdarrenm 	bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
1054*1694Sdarrenm 	kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
1055*1694Sdarrenm 	ctx->cc_provider_private = NULL;
1056*1694Sdarrenm 
1057*1694Sdarrenm 	return (ret);
1058*1694Sdarrenm }
1059*1694Sdarrenm 
1060*1694Sdarrenm #define	SHA1_MAC_UPDATE(data, ctx, ret) {				\
1061*1694Sdarrenm 	switch (data->cd_format) {					\
1062*1694Sdarrenm 	case CRYPTO_DATA_RAW:						\
1063*1694Sdarrenm 		SHA1Update(&(ctx).hc_icontext,				\
1064*1694Sdarrenm 		    (uint8_t *)data->cd_raw.iov_base +			\
1065*1694Sdarrenm 		    data->cd_offset, data->cd_length);			\
1066*1694Sdarrenm 		break;							\
1067*1694Sdarrenm 	case CRYPTO_DATA_UIO:						\
1068*1694Sdarrenm 		ret = sha1_digest_update_uio(&(ctx).hc_icontext, data); \
1069*1694Sdarrenm 		break;							\
1070*1694Sdarrenm 	case CRYPTO_DATA_MBLK:						\
1071*1694Sdarrenm 		ret = sha1_digest_update_mblk(&(ctx).hc_icontext,	\
1072*1694Sdarrenm 		    data);						\
1073*1694Sdarrenm 		break;							\
1074*1694Sdarrenm 	default:							\
1075*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;				\
1076*1694Sdarrenm 	}								\
1077*1694Sdarrenm }
1078*1694Sdarrenm 
1079*1694Sdarrenm /* ARGSUSED */
1080*1694Sdarrenm static int
1081*1694Sdarrenm sha1_mac_atomic(crypto_provider_handle_t provider,
1082*1694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1083*1694Sdarrenm     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1084*1694Sdarrenm     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
1085*1694Sdarrenm {
1086*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
1087*1694Sdarrenm 	uchar_t digest[SHA1_DIGEST_LENGTH];
1088*1694Sdarrenm 	sha1_hmac_ctx_t sha1_hmac_ctx;
1089*1694Sdarrenm 	uint32_t digest_len = SHA1_DIGEST_LENGTH;
1090*1694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1091*1694Sdarrenm 
1092*1694Sdarrenm 	if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
1093*1694Sdarrenm 	    mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
1094*1694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
1095*1694Sdarrenm 
1096*1694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
1097*1694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
1098*1694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
1099*1694Sdarrenm 
1100*1694Sdarrenm 	if (ctx_template != NULL) {
1101*1694Sdarrenm 		/* reuse context template */
1102*1694Sdarrenm 		bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
1103*1694Sdarrenm 	} else {
1104*1694Sdarrenm 		/* no context template, initialize context */
1105*1694Sdarrenm 		if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
1106*1694Sdarrenm 			/*
1107*1694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
1108*1694Sdarrenm 			 * The inner context is used since it hasn't been
1109*1694Sdarrenm 			 * initialized yet.
1110*1694Sdarrenm 			 */
1111*1694Sdarrenm 			PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext,
1112*1694Sdarrenm 			    key->ck_data, keylen_in_bytes, digest);
1113*1694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, digest,
1114*1694Sdarrenm 			    SHA1_DIGEST_LENGTH);
1115*1694Sdarrenm 		} else {
1116*1694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data,
1117*1694Sdarrenm 			    keylen_in_bytes);
1118*1694Sdarrenm 		}
1119*1694Sdarrenm 	}
1120*1694Sdarrenm 
1121*1694Sdarrenm 	/* get the mechanism parameters, if applicable */
1122*1694Sdarrenm 	if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
1123*1694Sdarrenm 		if (mechanism->cm_param == NULL ||
1124*1694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t)) {
1125*1694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1126*1694Sdarrenm 			goto bail;
1127*1694Sdarrenm 		}
1128*1694Sdarrenm 		PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len);
1129*1694Sdarrenm 		if (digest_len > SHA1_DIGEST_LENGTH) {
1130*1694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1131*1694Sdarrenm 			goto bail;
1132*1694Sdarrenm 		}
1133*1694Sdarrenm 	}
1134*1694Sdarrenm 
1135*1694Sdarrenm 	/* do a SHA1 update of the inner context using the specified data */
1136*1694Sdarrenm 	SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret);
1137*1694Sdarrenm 	if (ret != CRYPTO_SUCCESS)
1138*1694Sdarrenm 		/* the update failed, free context and bail */
1139*1694Sdarrenm 		goto bail;
1140*1694Sdarrenm 
1141*1694Sdarrenm 	/*
1142*1694Sdarrenm 	 * Do a SHA1 final on the inner context.
1143*1694Sdarrenm 	 */
1144*1694Sdarrenm 	SHA1Final(digest, &sha1_hmac_ctx.hc_icontext);
1145*1694Sdarrenm 
1146*1694Sdarrenm 	/*
1147*1694Sdarrenm 	 * Do an SHA1 update on the outer context, feeding the inner
1148*1694Sdarrenm 	 * digest as data.
1149*1694Sdarrenm 	 */
1150*1694Sdarrenm 	SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH);
1151*1694Sdarrenm 
1152*1694Sdarrenm 	/*
1153*1694Sdarrenm 	 * Do a SHA1 final on the outer context, storing the computed
1154*1694Sdarrenm 	 * digest in the users buffer.
1155*1694Sdarrenm 	 */
1156*1694Sdarrenm 	switch (mac->cd_format) {
1157*1694Sdarrenm 	case CRYPTO_DATA_RAW:
1158*1694Sdarrenm 		if (digest_len != SHA1_DIGEST_LENGTH) {
1159*1694Sdarrenm 			/*
1160*1694Sdarrenm 			 * The caller requested a short digest. Digest
1161*1694Sdarrenm 			 * into a scratch buffer and return to
1162*1694Sdarrenm 			 * the user only what was requested.
1163*1694Sdarrenm 			 */
1164*1694Sdarrenm 			SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext);
1165*1694Sdarrenm 			bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
1166*1694Sdarrenm 			    mac->cd_offset, digest_len);
1167*1694Sdarrenm 		} else {
1168*1694Sdarrenm 			SHA1Final((unsigned char *)mac->cd_raw.iov_base +
1169*1694Sdarrenm 			    mac->cd_offset, &sha1_hmac_ctx.hc_ocontext);
1170*1694Sdarrenm 		}
1171*1694Sdarrenm 		break;
1172*1694Sdarrenm 	case CRYPTO_DATA_UIO:
1173*1694Sdarrenm 		ret = sha1_digest_final_uio(&sha1_hmac_ctx.hc_ocontext, mac,
1174*1694Sdarrenm 		    digest_len, digest);
1175*1694Sdarrenm 		break;
1176*1694Sdarrenm 	case CRYPTO_DATA_MBLK:
1177*1694Sdarrenm 		ret = sha1_digest_final_mblk(&sha1_hmac_ctx.hc_ocontext, mac,
1178*1694Sdarrenm 		    digest_len, digest);
1179*1694Sdarrenm 		break;
1180*1694Sdarrenm 	default:
1181*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
1182*1694Sdarrenm 	}
1183*1694Sdarrenm 
1184*1694Sdarrenm 	if (ret == CRYPTO_SUCCESS) {
1185*1694Sdarrenm 		mac->cd_length = digest_len;
1186*1694Sdarrenm 	} else {
1187*1694Sdarrenm 		mac->cd_length = 0;
1188*1694Sdarrenm 	}
1189*1694Sdarrenm 	/* Extra paranoia: zeroize the context on the stack */
1190*1694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
1191*1694Sdarrenm 
1192*1694Sdarrenm 	return (ret);
1193*1694Sdarrenm bail:
1194*1694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
1195*1694Sdarrenm 	mac->cd_length = 0;
1196*1694Sdarrenm 	return (ret);
1197*1694Sdarrenm }
1198*1694Sdarrenm 
1199*1694Sdarrenm /* ARGSUSED */
1200*1694Sdarrenm static int
1201*1694Sdarrenm sha1_mac_verify_atomic(crypto_provider_handle_t provider,
1202*1694Sdarrenm     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1203*1694Sdarrenm     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
1204*1694Sdarrenm     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
1205*1694Sdarrenm {
1206*1694Sdarrenm 	int ret = CRYPTO_SUCCESS;
1207*1694Sdarrenm 	uchar_t digest[SHA1_DIGEST_LENGTH];
1208*1694Sdarrenm 	sha1_hmac_ctx_t sha1_hmac_ctx;
1209*1694Sdarrenm 	uint32_t digest_len = SHA1_DIGEST_LENGTH;
1210*1694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1211*1694Sdarrenm 
1212*1694Sdarrenm 	if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
1213*1694Sdarrenm 	    mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
1214*1694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
1215*1694Sdarrenm 
1216*1694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
1217*1694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
1218*1694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
1219*1694Sdarrenm 
1220*1694Sdarrenm 	if (ctx_template != NULL) {
1221*1694Sdarrenm 		/* reuse context template */
1222*1694Sdarrenm 		bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
1223*1694Sdarrenm 	} else {
1224*1694Sdarrenm 		/* no context template, initialize context */
1225*1694Sdarrenm 		if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
1226*1694Sdarrenm 			/*
1227*1694Sdarrenm 			 * Hash the passed-in key to get a smaller key.
1228*1694Sdarrenm 			 * The inner context is used since it hasn't been
1229*1694Sdarrenm 			 * initialized yet.
1230*1694Sdarrenm 			 */
1231*1694Sdarrenm 			PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext,
1232*1694Sdarrenm 			    key->ck_data, keylen_in_bytes, digest);
1233*1694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, digest,
1234*1694Sdarrenm 			    SHA1_DIGEST_LENGTH);
1235*1694Sdarrenm 		} else {
1236*1694Sdarrenm 			sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data,
1237*1694Sdarrenm 			    keylen_in_bytes);
1238*1694Sdarrenm 		}
1239*1694Sdarrenm 	}
1240*1694Sdarrenm 
1241*1694Sdarrenm 	/* get the mechanism parameters, if applicable */
1242*1694Sdarrenm 	if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
1243*1694Sdarrenm 		if (mechanism->cm_param == NULL ||
1244*1694Sdarrenm 		    mechanism->cm_param_len != sizeof (ulong_t)) {
1245*1694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1246*1694Sdarrenm 			goto bail;
1247*1694Sdarrenm 		}
1248*1694Sdarrenm 		PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len);
1249*1694Sdarrenm 		if (digest_len > SHA1_DIGEST_LENGTH) {
1250*1694Sdarrenm 			ret = CRYPTO_MECHANISM_PARAM_INVALID;
1251*1694Sdarrenm 			goto bail;
1252*1694Sdarrenm 		}
1253*1694Sdarrenm 	}
1254*1694Sdarrenm 
1255*1694Sdarrenm 	if (mac->cd_length != digest_len) {
1256*1694Sdarrenm 		ret = CRYPTO_INVALID_MAC;
1257*1694Sdarrenm 		goto bail;
1258*1694Sdarrenm 	}
1259*1694Sdarrenm 
1260*1694Sdarrenm 	/* do a SHA1 update of the inner context using the specified data */
1261*1694Sdarrenm 	SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret);
1262*1694Sdarrenm 	if (ret != CRYPTO_SUCCESS)
1263*1694Sdarrenm 		/* the update failed, free context and bail */
1264*1694Sdarrenm 		goto bail;
1265*1694Sdarrenm 
1266*1694Sdarrenm 	/* do a SHA1 final on the inner context */
1267*1694Sdarrenm 	SHA1Final(digest, &sha1_hmac_ctx.hc_icontext);
1268*1694Sdarrenm 
1269*1694Sdarrenm 	/*
1270*1694Sdarrenm 	 * Do an SHA1 update on the outer context, feeding the inner
1271*1694Sdarrenm 	 * digest as data.
1272*1694Sdarrenm 	 */
1273*1694Sdarrenm 	SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH);
1274*1694Sdarrenm 
1275*1694Sdarrenm 	/*
1276*1694Sdarrenm 	 * Do a SHA1 final on the outer context, storing the computed
1277*1694Sdarrenm 	 * digest in the users buffer.
1278*1694Sdarrenm 	 */
1279*1694Sdarrenm 	SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext);
1280*1694Sdarrenm 
1281*1694Sdarrenm 	/*
1282*1694Sdarrenm 	 * Compare the computed digest against the expected digest passed
1283*1694Sdarrenm 	 * as argument.
1284*1694Sdarrenm 	 */
1285*1694Sdarrenm 
1286*1694Sdarrenm 	switch (mac->cd_format) {
1287*1694Sdarrenm 
1288*1694Sdarrenm 	case CRYPTO_DATA_RAW:
1289*1694Sdarrenm 		if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
1290*1694Sdarrenm 		    mac->cd_offset, digest_len) != 0)
1291*1694Sdarrenm 			ret = CRYPTO_INVALID_MAC;
1292*1694Sdarrenm 		break;
1293*1694Sdarrenm 
1294*1694Sdarrenm 	case CRYPTO_DATA_UIO: {
1295*1694Sdarrenm 		off_t offset = mac->cd_offset;
1296*1694Sdarrenm 		uint_t vec_idx;
1297*1694Sdarrenm 		off_t scratch_offset = 0;
1298*1694Sdarrenm 		size_t length = digest_len;
1299*1694Sdarrenm 		size_t cur_len;
1300*1694Sdarrenm 
1301*1694Sdarrenm 		/* we support only kernel buffer */
1302*1694Sdarrenm 		if (mac->cd_uio->uio_segflg != UIO_SYSSPACE)
1303*1694Sdarrenm 			return (CRYPTO_ARGUMENTS_BAD);
1304*1694Sdarrenm 
1305*1694Sdarrenm 		/* jump to the first iovec containing the expected digest */
1306*1694Sdarrenm 		for (vec_idx = 0;
1307*1694Sdarrenm 		    offset >= mac->cd_uio->uio_iov[vec_idx].iov_len &&
1308*1694Sdarrenm 		    vec_idx < mac->cd_uio->uio_iovcnt;
1309*1694Sdarrenm 		    offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len);
1310*1694Sdarrenm 		if (vec_idx == mac->cd_uio->uio_iovcnt) {
1311*1694Sdarrenm 			/*
1312*1694Sdarrenm 			 * The caller specified an offset that is
1313*1694Sdarrenm 			 * larger than the total size of the buffers
1314*1694Sdarrenm 			 * it provided.
1315*1694Sdarrenm 			 */
1316*1694Sdarrenm 			ret = CRYPTO_DATA_LEN_RANGE;
1317*1694Sdarrenm 			break;
1318*1694Sdarrenm 		}
1319*1694Sdarrenm 
1320*1694Sdarrenm 		/* do the comparison of computed digest vs specified one */
1321*1694Sdarrenm 		while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) {
1322*1694Sdarrenm 			cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len -
1323*1694Sdarrenm 			    offset, length);
1324*1694Sdarrenm 
1325*1694Sdarrenm 			if (bcmp(digest + scratch_offset,
1326*1694Sdarrenm 			    mac->cd_uio->uio_iov[vec_idx].iov_base + offset,
1327*1694Sdarrenm 			    cur_len) != 0) {
1328*1694Sdarrenm 				ret = CRYPTO_INVALID_MAC;
1329*1694Sdarrenm 				break;
1330*1694Sdarrenm 			}
1331*1694Sdarrenm 
1332*1694Sdarrenm 			length -= cur_len;
1333*1694Sdarrenm 			vec_idx++;
1334*1694Sdarrenm 			scratch_offset += cur_len;
1335*1694Sdarrenm 			offset = 0;
1336*1694Sdarrenm 		}
1337*1694Sdarrenm 		break;
1338*1694Sdarrenm 	}
1339*1694Sdarrenm 
1340*1694Sdarrenm 	case CRYPTO_DATA_MBLK: {
1341*1694Sdarrenm 		off_t offset = mac->cd_offset;
1342*1694Sdarrenm 		mblk_t *mp;
1343*1694Sdarrenm 		off_t scratch_offset = 0;
1344*1694Sdarrenm 		size_t length = digest_len;
1345*1694Sdarrenm 		size_t cur_len;
1346*1694Sdarrenm 
1347*1694Sdarrenm 		/* jump to the first mblk_t containing the expected digest */
1348*1694Sdarrenm 		for (mp = mac->cd_mp; mp != NULL && offset >= MBLKL(mp);
1349*1694Sdarrenm 		    offset -= MBLKL(mp), mp = mp->b_cont);
1350*1694Sdarrenm 		if (mp == NULL) {
1351*1694Sdarrenm 			/*
1352*1694Sdarrenm 			 * The caller specified an offset that is larger than
1353*1694Sdarrenm 			 * the total size of the buffers it provided.
1354*1694Sdarrenm 			 */
1355*1694Sdarrenm 			ret = CRYPTO_DATA_LEN_RANGE;
1356*1694Sdarrenm 			break;
1357*1694Sdarrenm 		}
1358*1694Sdarrenm 
1359*1694Sdarrenm 		while (mp != NULL && length > 0) {
1360*1694Sdarrenm 			cur_len = MIN(MBLKL(mp) - offset, length);
1361*1694Sdarrenm 			if (bcmp(digest + scratch_offset,
1362*1694Sdarrenm 			    mp->b_rptr + offset, cur_len) != 0) {
1363*1694Sdarrenm 				ret = CRYPTO_INVALID_MAC;
1364*1694Sdarrenm 				break;
1365*1694Sdarrenm 			}
1366*1694Sdarrenm 
1367*1694Sdarrenm 			length -= cur_len;
1368*1694Sdarrenm 			mp = mp->b_cont;
1369*1694Sdarrenm 			scratch_offset += cur_len;
1370*1694Sdarrenm 			offset = 0;
1371*1694Sdarrenm 		}
1372*1694Sdarrenm 		break;
1373*1694Sdarrenm 	}
1374*1694Sdarrenm 
1375*1694Sdarrenm 	default:
1376*1694Sdarrenm 		ret = CRYPTO_ARGUMENTS_BAD;
1377*1694Sdarrenm 	}
1378*1694Sdarrenm 
1379*1694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
1380*1694Sdarrenm 	return (ret);
1381*1694Sdarrenm bail:
1382*1694Sdarrenm 	bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
1383*1694Sdarrenm 	mac->cd_length = 0;
1384*1694Sdarrenm 	return (ret);
1385*1694Sdarrenm }
1386*1694Sdarrenm 
1387*1694Sdarrenm /*
1388*1694Sdarrenm  * KCF software provider context management entry points.
1389*1694Sdarrenm  */
1390*1694Sdarrenm 
1391*1694Sdarrenm /* ARGSUSED */
1392*1694Sdarrenm static int
1393*1694Sdarrenm sha1_create_ctx_template(crypto_provider_handle_t provider,
1394*1694Sdarrenm     crypto_mechanism_t *mechanism, crypto_key_t *key,
1395*1694Sdarrenm     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
1396*1694Sdarrenm     crypto_req_handle_t req)
1397*1694Sdarrenm {
1398*1694Sdarrenm 	sha1_hmac_ctx_t *sha1_hmac_ctx_tmpl;
1399*1694Sdarrenm 	uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
1400*1694Sdarrenm 
1401*1694Sdarrenm 	if ((mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE) &&
1402*1694Sdarrenm 	    (mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)) {
1403*1694Sdarrenm 		return (CRYPTO_MECHANISM_INVALID);
1404*1694Sdarrenm 	}
1405*1694Sdarrenm 
1406*1694Sdarrenm 	/* Add support for key by attributes (RFE 4706552) */
1407*1694Sdarrenm 	if (key->ck_format != CRYPTO_KEY_RAW)
1408*1694Sdarrenm 		return (CRYPTO_ARGUMENTS_BAD);
1409*1694Sdarrenm 
1410*1694Sdarrenm 	/*
1411*1694Sdarrenm 	 * Allocate and initialize SHA1 context.
1412*1694Sdarrenm 	 */
1413*1694Sdarrenm 	sha1_hmac_ctx_tmpl = kmem_alloc(sizeof (sha1_hmac_ctx_t),
1414*1694Sdarrenm 	    crypto_kmflag(req));
1415*1694Sdarrenm 	if (sha1_hmac_ctx_tmpl == NULL)
1416*1694Sdarrenm 		return (CRYPTO_HOST_MEMORY);
1417*1694Sdarrenm 
1418*1694Sdarrenm 	if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
1419*1694Sdarrenm 		uchar_t digested_key[SHA1_DIGEST_LENGTH];
1420*1694Sdarrenm 
1421*1694Sdarrenm 		/*
1422*1694Sdarrenm 		 * Hash the passed-in key to get a smaller key.
1423*1694Sdarrenm 		 * The inner context is used since it hasn't been
1424*1694Sdarrenm 		 * initialized yet.
1425*1694Sdarrenm 		 */
1426*1694Sdarrenm 		PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx_tmpl->hc_icontext,
1427*1694Sdarrenm 		    key->ck_data, keylen_in_bytes, digested_key);
1428*1694Sdarrenm 		sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, digested_key,
1429*1694Sdarrenm 		    SHA1_DIGEST_LENGTH);
1430*1694Sdarrenm 	} else {
1431*1694Sdarrenm 		sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, key->ck_data,
1432*1694Sdarrenm 		    keylen_in_bytes);
1433*1694Sdarrenm 	}
1434*1694Sdarrenm 
1435*1694Sdarrenm 	sha1_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
1436*1694Sdarrenm 	*ctx_template = (crypto_spi_ctx_template_t)sha1_hmac_ctx_tmpl;
1437*1694Sdarrenm 	*ctx_template_size = sizeof (sha1_hmac_ctx_t);
1438*1694Sdarrenm 
1439*1694Sdarrenm 
1440*1694Sdarrenm 	return (CRYPTO_SUCCESS);
1441*1694Sdarrenm }
1442*1694Sdarrenm 
1443*1694Sdarrenm static int
1444*1694Sdarrenm sha1_free_context(crypto_ctx_t *ctx)
1445*1694Sdarrenm {
1446*1694Sdarrenm 	uint_t ctx_len;
1447*1694Sdarrenm 	sha1_mech_type_t mech_type;
1448*1694Sdarrenm 
1449*1694Sdarrenm 	if (ctx->cc_provider_private == NULL)
1450*1694Sdarrenm 		return (CRYPTO_SUCCESS);
1451*1694Sdarrenm 
1452*1694Sdarrenm 	/*
1453*1694Sdarrenm 	 * We have to free either SHA1 or SHA1-HMAC contexts, which
1454*1694Sdarrenm 	 * have different lengths.
1455*1694Sdarrenm 	 */
1456*1694Sdarrenm 
1457*1694Sdarrenm 	mech_type = PROV_SHA1_CTX(ctx)->sc_mech_type;
1458*1694Sdarrenm 	if (mech_type == SHA1_MECH_INFO_TYPE)
1459*1694Sdarrenm 		ctx_len = sizeof (sha1_ctx_t);
1460*1694Sdarrenm 	else {
1461*1694Sdarrenm 		ASSERT(mech_type == SHA1_HMAC_MECH_INFO_TYPE ||
1462*1694Sdarrenm 		    mech_type == SHA1_HMAC_GEN_MECH_INFO_TYPE);
1463*1694Sdarrenm 		ctx_len = sizeof (sha1_hmac_ctx_t);
1464*1694Sdarrenm 	}
1465*1694Sdarrenm 
1466*1694Sdarrenm 	bzero(ctx->cc_provider_private, ctx_len);
1467*1694Sdarrenm 	kmem_free(ctx->cc_provider_private, ctx_len);
1468*1694Sdarrenm 	ctx->cc_provider_private = NULL;
1469*1694Sdarrenm 
1470*1694Sdarrenm 	return (CRYPTO_SUCCESS);
1471*1694Sdarrenm }
1472