xref: /titanic_52/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSSL.c (revision 1f49a79a97c031bfe0722e2e812dd0e192355be5)
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
51c02caffSmcpowers  * Common Development and Distribution License (the "License").
61c02caffSmcpowers  * 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  */
217c478bd9Sstevel@tonic-gate /*
22*1f49a79aSZdenek Kotala  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <fcntl.h>
277c478bd9Sstevel@tonic-gate #include <strings.h>
287c478bd9Sstevel@tonic-gate #include <sys/stat.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/sha1.h>
317c478bd9Sstevel@tonic-gate #include <sys/md5.h>
327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
337c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
347c478bd9Sstevel@tonic-gate #include "softGlobal.h"
357c478bd9Sstevel@tonic-gate #include "softKeys.h"
367c478bd9Sstevel@tonic-gate #include "softKeystore.h"
377c478bd9Sstevel@tonic-gate #include "softMAC.h"
387c478bd9Sstevel@tonic-gate #include "softObject.h"
397c478bd9Sstevel@tonic-gate #include "softSession.h"
407c478bd9Sstevel@tonic-gate #include "softSSL.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * This files contains the implementation of the following PKCS#11
447c478bd9Sstevel@tonic-gate  * mechanisms needed by SSL:
457c478bd9Sstevel@tonic-gate  * CKM_SSL3_MASTER_KEY_DERIVE
467c478bd9Sstevel@tonic-gate  * CKM_SSL3_MASTER_KEY_DERIVE_DH
477c478bd9Sstevel@tonic-gate  * CKM_SSL3_KEY_AND_DERIVE
487c478bd9Sstevel@tonic-gate  * CKM_TLS_MASTER_KEY_DERIVE
497c478bd9Sstevel@tonic-gate  * CKM_TLS_MASTER_KEY_DERIVE_DH
507c478bd9Sstevel@tonic-gate  * CKM_TLS_KEY_AND_DERIVE
517c478bd9Sstevel@tonic-gate  *
527c478bd9Sstevel@tonic-gate  * SSL refers to common functions between SSL v3.0 and SSL v3.1 (a.k.a TLS.)
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #define	MAX_KEYBLOCK	160	/* should be plenty for all known cipherspecs */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define	MAX_DEFAULT_ATTRS	10	/* Enough for major applicarions */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static	char *ssl3_const_vals[] = {
607c478bd9Sstevel@tonic-gate 	"A",
617c478bd9Sstevel@tonic-gate 	"BB",
627c478bd9Sstevel@tonic-gate 	"CCC",
637c478bd9Sstevel@tonic-gate 	"DDDD",
647c478bd9Sstevel@tonic-gate 	"EEEEE",
657c478bd9Sstevel@tonic-gate 	"FFFFFF",
667c478bd9Sstevel@tonic-gate 	"GGGGGGG",
677c478bd9Sstevel@tonic-gate 	"HHHHHHHH",
687c478bd9Sstevel@tonic-gate 	"IIIIIIIII",
697c478bd9Sstevel@tonic-gate 	"JJJJJJJJJJ",
707c478bd9Sstevel@tonic-gate };
717c478bd9Sstevel@tonic-gate static	uint_t ssl3_const_lens[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static uchar_t TLS_MASTER_SECRET_LABEL[] = {"master secret"};
747c478bd9Sstevel@tonic-gate #define	TLS_MASTER_SECRET_LABEL_LEN	13
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static uchar_t TLS_KEY_EXPANSION_LABEL[] = {"key expansion"};
777c478bd9Sstevel@tonic-gate #define	TLS_KEY_EXPANSION_LABEL_LEN	13
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static uchar_t TLS_CLIENT_KEY_LABEL[] = {"client write key"};
807c478bd9Sstevel@tonic-gate #define	TLS_CLIENT_KEY_LABEL_LEN	16
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static uchar_t TLS_SERVER_KEY_LABEL[] = {"server write key"};
837c478bd9Sstevel@tonic-gate #define	TLS_SERVER_KEY_LABEL_LEN	16
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static uchar_t TLS_IV_BLOCK_LABEL[] = {"IV block"};
867c478bd9Sstevel@tonic-gate #define	TLS_IV_BLOCK_LABEL_LEN	8
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static void P_MD5(uchar_t *, uint_t, uchar_t *, uint_t, uchar_t *, uint_t,
897c478bd9Sstevel@tonic-gate     uchar_t *, uint_t, uchar_t *, uint_t, boolean_t);
907c478bd9Sstevel@tonic-gate static void P_SHA1(uchar_t *, uint_t, uchar_t *, uint_t, uchar_t *, uint_t,
917c478bd9Sstevel@tonic-gate     uchar_t *, uint_t, uchar_t *, uint_t, boolean_t);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate static CK_RV soft_add_derived_key(CK_ATTRIBUTE_PTR, CK_ULONG,
947c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE_PTR, soft_session_t *, soft_object_t *);
957c478bd9Sstevel@tonic-gate static void soft_delete_derived_key(soft_session_t *, soft_object_t *);
967c478bd9Sstevel@tonic-gate static void soft_ssl_weaken_key(CK_MECHANISM_PTR, uchar_t *, uint_t,
977c478bd9Sstevel@tonic-gate     uchar_t *, uint_t, uchar_t *, uint_t, uchar_t *, boolean_t);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * soft_ssl3_churn()
1017c478bd9Sstevel@tonic-gate  * Called for derivation of the master secret from the pre-master secret,
1027c478bd9Sstevel@tonic-gate  * and for the derivation of the key_block in an SSL3 handshake
1037c478bd9Sstevel@tonic-gate  * result is assumed to be larger than rounds * MD5_HASH_SIZE.
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate static void
1067c478bd9Sstevel@tonic-gate soft_ssl3_churn(uchar_t *secret, uint_t secretlen, uchar_t *rand1,
1077c478bd9Sstevel@tonic-gate     uint_t rand1len, uchar_t *rand2, uint_t rand2len, int rounds,
1087c478bd9Sstevel@tonic-gate     uchar_t *result)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	SHA1_CTX sha1_ctx;
1117c478bd9Sstevel@tonic-gate 	MD5_CTX	md5_ctx;
1127c478bd9Sstevel@tonic-gate 	uchar_t sha1_digest[SHA1_HASH_SIZE];
1137c478bd9Sstevel@tonic-gate 	int i;
1147c478bd9Sstevel@tonic-gate 	uchar_t *ms = result;
1157c478bd9Sstevel@tonic-gate 	for (i = 0; i < rounds; i++) {
1167c478bd9Sstevel@tonic-gate 		SHA1Init(&sha1_ctx);
1177c478bd9Sstevel@tonic-gate 		SHA1Update(&sha1_ctx, (const uint8_t *)ssl3_const_vals[i],
1187c478bd9Sstevel@tonic-gate 		    ssl3_const_lens[i]);
1197c478bd9Sstevel@tonic-gate 		SHA1Update(&sha1_ctx, secret, secretlen);
1207c478bd9Sstevel@tonic-gate 		SHA1Update(&sha1_ctx, rand1, rand1len);
1217c478bd9Sstevel@tonic-gate 		SHA1Update(&sha1_ctx, rand2, rand2len);
1227c478bd9Sstevel@tonic-gate 		SHA1Final(sha1_digest, &sha1_ctx);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 		MD5Init(&md5_ctx);
1257c478bd9Sstevel@tonic-gate 		MD5Update(&md5_ctx, secret, secretlen);
1267c478bd9Sstevel@tonic-gate 		MD5Update(&md5_ctx, sha1_digest, SHA1_HASH_SIZE);
1277c478bd9Sstevel@tonic-gate 		MD5Final(ms, &md5_ctx);
1287c478bd9Sstevel@tonic-gate 		ms += MD5_HASH_SIZE;
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * This TLS generic Pseudo Random Function expands a triplet
1347c478bd9Sstevel@tonic-gate  * {secret, label, seed} into any arbitrary length string of pseudo
1357c478bd9Sstevel@tonic-gate  * random bytes.
1367c478bd9Sstevel@tonic-gate  * Here, it is called for the derivation of the master secret from the
1377c478bd9Sstevel@tonic-gate  * pre-master secret, and for the derivation of the key_block in a TLS
1387c478bd9Sstevel@tonic-gate  * handshake
1397c478bd9Sstevel@tonic-gate  */
1407c478bd9Sstevel@tonic-gate static void
1417c478bd9Sstevel@tonic-gate soft_tls_prf(uchar_t *secret, uint_t secretlen, uchar_t *label, uint_t labellen,
1427c478bd9Sstevel@tonic-gate     uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
1437c478bd9Sstevel@tonic-gate     uchar_t *result, uint_t resultlen)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	uchar_t *S1, *S2;
1467c478bd9Sstevel@tonic-gate 	uchar_t md5_digested_key[MD5_HASH_SIZE];
1477c478bd9Sstevel@tonic-gate 	uchar_t sha1_digested_key[SHA1_HASH_SIZE];
1487c478bd9Sstevel@tonic-gate 	uint_t L_S, L_S1, L_S2;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/* secret is NULL for IV's in exportable ciphersuites */
1517c478bd9Sstevel@tonic-gate 	if (secret == NULL) {
1527c478bd9Sstevel@tonic-gate 		L_S = 0;
1537c478bd9Sstevel@tonic-gate 		L_S2 = L_S1 = 0;
1547c478bd9Sstevel@tonic-gate 		S1 = NULL;
1557c478bd9Sstevel@tonic-gate 		S2 = NULL;
1567c478bd9Sstevel@tonic-gate 		goto do_P_HASH;
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	L_S = roundup(secretlen, 2) / 2;
1607c478bd9Sstevel@tonic-gate 	L_S1 = L_S;
1617c478bd9Sstevel@tonic-gate 	L_S2 = L_S;
1627c478bd9Sstevel@tonic-gate 	S1 = secret;
1637c478bd9Sstevel@tonic-gate 	S2 = secret + (secretlen / 2);	/* Possible overlap of S1 and S2. */
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* Reduce the half secrets if bigger than the HASH's block size */
1667c478bd9Sstevel@tonic-gate 	if (L_S > MD5_HMAC_BLOCK_SIZE) {
1677c478bd9Sstevel@tonic-gate 		MD5_CTX	md5_ctx;
1687c478bd9Sstevel@tonic-gate 		SHA1_CTX sha1_ctx;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 		MD5Init(&md5_ctx);
1717c478bd9Sstevel@tonic-gate 		MD5Update(&md5_ctx, S1, L_S);
1727c478bd9Sstevel@tonic-gate 		MD5Final(md5_digested_key, &md5_ctx);
1737c478bd9Sstevel@tonic-gate 		S1 = md5_digested_key;
1747c478bd9Sstevel@tonic-gate 		L_S1 = MD5_HASH_SIZE;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		SHA1Init(&sha1_ctx);
1777c478bd9Sstevel@tonic-gate 		SHA1Update(&sha1_ctx, S2, L_S);
1787c478bd9Sstevel@tonic-gate 		SHA1Final(sha1_digested_key, &sha1_ctx);
1797c478bd9Sstevel@tonic-gate 		S2 = sha1_digested_key;
1807c478bd9Sstevel@tonic-gate 		L_S2 = SHA1_HASH_SIZE;
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/*
1847c478bd9Sstevel@tonic-gate 	 * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
1857c478bd9Sstevel@tonic-gate 	 *				P_SHA-1(S2, label + seed);
1867c478bd9Sstevel@tonic-gate 	 * the 'seed' here is rand1 + rand2
1877c478bd9Sstevel@tonic-gate 	 */
1887c478bd9Sstevel@tonic-gate do_P_HASH:
1897c478bd9Sstevel@tonic-gate 	/* The first one writes directly to the result */
1907c478bd9Sstevel@tonic-gate 	P_MD5(S1, L_S1, label, labellen, rand1, rand1len, rand2, rand2len,
1917c478bd9Sstevel@tonic-gate 	    result, resultlen, B_FALSE);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/* The second one XOR's with the result. */
1947c478bd9Sstevel@tonic-gate 	P_SHA1(S2, L_S2, label, labellen, rand1, rand1len, rand2, rand2len,
1957c478bd9Sstevel@tonic-gate 	    result, resultlen, B_TRUE);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate  * These two expansion routines are very similar. (they can merge one day).
2007c478bd9Sstevel@tonic-gate  * They implement the P_HASH() function for MD5 and for SHA1, as defined in
2017c478bd9Sstevel@tonic-gate  * RFC2246:
2027c478bd9Sstevel@tonic-gate  *
2037c478bd9Sstevel@tonic-gate  *	P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
2047c478bd9Sstevel@tonic-gate  *				HMAC_hash(secret, A(2) + seed) +
2057c478bd9Sstevel@tonic-gate  *				HMAC_hash(secret, A(3) + seed) + ...
2067c478bd9Sstevel@tonic-gate  * Where + indicates concatenation.
2077c478bd9Sstevel@tonic-gate  * A() is defined as:
2087c478bd9Sstevel@tonic-gate  *	A(0) = seed
2097c478bd9Sstevel@tonic-gate  *	A(i) = HMAC_hash(secret, A(i-1))
2107c478bd9Sstevel@tonic-gate  *
2117c478bd9Sstevel@tonic-gate  * The seed is the concatenation of 'babel', 'rand1', and 'rand2'.
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate static void
2147c478bd9Sstevel@tonic-gate P_MD5(uchar_t *secret, uint_t secretlen, uchar_t *label, uint_t labellen,
2157c478bd9Sstevel@tonic-gate     uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
2167c478bd9Sstevel@tonic-gate     uchar_t *result, uint_t resultlen, boolean_t xor_it)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	uint32_t md5_ipad[MD5_HMAC_INTS_PER_BLOCK];
2197c478bd9Sstevel@tonic-gate 	uint32_t md5_opad[MD5_HMAC_INTS_PER_BLOCK];
2207c478bd9Sstevel@tonic-gate 	uchar_t	md5_hmac[MD5_HASH_SIZE];
2217c478bd9Sstevel@tonic-gate 	uchar_t	A[MD5_HASH_SIZE];
2227c478bd9Sstevel@tonic-gate 	md5_hc_ctx_t md5_hmac_ctx;
2237c478bd9Sstevel@tonic-gate 	uchar_t *res, *cur;
2247c478bd9Sstevel@tonic-gate 	uint_t left = resultlen;
2257c478bd9Sstevel@tonic-gate 	int i;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/* good compilers will leverage the aligment */
2287c478bd9Sstevel@tonic-gate 	bzero(md5_ipad, MD5_HMAC_BLOCK_SIZE);
2297c478bd9Sstevel@tonic-gate 	bzero(md5_opad, MD5_HMAC_BLOCK_SIZE);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	if (secretlen > 0) {
2327c478bd9Sstevel@tonic-gate 		bcopy(secret, md5_ipad, secretlen);
2337c478bd9Sstevel@tonic-gate 		bcopy(secret, md5_opad, secretlen);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	/* A(1) = HMAC_MD5(secret, rand1 + rand2) */
2377c478bd9Sstevel@tonic-gate 	md5_hmac_ctx_init(&md5_hmac_ctx, md5_ipad, md5_opad);
2387c478bd9Sstevel@tonic-gate 	SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, label, labellen);
2397c478bd9Sstevel@tonic-gate 	SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand1, rand1len);
2407c478bd9Sstevel@tonic-gate 	SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand2, rand2len);
2417c478bd9Sstevel@tonic-gate 	SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, A);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	if (xor_it) {
2447c478bd9Sstevel@tonic-gate 		res = md5_hmac;
2457c478bd9Sstevel@tonic-gate 		cur = result;
2467c478bd9Sstevel@tonic-gate 	} else {
2477c478bd9Sstevel@tonic-gate 		res = result;
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	while (left > 0) {
2517c478bd9Sstevel@tonic-gate 		/*
2527c478bd9Sstevel@tonic-gate 		 * Compute HMAC_MD5(secret, A(i) + seed);
2537c478bd9Sstevel@tonic-gate 		 * The secret is already expanded in the ictx and octx, so
2547c478bd9Sstevel@tonic-gate 		 * we can call the SOFT_MAC_INIT_CTX() directly.
2557c478bd9Sstevel@tonic-gate 		 */
2567c478bd9Sstevel@tonic-gate 		SOFT_MAC_INIT_CTX(MD5, &md5_hmac_ctx, md5_ipad, md5_opad,
2577c478bd9Sstevel@tonic-gate 		    MD5_HMAC_BLOCK_SIZE);
2587c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, A, MD5_HASH_SIZE);
2597c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, label, labellen);
2607c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand1, rand1len);
2617c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand2, rand2len);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 		if (left > MD5_HASH_SIZE) {
2647c478bd9Sstevel@tonic-gate 			SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, res);
2657c478bd9Sstevel@tonic-gate 			if (xor_it) {
2667c478bd9Sstevel@tonic-gate 				for (i = 0; i < MD5_HASH_SIZE; i++) {
2677c478bd9Sstevel@tonic-gate 					*cur ^= res[i];
2687c478bd9Sstevel@tonic-gate 					cur++;
2697c478bd9Sstevel@tonic-gate 				}
2707c478bd9Sstevel@tonic-gate 			} else {
2717c478bd9Sstevel@tonic-gate 				res += MD5_HASH_SIZE;
2727c478bd9Sstevel@tonic-gate 			}
2737c478bd9Sstevel@tonic-gate 			left -= MD5_HASH_SIZE;
2747c478bd9Sstevel@tonic-gate 		} else {
2757c478bd9Sstevel@tonic-gate 			SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, md5_hmac);
2767c478bd9Sstevel@tonic-gate 			if (xor_it) {
2777c478bd9Sstevel@tonic-gate 				for (i = 0; i < left; i++) {
2787c478bd9Sstevel@tonic-gate 					*cur ^= md5_hmac[i];
2797c478bd9Sstevel@tonic-gate 					cur++;
2807c478bd9Sstevel@tonic-gate 				}
2817c478bd9Sstevel@tonic-gate 			} else {
2827c478bd9Sstevel@tonic-gate 				bcopy(md5_hmac, res, left);
2837c478bd9Sstevel@tonic-gate 			}
2847c478bd9Sstevel@tonic-gate 			break;
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		/* A(i) = HMAC_MD5(secret, A(i-1) */
2877c478bd9Sstevel@tonic-gate 		SOFT_MAC_INIT_CTX(MD5, &md5_hmac_ctx, md5_ipad, md5_opad,
2887c478bd9Sstevel@tonic-gate 		    MD5_HMAC_BLOCK_SIZE);
2897c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, A, MD5_HASH_SIZE);
2907c478bd9Sstevel@tonic-gate 		SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, A);
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate static void
2947c478bd9Sstevel@tonic-gate P_SHA1(uchar_t *secret, uint_t secretlen, uchar_t *label, uint_t labellen,
2957c478bd9Sstevel@tonic-gate     uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
2967c478bd9Sstevel@tonic-gate     uchar_t *result, uint_t resultlen, boolean_t xor_it)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	uint32_t sha1_ipad[SHA1_HMAC_INTS_PER_BLOCK];
2997c478bd9Sstevel@tonic-gate 	uint32_t sha1_opad[SHA1_HMAC_INTS_PER_BLOCK];
3007c478bd9Sstevel@tonic-gate 	uchar_t	sha1_hmac[SHA1_HASH_SIZE];
3017c478bd9Sstevel@tonic-gate 	uchar_t	A[SHA1_HASH_SIZE];
3027c478bd9Sstevel@tonic-gate 	sha1_hc_ctx_t sha1_hmac_ctx;
3037c478bd9Sstevel@tonic-gate 	uchar_t *res, *cur;
3047c478bd9Sstevel@tonic-gate 	uint_t left = resultlen;
3057c478bd9Sstevel@tonic-gate 	int i;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* good compilers will leverage the aligment */
3087c478bd9Sstevel@tonic-gate 	bzero(sha1_ipad, SHA1_HMAC_BLOCK_SIZE);
3097c478bd9Sstevel@tonic-gate 	bzero(sha1_opad, SHA1_HMAC_BLOCK_SIZE);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if (secretlen > 0) {
3127c478bd9Sstevel@tonic-gate 		bcopy(secret, sha1_ipad, secretlen);
3137c478bd9Sstevel@tonic-gate 		bcopy(secret, sha1_opad, secretlen);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	/* A(1) = HMAC_SHA1(secret, rand1 + rand2) */
3177c478bd9Sstevel@tonic-gate 	sha1_hmac_ctx_init(&sha1_hmac_ctx, sha1_ipad, sha1_opad);
3187c478bd9Sstevel@tonic-gate 	SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, label, labellen);
3197c478bd9Sstevel@tonic-gate 	SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand1, rand1len);
3207c478bd9Sstevel@tonic-gate 	SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand2, rand2len);
3217c478bd9Sstevel@tonic-gate 	SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, A);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	if (xor_it) {
3247c478bd9Sstevel@tonic-gate 		res = sha1_hmac;
3257c478bd9Sstevel@tonic-gate 		cur = result;
3267c478bd9Sstevel@tonic-gate 	} else {
3277c478bd9Sstevel@tonic-gate 		res = result;
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	while (left > 0) {
3317c478bd9Sstevel@tonic-gate 		/*
3327c478bd9Sstevel@tonic-gate 		 * Compute HMAC_SHA1(secret, A(i) + seed);
3337c478bd9Sstevel@tonic-gate 		 * The secret is already expanded in the ictx and octx, so
3347c478bd9Sstevel@tonic-gate 		 * we can call the SOFT_MAC_INIT_CTX() directly.
3357c478bd9Sstevel@tonic-gate 		 */
3367c478bd9Sstevel@tonic-gate 		SOFT_MAC_INIT_CTX(SHA1, &sha1_hmac_ctx,
3377c478bd9Sstevel@tonic-gate 		    (const uchar_t *)sha1_ipad, (const uchar_t *)sha1_opad,
3387c478bd9Sstevel@tonic-gate 		    SHA1_HMAC_BLOCK_SIZE);
3397c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, A, SHA1_HASH_SIZE);
3407c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, label, labellen);
3417c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand1, rand1len);
3427c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand2, rand2len);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		if (left > SHA1_HASH_SIZE) {
3457c478bd9Sstevel@tonic-gate 			SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, res);
3467c478bd9Sstevel@tonic-gate 			if (xor_it) {
3477c478bd9Sstevel@tonic-gate 				for (i = 0; i < SHA1_HASH_SIZE; i++) {
3487c478bd9Sstevel@tonic-gate 					*cur ^= res[i];
3497c478bd9Sstevel@tonic-gate 					cur++;
3507c478bd9Sstevel@tonic-gate 				}
3517c478bd9Sstevel@tonic-gate 			} else {
3527c478bd9Sstevel@tonic-gate 				res += SHA1_HASH_SIZE;
3537c478bd9Sstevel@tonic-gate 			}
3547c478bd9Sstevel@tonic-gate 			left -= SHA1_HASH_SIZE;
3557c478bd9Sstevel@tonic-gate 		} else {
3567c478bd9Sstevel@tonic-gate 			SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, sha1_hmac);
3577c478bd9Sstevel@tonic-gate 			if (xor_it) {
3587c478bd9Sstevel@tonic-gate 				for (i = 0; i < left; i++) {
3597c478bd9Sstevel@tonic-gate 					*cur ^= sha1_hmac[i];
3607c478bd9Sstevel@tonic-gate 					cur++;
3617c478bd9Sstevel@tonic-gate 				}
3627c478bd9Sstevel@tonic-gate 			} else {
3637c478bd9Sstevel@tonic-gate 				bcopy(sha1_hmac, res, left);
3647c478bd9Sstevel@tonic-gate 			}
3657c478bd9Sstevel@tonic-gate 			break;
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 		/* A(i) = HMAC_SHA1(secret, A(i-1) */
3687c478bd9Sstevel@tonic-gate 		SOFT_MAC_INIT_CTX(SHA1, &sha1_hmac_ctx,
3697c478bd9Sstevel@tonic-gate 		    (const uchar_t *)sha1_ipad, (const uchar_t *)sha1_opad,
3707c478bd9Sstevel@tonic-gate 		    SHA1_HMAC_BLOCK_SIZE);
3717c478bd9Sstevel@tonic-gate 		SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, A, SHA1_HASH_SIZE);
3727c478bd9Sstevel@tonic-gate 		SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, A);
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate }
37560722cc8Sizick 
37660722cc8Sizick /* This function handles the call from C_DeriveKey for CKM_TLS_PRF */
37760722cc8Sizick CK_RV
37860722cc8Sizick derive_tls_prf(CK_TLS_PRF_PARAMS_PTR param, soft_object_t *basekey_p)
37960722cc8Sizick {
38060722cc8Sizick 
38160722cc8Sizick 	if (param->pOutput == NULL || param->pulOutputLen == 0)
38260722cc8Sizick 		return (CKR_BUFFER_TOO_SMALL);
38360722cc8Sizick 
38460722cc8Sizick 	(void) soft_tls_prf(OBJ_SEC_VALUE(basekey_p),
38560722cc8Sizick 	    OBJ_SEC_VALUE_LEN(basekey_p), param->pLabel, param->ulLabelLen,
38660722cc8Sizick 	    param->pSeed, param->ulSeedLen, NULL, 0, param->pOutput,
38760722cc8Sizick 	    *param->pulOutputLen);
38860722cc8Sizick 
38960722cc8Sizick 	return (CKR_OK);
39060722cc8Sizick }
39160722cc8Sizick 
39260722cc8Sizick 
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate  * soft_ssl_master_key_derive()
3957c478bd9Sstevel@tonic-gate  *
3967c478bd9Sstevel@tonic-gate  * Arguments:
3977c478bd9Sstevel@tonic-gate  * . session_p
3987c478bd9Sstevel@tonic-gate  * . mech_p:	key derivation mechanism. the mechanism parameter carries the
3997c478bd9Sstevel@tonic-gate  *		client and master random from the Hello handshake messages.
4007c478bd9Sstevel@tonic-gate  * . basekey_p: The pre-master secret key.
4017c478bd9Sstevel@tonic-gate  * . pTemplate & ulAttributeCount: Any extra attributes for the key to be
4027c478bd9Sstevel@tonic-gate  *		created.
4037c478bd9Sstevel@tonic-gate  * . phKey:	store for handle to the derived key.
4047c478bd9Sstevel@tonic-gate  *
4057c478bd9Sstevel@tonic-gate  * Description:
4067c478bd9Sstevel@tonic-gate  *	Derive the SSL master secret from the pre-master secret, the client
4077c478bd9Sstevel@tonic-gate  *	and server random.
4087c478bd9Sstevel@tonic-gate  *	In SSL 3.0, master_secret =
4097c478bd9Sstevel@tonic-gate  *	    MD5(pre_master_secret + SHA('A' + pre_master_secret +
4107c478bd9Sstevel@tonic-gate  *	        ClientHello.random + ServerHello.random)) +
4117c478bd9Sstevel@tonic-gate  *	    MD5(pre_master_secret + SHA('BB' + pre_master_secret +
4127c478bd9Sstevel@tonic-gate  *	        ClientHello.random + ServerHello.random)) +
4137c478bd9Sstevel@tonic-gate  *	    MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
4147c478bd9Sstevel@tonic-gate  *	        ClientHello.random + ServerHello.random));
4157c478bd9Sstevel@tonic-gate  *
4167c478bd9Sstevel@tonic-gate  *	In TLS 1.0 (a.k.a. SSL 3.1), master_secret =
4177c478bd9Sstevel@tonic-gate  *	    PRF(pre_master_secret, "master secret",
4187c478bd9Sstevel@tonic-gate  *		ClientHello.random + ServerHello.random)
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate CK_RV
4217c478bd9Sstevel@tonic-gate soft_ssl_master_key_derive(soft_session_t *sp, CK_MECHANISM_PTR mech,
4227c478bd9Sstevel@tonic-gate     soft_object_t *basekey_p, CK_ATTRIBUTE_PTR pTemplate,
4237c478bd9Sstevel@tonic-gate     CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	uchar_t	*pmsecret = OBJ_SEC_VALUE(basekey_p);
4267c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
4277c478bd9Sstevel@tonic-gate 	/* LINTED */
4287c478bd9Sstevel@tonic-gate 	uint_t pmlen = (uint_t)OBJ_SEC_VALUE_LEN(basekey_p);
4297c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
4307c478bd9Sstevel@tonic-gate 	uint_t pmlen = OBJ_SEC_VALUE_LEN(basekey_p);
4317c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
4327c478bd9Sstevel@tonic-gate 	CK_SSL3_MASTER_KEY_DERIVE_PARAMS *mkd_params;
4337c478bd9Sstevel@tonic-gate 	CK_SSL3_RANDOM_DATA *random_data;
4347c478bd9Sstevel@tonic-gate 	CK_VERSION_PTR	pVersion;
4357c478bd9Sstevel@tonic-gate 	uchar_t	ssl_master_secret[48];
4367c478bd9Sstevel@tonic-gate 	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
4377c478bd9Sstevel@tonic-gate 	CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
4387c478bd9Sstevel@tonic-gate 	CK_BBOOL true = TRUE;
4397c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE obj_tmpl[MAX_DEFAULT_ATTRS];
4407c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE_PTR new_tmpl;
4417c478bd9Sstevel@tonic-gate 	CK_ULONG newattrcount;
4427c478bd9Sstevel@tonic-gate 	boolean_t new_tmpl_allocated = B_FALSE, is_tls = B_FALSE;
4437c478bd9Sstevel@tonic-gate 	ulong_t i;
4447c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
4457c478bd9Sstevel@tonic-gate 	uint_t ClientRandomLen, ServerRandomLen;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	/* Check the validity of the mechanism's parameter */
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	mkd_params = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)mech->pParameter;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if (mkd_params == NULL ||
4527c478bd9Sstevel@tonic-gate 	    mech->ulParameterLen != sizeof (CK_SSL3_MASTER_KEY_DERIVE_PARAMS))
4537c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_PARAM_INVALID);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	pVersion = mkd_params->pVersion;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	switch (mech->mechanism) {
4587c478bd9Sstevel@tonic-gate 	case CKM_TLS_MASTER_KEY_DERIVE:
4597c478bd9Sstevel@tonic-gate 		is_tls = B_TRUE;
4607c478bd9Sstevel@tonic-gate 	/* FALLTHRU */
4617c478bd9Sstevel@tonic-gate 	case CKM_SSL3_MASTER_KEY_DERIVE:
4627c478bd9Sstevel@tonic-gate 		/* Invalid pre-master key length. What else to return? */
4637c478bd9Sstevel@tonic-gate 		if (pmlen != 48)
4647c478bd9Sstevel@tonic-gate 			return (CKR_ARGUMENTS_BAD);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		/* Get the SSL version number from the premaster secret */
4677c478bd9Sstevel@tonic-gate 		if (pVersion == NULL_PTR)
4687c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 		bcopy(pmsecret, pVersion, sizeof (CK_VERSION));
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		break;
4737c478bd9Sstevel@tonic-gate 	case CKM_TLS_MASTER_KEY_DERIVE_DH:
4747c478bd9Sstevel@tonic-gate 		is_tls = B_TRUE;
4757c478bd9Sstevel@tonic-gate 	/* FALLTHRU */
4767c478bd9Sstevel@tonic-gate 	case CKM_SSL3_MASTER_KEY_DERIVE_DH:
4777c478bd9Sstevel@tonic-gate 		if (pVersion != NULL_PTR)
4787c478bd9Sstevel@tonic-gate 			return (CKR_MECHANISM_PARAM_INVALID);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	random_data = &mkd_params->RandomInfo;
4827c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
4837c478bd9Sstevel@tonic-gate 	/* LINTED */
4847c478bd9Sstevel@tonic-gate 	ClientRandomLen = (uint_t)random_data->ulClientRandomLen;
4857c478bd9Sstevel@tonic-gate 	/* LINTED */
4867c478bd9Sstevel@tonic-gate 	ServerRandomLen = (uint_t)random_data->ulServerRandomLen;
4877c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
4887c478bd9Sstevel@tonic-gate 	ClientRandomLen = random_data->ulClientRandomLen;
4897c478bd9Sstevel@tonic-gate 	ServerRandomLen = random_data->ulServerRandomLen;
4907c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	if (random_data->pClientRandom == NULL_PTR || ClientRandomLen == 0 ||
4937c478bd9Sstevel@tonic-gate 	    random_data->pServerRandom == NULL_PTR || ServerRandomLen == 0) {
4947c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_PARAM_INVALID);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/* Now the actual secret derivation */
4987c478bd9Sstevel@tonic-gate 	if (!is_tls) {
4997c478bd9Sstevel@tonic-gate 		soft_ssl3_churn(pmsecret, pmlen, random_data->pClientRandom,
5007c478bd9Sstevel@tonic-gate 		    ClientRandomLen, random_data->pServerRandom,
5017c478bd9Sstevel@tonic-gate 		    ServerRandomLen, 3, ssl_master_secret);
5027c478bd9Sstevel@tonic-gate 	} else {
5037c478bd9Sstevel@tonic-gate 		soft_tls_prf(pmsecret, pmlen, TLS_MASTER_SECRET_LABEL,
5047c478bd9Sstevel@tonic-gate 		    TLS_MASTER_SECRET_LABEL_LEN, random_data->pClientRandom,
5057c478bd9Sstevel@tonic-gate 		    ClientRandomLen, random_data->pServerRandom,
5067c478bd9Sstevel@tonic-gate 		    ServerRandomLen, ssl_master_secret, 48);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
5107c478bd9Sstevel@tonic-gate 	 * The object creation attributes need to be in one contiguous
5117c478bd9Sstevel@tonic-gate 	 * array. In addition to the attrs from the application supplied
5127c478bd9Sstevel@tonic-gate 	 * pTemplates, We need to add the class, type, value, valuelen and
5137c478bd9Sstevel@tonic-gate 	 * CKA_DERIVE.
5147c478bd9Sstevel@tonic-gate 	 * In the most likely case, the application passes between zero and
5157c478bd9Sstevel@tonic-gate 	 * handful of attributes, We optimize for that case by allocating
5167c478bd9Sstevel@tonic-gate 	 * the new template on the stack. Oherwise we malloc() it.
5177c478bd9Sstevel@tonic-gate 	 */
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	newattrcount = ulAttributeCount + 4;
5207c478bd9Sstevel@tonic-gate 	if (newattrcount > MAX_DEFAULT_ATTRS) {
5217c478bd9Sstevel@tonic-gate 		new_tmpl = malloc(sizeof (CK_ATTRIBUTE) * newattrcount);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		if (new_tmpl == NULL)
5247c478bd9Sstevel@tonic-gate 			return (CKR_HOST_MEMORY);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 		new_tmpl_allocated = B_TRUE;
5277c478bd9Sstevel@tonic-gate 	} else
5287c478bd9Sstevel@tonic-gate 		new_tmpl = obj_tmpl;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	/*
5317c478bd9Sstevel@tonic-gate 	 * Fill in the new template.
5327c478bd9Sstevel@tonic-gate 	 * We put the attributes contributed by the mechanism first
5337c478bd9Sstevel@tonic-gate 	 * so that they override the application supplied ones.
5347c478bd9Sstevel@tonic-gate 	 */
5357c478bd9Sstevel@tonic-gate 	new_tmpl[0].type = CKA_CLASS;
5367c478bd9Sstevel@tonic-gate 	new_tmpl[0].pValue = &class;
5377c478bd9Sstevel@tonic-gate 	new_tmpl[0].ulValueLen = sizeof (class);
5387c478bd9Sstevel@tonic-gate 	new_tmpl[1].type = CKA_KEY_TYPE;
5397c478bd9Sstevel@tonic-gate 	new_tmpl[1].pValue = &keyType;
5407c478bd9Sstevel@tonic-gate 	new_tmpl[1].ulValueLen = sizeof (keyType);
5417c478bd9Sstevel@tonic-gate 	new_tmpl[2].type = CKA_DERIVE;
5427c478bd9Sstevel@tonic-gate 	new_tmpl[2].pValue = &true;
5437c478bd9Sstevel@tonic-gate 	new_tmpl[2].ulValueLen = sizeof (true);
5447c478bd9Sstevel@tonic-gate 	new_tmpl[3].type = CKA_VALUE;
5457c478bd9Sstevel@tonic-gate 	new_tmpl[3].pValue = ssl_master_secret;
5467c478bd9Sstevel@tonic-gate 	new_tmpl[3].ulValueLen = 48;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	/* Any attributes left? */
5497c478bd9Sstevel@tonic-gate 	if (ulAttributeCount > 0) {
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		/* Validate the default class and type attributes */
5527c478bd9Sstevel@tonic-gate 		for (i = 0; i < ulAttributeCount; i++) {
5537c478bd9Sstevel@tonic-gate 			/* The caller is responsible for proper alignment */
5547c478bd9Sstevel@tonic-gate 			if ((pTemplate[i].type == CKA_CLASS) &&
5557c478bd9Sstevel@tonic-gate 			    (*((CK_OBJECT_CLASS *)pTemplate[i].pValue) !=
5567c478bd9Sstevel@tonic-gate 			    CKO_SECRET_KEY)) {
5577c478bd9Sstevel@tonic-gate 				rv = CKR_TEMPLATE_INCONSISTENT;
5587c478bd9Sstevel@tonic-gate 				goto out;
5597c478bd9Sstevel@tonic-gate 			}
5607c478bd9Sstevel@tonic-gate 			if ((pTemplate[i].type == CKA_KEY_TYPE) &&
5617c478bd9Sstevel@tonic-gate 			    (*((CK_KEY_TYPE *)pTemplate[i].pValue) !=
5627c478bd9Sstevel@tonic-gate 			    CKK_GENERIC_SECRET)) {
5637c478bd9Sstevel@tonic-gate 				rv = CKR_TEMPLATE_INCONSISTENT;
5647c478bd9Sstevel@tonic-gate 				goto out;
5657c478bd9Sstevel@tonic-gate 			}
5667c478bd9Sstevel@tonic-gate 		}
5677c478bd9Sstevel@tonic-gate 		bcopy(pTemplate, &new_tmpl[4],
5687c478bd9Sstevel@tonic-gate 		    ulAttributeCount * sizeof (CK_ATTRIBUTE));
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	rv = soft_add_derived_key(new_tmpl, newattrcount, phKey, sp, basekey_p);
5727c478bd9Sstevel@tonic-gate out:
5737c478bd9Sstevel@tonic-gate 	if (new_tmpl_allocated)
5747c478bd9Sstevel@tonic-gate 		free(new_tmpl);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	return (rv);
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate  * soft_ssl3_key_and_mac_derive()
5817c478bd9Sstevel@tonic-gate  *
5827c478bd9Sstevel@tonic-gate  * Arguments:
5837c478bd9Sstevel@tonic-gate  * . session_p
5847c478bd9Sstevel@tonic-gate  * . mech_p:	key derivation mechanism. the mechanism parameter carries the
5857c478bd9Sstevel@tonic-gate  *		client and mastter random from the Hello handshake messages,
5867c478bd9Sstevel@tonic-gate  *		the specification of the key and IV sizes, and the location
5877c478bd9Sstevel@tonic-gate  * 		for the resulting keys and IVs.
5887c478bd9Sstevel@tonic-gate  * . basekey_p: The master secret key.
5897c478bd9Sstevel@tonic-gate  * . pTemplate & ulAttributeCount: Any extra attributes for the key to be
5907c478bd9Sstevel@tonic-gate  *		created.
5917c478bd9Sstevel@tonic-gate  *
5927c478bd9Sstevel@tonic-gate  * Description:
5937c478bd9Sstevel@tonic-gate  *	Derive the SSL key material (Client and server MAC secrets, symmetric
5947c478bd9Sstevel@tonic-gate  *	keys and IVs), from the master secret and the client
5957c478bd9Sstevel@tonic-gate  *	and server random.
5967c478bd9Sstevel@tonic-gate  *	First a keyblock is generated usining the following formula:
5977c478bd9Sstevel@tonic-gate  *	key_block =
5987c478bd9Sstevel@tonic-gate  *      	MD5(master_secret + SHA(`A' + master_secret +
5997c478bd9Sstevel@tonic-gate  *					ServerHello.random +
6007c478bd9Sstevel@tonic-gate  *					ClientHello.random)) +
6017c478bd9Sstevel@tonic-gate  *      	MD5(master_secret + SHA(`BB' + master_secret +
6027c478bd9Sstevel@tonic-gate  *					ServerHello.random +
6037c478bd9Sstevel@tonic-gate  *					ClientHello.random)) +
6047c478bd9Sstevel@tonic-gate  *      	MD5(master_secret + SHA(`CCC' + master_secret +
6057c478bd9Sstevel@tonic-gate  *					ServerHello.random +
6067c478bd9Sstevel@tonic-gate  *					ClientHello.random)) + [...];
6077c478bd9Sstevel@tonic-gate  *
6087c478bd9Sstevel@tonic-gate  *	In TLS 1.0 (a.k.a. SSL 3.1), key_block =
6097c478bd9Sstevel@tonic-gate  *	    PRF(master_secret, "key expansion",
6107c478bd9Sstevel@tonic-gate  *		ServerHello.random + ClientHello.random)
6117c478bd9Sstevel@tonic-gate  *
6127c478bd9Sstevel@tonic-gate  *	Then the keys materials are taken from the keyblock.
6137c478bd9Sstevel@tonic-gate  */
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate CK_RV
6167c478bd9Sstevel@tonic-gate soft_ssl_key_and_mac_derive(soft_session_t *sp, CK_MECHANISM_PTR mech,
6177c478bd9Sstevel@tonic-gate     soft_object_t *basekey_p, CK_ATTRIBUTE_PTR pTemplate,
6187c478bd9Sstevel@tonic-gate     CK_ULONG ulAttributeCount)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate 	uchar_t	*msecret = OBJ_SEC_VALUE(basekey_p);
6217c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
6227c478bd9Sstevel@tonic-gate 	/* LINTED */
6237c478bd9Sstevel@tonic-gate 	uint_t mslen = (uint_t)OBJ_SEC_VALUE_LEN(basekey_p);
6247c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
6257c478bd9Sstevel@tonic-gate 	uint_t mslen = OBJ_SEC_VALUE_LEN(basekey_p);
6267c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
6277c478bd9Sstevel@tonic-gate 	CK_SSL3_KEY_MAT_PARAMS *km_params;
6287c478bd9Sstevel@tonic-gate 	CK_SSL3_RANDOM_DATA *random_data;
6297c478bd9Sstevel@tonic-gate 	CK_SSL3_KEY_MAT_OUT *kmo;
6307c478bd9Sstevel@tonic-gate 	uchar_t key_block[MAX_KEYBLOCK], *kb, *export_keys = NULL;
6317c478bd9Sstevel@tonic-gate 	CK_OBJECT_CLASS class = CKO_SECRET_KEY;
6327c478bd9Sstevel@tonic-gate 	CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
6337c478bd9Sstevel@tonic-gate 	CK_BBOOL true = TRUE;
6347c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE obj_tmpl[MAX_DEFAULT_ATTRS];
6357c478bd9Sstevel@tonic-gate 	CK_ATTRIBUTE_PTR new_tmpl;
6367c478bd9Sstevel@tonic-gate 	ulong_t newattrcount, mac_key_bytes, secret_key_bytes, iv_bytes;
6371c02caffSmcpowers 	ulong_t extra_attr_count;
6387c478bd9Sstevel@tonic-gate 	uint_t size;
6391c02caffSmcpowers 	int rounds, n = 0;
6407c478bd9Sstevel@tonic-gate 	boolean_t new_tmpl_allocated = B_FALSE, isExport;
6417c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
6427c478bd9Sstevel@tonic-gate 	uint_t ClientRandomLen, ServerRandomLen;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	/* Check the validity of the mechanism's parameter */
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	km_params = (CK_SSL3_KEY_MAT_PARAMS *)mech->pParameter;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if (km_params == NULL ||
6497c478bd9Sstevel@tonic-gate 	    mech->ulParameterLen != sizeof (CK_SSL3_KEY_MAT_PARAMS) ||
6507c478bd9Sstevel@tonic-gate 	    (kmo = km_params->pReturnedKeyMaterial) == NULL)
6517c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_PARAM_INVALID);
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	isExport = (km_params->bIsExport == TRUE);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	random_data = &km_params->RandomInfo;
6567c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
6577c478bd9Sstevel@tonic-gate 	/* LINTED */
6587c478bd9Sstevel@tonic-gate 	ClientRandomLen = (uint_t)random_data->ulClientRandomLen;
6597c478bd9Sstevel@tonic-gate 	/* LINTED */
6607c478bd9Sstevel@tonic-gate 	ServerRandomLen = (uint_t)random_data->ulServerRandomLen;
6617c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
6627c478bd9Sstevel@tonic-gate 	ClientRandomLen = random_data->ulClientRandomLen;
6637c478bd9Sstevel@tonic-gate 	ServerRandomLen = random_data->ulServerRandomLen;
6647c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (random_data->pClientRandom == NULL_PTR || ClientRandomLen == 0 ||
6677c478bd9Sstevel@tonic-gate 	    random_data->pServerRandom == NULL_PTR || ServerRandomLen == 0) {
6687c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_PARAM_INVALID);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	mac_key_bytes = km_params->ulMacSizeInBits / 8;
6727c478bd9Sstevel@tonic-gate 	secret_key_bytes = km_params->ulKeySizeInBits / 8;
6737c478bd9Sstevel@tonic-gate 	iv_bytes = km_params->ulIVSizeInBits / 8;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	if ((iv_bytes > 0) &&
6767c478bd9Sstevel@tonic-gate 	    ((kmo->pIVClient == NULL) || (kmo->pIVServer == NULL)))
6777c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_PARAM_INVALID);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	/*
6807c478bd9Sstevel@tonic-gate 	 * For exportable ciphersuites, the IV's aren't taken from the
6817c478bd9Sstevel@tonic-gate 	 * key block. They are directly derived from the client and
6827c478bd9Sstevel@tonic-gate 	 * server random data.
6837c478bd9Sstevel@tonic-gate 	 * For SSL3.0:
6847c478bd9Sstevel@tonic-gate 	 *	client_write_IV = MD5(ClientHello.random + ServerHello.random);
6857c478bd9Sstevel@tonic-gate 	 *	server_write_IV = MD5(ServerHello.random + ClientHello.random);
6867c478bd9Sstevel@tonic-gate 	 * For TLS1.0:
6877c478bd9Sstevel@tonic-gate 	 *	iv_block = PRF("", "IV block", client_random +
6887c478bd9Sstevel@tonic-gate 	 *			server_random)[0..15]
6897c478bd9Sstevel@tonic-gate 	 *	client_write_IV = iv_block[0..7]
6907c478bd9Sstevel@tonic-gate 	 *	server_write_IV = iv_block[8..15]
6917c478bd9Sstevel@tonic-gate 	 */
6927c478bd9Sstevel@tonic-gate 	if ((isExport) && (iv_bytes > 0)) {
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 		if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE) {
6957c478bd9Sstevel@tonic-gate 			MD5_CTX	exp_md5_ctx;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 			if (iv_bytes > MD5_HASH_SIZE)
6987c478bd9Sstevel@tonic-gate 				return (CKR_MECHANISM_PARAM_INVALID);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 			MD5Init(&exp_md5_ctx);
7017c478bd9Sstevel@tonic-gate 			MD5Update(&exp_md5_ctx, random_data->pClientRandom,
7027c478bd9Sstevel@tonic-gate 			    ClientRandomLen);
7037c478bd9Sstevel@tonic-gate 			MD5Update(&exp_md5_ctx, random_data->pServerRandom,
7047c478bd9Sstevel@tonic-gate 			    ServerRandomLen);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 			/* there's room in key_block. use it */
7077c478bd9Sstevel@tonic-gate 			MD5Final(key_block, &exp_md5_ctx);
7087c478bd9Sstevel@tonic-gate 			bcopy(key_block, kmo->pIVClient, iv_bytes);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 			MD5Init(&exp_md5_ctx);
7117c478bd9Sstevel@tonic-gate 			MD5Update(&exp_md5_ctx, random_data->pServerRandom,
7127c478bd9Sstevel@tonic-gate 			    ServerRandomLen);
7137c478bd9Sstevel@tonic-gate 			MD5Update(&exp_md5_ctx, random_data->pClientRandom,
7147c478bd9Sstevel@tonic-gate 			    ClientRandomLen);
7157c478bd9Sstevel@tonic-gate 			MD5Final(key_block, &exp_md5_ctx);
7167c478bd9Sstevel@tonic-gate 			bcopy(key_block, kmo->pIVServer, iv_bytes);
7177c478bd9Sstevel@tonic-gate 		} else {
7187c478bd9Sstevel@tonic-gate 			uchar_t	iv_block[16];
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 			if (iv_bytes != 8)
7217c478bd9Sstevel@tonic-gate 				return (CKR_MECHANISM_PARAM_INVALID);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 			soft_tls_prf(NULL, 0, TLS_IV_BLOCK_LABEL,
7247c478bd9Sstevel@tonic-gate 			    TLS_IV_BLOCK_LABEL_LEN,
7257c478bd9Sstevel@tonic-gate 			    random_data->pClientRandom, ClientRandomLen,
7267c478bd9Sstevel@tonic-gate 			    random_data->pServerRandom, ServerRandomLen,
7277c478bd9Sstevel@tonic-gate 			    iv_block, 16);
7281c02caffSmcpowers 			bcopy(iv_block, kmo->pIVClient, 8);
7291c02caffSmcpowers 			bcopy(iv_block + 8, kmo->pIVServer, 8);
7307c478bd9Sstevel@tonic-gate 		}
7317c478bd9Sstevel@tonic-gate 		/* so we won't allocate a key_block bigger than needed */
7327c478bd9Sstevel@tonic-gate 		iv_bytes = 0;
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	/* Now the actual secret derivation */
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
7387c478bd9Sstevel@tonic-gate 	/* LINTED */
7397c478bd9Sstevel@tonic-gate 	size = (uint_t)((mac_key_bytes + secret_key_bytes + iv_bytes) * 2);
7407c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
7417c478bd9Sstevel@tonic-gate 	size = (mac_key_bytes + secret_key_bytes + iv_bytes) * 2;
7427c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	/* Need to handle this better */
7457c478bd9Sstevel@tonic-gate 	if (size > MAX_KEYBLOCK)
7467c478bd9Sstevel@tonic-gate 		return (CKR_MECHANISM_PARAM_INVALID);
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	rounds = howmany(size, MD5_HASH_SIZE);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	kb = key_block;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE) {
7537c478bd9Sstevel@tonic-gate 		soft_ssl3_churn(msecret, mslen, random_data->pServerRandom,
7547c478bd9Sstevel@tonic-gate 		    ServerRandomLen, random_data->pClientRandom,
7557c478bd9Sstevel@tonic-gate 		    ClientRandomLen, rounds, kb);
7567c478bd9Sstevel@tonic-gate 	} else {
7577c478bd9Sstevel@tonic-gate 		soft_tls_prf(msecret, mslen, TLS_KEY_EXPANSION_LABEL,
7587c478bd9Sstevel@tonic-gate 		    TLS_KEY_EXPANSION_LABEL_LEN,
7597c478bd9Sstevel@tonic-gate 		    random_data->pServerRandom, ServerRandomLen,
7607c478bd9Sstevel@tonic-gate 		    random_data->pClientRandom, ClientRandomLen,
7617c478bd9Sstevel@tonic-gate 		    kb, size);
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	/* Now create the objects */
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	kmo->hClientMacSecret = CK_INVALID_HANDLE;
7677c478bd9Sstevel@tonic-gate 	kmo->hServerMacSecret = CK_INVALID_HANDLE;
7687c478bd9Sstevel@tonic-gate 	kmo->hClientKey = CK_INVALID_HANDLE;
7697c478bd9Sstevel@tonic-gate 	kmo->hServerKey = CK_INVALID_HANDLE;
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/* First the MAC secrets */
7727c478bd9Sstevel@tonic-gate 	if (mac_key_bytes > 0) {
7737c478bd9Sstevel@tonic-gate 		obj_tmpl[0].type = CKA_CLASS;
7747c478bd9Sstevel@tonic-gate 		obj_tmpl[0].pValue = &class;	/* CKO_SECRET_KEY */
7757c478bd9Sstevel@tonic-gate 		obj_tmpl[0].ulValueLen = sizeof (class);
7767c478bd9Sstevel@tonic-gate 		obj_tmpl[1].type = CKA_KEY_TYPE;
7777c478bd9Sstevel@tonic-gate 		obj_tmpl[1].pValue = &keyType;	/* CKK_GENERIC_SECRET */
7787c478bd9Sstevel@tonic-gate 		obj_tmpl[1].ulValueLen = sizeof (keyType);
7797c478bd9Sstevel@tonic-gate 		obj_tmpl[2].type = CKA_DERIVE;
7807c478bd9Sstevel@tonic-gate 		obj_tmpl[2].pValue = &true;
7817c478bd9Sstevel@tonic-gate 		obj_tmpl[2].ulValueLen = sizeof (true);
7827c478bd9Sstevel@tonic-gate 		obj_tmpl[3].type = CKA_SIGN;
7837c478bd9Sstevel@tonic-gate 		obj_tmpl[3].pValue = &true;
7847c478bd9Sstevel@tonic-gate 		obj_tmpl[3].ulValueLen = sizeof (true);
7857c478bd9Sstevel@tonic-gate 		obj_tmpl[4].type = CKA_VERIFY;
7867c478bd9Sstevel@tonic-gate 		obj_tmpl[4].pValue = &true;
7877c478bd9Sstevel@tonic-gate 		obj_tmpl[4].ulValueLen = sizeof (true);
7887c478bd9Sstevel@tonic-gate 		obj_tmpl[5].type = CKA_VALUE;
7897c478bd9Sstevel@tonic-gate 		obj_tmpl[5].pValue = kb;
7907c478bd9Sstevel@tonic-gate 		obj_tmpl[5].ulValueLen = mac_key_bytes;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 		rv = soft_add_derived_key(obj_tmpl, 6,
7937c478bd9Sstevel@tonic-gate 		    &(kmo->hClientMacSecret), sp, basekey_p);
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
7967c478bd9Sstevel@tonic-gate 			goto out_err;
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		kb += mac_key_bytes;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 		obj_tmpl[5].pValue = kb;
8017c478bd9Sstevel@tonic-gate 		rv = soft_add_derived_key(obj_tmpl, 6,
8027c478bd9Sstevel@tonic-gate 		    &(kmo->hServerMacSecret), sp, basekey_p);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
8057c478bd9Sstevel@tonic-gate 			goto out_err;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 		kb += mac_key_bytes;
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	/* Then the symmetric ciphers keys */
8117c478bd9Sstevel@tonic-gate 
8121c02caffSmcpowers 	extra_attr_count = (secret_key_bytes == 0) ? 6 : 5;
8131c02caffSmcpowers 	newattrcount = ulAttributeCount + extra_attr_count;
8147c478bd9Sstevel@tonic-gate 	if (newattrcount > MAX_DEFAULT_ATTRS) {
8157c478bd9Sstevel@tonic-gate 		new_tmpl = malloc(sizeof (CK_ATTRIBUTE) * newattrcount);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 		if (new_tmpl == NULL)
8187c478bd9Sstevel@tonic-gate 			return (CKR_HOST_MEMORY);
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 		new_tmpl_allocated = B_TRUE;
8217c478bd9Sstevel@tonic-gate 	} else
8227c478bd9Sstevel@tonic-gate 		new_tmpl = obj_tmpl;
8237c478bd9Sstevel@tonic-gate 
8241c02caffSmcpowers 	new_tmpl[n].type = CKA_CLASS;
8251c02caffSmcpowers 	new_tmpl[n].pValue = &class;	/* CKO_SECRET_KEY */
8261c02caffSmcpowers 	new_tmpl[n].ulValueLen = sizeof (class);
8271c02caffSmcpowers 	++n;
8287c478bd9Sstevel@tonic-gate 	/*
8291c02caffSmcpowers 	 * The keyType comes from the application's template, and depends
8301c02caffSmcpowers 	 * on the ciphersuite. The only exception is authentication only
8311c02caffSmcpowers 	 * ciphersuites which do not use cipher keys.
8327c478bd9Sstevel@tonic-gate 	 */
8331c02caffSmcpowers 	if (secret_key_bytes == 0) {
8341c02caffSmcpowers 		new_tmpl[n].type = CKA_KEY_TYPE;
8351c02caffSmcpowers 		new_tmpl[n].pValue = &keyType;	/* CKK_GENERIC_SECRET */
8361c02caffSmcpowers 		new_tmpl[n].ulValueLen = sizeof (keyType);
8371c02caffSmcpowers 		n++;
8381c02caffSmcpowers 	}
8391c02caffSmcpowers 	new_tmpl[n].type = CKA_DERIVE;
8401c02caffSmcpowers 	new_tmpl[n].pValue = &true;
8411c02caffSmcpowers 	new_tmpl[n].ulValueLen = sizeof (true);
8421c02caffSmcpowers 	n++;
8431c02caffSmcpowers 	new_tmpl[n].type = CKA_ENCRYPT;
8441c02caffSmcpowers 	new_tmpl[n].pValue = &true;
8451c02caffSmcpowers 	new_tmpl[n].ulValueLen = sizeof (true);
8461c02caffSmcpowers 	n++;
8471c02caffSmcpowers 	new_tmpl[n].type = CKA_DECRYPT;
8481c02caffSmcpowers 	new_tmpl[n].pValue = &true;
8491c02caffSmcpowers 	new_tmpl[n].ulValueLen = sizeof (true);
8501c02caffSmcpowers 	n++;
8511c02caffSmcpowers 	new_tmpl[n].type = CKA_VALUE;
8521c02caffSmcpowers 	new_tmpl[n].pValue = NULL;
8531c02caffSmcpowers 	new_tmpl[n].ulValueLen = 0;
8547c478bd9Sstevel@tonic-gate 
8551c02caffSmcpowers 	if (secret_key_bytes > 0) {
8567c478bd9Sstevel@tonic-gate 		if (isExport) {
8577c478bd9Sstevel@tonic-gate 			if (secret_key_bytes > MD5_HASH_SIZE) {
8587c478bd9Sstevel@tonic-gate 				rv = CKR_MECHANISM_PARAM_INVALID;
8597c478bd9Sstevel@tonic-gate 				goto out_err;
8607c478bd9Sstevel@tonic-gate 			}
8617c478bd9Sstevel@tonic-gate 			if ((export_keys = malloc(2 * MD5_HASH_SIZE)) == NULL) {
8627c478bd9Sstevel@tonic-gate 				rv = CKR_HOST_MEMORY;
8637c478bd9Sstevel@tonic-gate 				goto out_err;
8647c478bd9Sstevel@tonic-gate 			}
8657c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
8667c478bd9Sstevel@tonic-gate 			/* LINTED */
8677c478bd9Sstevel@tonic-gate 			soft_ssl_weaken_key(mech, kb, (uint_t)secret_key_bytes,
8687c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
8697c478bd9Sstevel@tonic-gate 			soft_ssl_weaken_key(mech, kb, secret_key_bytes,
8707c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
8717c478bd9Sstevel@tonic-gate 			    random_data->pClientRandom, ClientRandomLen,
8727c478bd9Sstevel@tonic-gate 			    random_data->pServerRandom, ServerRandomLen,
8737c478bd9Sstevel@tonic-gate 			    export_keys, B_TRUE);
8741c02caffSmcpowers 			new_tmpl[n].pValue = export_keys;
8751c02caffSmcpowers 			new_tmpl[n].ulValueLen = MD5_HASH_SIZE;
8767c478bd9Sstevel@tonic-gate 		} else {
8771c02caffSmcpowers 			new_tmpl[n].pValue = kb;
8781c02caffSmcpowers 			new_tmpl[n].ulValueLen = secret_key_bytes;
8791c02caffSmcpowers 		}
8800106fafcShaimay 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (ulAttributeCount > 0)
8831c02caffSmcpowers 		bcopy(pTemplate, &new_tmpl[extra_attr_count],
8847c478bd9Sstevel@tonic-gate 		    ulAttributeCount * sizeof (CK_ATTRIBUTE));
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	rv = soft_add_derived_key(new_tmpl, newattrcount,
8877c478bd9Sstevel@tonic-gate 	    &(kmo->hClientKey), sp, basekey_p);
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
8907c478bd9Sstevel@tonic-gate 		goto out_err;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	kb += secret_key_bytes;
8937c478bd9Sstevel@tonic-gate 
8941c02caffSmcpowers 	if (secret_key_bytes > 0) {
8957c478bd9Sstevel@tonic-gate 		if (isExport) {
8967c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
8977c478bd9Sstevel@tonic-gate 			/* LINTED */
8987c478bd9Sstevel@tonic-gate 			soft_ssl_weaken_key(mech, kb, (uint_t)secret_key_bytes,
8997c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
9007c478bd9Sstevel@tonic-gate 			soft_ssl_weaken_key(mech, kb, secret_key_bytes,
9017c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
9027c478bd9Sstevel@tonic-gate 			    random_data->pServerRandom, ServerRandomLen,
9037c478bd9Sstevel@tonic-gate 			    random_data->pClientRandom, ClientRandomLen,
9047c478bd9Sstevel@tonic-gate 			    export_keys + MD5_HASH_SIZE, B_FALSE);
9051c02caffSmcpowers 			new_tmpl[n].pValue = export_keys + MD5_HASH_SIZE;
9067c478bd9Sstevel@tonic-gate 		} else
9071c02caffSmcpowers 			new_tmpl[n].pValue = kb;
9081c02caffSmcpowers 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	rv = soft_add_derived_key(new_tmpl, newattrcount,
9117c478bd9Sstevel@tonic-gate 	    &(kmo->hServerKey), sp, basekey_p);
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
9147c478bd9Sstevel@tonic-gate 		goto out_err;
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	kb += secret_key_bytes;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	/* Finally, the IVs */
9197c478bd9Sstevel@tonic-gate 	if (iv_bytes > 0) {
9207c478bd9Sstevel@tonic-gate 		bcopy(kb, kmo->pIVClient, iv_bytes);
9217c478bd9Sstevel@tonic-gate 		kb += iv_bytes;
9227c478bd9Sstevel@tonic-gate 		bcopy(kb, kmo->pIVServer, iv_bytes);
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	if (new_tmpl_allocated)
9267c478bd9Sstevel@tonic-gate 		free(new_tmpl);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	if (export_keys != NULL)
9297c478bd9Sstevel@tonic-gate 		free(export_keys);
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	return (rv);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate out_err:
9347c478bd9Sstevel@tonic-gate 	if (kmo->hClientMacSecret != CK_INVALID_HANDLE) {
9357c478bd9Sstevel@tonic-gate 		(void) soft_delete_derived_key(sp,
9367c478bd9Sstevel@tonic-gate 		    (soft_object_t *)(kmo->hClientMacSecret));
9377c478bd9Sstevel@tonic-gate 		kmo->hClientMacSecret = CK_INVALID_HANDLE;
9387c478bd9Sstevel@tonic-gate 	}
9397c478bd9Sstevel@tonic-gate 	if (kmo->hServerMacSecret != CK_INVALID_HANDLE) {
9407c478bd9Sstevel@tonic-gate 		(void) soft_delete_derived_key(sp,
9417c478bd9Sstevel@tonic-gate 		    (soft_object_t *)(kmo->hServerMacSecret));
9427c478bd9Sstevel@tonic-gate 		kmo->hServerMacSecret = CK_INVALID_HANDLE;
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate 	if (kmo->hClientKey != CK_INVALID_HANDLE) {
9457c478bd9Sstevel@tonic-gate 		(void) soft_delete_derived_key(sp,
9467c478bd9Sstevel@tonic-gate 		    (soft_object_t *)(kmo->hClientKey));
9477c478bd9Sstevel@tonic-gate 		kmo->hClientKey = CK_INVALID_HANDLE;
9487c478bd9Sstevel@tonic-gate 	}
9497c478bd9Sstevel@tonic-gate 	if (kmo->hServerKey != CK_INVALID_HANDLE) {
9507c478bd9Sstevel@tonic-gate 		(void) soft_delete_derived_key(sp,
9517c478bd9Sstevel@tonic-gate 		    (soft_object_t *)(kmo->hServerKey));
9527c478bd9Sstevel@tonic-gate 		kmo->hServerKey = CK_INVALID_HANDLE;
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	if (new_tmpl_allocated)
9567c478bd9Sstevel@tonic-gate 		free(new_tmpl);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	if (export_keys != NULL)
9597c478bd9Sstevel@tonic-gate 		free(export_keys);
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	return (rv);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate /*
9657c478bd9Sstevel@tonic-gate  * Add the derived key to the session, and, if it's a token object,
9667c478bd9Sstevel@tonic-gate  * write it to the token.
9677c478bd9Sstevel@tonic-gate  */
9687c478bd9Sstevel@tonic-gate static CK_RV
9697c478bd9Sstevel@tonic-gate soft_add_derived_key(CK_ATTRIBUTE_PTR tmpl, CK_ULONG attrcount,
9707c478bd9Sstevel@tonic-gate     CK_OBJECT_HANDLE_PTR phKey, soft_session_t *sp, soft_object_t *basekey_p)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate 	CK_RV rv;
9737c478bd9Sstevel@tonic-gate 	soft_object_t *secret_key;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	if ((secret_key = calloc(1, sizeof (soft_object_t))) == NULL) {
9767c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	if (((rv = soft_build_secret_key_object(tmpl, attrcount, secret_key,
9807c478bd9Sstevel@tonic-gate 	    SOFT_CREATE_OBJ_INT, 0, (CK_KEY_TYPE)~0UL)) != CKR_OK) ||
9817c478bd9Sstevel@tonic-gate 	    ((rv = soft_pin_expired_check(secret_key)) != CKR_OK) ||
9827c478bd9Sstevel@tonic-gate 	    ((rv = soft_object_write_access_check(sp, secret_key)) != CKR_OK)) {
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 		free(secret_key);
9857c478bd9Sstevel@tonic-gate 		return (rv);
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	/* Set the sensitivity and extractability attributes as a needed */
9897c478bd9Sstevel@tonic-gate 	soft_derive_enforce_flags(basekey_p, secret_key);
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	/* Initialize the rest of stuffs in soft_object_t. */
9927c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&secret_key->object_mutex, NULL);
9937c478bd9Sstevel@tonic-gate 	secret_key->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	/* ... and, if it needs to persist, write on the token */
9967c478bd9Sstevel@tonic-gate 	if (IS_TOKEN_OBJECT(secret_key)) {
9977c478bd9Sstevel@tonic-gate 		secret_key->session_handle = (CK_SESSION_HANDLE)NULL;
9987c478bd9Sstevel@tonic-gate 		soft_add_token_object_to_slot(secret_key);
9997c478bd9Sstevel@tonic-gate 		rv = soft_put_object_to_keystore(secret_key);
10007c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK) {
10017c478bd9Sstevel@tonic-gate 			soft_delete_token_object(secret_key, B_FALSE, B_FALSE);
10027c478bd9Sstevel@tonic-gate 			return (rv);
10037c478bd9Sstevel@tonic-gate 		}
10047c478bd9Sstevel@tonic-gate 		*phKey = (CK_OBJECT_HANDLE)secret_key;
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 		return (CKR_OK);
10077c478bd9Sstevel@tonic-gate 	}
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	/* Add the new object to the session's object list. */
10107c478bd9Sstevel@tonic-gate 	soft_add_object_to_session(secret_key, sp);
10117c478bd9Sstevel@tonic-gate 	secret_key->session_handle = (CK_SESSION_HANDLE)sp;
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	*phKey = (CK_OBJECT_HANDLE)secret_key;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	return (rv);
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate /*
10197c478bd9Sstevel@tonic-gate  * Delete the derived key from the session, and, if it's a token object,
10207c478bd9Sstevel@tonic-gate  * remove it from the token.
10217c478bd9Sstevel@tonic-gate  */
10227c478bd9Sstevel@tonic-gate static void
10237c478bd9Sstevel@tonic-gate soft_delete_derived_key(soft_session_t *sp, soft_object_t *key)
10247c478bd9Sstevel@tonic-gate {
10257c478bd9Sstevel@tonic-gate 	/* session_handle is the creating session. It's NULL for token objs */
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	if (IS_TOKEN_OBJECT(key))
10287c478bd9Sstevel@tonic-gate 		soft_delete_token_object(key, B_FALSE, B_FALSE);
10297c478bd9Sstevel@tonic-gate 	else
1030*1f49a79aSZdenek Kotala 		soft_delete_object(sp, key, B_FALSE, B_FALSE);
10317c478bd9Sstevel@tonic-gate }
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate /*
10347c478bd9Sstevel@tonic-gate  * soft_ssl_weaken_key()
10357c478bd9Sstevel@tonic-gate  * Reduce the key length to an exportable size.
10367c478bd9Sstevel@tonic-gate  * For SSL3.0:
10377c478bd9Sstevel@tonic-gate  *	final_client_write_key = MD5(client_write_key +
10387c478bd9Sstevel@tonic-gate  *                                ClientHello.random +
10397c478bd9Sstevel@tonic-gate  *                                ServerHello.random);
10407c478bd9Sstevel@tonic-gate  *	final_server_write_key = MD5(server_write_key +
10417c478bd9Sstevel@tonic-gate  *                                ServerHello.random +
10427c478bd9Sstevel@tonic-gate  *                                ClientHello.random);
10437c478bd9Sstevel@tonic-gate  * For TLS1.0:
10447c478bd9Sstevel@tonic-gate  *	final_client_write_key = PRF(SecurityParameters.client_write_key,
10457c478bd9Sstevel@tonic-gate  *				    "client write key",
10467c478bd9Sstevel@tonic-gate  *				    SecurityParameters.client_random +
10477c478bd9Sstevel@tonic-gate  *				    SecurityParameters.server_random)[0..15];
10487c478bd9Sstevel@tonic-gate  *	final_server_write_key = PRF(SecurityParameters.server_write_key,
10497c478bd9Sstevel@tonic-gate  *				    "server write key",
10507c478bd9Sstevel@tonic-gate  *				    SecurityParameters.client_random +
10517c478bd9Sstevel@tonic-gate  *				    SecurityParameters.server_random)[0..15];
10527c478bd9Sstevel@tonic-gate  */
10537c478bd9Sstevel@tonic-gate static void
10547c478bd9Sstevel@tonic-gate soft_ssl_weaken_key(CK_MECHANISM_PTR mech, uchar_t *secret, uint_t secretlen,
10557c478bd9Sstevel@tonic-gate     uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
10567c478bd9Sstevel@tonic-gate     uchar_t *result, boolean_t isclient)
10577c478bd9Sstevel@tonic-gate {
10587c478bd9Sstevel@tonic-gate 	MD5_CTX exp_md5_ctx;
10597c478bd9Sstevel@tonic-gate 	uchar_t *label;
10607c478bd9Sstevel@tonic-gate 	uint_t labellen;
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE) {
10637c478bd9Sstevel@tonic-gate 		MD5Init(&exp_md5_ctx);
10647c478bd9Sstevel@tonic-gate 		MD5Update(&exp_md5_ctx, secret, secretlen);
10657c478bd9Sstevel@tonic-gate 		MD5Update(&exp_md5_ctx, rand1, rand1len);
10667c478bd9Sstevel@tonic-gate 		MD5Update(&exp_md5_ctx, rand2, rand2len);
10677c478bd9Sstevel@tonic-gate 		MD5Final(result, &exp_md5_ctx);
10687c478bd9Sstevel@tonic-gate 	} else {
10697c478bd9Sstevel@tonic-gate 		if (isclient) {
10707c478bd9Sstevel@tonic-gate 			label = TLS_CLIENT_KEY_LABEL;
10717c478bd9Sstevel@tonic-gate 			labellen = TLS_CLIENT_KEY_LABEL_LEN;
10721c02caffSmcpowers 			soft_tls_prf(secret, secretlen, label, labellen,
10731c02caffSmcpowers 			    rand1, rand1len, rand2, rand2len, result, 16);
10747c478bd9Sstevel@tonic-gate 		} else {
10757c478bd9Sstevel@tonic-gate 			label = TLS_SERVER_KEY_LABEL;
10767c478bd9Sstevel@tonic-gate 			labellen = TLS_SERVER_KEY_LABEL_LEN;
10777c478bd9Sstevel@tonic-gate 			soft_tls_prf(secret, secretlen, label, labellen,
10781c02caffSmcpowers 			    rand2, rand2len, rand1, rand1len, result, 16);
10791c02caffSmcpowers 		}
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate }
1082