1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://opensource.org/licenses/CDDL-1.0.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2013 Saso Kiselkov. All rights reserved.
24  */
25 
26 #include <sys/modctl.h>
27 #include <sys/crypto/common.h>
28 #include <sys/crypto/icp.h>
29 #include <sys/crypto/spi.h>
30 #include <sys/sysmacros.h>
31 #define	SKEIN_MODULE_IMPL
32 #include <sys/skein.h>
33 
34 /*
35  * Like the sha2 module, we create the skein module with two modlinkages:
36  * - modlmisc to allow direct calls to Skein_* API functions.
37  * - modlcrypto to integrate well into the Kernel Crypto Framework (KCF).
38  */
39 static struct modlmisc modlmisc = {
40 	&mod_cryptoops,
41 	"Skein Message-Digest Algorithm"
42 };
43 
44 static struct modlcrypto modlcrypto = {
45 	&mod_cryptoops,
46 	"Skein Kernel SW Provider"
47 };
48 
49 static struct modlinkage modlinkage = {
50 	MODREV_1, {&modlmisc, &modlcrypto, NULL}
51 };
52 
53 static crypto_mech_info_t skein_mech_info_tab[] = {
54 	{CKM_SKEIN_256, SKEIN_256_MECH_INFO_TYPE,
55 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
56 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
57 	{CKM_SKEIN_256_MAC, SKEIN_256_MAC_MECH_INFO_TYPE,
58 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
59 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
60 	{CKM_SKEIN_512, SKEIN_512_MECH_INFO_TYPE,
61 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
62 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
63 	{CKM_SKEIN_512_MAC, SKEIN_512_MAC_MECH_INFO_TYPE,
64 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
65 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
66 	{CKM_SKEIN1024, SKEIN1024_MECH_INFO_TYPE,
67 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
68 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
69 	{CKM_SKEIN1024_MAC, SKEIN1024_MAC_MECH_INFO_TYPE,
70 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
71 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES}
72 };
73 
74 static void skein_provider_status(crypto_provider_handle_t, uint_t *);
75 
76 static crypto_control_ops_t skein_control_ops = {
77 	skein_provider_status
78 };
79 
80 static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
81     crypto_req_handle_t);
82 static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
83     crypto_req_handle_t);
84 static int skein_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
85 static int skein_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
86 static int skein_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
87     crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
88     crypto_req_handle_t);
89 
90 static crypto_digest_ops_t skein_digest_ops = {
91 	.digest_init = skein_digest_init,
92 	.digest = skein_digest,
93 	.digest_update = skein_update,
94 	.digest_key = NULL,
95 	.digest_final = skein_final,
96 	.digest_atomic = skein_digest_atomic
97 };
98 
99 static int skein_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
100     crypto_spi_ctx_template_t, crypto_req_handle_t);
101 static int skein_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
102     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
103     crypto_spi_ctx_template_t, crypto_req_handle_t);
104 
105 static crypto_mac_ops_t skein_mac_ops = {
106 	.mac_init = skein_mac_init,
107 	.mac = NULL,
108 	.mac_update = skein_update, /* using regular digest update is OK here */
109 	.mac_final = skein_final,   /* using regular digest final is OK here */
110 	.mac_atomic = skein_mac_atomic,
111 	.mac_verify_atomic = NULL
112 };
113 
114 static int skein_create_ctx_template(crypto_provider_handle_t,
115     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
116     size_t *, crypto_req_handle_t);
117 static int skein_free_context(crypto_ctx_t *);
118 
119 static crypto_ctx_ops_t skein_ctx_ops = {
120 	.create_ctx_template = skein_create_ctx_template,
121 	.free_context = skein_free_context
122 };
123 
124 static crypto_ops_t skein_crypto_ops = {{{{{
125 	&skein_control_ops,
126 	&skein_digest_ops,
127 	NULL,
128 	&skein_mac_ops,
129 	NULL,
130 	NULL,
131 	NULL,
132 	NULL,
133 	NULL,
134 	NULL,
135 	NULL,
136 	NULL,
137 	NULL,
138 	&skein_ctx_ops,
139 }}}}};
140 
141 static crypto_provider_info_t skein_prov_info = {{{{
142 	CRYPTO_SPI_VERSION_1,
143 	"Skein Software Provider",
144 	CRYPTO_SW_PROVIDER,
145 	NULL,
146 	&skein_crypto_ops,
147 	sizeof (skein_mech_info_tab) / sizeof (crypto_mech_info_t),
148 	skein_mech_info_tab
149 }}}};
150 
151 static crypto_kcf_provider_handle_t skein_prov_handle = 0;
152 
153 typedef struct skein_ctx {
154 	skein_mech_type_t		sc_mech_type;
155 	size_t				sc_digest_bitlen;
156 	/*LINTED(E_ANONYMOUS_UNION_DECL)*/
157 	union {
158 		Skein_256_Ctxt_t	sc_256;
159 		Skein_512_Ctxt_t	sc_512;
160 		Skein1024_Ctxt_t	sc_1024;
161 	};
162 } skein_ctx_t;
163 #define	SKEIN_CTX(_ctx_)	((skein_ctx_t *)((_ctx_)->cc_provider_private))
164 #define	SKEIN_CTX_LVALUE(_ctx_)	(_ctx_)->cc_provider_private
165 #define	SKEIN_OP(_skein_ctx, _op, ...)					\
166 	do {								\
167 		skein_ctx_t	*sc = (_skein_ctx);			\
168 		switch (sc->sc_mech_type) {				\
169 		case SKEIN_256_MECH_INFO_TYPE:				\
170 		case SKEIN_256_MAC_MECH_INFO_TYPE:			\
171 			(void) Skein_256_ ## _op(&sc->sc_256, __VA_ARGS__);\
172 			break;						\
173 		case SKEIN_512_MECH_INFO_TYPE:				\
174 		case SKEIN_512_MAC_MECH_INFO_TYPE:			\
175 			(void) Skein_512_ ## _op(&sc->sc_512, __VA_ARGS__);\
176 			break;						\
177 		case SKEIN1024_MECH_INFO_TYPE:				\
178 		case SKEIN1024_MAC_MECH_INFO_TYPE:			\
179 			(void) Skein1024_ ## _op(&sc->sc_1024, __VA_ARGS__);\
180 			break;						\
181 		}							\
182 		_NOTE(CONSTCOND)					\
183 	} while (0)
184 
185 static int
skein_get_digest_bitlen(const crypto_mechanism_t * mechanism,size_t * result)186 skein_get_digest_bitlen(const crypto_mechanism_t *mechanism, size_t *result)
187 {
188 	if (mechanism->cm_param != NULL) {
189 		/*LINTED(E_BAD_PTR_CAST_ALIGN)*/
190 		skein_param_t	*param = (skein_param_t *)mechanism->cm_param;
191 
192 		if (mechanism->cm_param_len != sizeof (*param) ||
193 		    param->sp_digest_bitlen == 0) {
194 			return (CRYPTO_MECHANISM_PARAM_INVALID);
195 		}
196 		*result = param->sp_digest_bitlen;
197 	} else {
198 		switch (mechanism->cm_type) {
199 		case SKEIN_256_MECH_INFO_TYPE:
200 			*result = 256;
201 			break;
202 		case SKEIN_512_MECH_INFO_TYPE:
203 			*result = 512;
204 			break;
205 		case SKEIN1024_MECH_INFO_TYPE:
206 			*result = 1024;
207 			break;
208 		default:
209 			return (CRYPTO_MECHANISM_INVALID);
210 		}
211 	}
212 	return (CRYPTO_SUCCESS);
213 }
214 
215 int
skein_mod_init(void)216 skein_mod_init(void)
217 {
218 	int error;
219 
220 	if ((error = mod_install(&modlinkage)) != 0)
221 		return (error);
222 
223 	/*
224 	 * Try to register with KCF - failure shouldn't unload us, since we
225 	 * still may want to continue providing misc/skein functionality.
226 	 */
227 	(void) crypto_register_provider(&skein_prov_info, &skein_prov_handle);
228 
229 	return (0);
230 }
231 
232 int
skein_mod_fini(void)233 skein_mod_fini(void)
234 {
235 	int ret;
236 
237 	if (skein_prov_handle != 0) {
238 		if ((ret = crypto_unregister_provider(skein_prov_handle)) !=
239 		    CRYPTO_SUCCESS) {
240 			cmn_err(CE_WARN,
241 			    "skein _fini: crypto_unregister_provider() "
242 			    "failed (0x%x)", ret);
243 			return (EBUSY);
244 		}
245 		skein_prov_handle = 0;
246 	}
247 
248 	return (mod_remove(&modlinkage));
249 }
250 
251 /*
252  * KCF software provider control entry points.
253  */
254 /* ARGSUSED */
255 static void
skein_provider_status(crypto_provider_handle_t provider,uint_t * status)256 skein_provider_status(crypto_provider_handle_t provider, uint_t *status)
257 {
258 	*status = CRYPTO_PROVIDER_READY;
259 }
260 
261 /*
262  * General Skein hashing helper functions.
263  */
264 
265 /*
266  * Performs an Update on a context with uio input data.
267  */
268 static int
skein_digest_update_uio(skein_ctx_t * ctx,const crypto_data_t * data)269 skein_digest_update_uio(skein_ctx_t *ctx, const crypto_data_t *data)
270 {
271 	off_t		offset = data->cd_offset;
272 	size_t		length = data->cd_length;
273 	uint_t		vec_idx = 0;
274 	size_t		cur_len;
275 	uio_t		*uio = data->cd_uio;
276 
277 	/* we support only kernel buffer */
278 	if (uio_segflg(uio) != UIO_SYSSPACE)
279 		return (CRYPTO_ARGUMENTS_BAD);
280 
281 	/*
282 	 * Jump to the first iovec containing data to be
283 	 * digested.
284 	 */
285 	offset = uio_index_at_offset(uio, offset, &vec_idx);
286 	if (vec_idx == uio_iovcnt(uio)) {
287 		/*
288 		 * The caller specified an offset that is larger than the
289 		 * total size of the buffers it provided.
290 		 */
291 		return (CRYPTO_DATA_LEN_RANGE);
292 	}
293 
294 	/*
295 	 * Now do the digesting on the iovecs.
296 	 */
297 	while (vec_idx < uio_iovcnt(uio) && length > 0) {
298 		cur_len = MIN(uio_iovlen(uio, vec_idx) - offset, length);
299 		SKEIN_OP(ctx, Update, (uint8_t *)uio_iovbase(uio, vec_idx)
300 		    + offset, cur_len);
301 		length -= cur_len;
302 		vec_idx++;
303 		offset = 0;
304 	}
305 
306 	if (vec_idx == uio_iovcnt(uio) && length > 0) {
307 		/*
308 		 * The end of the specified iovec's was reached but
309 		 * the length requested could not be processed, i.e.
310 		 * The caller requested to digest more data than it provided.
311 		 */
312 		return (CRYPTO_DATA_LEN_RANGE);
313 	}
314 
315 	return (CRYPTO_SUCCESS);
316 }
317 
318 /*
319  * Performs a Final on a context and writes to a uio digest output.
320  */
321 static int
skein_digest_final_uio(skein_ctx_t * ctx,crypto_data_t * digest,crypto_req_handle_t req)322 skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest,
323     crypto_req_handle_t req)
324 {
325 	off_t	offset = digest->cd_offset;
326 	uint_t	vec_idx = 0;
327 	uio_t	*uio = digest->cd_uio;
328 
329 	/* we support only kernel buffer */
330 	if (uio_segflg(uio) != UIO_SYSSPACE)
331 		return (CRYPTO_ARGUMENTS_BAD);
332 
333 	/*
334 	 * Jump to the first iovec containing ptr to the digest to be returned.
335 	 */
336 	offset = uio_index_at_offset(uio, offset, &vec_idx);
337 	if (vec_idx == uio_iovcnt(uio)) {
338 		/*
339 		 * The caller specified an offset that is larger than the
340 		 * total size of the buffers it provided.
341 		 */
342 		return (CRYPTO_DATA_LEN_RANGE);
343 	}
344 	if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <=
345 	    uio_iovlen(uio, vec_idx)) {
346 		/* The computed digest will fit in the current iovec. */
347 		SKEIN_OP(ctx, Final,
348 		    (uchar_t *)uio_iovbase(uio, vec_idx) + offset);
349 	} else {
350 		uint8_t *digest_tmp;
351 		off_t scratch_offset = 0;
352 		size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen);
353 		size_t cur_len;
354 
355 		digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES(
356 		    ctx->sc_digest_bitlen), crypto_kmflag(req));
357 		if (digest_tmp == NULL)
358 			return (CRYPTO_HOST_MEMORY);
359 		SKEIN_OP(ctx, Final, digest_tmp);
360 		while (vec_idx < uio_iovcnt(uio) && length > 0) {
361 			cur_len = MIN(uio_iovlen(uio, vec_idx) - offset,
362 			    length);
363 			bcopy(digest_tmp + scratch_offset,
364 			    uio_iovbase(uio, vec_idx) + offset, cur_len);
365 
366 			length -= cur_len;
367 			vec_idx++;
368 			scratch_offset += cur_len;
369 			offset = 0;
370 		}
371 		kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen));
372 
373 		if (vec_idx == uio_iovcnt(uio) && length > 0) {
374 			/*
375 			 * The end of the specified iovec's was reached but
376 			 * the length requested could not be processed, i.e.
377 			 * The caller requested to digest more data than it
378 			 * provided.
379 			 */
380 			return (CRYPTO_DATA_LEN_RANGE);
381 		}
382 	}
383 
384 	return (CRYPTO_SUCCESS);
385 }
386 
387 /*
388  * KCF software provider digest entry points.
389  */
390 
391 /*
392  * Initializes a skein digest context to the configuration in `mechanism'.
393  * The mechanism cm_type must be one of SKEIN_*_MECH_INFO_TYPE. The cm_param
394  * field may contain a skein_param_t structure indicating the length of the
395  * digest the algorithm should produce. Otherwise the default output lengths
396  * are applied (32 bytes for Skein-256, 64 bytes for Skein-512 and 128 bytes
397  * for Skein-1024).
398  */
399 static int
skein_digest_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_req_handle_t req)400 skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
401     crypto_req_handle_t req)
402 {
403 	int	error = CRYPTO_SUCCESS;
404 
405 	if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
406 		return (CRYPTO_MECHANISM_INVALID);
407 
408 	SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
409 	    crypto_kmflag(req));
410 	if (SKEIN_CTX(ctx) == NULL)
411 		return (CRYPTO_HOST_MEMORY);
412 
413 	SKEIN_CTX(ctx)->sc_mech_type = mechanism->cm_type;
414 	error = skein_get_digest_bitlen(mechanism,
415 	    &SKEIN_CTX(ctx)->sc_digest_bitlen);
416 	if (error != CRYPTO_SUCCESS)
417 		goto errout;
418 	SKEIN_OP(SKEIN_CTX(ctx), Init, SKEIN_CTX(ctx)->sc_digest_bitlen);
419 
420 	return (CRYPTO_SUCCESS);
421 errout:
422 	bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
423 	kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
424 	SKEIN_CTX_LVALUE(ctx) = NULL;
425 	return (error);
426 }
427 
428 /*
429  * Executes a skein_update and skein_digest on a pre-initialized crypto
430  * context in a single step. See the documentation to these functions to
431  * see what to pass here.
432  */
433 static int
skein_digest(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * digest,crypto_req_handle_t req)434 skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
435     crypto_req_handle_t req)
436 {
437 	int error = CRYPTO_SUCCESS;
438 
439 	ASSERT(SKEIN_CTX(ctx) != NULL);
440 
441 	if (digest->cd_length <
442 	    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
443 		digest->cd_length =
444 		    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
445 		return (CRYPTO_BUFFER_TOO_SMALL);
446 	}
447 
448 	error = skein_update(ctx, data, req);
449 	if (error != CRYPTO_SUCCESS) {
450 		bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
451 		kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
452 		SKEIN_CTX_LVALUE(ctx) = NULL;
453 		digest->cd_length = 0;
454 		return (error);
455 	}
456 	error = skein_final(ctx, digest, req);
457 
458 	return (error);
459 }
460 
461 /*
462  * Performs a skein Update with the input message in `data' (successive calls
463  * can push more data). This is used both for digest and MAC operation.
464  * Supported input data formats are raw, uio and mblk.
465  */
466 /*ARGSUSED*/
467 static int
skein_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)468 skein_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
469 {
470 	int error = CRYPTO_SUCCESS;
471 
472 	ASSERT(SKEIN_CTX(ctx) != NULL);
473 
474 	switch (data->cd_format) {
475 	case CRYPTO_DATA_RAW:
476 		SKEIN_OP(SKEIN_CTX(ctx), Update,
477 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
478 		    data->cd_length);
479 		break;
480 	case CRYPTO_DATA_UIO:
481 		error = skein_digest_update_uio(SKEIN_CTX(ctx), data);
482 		break;
483 	default:
484 		error = CRYPTO_ARGUMENTS_BAD;
485 	}
486 
487 	return (error);
488 }
489 
490 /*
491  * Performs a skein Final, writing the output to `digest'. This is used both
492  * for digest and MAC operation.
493  * Supported output digest formats are raw, uio and mblk.
494  */
495 /*ARGSUSED*/
496 static int
skein_final(crypto_ctx_t * ctx,crypto_data_t * digest,crypto_req_handle_t req)497 skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req)
498 {
499 	int error = CRYPTO_SUCCESS;
500 
501 	ASSERT(SKEIN_CTX(ctx) != NULL);
502 
503 	if (digest->cd_length <
504 	    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
505 		digest->cd_length =
506 		    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
507 		return (CRYPTO_BUFFER_TOO_SMALL);
508 	}
509 
510 	switch (digest->cd_format) {
511 	case CRYPTO_DATA_RAW:
512 		SKEIN_OP(SKEIN_CTX(ctx), Final,
513 		    (uint8_t *)digest->cd_raw.iov_base + digest->cd_offset);
514 		break;
515 	case CRYPTO_DATA_UIO:
516 		error = skein_digest_final_uio(SKEIN_CTX(ctx), digest, req);
517 		break;
518 	default:
519 		error = CRYPTO_ARGUMENTS_BAD;
520 	}
521 
522 	if (error == CRYPTO_SUCCESS)
523 		digest->cd_length =
524 		    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
525 	else
526 		digest->cd_length = 0;
527 
528 	bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
529 	kmem_free(SKEIN_CTX(ctx), sizeof (*(SKEIN_CTX(ctx))));
530 	SKEIN_CTX_LVALUE(ctx) = NULL;
531 
532 	return (error);
533 }
534 
535 /*
536  * Performs a full skein digest computation in a single call, configuring the
537  * algorithm according to `mechanism', reading the input to be digested from
538  * `data' and writing the output to `digest'.
539  * Supported input/output formats are raw, uio and mblk.
540  */
541 /*ARGSUSED*/
542 static int
skein_digest_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_data_t * data,crypto_data_t * digest,crypto_req_handle_t req)543 skein_digest_atomic(crypto_provider_handle_t provider,
544     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
545     crypto_data_t *data, crypto_data_t *digest, crypto_req_handle_t req)
546 {
547 	int		error;
548 	skein_ctx_t	skein_ctx;
549 	crypto_ctx_t	ctx;
550 	SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
551 
552 	/* Init */
553 	if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
554 		return (CRYPTO_MECHANISM_INVALID);
555 	skein_ctx.sc_mech_type = mechanism->cm_type;
556 	error = skein_get_digest_bitlen(mechanism, &skein_ctx.sc_digest_bitlen);
557 	if (error != CRYPTO_SUCCESS)
558 		goto out;
559 	SKEIN_OP(&skein_ctx, Init, skein_ctx.sc_digest_bitlen);
560 
561 	if ((error = skein_update(&ctx, data, digest)) != CRYPTO_SUCCESS)
562 		goto out;
563 	if ((error = skein_final(&ctx, data, digest)) != CRYPTO_SUCCESS)
564 		goto out;
565 
566 out:
567 	if (error == CRYPTO_SUCCESS)
568 		digest->cd_length =
569 		    CRYPTO_BITS2BYTES(skein_ctx.sc_digest_bitlen);
570 	else
571 		digest->cd_length = 0;
572 	bzero(&skein_ctx, sizeof (skein_ctx));
573 
574 	return (error);
575 }
576 
577 /*
578  * Helper function that builds a Skein MAC context from the provided
579  * mechanism and key.
580  */
581 static int
skein_mac_ctx_build(skein_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key)582 skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism,
583     crypto_key_t *key)
584 {
585 	int error;
586 
587 	if (!VALID_SKEIN_MAC_MECH(mechanism->cm_type))
588 		return (CRYPTO_MECHANISM_INVALID);
589 	if (key->ck_format != CRYPTO_KEY_RAW)
590 		return (CRYPTO_ARGUMENTS_BAD);
591 	ctx->sc_mech_type = mechanism->cm_type;
592 	error = skein_get_digest_bitlen(mechanism, &ctx->sc_digest_bitlen);
593 	if (error != CRYPTO_SUCCESS)
594 		return (error);
595 	SKEIN_OP(ctx, InitExt, ctx->sc_digest_bitlen, 0, key->ck_data,
596 	    CRYPTO_BITS2BYTES(key->ck_length));
597 
598 	return (CRYPTO_SUCCESS);
599 }
600 
601 /*
602  * KCF software provide mac entry points.
603  */
604 /*
605  * Initializes a skein MAC context. You may pass a ctx_template, in which
606  * case the template will be reused to make initialization more efficient.
607  * Otherwise a new context will be constructed. The mechanism cm_type must
608  * be one of SKEIN_*_MAC_MECH_INFO_TYPE. Same as in skein_digest_init, you
609  * may pass a skein_param_t in cm_param to configure the length of the
610  * digest. The key must be in raw format.
611  */
612 static int
skein_mac_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)613 skein_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
614     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
615     crypto_req_handle_t req)
616 {
617 	int	error;
618 
619 	SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
620 	    crypto_kmflag(req));
621 	if (SKEIN_CTX(ctx) == NULL)
622 		return (CRYPTO_HOST_MEMORY);
623 
624 	if (ctx_template != NULL) {
625 		bcopy(ctx_template, SKEIN_CTX(ctx),
626 		    sizeof (*SKEIN_CTX(ctx)));
627 	} else {
628 		error = skein_mac_ctx_build(SKEIN_CTX(ctx), mechanism, key);
629 		if (error != CRYPTO_SUCCESS)
630 			goto errout;
631 	}
632 
633 	return (CRYPTO_SUCCESS);
634 errout:
635 	bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
636 	kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
637 	return (error);
638 }
639 
640 /*
641  * The MAC update and final calls are reused from the regular digest code.
642  */
643 
644 /*ARGSUSED*/
645 /*
646  * Same as skein_digest_atomic, performs an atomic Skein MAC operation in
647  * one step. All the same properties apply to the arguments of this
648  * function as to those of the partial operations above.
649  */
650 static int
skein_mac_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * mac,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)651 skein_mac_atomic(crypto_provider_handle_t provider,
652     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
653     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
654     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
655 {
656 	/* faux crypto context just for skein_digest_{update,final} */
657 	int		error;
658 	crypto_ctx_t	ctx;
659 	skein_ctx_t	skein_ctx;
660 	SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
661 
662 	if (ctx_template != NULL) {
663 		bcopy(ctx_template, &skein_ctx, sizeof (skein_ctx));
664 	} else {
665 		error = skein_mac_ctx_build(&skein_ctx, mechanism, key);
666 		if (error != CRYPTO_SUCCESS)
667 			goto errout;
668 	}
669 
670 	if ((error = skein_update(&ctx, data, req)) != CRYPTO_SUCCESS)
671 		goto errout;
672 	if ((error = skein_final(&ctx, mac, req)) != CRYPTO_SUCCESS)
673 		goto errout;
674 
675 	return (CRYPTO_SUCCESS);
676 errout:
677 	bzero(&skein_ctx, sizeof (skein_ctx));
678 	return (error);
679 }
680 
681 /*
682  * KCF software provider context management entry points.
683  */
684 
685 /*
686  * Constructs a context template for the Skein MAC algorithm. The same
687  * properties apply to the arguments of this function as to those of
688  * skein_mac_init.
689  */
690 /*ARGSUSED*/
691 static int
skein_create_ctx_template(crypto_provider_handle_t provider,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t * ctx_template,size_t * ctx_template_size,crypto_req_handle_t req)692 skein_create_ctx_template(crypto_provider_handle_t provider,
693     crypto_mechanism_t *mechanism, crypto_key_t *key,
694     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
695     crypto_req_handle_t req)
696 {
697 	int		error;
698 	skein_ctx_t	*ctx_tmpl;
699 
700 	ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), crypto_kmflag(req));
701 	if (ctx_tmpl == NULL)
702 		return (CRYPTO_HOST_MEMORY);
703 	error = skein_mac_ctx_build(ctx_tmpl, mechanism, key);
704 	if (error != CRYPTO_SUCCESS)
705 		goto errout;
706 	*ctx_template = ctx_tmpl;
707 	*ctx_template_size = sizeof (*ctx_tmpl);
708 
709 	return (CRYPTO_SUCCESS);
710 errout:
711 	bzero(ctx_tmpl, sizeof (*ctx_tmpl));
712 	kmem_free(ctx_tmpl, sizeof (*ctx_tmpl));
713 	return (error);
714 }
715 
716 /*
717  * Frees a skein context in a parent crypto context.
718  */
719 static int
skein_free_context(crypto_ctx_t * ctx)720 skein_free_context(crypto_ctx_t *ctx)
721 {
722 	if (SKEIN_CTX(ctx) != NULL) {
723 		bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
724 		kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
725 		SKEIN_CTX_LVALUE(ctx) = NULL;
726 	}
727 
728 	return (CRYPTO_SUCCESS);
729 }
730