17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59627968bSmcpowers  * Common Development and Distribution License (the "License").
69627968bSmcpowers  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21726fad2aSDina K Nimeh 
227c478bd9Sstevel@tonic-gate /*
23726fad2aSDina K Nimeh  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24*a8793c76SJason King  * Copyright (c) 2018, Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <pthread.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <strings.h>
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
3323c57df7Smcpowers #include <modes/modes.h>
347c478bd9Sstevel@tonic-gate #include <des_impl.h>
357c478bd9Sstevel@tonic-gate #include "softSession.h"
367c478bd9Sstevel@tonic-gate #include "softObject.h"
377c478bd9Sstevel@tonic-gate #include "softCrypt.h"
387c478bd9Sstevel@tonic-gate #include "softOps.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Allocate context for the active encryption or decryption operation, and
427c478bd9Sstevel@tonic-gate  * generate DES or DES3 key schedule to speed up the operation.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate CK_RV
soft_des_crypt_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t encrypt)457c478bd9Sstevel@tonic-gate soft_des_crypt_init_common(soft_session_t *session_p,
467c478bd9Sstevel@tonic-gate     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
477c478bd9Sstevel@tonic-gate     boolean_t encrypt)
487c478bd9Sstevel@tonic-gate {
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	size_t size;
517c478bd9Sstevel@tonic-gate 	soft_des_ctx_t *soft_des_ctx;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate 	soft_des_ctx = calloc(1, sizeof (soft_des_ctx_t));
547c478bd9Sstevel@tonic-gate 	if (soft_des_ctx == NULL) {
557c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
567c478bd9Sstevel@tonic-gate 	}
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	/* Allocate key schedule for DES or DES3 based on key type. */
597c478bd9Sstevel@tonic-gate 	if (key_p->key_type == CKK_DES)
607c478bd9Sstevel@tonic-gate 		soft_des_ctx->key_sched = des_alloc_keysched(&size, DES, 0);
617c478bd9Sstevel@tonic-gate 	else
627c478bd9Sstevel@tonic-gate 		soft_des_ctx->key_sched = des_alloc_keysched(&size, DES3, 0);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	if (soft_des_ctx->key_sched == NULL) {
657c478bd9Sstevel@tonic-gate 		free(soft_des_ctx);
667c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
677c478bd9Sstevel@tonic-gate 	}
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	soft_des_ctx->keysched_len = size;
707c478bd9Sstevel@tonic-gate 	soft_des_ctx->key_type = key_p->key_type;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
737c478bd9Sstevel@tonic-gate 	if (encrypt) {
747c478bd9Sstevel@tonic-gate 		/* Called by C_EncryptInit. */
757c478bd9Sstevel@tonic-gate 		session_p->encrypt.context = soft_des_ctx;
767c478bd9Sstevel@tonic-gate 		session_p->encrypt.mech.mechanism = pMechanism->mechanism;
777c478bd9Sstevel@tonic-gate 	} else {
787c478bd9Sstevel@tonic-gate 		/* Called by C_DecryptInit. */
797c478bd9Sstevel@tonic-gate 		session_p->decrypt.context = soft_des_ctx;
807c478bd9Sstevel@tonic-gate 		session_p->decrypt.mech.mechanism = pMechanism->mechanism;
817c478bd9Sstevel@tonic-gate 	}
827c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	/*
857c478bd9Sstevel@tonic-gate 	 * If this is a non-sensitive key and it does NOT have
867c478bd9Sstevel@tonic-gate 	 * a key schedule yet, then allocate one and expand it.
877c478bd9Sstevel@tonic-gate 	 * Otherwise, if its a non-sensitive key, and it DOES have
887c478bd9Sstevel@tonic-gate 	 * a key schedule already attached to it, just copy the
897c478bd9Sstevel@tonic-gate 	 * pre-expanded schedule to the context and avoid the
907c478bd9Sstevel@tonic-gate 	 * extra key schedule expansion operation.
917c478bd9Sstevel@tonic-gate 	 */
927c478bd9Sstevel@tonic-gate 	if (!(key_p->bool_attr_mask & SENSITIVE_BOOL_ON)) {
939627968bSmcpowers 		if (OBJ_KEY_SCHED(key_p) == NULL) {
947c478bd9Sstevel@tonic-gate 			void *ks;
959627968bSmcpowers 			(void) pthread_mutex_lock(&key_p->object_mutex);
969627968bSmcpowers 			if (OBJ_KEY_SCHED(key_p) == NULL) {
979627968bSmcpowers 				if (key_p->key_type == CKK_DES)
989627968bSmcpowers 					ks = des_alloc_keysched(&size, DES, 0);
999627968bSmcpowers 				else
1009627968bSmcpowers 					ks = des_alloc_keysched(&size, DES3, 0);
1019627968bSmcpowers 				if (ks == NULL) {
1029627968bSmcpowers 					(void) pthread_mutex_unlock(
1039627968bSmcpowers 					    &key_p->object_mutex);
1049627968bSmcpowers 					free(soft_des_ctx);
1059627968bSmcpowers 					return (CKR_HOST_MEMORY);
1069627968bSmcpowers 				}
1079627968bSmcpowers 				/* Initialize key schedule for DES or DES3. */
1089627968bSmcpowers 				if (key_p->key_type == CKK_DES)
1099627968bSmcpowers 					des_init_keysched(
1109627968bSmcpowers 					    OBJ_SEC(key_p)->sk_value, DES, ks);
1119627968bSmcpowers 				else if (key_p->key_type == CKK_DES2)
1129627968bSmcpowers 					/*
1139627968bSmcpowers 					 * DES3 encryption/decryption needs to
1149627968bSmcpowers 					 * support a DES2 key.
1159627968bSmcpowers 					 */
1169627968bSmcpowers 					des_init_keysched(
1179627968bSmcpowers 					    OBJ_SEC(key_p)->sk_value, DES2, ks);
1189627968bSmcpowers 				else
1199627968bSmcpowers 					des_init_keysched(
1209627968bSmcpowers 					    OBJ_SEC(key_p)->sk_value, DES3, ks);
1219627968bSmcpowers 
1229627968bSmcpowers 				OBJ_KEY_SCHED_LEN(key_p) = size;
1239627968bSmcpowers 				OBJ_KEY_SCHED(key_p) = ks;
1247c478bd9Sstevel@tonic-gate 			}
1259627968bSmcpowers 			(void) pthread_mutex_unlock(&key_p->object_mutex);
1267c478bd9Sstevel@tonic-gate 		}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 		/* Copy the pre-expanded key schedule from the key object */
1297c478bd9Sstevel@tonic-gate 		(void) memcpy(soft_des_ctx->key_sched, OBJ_KEY_SCHED(key_p),
1309627968bSmcpowers 		    OBJ_KEY_SCHED_LEN(key_p));
1317c478bd9Sstevel@tonic-gate 		soft_des_ctx->keysched_len = OBJ_KEY_SCHED_LEN(key_p);
1327c478bd9Sstevel@tonic-gate 	} else {
1337c478bd9Sstevel@tonic-gate 		/* for sensitive keys, we cannot cache the key schedule */
1347c478bd9Sstevel@tonic-gate 		if (key_p->key_type == CKK_DES)
1357c478bd9Sstevel@tonic-gate 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
1369627968bSmcpowers 			    DES, soft_des_ctx->key_sched);
1377c478bd9Sstevel@tonic-gate 		else if (key_p->key_type == CKK_DES2)
1387c478bd9Sstevel@tonic-gate 			/*
1397c478bd9Sstevel@tonic-gate 			 * DES3 encryption/decryption needs to
1407c478bd9Sstevel@tonic-gate 			 * support a DES2 key.
1417c478bd9Sstevel@tonic-gate 			 */
1427c478bd9Sstevel@tonic-gate 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
1439627968bSmcpowers 			    DES2, soft_des_ctx->key_sched);
1447c478bd9Sstevel@tonic-gate 		else
1457c478bd9Sstevel@tonic-gate 			des_init_keysched(OBJ_SEC(key_p)->sk_value,
1469627968bSmcpowers 			    DES3, soft_des_ctx->key_sched);
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * soft_des_encrypt_common()
1557c478bd9Sstevel@tonic-gate  *
1567c478bd9Sstevel@tonic-gate  * Arguments:
1577c478bd9Sstevel@tonic-gate  *      session_p:	pointer to soft_session_t struct
1587c478bd9Sstevel@tonic-gate  *	pData:		pointer to the input data to be encrypted
1597c478bd9Sstevel@tonic-gate  *	ulDataLen:	length of the input data
1607c478bd9Sstevel@tonic-gate  *	pEncrypted:	pointer to the output data after encryption
1617c478bd9Sstevel@tonic-gate  *	pulEncryptedLen: pointer to the length of the output data
1627c478bd9Sstevel@tonic-gate  *	update:		boolean flag indicates caller is soft_encrypt
1637c478bd9Sstevel@tonic-gate  *			or soft_encrypt_update
1647c478bd9Sstevel@tonic-gate  *
1657c478bd9Sstevel@tonic-gate  * Description:
1667c478bd9Sstevel@tonic-gate  *      This function calls the corresponding encrypt routine based
1677c478bd9Sstevel@tonic-gate  *	on the mechanism.
1687c478bd9Sstevel@tonic-gate  *
1697c478bd9Sstevel@tonic-gate  * Returns:
1707c478bd9Sstevel@tonic-gate  *      CKR_OK: success
1717c478bd9Sstevel@tonic-gate  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
1727c478bd9Sstevel@tonic-gate  *			      is too small
1737c478bd9Sstevel@tonic-gate  *	CKR_FUNCTION_FAILED: encrypt function failed
1747c478bd9Sstevel@tonic-gate  *	CKR_DATA_LEN_RANGE: the input data is not a multiple of blocksize
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate CK_RV
soft_des_encrypt_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pEncrypted,CK_ULONG_PTR pulEncryptedLen,boolean_t update)1777c478bd9Sstevel@tonic-gate soft_des_encrypt_common(soft_session_t *session_p, CK_BYTE_PTR pData,
1787c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pEncrypted,
1797c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulEncryptedLen, boolean_t update)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate 	int rc = 0;
1827c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
1837c478bd9Sstevel@tonic-gate 	soft_des_ctx_t *soft_des_ctx =
1847c478bd9Sstevel@tonic-gate 	    (soft_des_ctx_t *)session_p->encrypt.context;
1857c478bd9Sstevel@tonic-gate 	des_ctx_t *des_ctx;
1867c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mechanism = session_p->encrypt.mech.mechanism;
1877c478bd9Sstevel@tonic-gate 	CK_BYTE *in_buf = NULL;
1887c478bd9Sstevel@tonic-gate 	CK_BYTE *out_buf = NULL;
1897c478bd9Sstevel@tonic-gate 	CK_ULONG out_len;
1907c478bd9Sstevel@tonic-gate 	CK_ULONG total_len;
1917c478bd9Sstevel@tonic-gate 	CK_ULONG remain;
1927c478bd9Sstevel@tonic-gate 	boolean_t pad_mechanism = B_FALSE;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
1957c478bd9Sstevel@tonic-gate 	    mechanism == CKM_DES3_CBC_PAD);
1967c478bd9Sstevel@tonic-gate 	/*
1977c478bd9Sstevel@tonic-gate 	 * DES only takes input length that is a multiple of blocksize
1987c478bd9Sstevel@tonic-gate 	 * for C_Encrypt function with the mechanism CKM_DES<n>_ECB or
1997c478bd9Sstevel@tonic-gate 	 * CKM_DES<n>_CBC.
2007c478bd9Sstevel@tonic-gate 	 *
2017c478bd9Sstevel@tonic-gate 	 * DES allows any input length for C_Encrypt function with the
2027c478bd9Sstevel@tonic-gate 	 * mechanism CKM_DES<n>_CBC_PAD and for C_EncryptUpdate function.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	if (!update && !pad_mechanism) {
2057c478bd9Sstevel@tonic-gate 		if ((ulDataLen % DES_BLOCK_LEN) != 0) {
2067c478bd9Sstevel@tonic-gate 			rv = CKR_DATA_LEN_RANGE;
2077c478bd9Sstevel@tonic-gate 			goto cleanup;
2087c478bd9Sstevel@tonic-gate 		}
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	if (!update) {
2127c478bd9Sstevel@tonic-gate 		/*
2137c478bd9Sstevel@tonic-gate 		 * Called by C_Encrypt
2147c478bd9Sstevel@tonic-gate 		 */
2157c478bd9Sstevel@tonic-gate 		if (pad_mechanism) {
2167c478bd9Sstevel@tonic-gate 			/*
2177c478bd9Sstevel@tonic-gate 			 * For CKM_DES<n>_CBC_PAD, compute output length to
2187c478bd9Sstevel@tonic-gate 			 * count for the padding. If the length of input
2197c478bd9Sstevel@tonic-gate 			 * data is a multiple of blocksize, then make output
2207c478bd9Sstevel@tonic-gate 			 * length to be the sum of the input length and
2217c478bd9Sstevel@tonic-gate 			 * one blocksize. Otherwise, output length will
2227c478bd9Sstevel@tonic-gate 			 * be rounded up to the next multiple of blocksize.
2237c478bd9Sstevel@tonic-gate 			 */
2247c478bd9Sstevel@tonic-gate 			out_len = DES_BLOCK_LEN *
2259627968bSmcpowers 			    (ulDataLen / DES_BLOCK_LEN + 1);
2267c478bd9Sstevel@tonic-gate 		} else {
2277c478bd9Sstevel@tonic-gate 			/*
2287c478bd9Sstevel@tonic-gate 			 * For non-padding mode, the output length will
2297c478bd9Sstevel@tonic-gate 			 * be same as the input length.
2307c478bd9Sstevel@tonic-gate 			 */
2317c478bd9Sstevel@tonic-gate 			out_len = ulDataLen;
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		/*
2357c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
2367c478bd9Sstevel@tonic-gate 		 * to hold the ciphertext?
2377c478bd9Sstevel@tonic-gate 		 */
2387c478bd9Sstevel@tonic-gate 		if (pEncrypted == NULL) {
2397c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
2407c478bd9Sstevel@tonic-gate 			return (CKR_OK);
2417c478bd9Sstevel@tonic-gate 		}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
2447c478bd9Sstevel@tonic-gate 		if (*pulEncryptedLen < out_len) {
2457c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
2467c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 		/* Encrypt pad bytes in a separate operation */
2507c478bd9Sstevel@tonic-gate 		if (pad_mechanism) {
2517c478bd9Sstevel@tonic-gate 			out_len -= DES_BLOCK_LEN;
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 		in_buf = pData;
2557c478bd9Sstevel@tonic-gate 		out_buf = pEncrypted;
2567c478bd9Sstevel@tonic-gate 	} else {
2577c478bd9Sstevel@tonic-gate 		/*
2587c478bd9Sstevel@tonic-gate 		 * Called by C_EncryptUpdate
2597c478bd9Sstevel@tonic-gate 		 *
2607c478bd9Sstevel@tonic-gate 		 * Add the lengths of last remaining data and current
2617c478bd9Sstevel@tonic-gate 		 * plaintext together to get the total input length.
2627c478bd9Sstevel@tonic-gate 		 */
2637c478bd9Sstevel@tonic-gate 		total_len = soft_des_ctx->remain_len + ulDataLen;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 		/*
2667c478bd9Sstevel@tonic-gate 		 * If the total input length is less than one blocksize,
2677c478bd9Sstevel@tonic-gate 		 * or if the total input length is just one blocksize and
2687c478bd9Sstevel@tonic-gate 		 * the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
2697c478bd9Sstevel@tonic-gate 		 * encryption until when more data comes in next
2707c478bd9Sstevel@tonic-gate 		 * C_EncryptUpdate or when C_EncryptFinal is called.
2717c478bd9Sstevel@tonic-gate 		 */
2727c478bd9Sstevel@tonic-gate 		if ((total_len < DES_BLOCK_LEN) ||
2737c478bd9Sstevel@tonic-gate 		    (pad_mechanism && (total_len == DES_BLOCK_LEN))) {
2747c478bd9Sstevel@tonic-gate 			if (pData != NULL) {
2757c478bd9Sstevel@tonic-gate 				/*
2767c478bd9Sstevel@tonic-gate 				 * Save input data and its length in
2777c478bd9Sstevel@tonic-gate 				 * the remaining buffer of DES context.
2787c478bd9Sstevel@tonic-gate 				 */
2797c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data +
2807c478bd9Sstevel@tonic-gate 				    soft_des_ctx->remain_len, pData, ulDataLen);
2817c478bd9Sstevel@tonic-gate 				soft_des_ctx->remain_len += ulDataLen;
2827c478bd9Sstevel@tonic-gate 			}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 			/* Set encrypted data length to 0. */
2857c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = 0;
2867c478bd9Sstevel@tonic-gate 			return (CKR_OK);
2877c478bd9Sstevel@tonic-gate 		}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 		/* Compute the length of remaing data. */
2907c478bd9Sstevel@tonic-gate 		remain = total_len % DES_BLOCK_LEN;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		/*
2937c478bd9Sstevel@tonic-gate 		 * Make sure that the output length is a multiple of
2947c478bd9Sstevel@tonic-gate 		 * blocksize.
2957c478bd9Sstevel@tonic-gate 		 */
2967c478bd9Sstevel@tonic-gate 		out_len = total_len - remain;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 		/*
2997c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
3007c478bd9Sstevel@tonic-gate 		 * to hold the ciphertext?
3017c478bd9Sstevel@tonic-gate 		 */
3027c478bd9Sstevel@tonic-gate 		if (pEncrypted == NULL) {
3037c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
3047c478bd9Sstevel@tonic-gate 			return (CKR_OK);
3057c478bd9Sstevel@tonic-gate 		}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
3087c478bd9Sstevel@tonic-gate 		if (*pulEncryptedLen < out_len) {
3097c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
3107c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
3117c478bd9Sstevel@tonic-gate 		}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		if (soft_des_ctx->remain_len != 0) {
3147c478bd9Sstevel@tonic-gate 			/*
3157c478bd9Sstevel@tonic-gate 			 * Copy last remaining data and current input data
3167c478bd9Sstevel@tonic-gate 			 * to the output buffer.
3177c478bd9Sstevel@tonic-gate 			 */
3187c478bd9Sstevel@tonic-gate 			(void) memmove(pEncrypted + soft_des_ctx->remain_len,
3197c478bd9Sstevel@tonic-gate 			    pData, out_len - soft_des_ctx->remain_len);
3207c478bd9Sstevel@tonic-gate 			(void) memcpy(pEncrypted, soft_des_ctx->data,
3217c478bd9Sstevel@tonic-gate 			    soft_des_ctx->remain_len);
3227c478bd9Sstevel@tonic-gate 			bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 			in_buf = pEncrypted;
3257c478bd9Sstevel@tonic-gate 		} else {
3267c478bd9Sstevel@tonic-gate 			in_buf = pData;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 		out_buf = pEncrypted;
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	/*
3327c478bd9Sstevel@tonic-gate 	 * Begin Encryption now.
3337c478bd9Sstevel@tonic-gate 	 */
3347c478bd9Sstevel@tonic-gate 	switch (mechanism) {
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
3377c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
3387c478bd9Sstevel@tonic-gate 	{
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		ulong_t i;
3417c478bd9Sstevel@tonic-gate 		uint8_t *tmp_inbuf;
3427c478bd9Sstevel@tonic-gate 		uint8_t *tmp_outbuf;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
3457c478bd9Sstevel@tonic-gate 			tmp_inbuf = &in_buf[i];
3467c478bd9Sstevel@tonic-gate 			tmp_outbuf = &out_buf[i];
3477c478bd9Sstevel@tonic-gate 			/* Crunch one block of data for DES. */
3487c478bd9Sstevel@tonic-gate 			if (soft_des_ctx->key_type == CKK_DES)
34923c57df7Smcpowers 				(void) des_crunch_block(
35023c57df7Smcpowers 				    soft_des_ctx->key_sched,
3517c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_FALSE);
3527c478bd9Sstevel@tonic-gate 			else
35323c57df7Smcpowers 				(void) des3_crunch_block(
35423c57df7Smcpowers 				    soft_des_ctx->key_sched,
3557c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_FALSE);
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		if (update) {
3597c478bd9Sstevel@tonic-gate 			/*
3607c478bd9Sstevel@tonic-gate 			 * For encrypt update, if there is remaining
3617c478bd9Sstevel@tonic-gate 			 * data, save it and its length in the context.
3627c478bd9Sstevel@tonic-gate 			 */
3637c478bd9Sstevel@tonic-gate 			if (remain != 0)
3647c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pData +
3657c478bd9Sstevel@tonic-gate 				    (ulDataLen - remain), remain);
3667c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
3677c478bd9Sstevel@tonic-gate 		}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		*pulEncryptedLen = out_len;
3707c478bd9Sstevel@tonic-gate 		break;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
3747c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
3757c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
3767c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
3777c478bd9Sstevel@tonic-gate 	{
3787c478bd9Sstevel@tonic-gate 		crypto_data_t out;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		out.cd_format =  CRYPTO_DATA_RAW;
3817c478bd9Sstevel@tonic-gate 		out.cd_offset = 0;
3827c478bd9Sstevel@tonic-gate 		out.cd_length = out_len;
3837c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_base = (char *)out_buf;
3847c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_len = out_len;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		/* Encrypt multiple blocks of data. */
3877c478bd9Sstevel@tonic-gate 		rc = des_encrypt_contiguous_blocks(
3887c478bd9Sstevel@tonic-gate 		    (des_ctx_t *)soft_des_ctx->des_cbc,
3897c478bd9Sstevel@tonic-gate 		    (char *)in_buf, out_len, &out);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 		if (rc != 0)
3927c478bd9Sstevel@tonic-gate 			goto encrypt_failed;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		if (update) {
3957c478bd9Sstevel@tonic-gate 			/*
3967c478bd9Sstevel@tonic-gate 			 * For encrypt update, if there is remaining data,
3977c478bd9Sstevel@tonic-gate 			 * save it and its length in the context.
3987c478bd9Sstevel@tonic-gate 			 */
3997c478bd9Sstevel@tonic-gate 			if (remain != 0)
4007c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pData +
4017c478bd9Sstevel@tonic-gate 				    (ulDataLen - remain), remain);
4027c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
4037c478bd9Sstevel@tonic-gate 		} else if (pad_mechanism) {
4047c478bd9Sstevel@tonic-gate 			/*
4057c478bd9Sstevel@tonic-gate 			 * Save the remainder of the input
4067c478bd9Sstevel@tonic-gate 			 * block in a temporary block because
4077c478bd9Sstevel@tonic-gate 			 * we don't want to overrun the input buffer
4087c478bd9Sstevel@tonic-gate 			 * by tacking on pad bytes.
4097c478bd9Sstevel@tonic-gate 			 */
4107c478bd9Sstevel@tonic-gate 			CK_BYTE tmpblock[DES_BLOCK_LEN];
4117c478bd9Sstevel@tonic-gate 			(void) memcpy(tmpblock, in_buf + out_len,
4129627968bSmcpowers 			    ulDataLen - out_len);
4137c478bd9Sstevel@tonic-gate 			soft_add_pkcs7_padding(tmpblock +
4149627968bSmcpowers 			    (ulDataLen - out_len),
4159627968bSmcpowers 			    DES_BLOCK_LEN, ulDataLen - out_len);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 			out.cd_offset = out_len;
4187c478bd9Sstevel@tonic-gate 			out.cd_length = DES_BLOCK_LEN;
4197c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_base = (char *)out_buf;
4207c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_len = out_len + DES_BLOCK_LEN;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 			/* Encrypt last block containing pad bytes. */
4237c478bd9Sstevel@tonic-gate 			rc = des_encrypt_contiguous_blocks(
4247c478bd9Sstevel@tonic-gate 			    (des_ctx_t *)soft_des_ctx->des_cbc,
4257c478bd9Sstevel@tonic-gate 			    (char *)tmpblock, DES_BLOCK_LEN, &out);
4267c478bd9Sstevel@tonic-gate 			out_len += DES_BLOCK_LEN;
4277c478bd9Sstevel@tonic-gate 		}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 		if (rc == 0) {
4307c478bd9Sstevel@tonic-gate 			*pulEncryptedLen = out_len;
4317c478bd9Sstevel@tonic-gate 			break;
4327c478bd9Sstevel@tonic-gate 		}
4337c478bd9Sstevel@tonic-gate encrypt_failed:
4347c478bd9Sstevel@tonic-gate 		*pulEncryptedLen = 0;
4357c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
4367c478bd9Sstevel@tonic-gate 		goto cleanup;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 	} /* end switch */
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	if (update)
4427c478bd9Sstevel@tonic-gate 		return (CKR_OK);
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/*
4457c478bd9Sstevel@tonic-gate 	 * The following code will be executed if the caller is
4467c478bd9Sstevel@tonic-gate 	 * soft_encrypt() or an error occurred. The encryption
4477c478bd9Sstevel@tonic-gate 	 * operation will be terminated so we need to do some cleanup.
4487c478bd9Sstevel@tonic-gate 	 */
4497c478bd9Sstevel@tonic-gate cleanup:
4507c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
4517c478bd9Sstevel@tonic-gate 	des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
452*a8793c76SJason King 	free(des_ctx);
453*a8793c76SJason King 	freezero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
454*a8793c76SJason King 	freezero(session_p->encrypt.context, sizeof (soft_des_ctx_t));
4557c478bd9Sstevel@tonic-gate 	session_p->encrypt.context = NULL;
4567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	return (rv);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate /*
4637c478bd9Sstevel@tonic-gate  * soft_des_decrypt_common()
4647c478bd9Sstevel@tonic-gate  *
4657c478bd9Sstevel@tonic-gate  * Arguments:
4667c478bd9Sstevel@tonic-gate  *      session_p:	pointer to soft_session_t struct
4677c478bd9Sstevel@tonic-gate  *	pEncrypted:	pointer to the input data to be decrypted
4687c478bd9Sstevel@tonic-gate  *	ulEncryptedLen:	length of the input data
4697c478bd9Sstevel@tonic-gate  *	pData:		pointer to the output data
4707c478bd9Sstevel@tonic-gate  *	pulDataLen:	pointer to the length of the output data
4717c478bd9Sstevel@tonic-gate  *	Update:		boolean flag indicates caller is soft_decrypt
4727c478bd9Sstevel@tonic-gate  *			or soft_decrypt_update
4737c478bd9Sstevel@tonic-gate  *
4747c478bd9Sstevel@tonic-gate  * Description:
4757c478bd9Sstevel@tonic-gate  *      This function calls the corresponding decrypt routine based
4767c478bd9Sstevel@tonic-gate  *	on the mechanism.
4777c478bd9Sstevel@tonic-gate  *
4787c478bd9Sstevel@tonic-gate  * Returns:
4797c478bd9Sstevel@tonic-gate  *      CKR_OK: success
4807c478bd9Sstevel@tonic-gate  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
4817c478bd9Sstevel@tonic-gate  *			      is too small
4827c478bd9Sstevel@tonic-gate  *	CKR_ENCRYPTED_DATA_LEN_RANGE: the input data is not a multiple
4837c478bd9Sstevel@tonic-gate  *				      of blocksize
4847c478bd9Sstevel@tonic-gate  *	CKR_FUNCTION_FAILED: decrypt function failed
4857c478bd9Sstevel@tonic-gate  */
4867c478bd9Sstevel@tonic-gate CK_RV
soft_des_decrypt_common(soft_session_t * session_p,CK_BYTE_PTR pEncrypted,CK_ULONG ulEncryptedLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen,boolean_t update)4877c478bd9Sstevel@tonic-gate soft_des_decrypt_common(soft_session_t *session_p, CK_BYTE_PTR pEncrypted,
4887c478bd9Sstevel@tonic-gate     CK_ULONG ulEncryptedLen, CK_BYTE_PTR pData,
4897c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulDataLen, boolean_t update)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	int rc = 0;
4937c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
4947c478bd9Sstevel@tonic-gate 	soft_des_ctx_t *soft_des_ctx =
4957c478bd9Sstevel@tonic-gate 	    (soft_des_ctx_t *)session_p->decrypt.context;
4967c478bd9Sstevel@tonic-gate 	des_ctx_t *des_ctx;
4977c478bd9Sstevel@tonic-gate 	CK_MECHANISM_TYPE mechanism = session_p->decrypt.mech.mechanism;
4987c478bd9Sstevel@tonic-gate 	CK_BYTE *in_buf = NULL;
4997c478bd9Sstevel@tonic-gate 	CK_BYTE *out_buf = NULL;
5007c478bd9Sstevel@tonic-gate 	CK_ULONG out_len;
5017c478bd9Sstevel@tonic-gate 	CK_ULONG total_len;
5027c478bd9Sstevel@tonic-gate 	CK_ULONG remain;
5037c478bd9Sstevel@tonic-gate 	boolean_t pad_mechanism = B_FALSE;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	pad_mechanism = (mechanism == CKM_DES_CBC_PAD ||
5067c478bd9Sstevel@tonic-gate 	    mechanism == CKM_DES3_CBC_PAD);
5077c478bd9Sstevel@tonic-gate 	/*
5087c478bd9Sstevel@tonic-gate 	 * DES only takes input length that is a multiple of 8 bytes
5097c478bd9Sstevel@tonic-gate 	 * for C_Decrypt function with the mechanism CKM_DES<n>_ECB,
5107c478bd9Sstevel@tonic-gate 	 * CKM_DES<n>_CBC or CKM_DES<n>_CBC_PAD.
5117c478bd9Sstevel@tonic-gate 	 *
5127c478bd9Sstevel@tonic-gate 	 * DES allows any input length for C_DecryptUpdate function.
5137c478bd9Sstevel@tonic-gate 	 */
5147c478bd9Sstevel@tonic-gate 	if (!update) {
5157c478bd9Sstevel@tonic-gate 		/*
5167c478bd9Sstevel@tonic-gate 		 * Called by C_Decrypt
5177c478bd9Sstevel@tonic-gate 		 */
5187c478bd9Sstevel@tonic-gate 		if ((ulEncryptedLen % DES_BLOCK_LEN) != 0) {
5197c478bd9Sstevel@tonic-gate 			rv = CKR_ENCRYPTED_DATA_LEN_RANGE;
5207c478bd9Sstevel@tonic-gate 			goto cleanup;
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		/*
5247c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
5257c478bd9Sstevel@tonic-gate 		 * to hold the plaintext?
5267c478bd9Sstevel@tonic-gate 		 */
5277c478bd9Sstevel@tonic-gate 		if (pData == NULL) {
5287c478bd9Sstevel@tonic-gate 			*pulDataLen = ulEncryptedLen;
5297c478bd9Sstevel@tonic-gate 			return (CKR_OK);
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
5337c478bd9Sstevel@tonic-gate 		if (!pad_mechanism) {
5347c478bd9Sstevel@tonic-gate 			if (*pulDataLen < ulEncryptedLen) {
5357c478bd9Sstevel@tonic-gate 				*pulDataLen = ulEncryptedLen;
5367c478bd9Sstevel@tonic-gate 				return (CKR_BUFFER_TOO_SMALL);
5377c478bd9Sstevel@tonic-gate 			}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 			/* Set output length same as input length. */
5407c478bd9Sstevel@tonic-gate 			out_len = ulEncryptedLen;
5417c478bd9Sstevel@tonic-gate 		} else {
5427c478bd9Sstevel@tonic-gate 			/*
5437c478bd9Sstevel@tonic-gate 			 * For CKM_DES<n>_CBC_PAD, we don't know how
5447c478bd9Sstevel@tonic-gate 			 * many bytes for padding at this time, so
5457c478bd9Sstevel@tonic-gate 			 * we'd assume one block was padded.
5467c478bd9Sstevel@tonic-gate 			 */
5477c478bd9Sstevel@tonic-gate 			if (*pulDataLen < (ulEncryptedLen - DES_BLOCK_LEN)) {
5487c478bd9Sstevel@tonic-gate 				*pulDataLen = ulEncryptedLen - DES_BLOCK_LEN;
5497c478bd9Sstevel@tonic-gate 				return (CKR_BUFFER_TOO_SMALL);
5507c478bd9Sstevel@tonic-gate 			}
5517c478bd9Sstevel@tonic-gate 			out_len = ulEncryptedLen - DES_BLOCK_LEN;
5527c478bd9Sstevel@tonic-gate 		}
5537c478bd9Sstevel@tonic-gate 		in_buf = pEncrypted;
5547c478bd9Sstevel@tonic-gate 		out_buf = pData;
5557c478bd9Sstevel@tonic-gate 	} else {
5567c478bd9Sstevel@tonic-gate 		/*
5577c478bd9Sstevel@tonic-gate 		 *  Called by C_DecryptUpdate
5587c478bd9Sstevel@tonic-gate 		 *
5597c478bd9Sstevel@tonic-gate 		 * Add the lengths of last remaining data and current
5607c478bd9Sstevel@tonic-gate 		 * input data together to get the total input length.
5617c478bd9Sstevel@tonic-gate 		 */
5627c478bd9Sstevel@tonic-gate 		total_len = soft_des_ctx->remain_len + ulEncryptedLen;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		/*
5657c478bd9Sstevel@tonic-gate 		 * If the total input length is less than one blocksize,
5667c478bd9Sstevel@tonic-gate 		 * or if the total input length is just one blocksize and
5677c478bd9Sstevel@tonic-gate 		 * the mechanism is CKM_DES<n>_CBC_PAD, we will need to delay
5687c478bd9Sstevel@tonic-gate 		 * decryption until when more data comes in next
5697c478bd9Sstevel@tonic-gate 		 * C_DecryptUpdate or when C_DecryptFinal is called.
5707c478bd9Sstevel@tonic-gate 		 */
5717c478bd9Sstevel@tonic-gate 		if ((total_len < DES_BLOCK_LEN) ||
5727c478bd9Sstevel@tonic-gate 		    (pad_mechanism && (total_len == DES_BLOCK_LEN))) {
5737c478bd9Sstevel@tonic-gate 			if (pEncrypted != NULL) {
5747c478bd9Sstevel@tonic-gate 				/*
5757c478bd9Sstevel@tonic-gate 				 * Save input data and its length in
5767c478bd9Sstevel@tonic-gate 				 * the remaining buffer of DES context.
5777c478bd9Sstevel@tonic-gate 				 */
5787c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data +
5797c478bd9Sstevel@tonic-gate 				    soft_des_ctx->remain_len,
5807c478bd9Sstevel@tonic-gate 				    pEncrypted, ulEncryptedLen);
5817c478bd9Sstevel@tonic-gate 				soft_des_ctx->remain_len += ulEncryptedLen;
5827c478bd9Sstevel@tonic-gate 			}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 			/* Set output data length to 0. */
5857c478bd9Sstevel@tonic-gate 			*pulDataLen = 0;
5867c478bd9Sstevel@tonic-gate 			return (CKR_OK);
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		/* Compute the length of remaing data. */
5907c478bd9Sstevel@tonic-gate 		remain = total_len % DES_BLOCK_LEN;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 		/*
5937c478bd9Sstevel@tonic-gate 		 * Make sure that the output length is a multiple of
5947c478bd9Sstevel@tonic-gate 		 * blocksize.
5957c478bd9Sstevel@tonic-gate 		 */
5967c478bd9Sstevel@tonic-gate 		out_len = total_len - remain;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		if (pad_mechanism) {
5997c478bd9Sstevel@tonic-gate 			/*
6007c478bd9Sstevel@tonic-gate 			 * If the input data length is a multiple of
6017c478bd9Sstevel@tonic-gate 			 * blocksize, then save the last block of input
6027c478bd9Sstevel@tonic-gate 			 * data in the remaining buffer. C_DecryptFinal
6037c478bd9Sstevel@tonic-gate 			 * will handle this last block of data.
6047c478bd9Sstevel@tonic-gate 			 */
6057c478bd9Sstevel@tonic-gate 			if (remain == 0) {
6067c478bd9Sstevel@tonic-gate 				remain = DES_BLOCK_LEN;
6077c478bd9Sstevel@tonic-gate 				out_len -= DES_BLOCK_LEN;
6087c478bd9Sstevel@tonic-gate 			}
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		/*
6127c478bd9Sstevel@tonic-gate 		 * If application asks for the length of the output buffer
6137c478bd9Sstevel@tonic-gate 		 * to hold the plaintext?
6147c478bd9Sstevel@tonic-gate 		 */
6157c478bd9Sstevel@tonic-gate 		if (pData == NULL) {
6167c478bd9Sstevel@tonic-gate 			*pulDataLen = out_len;
6177c478bd9Sstevel@tonic-gate 			return (CKR_OK);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 		/*
6217c478bd9Sstevel@tonic-gate 		 * Is the application-supplied buffer large enough?
6227c478bd9Sstevel@tonic-gate 		 */
6237c478bd9Sstevel@tonic-gate 		if (*pulDataLen < out_len) {
6247c478bd9Sstevel@tonic-gate 			*pulDataLen = out_len;
6257c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
6267c478bd9Sstevel@tonic-gate 		}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 		if (soft_des_ctx->remain_len != 0) {
6297c478bd9Sstevel@tonic-gate 			/*
6307c478bd9Sstevel@tonic-gate 			 * Copy last remaining data and current input data
6317c478bd9Sstevel@tonic-gate 			 * to the output buffer.
6327c478bd9Sstevel@tonic-gate 			 */
6337c478bd9Sstevel@tonic-gate 			(void) memmove(pData + soft_des_ctx->remain_len,
6347c478bd9Sstevel@tonic-gate 			    pEncrypted, out_len - soft_des_ctx->remain_len);
6357c478bd9Sstevel@tonic-gate 			(void) memcpy(pData, soft_des_ctx->data,
6367c478bd9Sstevel@tonic-gate 			    soft_des_ctx->remain_len);
6377c478bd9Sstevel@tonic-gate 			bzero(soft_des_ctx->data, soft_des_ctx->remain_len);
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 			in_buf = pData;
6407c478bd9Sstevel@tonic-gate 		} else {
6417c478bd9Sstevel@tonic-gate 			in_buf = pEncrypted;
6427c478bd9Sstevel@tonic-gate 		}
6437c478bd9Sstevel@tonic-gate 		out_buf = pData;
6447c478bd9Sstevel@tonic-gate 	}
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	/*
6477c478bd9Sstevel@tonic-gate 	 * Begin Decryption.
6487c478bd9Sstevel@tonic-gate 	 */
6497c478bd9Sstevel@tonic-gate 	switch (mechanism) {
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	case CKM_DES_ECB:
6527c478bd9Sstevel@tonic-gate 	case CKM_DES3_ECB:
6537c478bd9Sstevel@tonic-gate 	{
6547c478bd9Sstevel@tonic-gate 		uint8_t *tmp_inbuf;
6557c478bd9Sstevel@tonic-gate 		uint8_t *tmp_outbuf;
6567c478bd9Sstevel@tonic-gate 		ulong_t i;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 		for (i = 0; i < out_len; i += DES_BLOCK_LEN) {
6597c478bd9Sstevel@tonic-gate 			tmp_inbuf = &in_buf[i];
6607c478bd9Sstevel@tonic-gate 			tmp_outbuf = &out_buf[i];
6617c478bd9Sstevel@tonic-gate 			/* Crunch one block of data for DES. */
6627c478bd9Sstevel@tonic-gate 			if (soft_des_ctx->key_type == CKK_DES)
66323c57df7Smcpowers 				(void) des_crunch_block(
66423c57df7Smcpowers 				    soft_des_ctx->key_sched,
6657c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_TRUE);
6667c478bd9Sstevel@tonic-gate 			else
66723c57df7Smcpowers 				(void) des3_crunch_block(
66823c57df7Smcpowers 				    soft_des_ctx->key_sched,
6697c478bd9Sstevel@tonic-gate 				    tmp_inbuf, tmp_outbuf, B_TRUE);
6707c478bd9Sstevel@tonic-gate 		}
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		if (update) {
6737c478bd9Sstevel@tonic-gate 			/*
6747c478bd9Sstevel@tonic-gate 			 * For decrypt update, if there is remaining
6757c478bd9Sstevel@tonic-gate 			 * data, save it and its length in the context.
6767c478bd9Sstevel@tonic-gate 			 */
6777c478bd9Sstevel@tonic-gate 			if (remain != 0)
6787c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pEncrypted +
6797c478bd9Sstevel@tonic-gate 				    (ulEncryptedLen - remain), remain);
6807c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
6817c478bd9Sstevel@tonic-gate 		}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		*pulDataLen = out_len;
6847c478bd9Sstevel@tonic-gate 		break;
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC:
6887c478bd9Sstevel@tonic-gate 	case CKM_DES_CBC_PAD:
6897c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC:
6907c478bd9Sstevel@tonic-gate 	case CKM_DES3_CBC_PAD:
6917c478bd9Sstevel@tonic-gate 	{
6927c478bd9Sstevel@tonic-gate 		crypto_data_t out;
6937c478bd9Sstevel@tonic-gate 		CK_ULONG rem_len;
6947c478bd9Sstevel@tonic-gate 		uint8_t last_block[DES_BLOCK_LEN];
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 		out.cd_format =  CRYPTO_DATA_RAW;
6977c478bd9Sstevel@tonic-gate 		out.cd_offset = 0;
6987c478bd9Sstevel@tonic-gate 		out.cd_length = out_len;
6997c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_base = (char *)out_buf;
7007c478bd9Sstevel@tonic-gate 		out.cd_raw.iov_len = out_len;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 		/* Decrypt multiple blocks of data. */
7037c478bd9Sstevel@tonic-gate 		rc = des_decrypt_contiguous_blocks(
7047c478bd9Sstevel@tonic-gate 		    (des_ctx_t *)soft_des_ctx->des_cbc,
7057c478bd9Sstevel@tonic-gate 		    (char *)in_buf, out_len, &out);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 		if (rc != 0)
7087c478bd9Sstevel@tonic-gate 			goto decrypt_failed;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 		if (pad_mechanism && !update) {
7117c478bd9Sstevel@tonic-gate 			/* Decrypt last block containing pad bytes. */
7127c478bd9Sstevel@tonic-gate 			out.cd_offset = 0;
7137c478bd9Sstevel@tonic-gate 			out.cd_length = DES_BLOCK_LEN;
7147c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_base = (char *)last_block;
7157c478bd9Sstevel@tonic-gate 			out.cd_raw.iov_len = DES_BLOCK_LEN;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 			/* Decrypt last block containing pad bytes. */
7187c478bd9Sstevel@tonic-gate 			rc = des_decrypt_contiguous_blocks(
7197c478bd9Sstevel@tonic-gate 			    (des_ctx_t *)soft_des_ctx->des_cbc,
7207c478bd9Sstevel@tonic-gate 			    (char *)in_buf + out_len, DES_BLOCK_LEN, &out);
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 			if (rc != 0)
7237c478bd9Sstevel@tonic-gate 				goto decrypt_failed;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 			/*
7267c478bd9Sstevel@tonic-gate 			 * Remove padding bytes after decryption of
7277c478bd9Sstevel@tonic-gate 			 * ciphertext block to produce the original
7287c478bd9Sstevel@tonic-gate 			 * plaintext.
7297c478bd9Sstevel@tonic-gate 			 */
7307c478bd9Sstevel@tonic-gate 			rv = soft_remove_pkcs7_padding(last_block,
731726fad2aSDina K Nimeh 			    DES_BLOCK_LEN, &rem_len);
7327c478bd9Sstevel@tonic-gate 			if (rv == CKR_OK) {
7337c478bd9Sstevel@tonic-gate 				if (rem_len != 0)
7347c478bd9Sstevel@tonic-gate 					(void) memcpy(out_buf + out_len,
7359627968bSmcpowers 					    last_block, rem_len);
7367c478bd9Sstevel@tonic-gate 				*pulDataLen = out_len + rem_len;
7377c478bd9Sstevel@tonic-gate 			} else {
7387c478bd9Sstevel@tonic-gate 				*pulDataLen = 0;
7397c478bd9Sstevel@tonic-gate 				goto cleanup;
7407c478bd9Sstevel@tonic-gate 			}
7417c478bd9Sstevel@tonic-gate 		} else {
7427c478bd9Sstevel@tonic-gate 			*pulDataLen = out_len;
7437c478bd9Sstevel@tonic-gate 		}
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		if (update) {
7467c478bd9Sstevel@tonic-gate 			/*
7477c478bd9Sstevel@tonic-gate 			 * For decrypt update, if there is remaining data,
7487c478bd9Sstevel@tonic-gate 			 * save it and its length in the context.
7497c478bd9Sstevel@tonic-gate 			 */
7507c478bd9Sstevel@tonic-gate 			if (remain != 0)
7517c478bd9Sstevel@tonic-gate 				(void) memcpy(soft_des_ctx->data, pEncrypted +
7527c478bd9Sstevel@tonic-gate 				    (ulEncryptedLen - remain), remain);
7537c478bd9Sstevel@tonic-gate 			soft_des_ctx->remain_len = remain;
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		if (rc == 0)
7577c478bd9Sstevel@tonic-gate 			break;
7587c478bd9Sstevel@tonic-gate decrypt_failed:
7597c478bd9Sstevel@tonic-gate 		*pulDataLen = 0;
7607c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
7617c478bd9Sstevel@tonic-gate 		goto cleanup;
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 	} /* end switch */
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if (update)
7667c478bd9Sstevel@tonic-gate 		return (CKR_OK);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	/*
7697c478bd9Sstevel@tonic-gate 	 * The following code will be executed if the caller is
7707c478bd9Sstevel@tonic-gate 	 * soft_decrypt() or an error occurred. The decryption
7717c478bd9Sstevel@tonic-gate 	 * operation will be terminated so we need to do some cleanup.
7727c478bd9Sstevel@tonic-gate 	 */
7737c478bd9Sstevel@tonic-gate cleanup:
7747c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
7757c478bd9Sstevel@tonic-gate 	des_ctx = (des_ctx_t *)soft_des_ctx->des_cbc;
776*a8793c76SJason King 	free(des_ctx);
777*a8793c76SJason King 	freezero(soft_des_ctx->key_sched, soft_des_ctx->keysched_len);
778*a8793c76SJason King 	freezero(session_p->decrypt.context, sizeof (soft_des_ctx_t));
7797c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	return (rv);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate /*
7867c478bd9Sstevel@tonic-gate  * Allocate and initialize a context for DES CBC mode of operation.
7877c478bd9Sstevel@tonic-gate  */
7887c478bd9Sstevel@tonic-gate void *
des_cbc_ctx_init(void * key_sched,size_t size,uint8_t * ivec,CK_KEY_TYPE type)7897c478bd9Sstevel@tonic-gate des_cbc_ctx_init(void *key_sched, size_t size, uint8_t *ivec, CK_KEY_TYPE type)
7907c478bd9Sstevel@tonic-gate {
7917c478bd9Sstevel@tonic-gate 
79223c57df7Smcpowers 	cbc_ctx_t *cbc_ctx;
7937c478bd9Sstevel@tonic-gate 
79423c57df7Smcpowers 	if ((cbc_ctx = calloc(1, sizeof (cbc_ctx_t))) == NULL)
7957c478bd9Sstevel@tonic-gate 		return (NULL);
7967c478bd9Sstevel@tonic-gate 
79716239bc8SMark Powers 	cbc_ctx->cbc_keysched = key_sched;
7987c478bd9Sstevel@tonic-gate 
79916239bc8SMark Powers 	(void) memcpy(&cbc_ctx->cbc_iv[0], ivec, DES_BLOCK_LEN);
8007c478bd9Sstevel@tonic-gate 
80116239bc8SMark Powers 	cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
80216239bc8SMark Powers 	cbc_ctx->cbc_keysched_len = size;
8037c478bd9Sstevel@tonic-gate 	if (type == CKK_DES)
80416239bc8SMark Powers 		cbc_ctx->cbc_flags |= CBC_MODE;
8057c478bd9Sstevel@tonic-gate 	else
80616239bc8SMark Powers 		cbc_ctx->cbc_flags |= CBC_MODE | DES3_STRENGTH;
8077c478bd9Sstevel@tonic-gate 
80823c57df7Smcpowers 	return (cbc_ctx);
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate /*
8137c478bd9Sstevel@tonic-gate  * Allocate and initialize DES contexts for both signing and encrypting,
8147c478bd9Sstevel@tonic-gate  * saving both context pointers in the session struct. For general-length DES
8157c478bd9Sstevel@tonic-gate  * MAC, check the length in the parameter to see if it is in the right range.
8167c478bd9Sstevel@tonic-gate  */
8177c478bd9Sstevel@tonic-gate CK_RV
soft_des_sign_verify_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t sign_op)8187c478bd9Sstevel@tonic-gate soft_des_sign_verify_init_common(soft_session_t *session_p,
819*a8793c76SJason King     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p, boolean_t sign_op)
8207c478bd9Sstevel@tonic-gate {
8217c478bd9Sstevel@tonic-gate 	soft_des_ctx_t	*soft_des_ctx;
8227c478bd9Sstevel@tonic-gate 	CK_MECHANISM	encrypt_mech;
8237c478bd9Sstevel@tonic-gate 	CK_RV rv;
8247c478bd9Sstevel@tonic-gate 
8259627968bSmcpowers 	if ((key_p->class != CKO_SECRET_KEY) || (key_p->key_type != CKK_DES)) {
8267c478bd9Sstevel@tonic-gate 		return (CKR_KEY_TYPE_INCONSISTENT);
8277c478bd9Sstevel@tonic-gate 	}
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	/* allocate memory for the sign/verify context */
8307c478bd9Sstevel@tonic-gate 	soft_des_ctx = malloc(sizeof (soft_des_ctx_t));
8317c478bd9Sstevel@tonic-gate 	if (soft_des_ctx == NULL) {
8327c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	soft_des_ctx->key_type = key_p->key_type;
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	/* initialization vector is zero for DES MAC */
8387c478bd9Sstevel@tonic-gate 	bzero(soft_des_ctx->ivec, DES_BLOCK_LEN);
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	switch (pMechanism->mechanism) {
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	case CKM_DES_MAC_GENERAL:
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 		if (pMechanism->ulParameterLen !=
8459627968bSmcpowers 		    sizeof (CK_MAC_GENERAL_PARAMS)) {
8467c478bd9Sstevel@tonic-gate 			free(soft_des_ctx);
8477c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
8487c478bd9Sstevel@tonic-gate 		}
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 		if (*(CK_MAC_GENERAL_PARAMS *)pMechanism->pParameter >
8519627968bSmcpowers 		    DES_BLOCK_LEN) {
8527c478bd9Sstevel@tonic-gate 			free(soft_des_ctx);
8537c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
8547c478bd9Sstevel@tonic-gate 		}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		soft_des_ctx->mac_len = *((CK_MAC_GENERAL_PARAMS_PTR)
8579627968bSmcpowers 		    pMechanism->pParameter);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
8607c478bd9Sstevel@tonic-gate 	case CKM_DES_MAC:
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		/*
8637c478bd9Sstevel@tonic-gate 		 * For non-general DES MAC, output is always half as
8647c478bd9Sstevel@tonic-gate 		 * large as block size
8657c478bd9Sstevel@tonic-gate 		 */
8667c478bd9Sstevel@tonic-gate 		if (pMechanism->mechanism == CKM_DES_MAC) {
8677c478bd9Sstevel@tonic-gate 			soft_des_ctx->mac_len = DES_MAC_LEN;
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 		/* allocate a context for DES encryption */
8717c478bd9Sstevel@tonic-gate 		encrypt_mech.mechanism = CKM_DES_CBC_PAD;
8727c478bd9Sstevel@tonic-gate 		encrypt_mech.pParameter = (void *)soft_des_ctx->ivec;
8737c478bd9Sstevel@tonic-gate 		encrypt_mech.ulParameterLen = DES_BLOCK_LEN;
8747c478bd9Sstevel@tonic-gate 		rv = soft_encrypt_init_internal(session_p, &encrypt_mech,
8759627968bSmcpowers 		    key_p);
8767c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
8777c478bd9Sstevel@tonic-gate 			free(soft_des_ctx);
8787c478bd9Sstevel@tonic-gate 			return (rv);
8797c478bd9Sstevel@tonic-gate 		}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&session_p->session_mutex);
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 		if (sign_op) {
8847c478bd9Sstevel@tonic-gate 			session_p->sign.context = soft_des_ctx;
8857c478bd9Sstevel@tonic-gate 			session_p->sign.mech.mechanism = pMechanism->mechanism;
8867c478bd9Sstevel@tonic-gate 		} else {
8877c478bd9Sstevel@tonic-gate 			session_p->verify.context = soft_des_ctx;
8887c478bd9Sstevel@tonic-gate 			session_p->verify.mech.mechanism =
8899627968bSmcpowers 			    pMechanism->mechanism;
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&session_p->session_mutex);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 		break;
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 	return (CKR_OK);
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate /*
9007c478bd9Sstevel@tonic-gate  * Called by soft_sign(), soft_sign_final(), soft_verify() or
9017c478bd9Sstevel@tonic-gate  * soft_verify_final().
9027c478bd9Sstevel@tonic-gate  */
9037c478bd9Sstevel@tonic-gate CK_RV
soft_des_sign_verify_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen,boolean_t sign_op,boolean_t Final)9047c478bd9Sstevel@tonic-gate soft_des_sign_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
905*a8793c76SJason King     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned, CK_ULONG_PTR pulSignedLen,
906*a8793c76SJason King     boolean_t sign_op, boolean_t Final)
9077c478bd9Sstevel@tonic-gate {
9087c478bd9Sstevel@tonic-gate 	soft_des_ctx_t		*soft_des_ctx_sign_verify;
9097c478bd9Sstevel@tonic-gate 	soft_des_ctx_t		*soft_des_ctx_encrypt;
9107c478bd9Sstevel@tonic-gate 	CK_RV			rv;
9117c478bd9Sstevel@tonic-gate 	CK_BYTE			*pEncrypted = NULL;
9127c478bd9Sstevel@tonic-gate 	CK_ULONG		ulEncryptedLen = 0;
9137c478bd9Sstevel@tonic-gate 	uint8_t			remainder;
9147c478bd9Sstevel@tonic-gate 	CK_BYTE			last_block[DES_BLOCK_LEN];
9157c478bd9Sstevel@tonic-gate 	des_ctx_t		*des_ctx = NULL;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (sign_op) {
9187c478bd9Sstevel@tonic-gate 		soft_des_ctx_sign_verify =
9199627968bSmcpowers 		    (soft_des_ctx_t *)session_p->sign.context;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 		if (soft_des_ctx_sign_verify->mac_len == 0) {
9227c478bd9Sstevel@tonic-gate 			*pulSignedLen = 0;
9237c478bd9Sstevel@tonic-gate 			goto clean_exit;
9247c478bd9Sstevel@tonic-gate 		}
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 		/* Application asks for the length of the output buffer. */
9277c478bd9Sstevel@tonic-gate 		if (pSigned == NULL) {
9287c478bd9Sstevel@tonic-gate 			*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
9297c478bd9Sstevel@tonic-gate 			return (CKR_OK);
9307c478bd9Sstevel@tonic-gate 		}
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 		/* Is the application-supplied buffer large enough? */
9337c478bd9Sstevel@tonic-gate 		if (*pulSignedLen < soft_des_ctx_sign_verify->mac_len) {
9347c478bd9Sstevel@tonic-gate 			*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
9357c478bd9Sstevel@tonic-gate 			return (CKR_BUFFER_TOO_SMALL);
9367c478bd9Sstevel@tonic-gate 		}
9377c478bd9Sstevel@tonic-gate 	} else {
9387c478bd9Sstevel@tonic-gate 		soft_des_ctx_sign_verify =
9399627968bSmcpowers 		    (soft_des_ctx_t *)session_p->verify.context;
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	if (Final) {
9437c478bd9Sstevel@tonic-gate 		soft_des_ctx_encrypt =
9449627968bSmcpowers 		    (soft_des_ctx_t *)session_p->encrypt.context;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 		/*
9477c478bd9Sstevel@tonic-gate 		 * If there is data left in the buffer from a previous
9487c478bd9Sstevel@tonic-gate 		 * SignUpdate() call, pass enough zeroed data to a
9497c478bd9Sstevel@tonic-gate 		 * soft_sign_update call to pad the remainder
9507c478bd9Sstevel@tonic-gate 		 */
9517c478bd9Sstevel@tonic-gate 		if (soft_des_ctx_encrypt->remain_len != 0) {
9527c478bd9Sstevel@tonic-gate 			bzero(last_block, DES_BLOCK_LEN);
9537c478bd9Sstevel@tonic-gate 			ulEncryptedLen = DES_BLOCK_LEN;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 			/*
9567c478bd9Sstevel@tonic-gate 			 * By passing a buffer to soft_encrypt_final,
9577c478bd9Sstevel@tonic-gate 			 * we force it to pad the remaining block
9587c478bd9Sstevel@tonic-gate 			 * and encrypt it.
9597c478bd9Sstevel@tonic-gate 			 */
9607c478bd9Sstevel@tonic-gate 			rv = soft_encrypt_final(session_p, last_block,
9619627968bSmcpowers 			    &ulEncryptedLen);
9627c478bd9Sstevel@tonic-gate 			if (rv != CKR_OK) {
9637c478bd9Sstevel@tonic-gate 				goto clean_exit;
9647c478bd9Sstevel@tonic-gate 			}
9657c478bd9Sstevel@tonic-gate 		} else {
9667c478bd9Sstevel@tonic-gate 			/*
9677c478bd9Sstevel@tonic-gate 			 * The last block of enciphered data is stored in:
9687c478bd9Sstevel@tonic-gate 			 * soft_des_ctx_encrypt->des_cbc->des_ctx->dc_lastp
9697c478bd9Sstevel@tonic-gate 			 * Copy that data to last_block
9707c478bd9Sstevel@tonic-gate 			 */
9717c478bd9Sstevel@tonic-gate 			soft_des_ctx_encrypt =
9729627968bSmcpowers 			    (soft_des_ctx_t *)session_p->encrypt.context;
9737c478bd9Sstevel@tonic-gate 			des_ctx = (des_ctx_t *)soft_des_ctx_encrypt->des_cbc;
9747c478bd9Sstevel@tonic-gate 			(void) memcpy(last_block, des_ctx->dc_lastp,
9759627968bSmcpowers 			    DES_BLOCK_LEN);
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 			/*
9787c478bd9Sstevel@tonic-gate 			 * Passing a NULL output buffer here
9797c478bd9Sstevel@tonic-gate 			 * forces the routine to just return.
9807c478bd9Sstevel@tonic-gate 			 */
9817c478bd9Sstevel@tonic-gate 			rv = soft_encrypt_final(session_p, NULL,
9829627968bSmcpowers 			    &ulEncryptedLen);
9837c478bd9Sstevel@tonic-gate 		}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	} else {
9867c478bd9Sstevel@tonic-gate 		/*
9877c478bd9Sstevel@tonic-gate 		 * If the input length is not multiple of block size, then
9887c478bd9Sstevel@tonic-gate 		 * determine the correct encrypted data length by rounding
9897c478bd9Sstevel@tonic-gate 		 */
9907c478bd9Sstevel@tonic-gate 		remainder = ulDataLen % DES_BLOCK_LEN;
9917c478bd9Sstevel@tonic-gate 		/*
9927c478bd9Sstevel@tonic-gate 		 * Because we always use DES_CBC_PAD mechanism
9937c478bd9Sstevel@tonic-gate 		 * for sign/verify operations, the input will
9947c478bd9Sstevel@tonic-gate 		 * be padded to the next 8 byte boundary.
9957c478bd9Sstevel@tonic-gate 		 * Adjust the length fields here accordingly.
9967c478bd9Sstevel@tonic-gate 		 */
9979627968bSmcpowers 		ulEncryptedLen = ulDataLen + (DES_BLOCK_LEN - remainder);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
10007c478bd9Sstevel@tonic-gate 		if (pEncrypted == NULL) {
10017c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
10027c478bd9Sstevel@tonic-gate 			goto clean_exit;
10037c478bd9Sstevel@tonic-gate 		}
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 		/*
10067c478bd9Sstevel@tonic-gate 		 * Pad the last block with zeros by copying pData into a zeroed
10077c478bd9Sstevel@tonic-gate 		 * pEncrypted. Then pass pEncrypted into soft_encrypt as input
10087c478bd9Sstevel@tonic-gate 		 */
10097c478bd9Sstevel@tonic-gate 		bzero(pEncrypted, ulEncryptedLen);
10107c478bd9Sstevel@tonic-gate 		(void) memcpy(pEncrypted, pData, ulDataLen);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 		rv = soft_encrypt(session_p, pEncrypted, ulDataLen,
10139627968bSmcpowers 		    pEncrypted, &ulEncryptedLen);
10147c478bd9Sstevel@tonic-gate 		(void) memcpy(last_block,
10159627968bSmcpowers 		    &pEncrypted[ulEncryptedLen - DES_BLOCK_LEN], DES_BLOCK_LEN);
10167c478bd9Sstevel@tonic-gate 	}
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
10197c478bd9Sstevel@tonic-gate 		*pulSignedLen = soft_des_ctx_sign_verify->mac_len;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		/* the leftmost mac_len bytes of last_block is our MAC */
10227c478bd9Sstevel@tonic-gate 		(void) memcpy(pSigned, last_block, *pulSignedLen);
10237c478bd9Sstevel@tonic-gate 	}
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate clean_exit:
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	/* soft_encrypt_common() has freed the encrypt context */
10307c478bd9Sstevel@tonic-gate 	if (sign_op) {
10317c478bd9Sstevel@tonic-gate 		free(session_p->sign.context);
10327c478bd9Sstevel@tonic-gate 		session_p->sign.context = NULL;
10337c478bd9Sstevel@tonic-gate 	} else {
10347c478bd9Sstevel@tonic-gate 		free(session_p->verify.context);
10357c478bd9Sstevel@tonic-gate 		session_p->verify.context = NULL;
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 	session_p->encrypt.flags = 0;
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	if (pEncrypted) {
10427c478bd9Sstevel@tonic-gate 		free(pEncrypted);
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	return (rv);
10467c478bd9Sstevel@tonic-gate }
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate /*
10497c478bd9Sstevel@tonic-gate  * Called by soft_sign_update()
10507c478bd9Sstevel@tonic-gate  */
10517c478bd9Sstevel@tonic-gate CK_RV
soft_des_mac_sign_verify_update(soft_session_t * session_p,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)10527c478bd9Sstevel@tonic-gate soft_des_mac_sign_verify_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
1053*a8793c76SJason King     CK_ULONG ulPartLen)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate 	/*
10567c478bd9Sstevel@tonic-gate 	 * The DES MAC is calculated by taking the specified number of
10577c478bd9Sstevel@tonic-gate 	 * left-most bytes within the last block of
10587c478bd9Sstevel@tonic-gate 	 * encrypted data, while the context of the multi-part
10597c478bd9Sstevel@tonic-gate 	 * encryption stores the block necessary for XORing with the
10607c478bd9Sstevel@tonic-gate 	 * input as per cipher block chaining . Therefore, none of the
10617c478bd9Sstevel@tonic-gate 	 * intermediary encrypted blocks of data are necessary for
10627c478bd9Sstevel@tonic-gate 	 * the DES MAC, and we can create a placeholder local buffer
10637c478bd9Sstevel@tonic-gate 	 * for the encrypted data, which is immediately throw away.
10647c478bd9Sstevel@tonic-gate 	 */
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	soft_des_ctx_t	*soft_des_ctx_encrypt;
10677c478bd9Sstevel@tonic-gate 	CK_BYTE		*pEncrypted = NULL;
10687c478bd9Sstevel@tonic-gate 	CK_ULONG	ulEncryptedLen;
10697c478bd9Sstevel@tonic-gate 	CK_ULONG	total_len;
10707c478bd9Sstevel@tonic-gate 	uint8_t		remainder;
10717c478bd9Sstevel@tonic-gate 	CK_RV		rv;
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	soft_des_ctx_encrypt = (soft_des_ctx_t *)session_p->encrypt.context;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/* Avoid the malloc if we won't be encrypting any data */
10767c478bd9Sstevel@tonic-gate 	total_len = soft_des_ctx_encrypt->remain_len + ulPartLen;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	if (total_len < DES_BLOCK_LEN) {
10797c478bd9Sstevel@tonic-gate 		rv = soft_encrypt_update(session_p, pPart, ulPartLen, NULL,
10809627968bSmcpowers 		    &ulEncryptedLen);
10817c478bd9Sstevel@tonic-gate 	} else {
10827c478bd9Sstevel@tonic-gate 		remainder = ulPartLen % DES_BLOCK_LEN;
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 		/* round up to the nearest multiple of block size */
10857c478bd9Sstevel@tonic-gate 		ulEncryptedLen = ulPartLen + (DES_BLOCK_LEN - remainder);
10867c478bd9Sstevel@tonic-gate 		pEncrypted = malloc(sizeof (CK_BYTE) * ulEncryptedLen);
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 		if (pEncrypted != NULL) {
10897c478bd9Sstevel@tonic-gate 			rv = soft_encrypt_update(session_p, pPart, ulPartLen,
10909627968bSmcpowers 			    pEncrypted, &ulEncryptedLen);
10917c478bd9Sstevel@tonic-gate 			free(pEncrypted);
10927c478bd9Sstevel@tonic-gate 		} else {
10937c478bd9Sstevel@tonic-gate 			rv = CKR_HOST_MEMORY;
10947c478bd9Sstevel@tonic-gate 		}
10957c478bd9Sstevel@tonic-gate 	}
10967c478bd9Sstevel@tonic-gate 	return (rv);
10977c478bd9Sstevel@tonic-gate }
1098