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.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * In kernel module, the md5 module is created with two modlinkages:
29 * - a modlmisc that allows consumers to directly call the entry points
30 * MD5Init, MD5Update, and MD5Final.
31 * - a modlcrypto that allows the module to register with the Kernel
32 * Cryptographic Framework (KCF) as a software provider for the MD5
36 #include <sys/types.h>
37 #include <sys/systm.h>
38 #include <sys/modctl.h>
39 #include <sys/cmn_err.h>
41 #include <sys/crypto/common.h>
42 #include <sys/crypto/spi.h>
43 #include <sys/sysmacros.h>
44 #include <sys/strsun.h>
48 extern struct mod_ops mod_miscops
;
49 extern struct mod_ops mod_cryptoops
;
52 * Module linkage information for the kernel.
55 static struct modlmisc modlmisc
= {
57 "MD5 Message-Digest Algorithm"
60 static struct modlcrypto modlcrypto
= {
62 "MD5 Kernel SW Provider"
65 static struct modlinkage modlinkage
= {
73 * CSPI information (entry points, provider info, etc.)
76 typedef enum md5_mech_type
{
77 MD5_MECH_INFO_TYPE
, /* SUN_CKM_MD5 */
78 MD5_HMAC_MECH_INFO_TYPE
, /* SUN_CKM_MD5_HMAC */
79 MD5_HMAC_GEN_MECH_INFO_TYPE
/* SUN_CKM_MD5_HMAC_GENERAL */
82 #define MD5_DIGEST_LENGTH 16 /* MD5 digest length in bytes */
83 #define MD5_HMAC_BLOCK_SIZE 64 /* MD5 block size */
84 #define MD5_HMAC_MIN_KEY_LEN 1 /* MD5-HMAC min key length in bytes */
85 #define MD5_HMAC_MAX_KEY_LEN INT_MAX /* MD5-HMAC max key length in bytes */
86 #define MD5_HMAC_INTS_PER_BLOCK (MD5_HMAC_BLOCK_SIZE/sizeof (uint32_t))
89 * Context for MD5 mechanism.
91 typedef struct md5_ctx
{
92 md5_mech_type_t mc_mech_type
; /* type of context */
93 MD5_CTX mc_md5_ctx
; /* MD5 context */
97 * Context for MD5-HMAC and MD5-HMAC-GENERAL mechanisms.
99 typedef struct md5_hmac_ctx
{
100 md5_mech_type_t hc_mech_type
; /* type of context */
101 uint32_t hc_digest_len
; /* digest len in bytes */
102 MD5_CTX hc_icontext
; /* inner MD5 context */
103 MD5_CTX hc_ocontext
; /* outer MD5 context */
107 * Macros to access the MD5 or MD5-HMAC contexts from a context passed
108 * by KCF to one of the entry points.
111 #define PROV_MD5_CTX(ctx) ((md5_ctx_t *)(ctx)->cc_provider_private)
112 #define PROV_MD5_HMAC_CTX(ctx) ((md5_hmac_ctx_t *)(ctx)->cc_provider_private)
113 /* to extract the digest length passed as mechanism parameter */
115 #define PROV_MD5_GET_DIGEST_LEN(m, len) { \
116 if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t))) \
117 (len) = (uint32_t)*((ulong_t *)(void *)mechanism->cm_param); \
120 bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t)); \
121 (len) = (uint32_t)tmp_ulong; \
125 #define PROV_MD5_DIGEST_KEY(ctx, key, len, digest) { \
127 MD5Update(ctx, key, len); \
128 MD5Final(digest, ctx); \
132 * Mechanism info structure passed to KCF during registration.
134 static crypto_mech_info_t md5_mech_info_tab
[] = {
136 {SUN_CKM_MD5
, MD5_MECH_INFO_TYPE
,
137 CRYPTO_FG_DIGEST
| CRYPTO_FG_DIGEST_ATOMIC
,
138 0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS
},
140 {SUN_CKM_MD5_HMAC
, MD5_HMAC_MECH_INFO_TYPE
,
141 CRYPTO_FG_MAC
| CRYPTO_FG_MAC_ATOMIC
,
142 MD5_HMAC_MIN_KEY_LEN
, MD5_HMAC_MAX_KEY_LEN
,
143 CRYPTO_KEYSIZE_UNIT_IN_BYTES
},
144 /* MD5-HMAC GENERAL */
145 {SUN_CKM_MD5_HMAC_GENERAL
, MD5_HMAC_GEN_MECH_INFO_TYPE
,
146 CRYPTO_FG_MAC
| CRYPTO_FG_MAC_ATOMIC
,
147 MD5_HMAC_MIN_KEY_LEN
, MD5_HMAC_MAX_KEY_LEN
,
148 CRYPTO_KEYSIZE_UNIT_IN_BYTES
}
151 static void md5_provider_status(crypto_provider_handle_t
, uint_t
*);
153 static crypto_control_ops_t md5_control_ops
= {
157 static int md5_digest_init(crypto_ctx_t
*, crypto_mechanism_t
*,
158 crypto_req_handle_t
);
159 static int md5_digest(crypto_ctx_t
*, crypto_data_t
*, crypto_data_t
*,
160 crypto_req_handle_t
);
161 static int md5_digest_update(crypto_ctx_t
*, crypto_data_t
*,
162 crypto_req_handle_t
);
163 static int md5_digest_final(crypto_ctx_t
*, crypto_data_t
*,
164 crypto_req_handle_t
);
165 static int md5_digest_atomic(crypto_provider_handle_t
, crypto_session_id_t
,
166 crypto_mechanism_t
*, crypto_data_t
*, crypto_data_t
*,
167 crypto_req_handle_t
);
169 static crypto_digest_ops_t md5_digest_ops
= {
178 static int md5_mac_init(crypto_ctx_t
*, crypto_mechanism_t
*, crypto_key_t
*,
179 crypto_spi_ctx_template_t
, crypto_req_handle_t
);
180 static int md5_mac_update(crypto_ctx_t
*, crypto_data_t
*, crypto_req_handle_t
);
181 static int md5_mac_final(crypto_ctx_t
*, crypto_data_t
*, crypto_req_handle_t
);
182 static int md5_mac_atomic(crypto_provider_handle_t
, crypto_session_id_t
,
183 crypto_mechanism_t
*, crypto_key_t
*, crypto_data_t
*, crypto_data_t
*,
184 crypto_spi_ctx_template_t
, crypto_req_handle_t
);
185 static int md5_mac_verify_atomic(crypto_provider_handle_t
, crypto_session_id_t
,
186 crypto_mechanism_t
*, crypto_key_t
*, crypto_data_t
*, crypto_data_t
*,
187 crypto_spi_ctx_template_t
, crypto_req_handle_t
);
189 static crypto_mac_ops_t md5_mac_ops
= {
195 md5_mac_verify_atomic
198 static int md5_create_ctx_template(crypto_provider_handle_t
,
199 crypto_mechanism_t
*, crypto_key_t
*, crypto_spi_ctx_template_t
*,
200 size_t *, crypto_req_handle_t
);
201 static int md5_free_context(crypto_ctx_t
*);
203 static crypto_ctx_ops_t md5_ctx_ops
= {
204 md5_create_ctx_template
,
208 static crypto_ops_t md5_crypto_ops
= {
225 static crypto_provider_info_t md5_prov_info
= {
226 CRYPTO_SPI_VERSION_1
,
227 "MD5 Software Provider",
232 sizeof (md5_mech_info_tab
)/sizeof (crypto_mech_info_t
),
236 static crypto_kcf_provider_handle_t md5_prov_handle
= 0;
243 if ((ret
= mod_install(&modlinkage
)) != 0)
247 * Register with KCF. If the registration fails, do not uninstall the
248 * module, since the functionality provided by misc/md5 should still be
251 (void) crypto_register_provider(&md5_prov_info
, &md5_prov_handle
);
262 * Unregister from KCF if previous registration succeeded.
264 if (md5_prov_handle
!= 0) {
265 if ((ret
= crypto_unregister_provider(md5_prov_handle
)) !=
272 return (mod_remove(&modlinkage
));
276 _info(struct modinfo
*modinfop
)
278 return (mod_info(&modlinkage
, modinfop
));
282 * KCF software provider control entry points.
286 md5_provider_status(crypto_provider_handle_t provider
, uint_t
*status
)
288 *status
= CRYPTO_PROVIDER_READY
;
292 * KCF software provider digest entry points.
296 md5_digest_init(crypto_ctx_t
*ctx
, crypto_mechanism_t
*mechanism
,
297 crypto_req_handle_t req
)
299 if (mechanism
->cm_type
!= MD5_MECH_INFO_TYPE
)
300 return (CRYPTO_MECHANISM_INVALID
);
303 * Allocate and initialize MD5 context.
305 ctx
->cc_provider_private
= kmem_alloc(sizeof (md5_ctx_t
),
307 if (ctx
->cc_provider_private
== NULL
)
308 return (CRYPTO_HOST_MEMORY
);
310 PROV_MD5_CTX(ctx
)->mc_mech_type
= MD5_MECH_INFO_TYPE
;
311 MD5Init(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
);
313 return (CRYPTO_SUCCESS
);
317 * Helper MD5 digest update function for uio data.
320 md5_digest_update_uio(MD5_CTX
*md5_ctx
, crypto_data_t
*data
)
322 off_t offset
= data
->cd_offset
;
323 size_t length
= data
->cd_length
;
327 /* we support only kernel buffer */
328 if (data
->cd_uio
->uio_segflg
!= UIO_SYSSPACE
)
329 return (CRYPTO_ARGUMENTS_BAD
);
332 * Jump to the first iovec containing data to be
335 for (vec_idx
= 0; vec_idx
< data
->cd_uio
->uio_iovcnt
&&
336 offset
>= data
->cd_uio
->uio_iov
[vec_idx
].iov_len
;
337 offset
-= data
->cd_uio
->uio_iov
[vec_idx
++].iov_len
)
339 if (vec_idx
== data
->cd_uio
->uio_iovcnt
) {
341 * The caller specified an offset that is larger than the
342 * total size of the buffers it provided.
344 return (CRYPTO_DATA_LEN_RANGE
);
348 * Now do the digesting on the iovecs.
350 while (vec_idx
< data
->cd_uio
->uio_iovcnt
&& length
> 0) {
351 cur_len
= MIN(data
->cd_uio
->uio_iov
[vec_idx
].iov_len
-
354 MD5Update(md5_ctx
, data
->cd_uio
->uio_iov
[vec_idx
].iov_base
+
362 if (vec_idx
== data
->cd_uio
->uio_iovcnt
&& length
> 0) {
364 * The end of the specified iovec's was reached but
365 * the length requested could not be processed, i.e.
366 * The caller requested to digest more data than it provided.
368 return (CRYPTO_DATA_LEN_RANGE
);
371 return (CRYPTO_SUCCESS
);
375 * Helper MD5 digest final function for uio data.
376 * digest_len is the length of the desired digest. If digest_len
377 * is smaller than the default MD5 digest length, the caller
378 * must pass a scratch buffer, digest_scratch, which must
379 * be at least MD5_DIGEST_LENGTH bytes.
382 md5_digest_final_uio(MD5_CTX
*md5_ctx
, crypto_data_t
*digest
,
383 ulong_t digest_len
, uchar_t
*digest_scratch
)
385 off_t offset
= digest
->cd_offset
;
388 /* we support only kernel buffer */
389 if (digest
->cd_uio
->uio_segflg
!= UIO_SYSSPACE
)
390 return (CRYPTO_ARGUMENTS_BAD
);
393 * Jump to the first iovec containing ptr to the digest to
396 for (vec_idx
= 0; offset
>= digest
->cd_uio
->uio_iov
[vec_idx
].iov_len
&&
397 vec_idx
< digest
->cd_uio
->uio_iovcnt
;
398 offset
-= digest
->cd_uio
->uio_iov
[vec_idx
++].iov_len
)
400 if (vec_idx
== digest
->cd_uio
->uio_iovcnt
) {
402 * The caller specified an offset that is
403 * larger than the total size of the buffers
406 return (CRYPTO_DATA_LEN_RANGE
);
409 if (offset
+ digest_len
<=
410 digest
->cd_uio
->uio_iov
[vec_idx
].iov_len
) {
412 * The computed MD5 digest will fit in the current
415 if (digest_len
!= MD5_DIGEST_LENGTH
) {
417 * The caller requested a short digest. Digest
418 * into a scratch buffer and return to
419 * the user only what was requested.
421 MD5Final(digest_scratch
, md5_ctx
);
422 bcopy(digest_scratch
, (uchar_t
*)digest
->
423 cd_uio
->uio_iov
[vec_idx
].iov_base
+ offset
,
426 MD5Final((uchar_t
*)digest
->
427 cd_uio
->uio_iov
[vec_idx
].iov_base
+ offset
,
432 * The computed digest will be crossing one or more iovec's.
433 * This is bad performance-wise but we need to support it.
434 * Allocate a small scratch buffer on the stack and
435 * copy it piece meal to the specified digest iovec's.
437 uchar_t digest_tmp
[MD5_DIGEST_LENGTH
];
438 off_t scratch_offset
= 0;
439 size_t length
= digest_len
;
442 MD5Final(digest_tmp
, md5_ctx
);
444 while (vec_idx
< digest
->cd_uio
->uio_iovcnt
&& length
> 0) {
445 cur_len
= MIN(digest
->cd_uio
->uio_iov
[vec_idx
].iov_len
-
447 bcopy(digest_tmp
+ scratch_offset
,
448 digest
->cd_uio
->uio_iov
[vec_idx
].iov_base
+ offset
,
453 scratch_offset
+= cur_len
;
457 if (vec_idx
== digest
->cd_uio
->uio_iovcnt
&& length
> 0) {
459 * The end of the specified iovec's was reached but
460 * the length requested could not be processed, i.e.
461 * The caller requested to digest more data than it
464 return (CRYPTO_DATA_LEN_RANGE
);
468 return (CRYPTO_SUCCESS
);
472 * Helper MD5 digest update for mblk's.
475 md5_digest_update_mblk(MD5_CTX
*md5_ctx
, crypto_data_t
*data
)
477 off_t offset
= data
->cd_offset
;
478 size_t length
= data
->cd_length
;
483 * Jump to the first mblk_t containing data to be digested.
485 for (mp
= data
->cd_mp
; mp
!= NULL
&& offset
>= MBLKL(mp
);
486 offset
-= MBLKL(mp
), mp
= mp
->b_cont
)
490 * The caller specified an offset that is larger than the
491 * total size of the buffers it provided.
493 return (CRYPTO_DATA_LEN_RANGE
);
497 * Now do the digesting on the mblk chain.
499 while (mp
!= NULL
&& length
> 0) {
500 cur_len
= MIN(MBLKL(mp
) - offset
, length
);
501 MD5Update(md5_ctx
, mp
->b_rptr
+ offset
, cur_len
);
507 if (mp
== NULL
&& length
> 0) {
509 * The end of the mblk was reached but the length requested
510 * could not be processed, i.e. The caller requested
511 * to digest more data than it provided.
513 return (CRYPTO_DATA_LEN_RANGE
);
516 return (CRYPTO_SUCCESS
);
520 * Helper MD5 digest final for mblk's.
521 * digest_len is the length of the desired digest. If digest_len
522 * is smaller than the default MD5 digest length, the caller
523 * must pass a scratch buffer, digest_scratch, which must
524 * be at least MD5_DIGEST_LENGTH bytes.
527 md5_digest_final_mblk(MD5_CTX
*md5_ctx
, crypto_data_t
*digest
,
528 ulong_t digest_len
, uchar_t
*digest_scratch
)
530 off_t offset
= digest
->cd_offset
;
534 * Jump to the first mblk_t that will be used to store the digest.
536 for (mp
= digest
->cd_mp
; mp
!= NULL
&& offset
>= MBLKL(mp
);
537 offset
-= MBLKL(mp
), mp
= mp
->b_cont
)
541 * The caller specified an offset that is larger than the
542 * total size of the buffers it provided.
544 return (CRYPTO_DATA_LEN_RANGE
);
547 if (offset
+ digest_len
<= MBLKL(mp
)) {
549 * The computed MD5 digest will fit in the current mblk.
550 * Do the MD5Final() in-place.
552 if (digest_len
!= MD5_DIGEST_LENGTH
) {
554 * The caller requested a short digest. Digest
555 * into a scratch buffer and return to
556 * the user only what was requested.
558 MD5Final(digest_scratch
, md5_ctx
);
559 bcopy(digest_scratch
, mp
->b_rptr
+ offset
, digest_len
);
561 MD5Final(mp
->b_rptr
+ offset
, md5_ctx
);
565 * The computed digest will be crossing one or more mblk's.
566 * This is bad performance-wise but we need to support it.
567 * Allocate a small scratch buffer on the stack and
568 * copy it piece meal to the specified digest iovec's.
570 uchar_t digest_tmp
[MD5_DIGEST_LENGTH
];
571 off_t scratch_offset
= 0;
572 size_t length
= digest_len
;
575 MD5Final(digest_tmp
, md5_ctx
);
577 while (mp
!= NULL
&& length
> 0) {
578 cur_len
= MIN(MBLKL(mp
) - offset
, length
);
579 bcopy(digest_tmp
+ scratch_offset
,
580 mp
->b_rptr
+ offset
, cur_len
);
584 scratch_offset
+= cur_len
;
588 if (mp
== NULL
&& length
> 0) {
590 * The end of the specified mblk was reached but
591 * the length requested could not be processed, i.e.
592 * The caller requested to digest more data than it
595 return (CRYPTO_DATA_LEN_RANGE
);
599 return (CRYPTO_SUCCESS
);
604 md5_digest(crypto_ctx_t
*ctx
, crypto_data_t
*data
, crypto_data_t
*digest
,
605 crypto_req_handle_t req
)
607 int ret
= CRYPTO_SUCCESS
;
609 ASSERT(ctx
->cc_provider_private
!= NULL
);
612 * We need to just return the length needed to store the output.
613 * We should not destroy the context for the following cases.
615 if ((digest
->cd_length
== 0) ||
616 (digest
->cd_length
< MD5_DIGEST_LENGTH
)) {
617 digest
->cd_length
= MD5_DIGEST_LENGTH
;
618 return (CRYPTO_BUFFER_TOO_SMALL
);
622 * Do the MD5 update on the specified input data.
624 switch (data
->cd_format
) {
625 case CRYPTO_DATA_RAW
:
626 MD5Update(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
627 data
->cd_raw
.iov_base
+ data
->cd_offset
,
630 case CRYPTO_DATA_UIO
:
631 ret
= md5_digest_update_uio(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
634 case CRYPTO_DATA_MBLK
:
635 ret
= md5_digest_update_mblk(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
639 ret
= CRYPTO_ARGUMENTS_BAD
;
642 if (ret
!= CRYPTO_SUCCESS
) {
643 /* the update failed, free context and bail */
644 kmem_free(ctx
->cc_provider_private
, sizeof (md5_ctx_t
));
645 ctx
->cc_provider_private
= NULL
;
646 digest
->cd_length
= 0;
651 * Do an MD5 final, must be done separately since the digest
652 * type can be different than the input data type.
654 switch (digest
->cd_format
) {
655 case CRYPTO_DATA_RAW
:
656 MD5Final((unsigned char *)digest
->cd_raw
.iov_base
+
657 digest
->cd_offset
, &PROV_MD5_CTX(ctx
)->mc_md5_ctx
);
659 case CRYPTO_DATA_UIO
:
660 ret
= md5_digest_final_uio(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
661 digest
, MD5_DIGEST_LENGTH
, NULL
);
663 case CRYPTO_DATA_MBLK
:
664 ret
= md5_digest_final_mblk(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
665 digest
, MD5_DIGEST_LENGTH
, NULL
);
668 ret
= CRYPTO_ARGUMENTS_BAD
;
671 /* all done, free context and return */
673 if (ret
== CRYPTO_SUCCESS
) {
674 digest
->cd_length
= MD5_DIGEST_LENGTH
;
676 digest
->cd_length
= 0;
679 kmem_free(ctx
->cc_provider_private
, sizeof (md5_ctx_t
));
680 ctx
->cc_provider_private
= NULL
;
686 md5_digest_update(crypto_ctx_t
*ctx
, crypto_data_t
*data
,
687 crypto_req_handle_t req
)
689 int ret
= CRYPTO_SUCCESS
;
691 ASSERT(ctx
->cc_provider_private
!= NULL
);
694 * Do the MD5 update on the specified input data.
696 switch (data
->cd_format
) {
697 case CRYPTO_DATA_RAW
:
698 MD5Update(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
699 data
->cd_raw
.iov_base
+ data
->cd_offset
,
702 case CRYPTO_DATA_UIO
:
703 ret
= md5_digest_update_uio(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
706 case CRYPTO_DATA_MBLK
:
707 ret
= md5_digest_update_mblk(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
711 ret
= CRYPTO_ARGUMENTS_BAD
;
719 md5_digest_final(crypto_ctx_t
*ctx
, crypto_data_t
*digest
,
720 crypto_req_handle_t req
)
722 int ret
= CRYPTO_SUCCESS
;
724 ASSERT(ctx
->cc_provider_private
!= NULL
);
727 * We need to just return the length needed to store the output.
728 * We should not destroy the context for the following cases.
730 if ((digest
->cd_length
== 0) ||
731 (digest
->cd_length
< MD5_DIGEST_LENGTH
)) {
732 digest
->cd_length
= MD5_DIGEST_LENGTH
;
733 return (CRYPTO_BUFFER_TOO_SMALL
);
739 switch (digest
->cd_format
) {
740 case CRYPTO_DATA_RAW
:
741 MD5Final((unsigned char *)digest
->cd_raw
.iov_base
+
742 digest
->cd_offset
, &PROV_MD5_CTX(ctx
)->mc_md5_ctx
);
744 case CRYPTO_DATA_UIO
:
745 ret
= md5_digest_final_uio(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
746 digest
, MD5_DIGEST_LENGTH
, NULL
);
748 case CRYPTO_DATA_MBLK
:
749 ret
= md5_digest_final_mblk(&PROV_MD5_CTX(ctx
)->mc_md5_ctx
,
750 digest
, MD5_DIGEST_LENGTH
, NULL
);
753 ret
= CRYPTO_ARGUMENTS_BAD
;
756 /* all done, free context and return */
758 if (ret
== CRYPTO_SUCCESS
) {
759 digest
->cd_length
= MD5_DIGEST_LENGTH
;
761 digest
->cd_length
= 0;
764 kmem_free(ctx
->cc_provider_private
, sizeof (md5_ctx_t
));
765 ctx
->cc_provider_private
= NULL
;
772 md5_digest_atomic(crypto_provider_handle_t provider
,
773 crypto_session_id_t session_id
, crypto_mechanism_t
*mechanism
,
774 crypto_data_t
*data
, crypto_data_t
*digest
,
775 crypto_req_handle_t req
)
777 int ret
= CRYPTO_SUCCESS
;
780 if (mechanism
->cm_type
!= MD5_MECH_INFO_TYPE
)
781 return (CRYPTO_MECHANISM_INVALID
);
789 * Do the MD5 update on the specified input data.
791 switch (data
->cd_format
) {
792 case CRYPTO_DATA_RAW
:
793 MD5Update(&md5_ctx
, data
->cd_raw
.iov_base
+ data
->cd_offset
,
796 case CRYPTO_DATA_UIO
:
797 ret
= md5_digest_update_uio(&md5_ctx
, data
);
799 case CRYPTO_DATA_MBLK
:
800 ret
= md5_digest_update_mblk(&md5_ctx
, data
);
803 ret
= CRYPTO_ARGUMENTS_BAD
;
806 if (ret
!= CRYPTO_SUCCESS
) {
807 /* the update failed, bail */
808 digest
->cd_length
= 0;
813 * Do an MD5 final, must be done separately since the digest
814 * type can be different than the input data type.
816 switch (digest
->cd_format
) {
817 case CRYPTO_DATA_RAW
:
818 MD5Final((unsigned char *)digest
->cd_raw
.iov_base
+
819 digest
->cd_offset
, &md5_ctx
);
821 case CRYPTO_DATA_UIO
:
822 ret
= md5_digest_final_uio(&md5_ctx
, digest
,
823 MD5_DIGEST_LENGTH
, NULL
);
825 case CRYPTO_DATA_MBLK
:
826 ret
= md5_digest_final_mblk(&md5_ctx
, digest
,
827 MD5_DIGEST_LENGTH
, NULL
);
830 ret
= CRYPTO_ARGUMENTS_BAD
;
833 if (ret
== CRYPTO_SUCCESS
) {
834 digest
->cd_length
= MD5_DIGEST_LENGTH
;
836 digest
->cd_length
= 0;
843 * KCF software provider mac entry points.
845 * MD5 HMAC is: MD5(key XOR opad, MD5(key XOR ipad, text))
848 * The initialization routine initializes what we denote
849 * as the inner and outer contexts by doing
850 * - for inner context: MD5(key XOR ipad)
851 * - for outer context: MD5(key XOR opad)
854 * Each subsequent MD5 HMAC update will result in an
855 * update of the inner context with the specified data.
858 * The MD5 HMAC final will do a MD5 final operation on the
859 * inner context, and the resulting digest will be used
860 * as the data for an update on the outer context. Last
861 * but not least, an MD5 final on the outer context will
862 * be performed to obtain the MD5 HMAC digest to return
867 * Initialize a MD5-HMAC context.
870 md5_mac_init_ctx(md5_hmac_ctx_t
*ctx
, void *keyval
, uint_t length_in_bytes
)
872 uint32_t ipad
[MD5_HMAC_INTS_PER_BLOCK
];
873 uint32_t opad
[MD5_HMAC_INTS_PER_BLOCK
];
876 bzero(ipad
, MD5_HMAC_BLOCK_SIZE
);
877 bzero(opad
, MD5_HMAC_BLOCK_SIZE
);
879 bcopy(keyval
, ipad
, length_in_bytes
);
880 bcopy(keyval
, opad
, length_in_bytes
);
882 /* XOR key with ipad (0x36) and opad (0x5c) */
883 for (i
= 0; i
< MD5_HMAC_INTS_PER_BLOCK
; i
++) {
884 ipad
[i
] ^= 0x36363636;
885 opad
[i
] ^= 0x5c5c5c5c;
888 /* perform MD5 on ipad */
889 MD5Init(&ctx
->hc_icontext
);
890 MD5Update(&ctx
->hc_icontext
, ipad
, MD5_HMAC_BLOCK_SIZE
);
892 /* perform MD5 on opad */
893 MD5Init(&ctx
->hc_ocontext
);
894 MD5Update(&ctx
->hc_ocontext
, opad
, MD5_HMAC_BLOCK_SIZE
);
898 * Initializes a multi-part MAC operation.
901 md5_mac_init(crypto_ctx_t
*ctx
, crypto_mechanism_t
*mechanism
,
902 crypto_key_t
*key
, crypto_spi_ctx_template_t ctx_template
,
903 crypto_req_handle_t req
)
905 int ret
= CRYPTO_SUCCESS
;
906 uint_t keylen_in_bytes
= CRYPTO_BITS2BYTES(key
->ck_length
);
908 if (mechanism
->cm_type
!= MD5_HMAC_MECH_INFO_TYPE
&&
909 mechanism
->cm_type
!= MD5_HMAC_GEN_MECH_INFO_TYPE
)
910 return (CRYPTO_MECHANISM_INVALID
);
912 /* Add support for key by attributes (RFE 4706552) */
913 if (key
->ck_format
!= CRYPTO_KEY_RAW
)
914 return (CRYPTO_ARGUMENTS_BAD
);
916 ctx
->cc_provider_private
= kmem_alloc(sizeof (md5_hmac_ctx_t
),
918 if (ctx
->cc_provider_private
== NULL
)
919 return (CRYPTO_HOST_MEMORY
);
921 if (ctx_template
!= NULL
) {
922 /* reuse context template */
923 bcopy(ctx_template
, PROV_MD5_HMAC_CTX(ctx
),
924 sizeof (md5_hmac_ctx_t
));
926 /* no context template, compute context */
927 if (keylen_in_bytes
> MD5_HMAC_BLOCK_SIZE
) {
928 uchar_t digested_key
[MD5_DIGEST_LENGTH
];
929 md5_hmac_ctx_t
*hmac_ctx
= ctx
->cc_provider_private
;
932 * Hash the passed-in key to get a smaller key.
933 * The inner context is used since it hasn't been
936 PROV_MD5_DIGEST_KEY(&hmac_ctx
->hc_icontext
,
937 key
->ck_data
, keylen_in_bytes
, digested_key
);
938 md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx
),
939 digested_key
, MD5_DIGEST_LENGTH
);
941 md5_mac_init_ctx(PROV_MD5_HMAC_CTX(ctx
),
942 key
->ck_data
, keylen_in_bytes
);
947 * Get the mechanism parameters, if applicable.
949 PROV_MD5_HMAC_CTX(ctx
)->hc_mech_type
= mechanism
->cm_type
;
950 if (mechanism
->cm_type
== MD5_HMAC_GEN_MECH_INFO_TYPE
) {
951 if (mechanism
->cm_param
== NULL
||
952 mechanism
->cm_param_len
!= sizeof (ulong_t
))
953 ret
= CRYPTO_MECHANISM_PARAM_INVALID
;
954 PROV_MD5_GET_DIGEST_LEN(mechanism
,
955 PROV_MD5_HMAC_CTX(ctx
)->hc_digest_len
);
956 if (PROV_MD5_HMAC_CTX(ctx
)->hc_digest_len
>
958 ret
= CRYPTO_MECHANISM_PARAM_INVALID
;
961 if (ret
!= CRYPTO_SUCCESS
) {
962 bzero(ctx
->cc_provider_private
, sizeof (md5_hmac_ctx_t
));
963 kmem_free(ctx
->cc_provider_private
, sizeof (md5_hmac_ctx_t
));
964 ctx
->cc_provider_private
= NULL
;
973 md5_mac_update(crypto_ctx_t
*ctx
, crypto_data_t
*data
, crypto_req_handle_t req
)
975 int ret
= CRYPTO_SUCCESS
;
977 ASSERT(ctx
->cc_provider_private
!= NULL
);
980 * Do an MD5 update of the inner context using the specified
983 switch (data
->cd_format
) {
984 case CRYPTO_DATA_RAW
:
985 MD5Update(&PROV_MD5_HMAC_CTX(ctx
)->hc_icontext
,
986 data
->cd_raw
.iov_base
+ data
->cd_offset
,
989 case CRYPTO_DATA_UIO
:
990 ret
= md5_digest_update_uio(
991 &PROV_MD5_HMAC_CTX(ctx
)->hc_icontext
, data
);
993 case CRYPTO_DATA_MBLK
:
994 ret
= md5_digest_update_mblk(
995 &PROV_MD5_HMAC_CTX(ctx
)->hc_icontext
, data
);
998 ret
= CRYPTO_ARGUMENTS_BAD
;
1006 md5_mac_final(crypto_ctx_t
*ctx
, crypto_data_t
*mac
, crypto_req_handle_t req
)
1008 int ret
= CRYPTO_SUCCESS
;
1009 uchar_t digest
[MD5_DIGEST_LENGTH
];
1010 uint32_t digest_len
= MD5_DIGEST_LENGTH
;
1012 ASSERT(ctx
->cc_provider_private
!= NULL
);
1014 if (PROV_MD5_HMAC_CTX(ctx
)->hc_mech_type
== MD5_HMAC_GEN_MECH_INFO_TYPE
)
1015 digest_len
= PROV_MD5_HMAC_CTX(ctx
)->hc_digest_len
;
1018 * We need to just return the length needed to store the output.
1019 * We should not destroy the context for the following cases.
1021 if ((mac
->cd_length
== 0) || (mac
->cd_length
< digest_len
)) {
1022 mac
->cd_length
= digest_len
;
1023 return (CRYPTO_BUFFER_TOO_SMALL
);
1027 * Do an MD5 final on the inner context.
1029 MD5Final(digest
, &PROV_MD5_HMAC_CTX(ctx
)->hc_icontext
);
1032 * Do an MD5 update on the outer context, feeding the inner
1035 MD5Update(&PROV_MD5_HMAC_CTX(ctx
)->hc_ocontext
, digest
,
1039 * Do an MD5 final on the outer context, storing the computing
1040 * digest in the users buffer.
1042 switch (mac
->cd_format
) {
1043 case CRYPTO_DATA_RAW
:
1044 if (digest_len
!= MD5_DIGEST_LENGTH
) {
1046 * The caller requested a short digest. Digest
1047 * into a scratch buffer and return to
1048 * the user only what was requested.
1051 &PROV_MD5_HMAC_CTX(ctx
)->hc_ocontext
);
1052 bcopy(digest
, (unsigned char *)mac
->cd_raw
.iov_base
+
1053 mac
->cd_offset
, digest_len
);
1055 MD5Final((unsigned char *)mac
->cd_raw
.iov_base
+
1057 &PROV_MD5_HMAC_CTX(ctx
)->hc_ocontext
);
1060 case CRYPTO_DATA_UIO
:
1061 ret
= md5_digest_final_uio(
1062 &PROV_MD5_HMAC_CTX(ctx
)->hc_ocontext
, mac
,
1063 digest_len
, digest
);
1065 case CRYPTO_DATA_MBLK
:
1066 ret
= md5_digest_final_mblk(
1067 &PROV_MD5_HMAC_CTX(ctx
)->hc_ocontext
, mac
,
1068 digest_len
, digest
);
1071 ret
= CRYPTO_ARGUMENTS_BAD
;
1074 if (ret
== CRYPTO_SUCCESS
) {
1075 mac
->cd_length
= digest_len
;
1080 bzero(ctx
->cc_provider_private
, sizeof (md5_hmac_ctx_t
));
1081 kmem_free(ctx
->cc_provider_private
, sizeof (md5_hmac_ctx_t
));
1082 ctx
->cc_provider_private
= NULL
;
1087 #define MD5_MAC_UPDATE(data, ctx, ret) { \
1088 switch (data->cd_format) { \
1089 case CRYPTO_DATA_RAW: \
1090 MD5Update(&(ctx).hc_icontext, \
1091 data->cd_raw.iov_base + data->cd_offset, \
1094 case CRYPTO_DATA_UIO: \
1095 ret = md5_digest_update_uio(&(ctx).hc_icontext, data); \
1097 case CRYPTO_DATA_MBLK: \
1098 ret = md5_digest_update_mblk(&(ctx).hc_icontext, \
1102 ret = CRYPTO_ARGUMENTS_BAD; \
1109 md5_mac_atomic(crypto_provider_handle_t provider
,
1110 crypto_session_id_t session_id
, crypto_mechanism_t
*mechanism
,
1111 crypto_key_t
*key
, crypto_data_t
*data
, crypto_data_t
*mac
,
1112 crypto_spi_ctx_template_t ctx_template
, crypto_req_handle_t req
)
1114 int ret
= CRYPTO_SUCCESS
;
1115 uchar_t digest
[MD5_DIGEST_LENGTH
];
1116 md5_hmac_ctx_t md5_hmac_ctx
;
1117 uint32_t digest_len
= MD5_DIGEST_LENGTH
;
1118 uint_t keylen_in_bytes
= CRYPTO_BITS2BYTES(key
->ck_length
);
1120 if (mechanism
->cm_type
!= MD5_HMAC_MECH_INFO_TYPE
&&
1121 mechanism
->cm_type
!= MD5_HMAC_GEN_MECH_INFO_TYPE
)
1122 return (CRYPTO_MECHANISM_INVALID
);
1124 /* Add support for key by attributes (RFE 4706552) */
1125 if (key
->ck_format
!= CRYPTO_KEY_RAW
)
1126 return (CRYPTO_ARGUMENTS_BAD
);
1128 if (ctx_template
!= NULL
) {
1129 /* reuse context template */
1130 bcopy(ctx_template
, &md5_hmac_ctx
, sizeof (md5_hmac_ctx_t
));
1132 /* no context template, compute context */
1133 if (keylen_in_bytes
> MD5_HMAC_BLOCK_SIZE
) {
1135 * Hash the passed-in key to get a smaller key.
1136 * The inner context is used since it hasn't been
1139 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx
.hc_icontext
,
1140 key
->ck_data
, keylen_in_bytes
, digest
);
1141 md5_mac_init_ctx(&md5_hmac_ctx
, digest
,
1144 md5_mac_init_ctx(&md5_hmac_ctx
, key
->ck_data
,
1150 * Get the mechanism parameters, if applicable.
1152 if (mechanism
->cm_type
== MD5_HMAC_GEN_MECH_INFO_TYPE
) {
1153 if (mechanism
->cm_param
== NULL
||
1154 mechanism
->cm_param_len
!= sizeof (ulong_t
)) {
1155 ret
= CRYPTO_MECHANISM_PARAM_INVALID
;
1158 PROV_MD5_GET_DIGEST_LEN(mechanism
, digest_len
);
1159 if (digest_len
> MD5_DIGEST_LENGTH
) {
1160 ret
= CRYPTO_MECHANISM_PARAM_INVALID
;
1165 /* do an MD5 update of the inner context using the specified data */
1166 MD5_MAC_UPDATE(data
, md5_hmac_ctx
, ret
);
1167 if (ret
!= CRYPTO_SUCCESS
)
1168 /* the update failed, free context and bail */
1171 /* do an MD5 final on the inner context */
1172 MD5Final(digest
, &md5_hmac_ctx
.hc_icontext
);
1175 * Do an MD5 update on the outer context, feeding the inner
1178 MD5Update(&md5_hmac_ctx
.hc_ocontext
, digest
, MD5_DIGEST_LENGTH
);
1181 * Do an MD5 final on the outer context, storing the computed
1182 * digest in the users buffer.
1184 switch (mac
->cd_format
) {
1185 case CRYPTO_DATA_RAW
:
1186 if (digest_len
!= MD5_DIGEST_LENGTH
) {
1188 * The caller requested a short digest. Digest
1189 * into a scratch buffer and return to
1190 * the user only what was requested.
1192 MD5Final(digest
, &md5_hmac_ctx
.hc_ocontext
);
1193 bcopy(digest
, (unsigned char *)mac
->cd_raw
.iov_base
+
1194 mac
->cd_offset
, digest_len
);
1196 MD5Final((unsigned char *)mac
->cd_raw
.iov_base
+
1197 mac
->cd_offset
, &md5_hmac_ctx
.hc_ocontext
);
1200 case CRYPTO_DATA_UIO
:
1201 ret
= md5_digest_final_uio(&md5_hmac_ctx
.hc_ocontext
, mac
,
1202 digest_len
, digest
);
1204 case CRYPTO_DATA_MBLK
:
1205 ret
= md5_digest_final_mblk(&md5_hmac_ctx
.hc_ocontext
, mac
,
1206 digest_len
, digest
);
1209 ret
= CRYPTO_ARGUMENTS_BAD
;
1212 if (ret
== CRYPTO_SUCCESS
) {
1213 mac
->cd_length
= digest_len
;
1217 /* Extra paranoia: zeroizing the local context on the stack */
1218 bzero(&md5_hmac_ctx
, sizeof (md5_hmac_ctx_t
));
1222 bzero(&md5_hmac_ctx
, sizeof (md5_hmac_ctx_t
));
1229 md5_mac_verify_atomic(crypto_provider_handle_t provider
,
1230 crypto_session_id_t session_id
, crypto_mechanism_t
*mechanism
,
1231 crypto_key_t
*key
, crypto_data_t
*data
, crypto_data_t
*mac
,
1232 crypto_spi_ctx_template_t ctx_template
, crypto_req_handle_t req
)
1234 int ret
= CRYPTO_SUCCESS
;
1235 uchar_t digest
[MD5_DIGEST_LENGTH
];
1236 md5_hmac_ctx_t md5_hmac_ctx
;
1237 uint32_t digest_len
= MD5_DIGEST_LENGTH
;
1238 uint_t keylen_in_bytes
= CRYPTO_BITS2BYTES(key
->ck_length
);
1240 if (mechanism
->cm_type
!= MD5_HMAC_MECH_INFO_TYPE
&&
1241 mechanism
->cm_type
!= MD5_HMAC_GEN_MECH_INFO_TYPE
)
1242 return (CRYPTO_MECHANISM_INVALID
);
1244 /* Add support for key by attributes (RFE 4706552) */
1245 if (key
->ck_format
!= CRYPTO_KEY_RAW
)
1246 return (CRYPTO_ARGUMENTS_BAD
);
1248 if (ctx_template
!= NULL
) {
1249 /* reuse context template */
1250 bcopy(ctx_template
, &md5_hmac_ctx
, sizeof (md5_hmac_ctx_t
));
1252 /* no context template, compute context */
1253 if (keylen_in_bytes
> MD5_HMAC_BLOCK_SIZE
) {
1255 * Hash the passed-in key to get a smaller key.
1256 * The inner context is used since it hasn't been
1259 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx
.hc_icontext
,
1260 key
->ck_data
, keylen_in_bytes
, digest
);
1261 md5_mac_init_ctx(&md5_hmac_ctx
, digest
,
1264 md5_mac_init_ctx(&md5_hmac_ctx
, key
->ck_data
,
1270 * Get the mechanism parameters, if applicable.
1272 if (mechanism
->cm_type
== MD5_HMAC_GEN_MECH_INFO_TYPE
) {
1273 if (mechanism
->cm_param
== NULL
||
1274 mechanism
->cm_param_len
!= sizeof (ulong_t
)) {
1275 ret
= CRYPTO_MECHANISM_PARAM_INVALID
;
1278 PROV_MD5_GET_DIGEST_LEN(mechanism
, digest_len
);
1279 if (digest_len
> MD5_DIGEST_LENGTH
) {
1280 ret
= CRYPTO_MECHANISM_PARAM_INVALID
;
1285 if (mac
->cd_length
!= digest_len
) {
1286 ret
= CRYPTO_INVALID_MAC
;
1290 /* do an MD5 update of the inner context using the specified data */
1291 MD5_MAC_UPDATE(data
, md5_hmac_ctx
, ret
);
1292 if (ret
!= CRYPTO_SUCCESS
)
1293 /* the update failed, free context and bail */
1296 /* do an MD5 final on the inner context */
1297 MD5Final(digest
, &md5_hmac_ctx
.hc_icontext
);
1300 * Do an MD5 update on the outer context, feeding the inner
1303 MD5Update(&md5_hmac_ctx
.hc_ocontext
, digest
, MD5_DIGEST_LENGTH
);
1306 * Do an MD5 final on the outer context, storing the computed
1307 * digest in the local digest buffer.
1309 MD5Final(digest
, &md5_hmac_ctx
.hc_ocontext
);
1312 * Compare the computed digest against the expected digest passed
1315 switch (mac
->cd_format
) {
1317 case CRYPTO_DATA_RAW
:
1318 if (bcmp(digest
, (unsigned char *)mac
->cd_raw
.iov_base
+
1319 mac
->cd_offset
, digest_len
) != 0)
1320 ret
= CRYPTO_INVALID_MAC
;
1323 case CRYPTO_DATA_UIO
: {
1324 off_t offset
= mac
->cd_offset
;
1326 off_t scratch_offset
= 0;
1327 size_t length
= digest_len
;
1330 /* we support only kernel buffer */
1331 if (mac
->cd_uio
->uio_segflg
!= UIO_SYSSPACE
)
1332 return (CRYPTO_ARGUMENTS_BAD
);
1334 /* jump to the first iovec containing the expected digest */
1336 offset
>= mac
->cd_uio
->uio_iov
[vec_idx
].iov_len
&&
1337 vec_idx
< mac
->cd_uio
->uio_iovcnt
;
1338 offset
-= mac
->cd_uio
->uio_iov
[vec_idx
++].iov_len
)
1340 if (vec_idx
== mac
->cd_uio
->uio_iovcnt
) {
1342 * The caller specified an offset that is
1343 * larger than the total size of the buffers
1346 ret
= CRYPTO_DATA_LEN_RANGE
;
1350 /* do the comparison of computed digest vs specified one */
1351 while (vec_idx
< mac
->cd_uio
->uio_iovcnt
&& length
> 0) {
1352 cur_len
= MIN(mac
->cd_uio
->uio_iov
[vec_idx
].iov_len
-
1355 if (bcmp(digest
+ scratch_offset
,
1356 mac
->cd_uio
->uio_iov
[vec_idx
].iov_base
+ offset
,
1358 ret
= CRYPTO_INVALID_MAC
;
1364 scratch_offset
+= cur_len
;
1370 case CRYPTO_DATA_MBLK
: {
1371 off_t offset
= mac
->cd_offset
;
1373 off_t scratch_offset
= 0;
1374 size_t length
= digest_len
;
1377 /* jump to the first mblk_t containing the expected digest */
1378 for (mp
= mac
->cd_mp
; mp
!= NULL
&& offset
>= MBLKL(mp
);
1379 offset
-= MBLKL(mp
), mp
= mp
->b_cont
)
1383 * The caller specified an offset that is larger than
1384 * the total size of the buffers it provided.
1386 ret
= CRYPTO_DATA_LEN_RANGE
;
1390 while (mp
!= NULL
&& length
> 0) {
1391 cur_len
= MIN(MBLKL(mp
) - offset
, length
);
1392 if (bcmp(digest
+ scratch_offset
,
1393 mp
->b_rptr
+ offset
, cur_len
) != 0) {
1394 ret
= CRYPTO_INVALID_MAC
;
1400 scratch_offset
+= cur_len
;
1407 ret
= CRYPTO_ARGUMENTS_BAD
;
1410 bzero(&md5_hmac_ctx
, sizeof (md5_hmac_ctx_t
));
1413 bzero(&md5_hmac_ctx
, sizeof (md5_hmac_ctx_t
));
1419 * KCF software provider context management entry points.
1424 md5_create_ctx_template(crypto_provider_handle_t provider
,
1425 crypto_mechanism_t
*mechanism
, crypto_key_t
*key
,
1426 crypto_spi_ctx_template_t
*ctx_template
, size_t *ctx_template_size
,
1427 crypto_req_handle_t req
)
1429 md5_hmac_ctx_t
*md5_hmac_ctx_tmpl
;
1430 uint_t keylen_in_bytes
= CRYPTO_BITS2BYTES(key
->ck_length
);
1432 if ((mechanism
->cm_type
!= MD5_HMAC_MECH_INFO_TYPE
) &&
1433 (mechanism
->cm_type
!= MD5_HMAC_GEN_MECH_INFO_TYPE
))
1434 return (CRYPTO_MECHANISM_INVALID
);
1436 /* Add support for key by attributes (RFE 4706552) */
1437 if (key
->ck_format
!= CRYPTO_KEY_RAW
)
1438 return (CRYPTO_ARGUMENTS_BAD
);
1441 * Allocate and initialize MD5 context.
1443 md5_hmac_ctx_tmpl
= kmem_alloc(sizeof (md5_hmac_ctx_t
),
1444 crypto_kmflag(req
));
1445 if (md5_hmac_ctx_tmpl
== NULL
)
1446 return (CRYPTO_HOST_MEMORY
);
1448 if (keylen_in_bytes
> MD5_HMAC_BLOCK_SIZE
) {
1449 uchar_t digested_key
[MD5_DIGEST_LENGTH
];
1452 * Hash the passed-in key to get a smaller key.
1453 * The inner context is used since it hasn't been
1456 PROV_MD5_DIGEST_KEY(&md5_hmac_ctx_tmpl
->hc_icontext
,
1457 key
->ck_data
, keylen_in_bytes
, digested_key
);
1458 md5_mac_init_ctx(md5_hmac_ctx_tmpl
, digested_key
,
1461 md5_mac_init_ctx(md5_hmac_ctx_tmpl
, key
->ck_data
,
1465 md5_hmac_ctx_tmpl
->hc_mech_type
= mechanism
->cm_type
;
1466 *ctx_template
= (crypto_spi_ctx_template_t
)md5_hmac_ctx_tmpl
;
1467 *ctx_template_size
= sizeof (md5_hmac_ctx_t
);
1469 return (CRYPTO_SUCCESS
);
1473 md5_free_context(crypto_ctx_t
*ctx
)
1476 md5_mech_type_t mech_type
;
1478 if (ctx
->cc_provider_private
== NULL
)
1479 return (CRYPTO_SUCCESS
);
1482 * We have to free either MD5 or MD5-HMAC contexts, which
1483 * have different lengths.
1486 mech_type
= PROV_MD5_CTX(ctx
)->mc_mech_type
;
1487 if (mech_type
== MD5_MECH_INFO_TYPE
)
1488 ctx_len
= sizeof (md5_ctx_t
);
1490 ASSERT(mech_type
== MD5_HMAC_MECH_INFO_TYPE
||
1491 mech_type
== MD5_HMAC_GEN_MECH_INFO_TYPE
);
1492 ctx_len
= sizeof (md5_hmac_ctx_t
);
1495 bzero(ctx
->cc_provider_private
, ctx_len
);
1496 kmem_free(ctx
->cc_provider_private
, ctx_len
);
1497 ctx
->cc_provider_private
= NULL
;
1499 return (CRYPTO_SUCCESS
);