2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <fcntl.h>
2N/A#include <strings.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/types.h>
2N/A#include <sys/sha1.h>
2N/A#include <sys/md5.h>
2N/A#include <sys/sysmacros.h>
2N/A#include <security/cryptoki.h>
2N/A#include "softGlobal.h"
2N/A#include "softKeys.h"
2N/A#include "softKeystore.h"
2N/A#include "softMAC.h"
2N/A#include "softObject.h"
2N/A#include "softSession.h"
2N/A#include "softSSL.h"
2N/A
2N/A/*
2N/A * This files contains the implementation of the following PKCS#11
2N/A * mechanisms needed by SSL:
2N/A * CKM_SSL3_MASTER_KEY_DERIVE
2N/A * CKM_SSL3_MASTER_KEY_DERIVE_DH
2N/A * CKM_SSL3_KEY_AND_DERIVE
2N/A * CKM_TLS_MASTER_KEY_DERIVE
2N/A * CKM_TLS_MASTER_KEY_DERIVE_DH
2N/A * CKM_TLS_KEY_AND_DERIVE
2N/A *
2N/A * SSL refers to common functions between SSL v3.0 and SSL v3.1 (a.k.a TLS.)
2N/A */
2N/A
2N/A#define MAX_KEYBLOCK 160 /* should be plenty for all known cipherspecs */
2N/A
2N/A#define MAX_DEFAULT_ATTRS 10 /* Enough for major applications */
2N/A
2N/Astatic char *ssl3_const_vals[] = {
2N/A "A",
2N/A "BB",
2N/A "CCC",
2N/A "DDDD",
2N/A "EEEEE",
2N/A "FFFFFF",
2N/A "GGGGGGG",
2N/A "HHHHHHHH",
2N/A "IIIIIIIII",
2N/A "JJJJJJJJJJ",
2N/A};
2N/Astatic uint_t ssl3_const_lens[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
2N/A
2N/Astatic uchar_t TLS_MASTER_SECRET_LABEL[] = {"master secret"};
2N/A#define TLS_MASTER_SECRET_LABEL_LEN 13
2N/A
2N/Astatic uchar_t TLS_KEY_EXPANSION_LABEL[] = {"key expansion"};
2N/A#define TLS_KEY_EXPANSION_LABEL_LEN 13
2N/A
2N/Astatic uchar_t TLS_CLIENT_KEY_LABEL[] = {"client write key"};
2N/A#define TLS_CLIENT_KEY_LABEL_LEN 16
2N/A
2N/Astatic uchar_t TLS_SERVER_KEY_LABEL[] = {"server write key"};
2N/A#define TLS_SERVER_KEY_LABEL_LEN 16
2N/A
2N/Astatic uchar_t TLS_IV_BLOCK_LABEL[] = {"IV block"};
2N/A#define TLS_IV_BLOCK_LABEL_LEN 8
2N/A
2N/Astatic void P_MD5(uchar_t *secret, uint_t secretlen, uchar_t *label,
2N/A uint_t labellen, uchar_t *rand1, uint_t rand1len, uchar_t *rand2,
2N/A uint_t rand2len, uchar_t *result, uint_t resultlen, boolean_t xor_it);
2N/Astatic void P_SHA1(uchar_t *secret, uint_t secretlen, uchar_t *label,
2N/A uint_t labellen, uchar_t *rand1, uint_t rand1len, uchar_t *rand2,
2N/A uint_t rand2len, uchar_t *result, uint_t resultlen, boolean_t xor_it);
2N/A
2N/Astatic CK_RV soft_add_derived_key(CK_ATTRIBUTE_PTR tmpl, CK_ULONG attrcount,
2N/A CK_OBJECT_HANDLE_PTR phKey, soft_session_t *sp, soft_object_t *basekey_p);
2N/Astatic void soft_delete_derived_key(soft_session_t *sp, soft_object_t *key);
2N/Astatic void soft_ssl_weaken_key(CK_MECHANISM_PTR mech, uchar_t *secret,
2N/A uint_t secretlen, uchar_t *rand1, uint_t rand1len, uchar_t *rand2,
2N/A uint_t rand2len, uchar_t *result, boolean_t isclient);
2N/A
2N/A/*
2N/A * soft_ssl3_churn()
2N/A * Called for derivation of the master secret from the pre-master secret,
2N/A * and for the derivation of the key_block in an SSL3 handshake
2N/A * result is assumed to be larger than rounds * MD5_DIGEST_LENGTH.
2N/A */
2N/Astatic void
2N/Asoft_ssl3_churn(uchar_t *secret, uint_t secretlen, uchar_t *rand1,
2N/A uint_t rand1len, uchar_t *rand2, uint_t rand2len, int rounds,
2N/A uchar_t *result)
2N/A{
2N/A SHA1_CTX sha1_ctx;
2N/A MD5_CTX md5_ctx;
2N/A uchar_t sha1_digest[SHA1_DIGEST_LENGTH];
2N/A int i;
2N/A uchar_t *ms = result;
2N/A for (i = 0; i < rounds; i++) {
2N/A SHA1Init(&sha1_ctx);
2N/A SHA1Update(&sha1_ctx, (const uint8_t *)ssl3_const_vals[i],
2N/A ssl3_const_lens[i]);
2N/A SHA1Update(&sha1_ctx, secret, secretlen);
2N/A SHA1Update(&sha1_ctx, rand1, rand1len);
2N/A SHA1Update(&sha1_ctx, rand2, rand2len);
2N/A SHA1Final(sha1_digest, &sha1_ctx);
2N/A
2N/A MD5Init(&md5_ctx);
2N/A MD5Update(&md5_ctx, secret, secretlen);
2N/A MD5Update(&md5_ctx, sha1_digest, SHA1_DIGEST_LENGTH);
2N/A MD5Final(ms, &md5_ctx);
2N/A ms += MD5_DIGEST_LENGTH;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * This TLS generic Pseudo Random Function expands a triplet
2N/A * {secret, label, seed} into any arbitrary length string of pseudo
2N/A * random bytes.
2N/A * Here, it is called for the derivation of the master secret from the
2N/A * pre-master secret, and for the derivation of the key_block in a TLS
2N/A * handshake
2N/A */
2N/Astatic void
2N/Asoft_tls_prf(uchar_t *secret, uint_t secretlen, uchar_t *label, uint_t labellen,
2N/A uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
2N/A uchar_t *result, uint_t resultlen)
2N/A{
2N/A uchar_t *S1, *S2;
2N/A uchar_t md5_digested_key[MD5_DIGEST_LENGTH];
2N/A uchar_t sha1_digested_key[SHA1_DIGEST_LENGTH];
2N/A uint_t L_S, L_S1, L_S2;
2N/A
2N/A /* secret is NULL for IV's in exportable ciphersuites */
2N/A if (secret == NULL) {
2N/A L_S = 0;
2N/A L_S2 = L_S1 = 0;
2N/A S1 = NULL;
2N/A S2 = NULL;
2N/A goto do_P_HASH;
2N/A }
2N/A
2N/A L_S = roundup(secretlen, 2) / 2;
2N/A L_S1 = L_S;
2N/A L_S2 = L_S;
2N/A S1 = secret;
2N/A S2 = secret + (secretlen / 2); /* Possible overlap of S1 and S2. */
2N/A
2N/A /* Reduce the half secrets if bigger than the HASH's block size */
2N/A if (L_S > MD5_HMAC_BLOCK_SIZE) {
2N/A MD5_CTX md5_ctx;
2N/A SHA1_CTX sha1_ctx;
2N/A
2N/A MD5Init(&md5_ctx);
2N/A MD5Update(&md5_ctx, S1, L_S);
2N/A MD5Final(md5_digested_key, &md5_ctx);
2N/A S1 = md5_digested_key;
2N/A L_S1 = MD5_DIGEST_LENGTH;
2N/A
2N/A SHA1Init(&sha1_ctx);
2N/A SHA1Update(&sha1_ctx, S2, L_S);
2N/A SHA1Final(sha1_digested_key, &sha1_ctx);
2N/A S2 = sha1_digested_key;
2N/A L_S2 = SHA1_DIGEST_LENGTH;
2N/A }
2N/A
2N/A /*
2N/A * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
2N/A * P_SHA-1(S2, label + seed);
2N/A * the 'seed' here is rand1 + rand2
2N/A */
2N/Ado_P_HASH:
2N/A /* The first one writes directly to the result */
2N/A P_MD5(S1, L_S1, label, labellen, rand1, rand1len, rand2, rand2len,
2N/A result, resultlen, B_FALSE);
2N/A
2N/A /* The second one XOR's with the result. */
2N/A P_SHA1(S2, L_S2, label, labellen, rand1, rand1len, rand2, rand2len,
2N/A result, resultlen, B_TRUE);
2N/A}
2N/A
2N/A/*
2N/A * These two expansion routines are very similar. (they can merge one day).
2N/A * They implement the P_HASH() function for MD5 and for SHA1, as defined in
2N/A * RFC2246:
2N/A *
2N/A * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
2N/A * HMAC_hash(secret, A(2) + seed) +
2N/A * HMAC_hash(secret, A(3) + seed) + ...
2N/A * Where + indicates concatenation.
2N/A * A() is defined as:
2N/A * A(0) = seed
2N/A * A(i) = HMAC_hash(secret, A(i-1))
2N/A *
2N/A * The seed is the concatenation of 'babel', 'rand1', and 'rand2'.
2N/A */
2N/Astatic void
2N/AP_MD5(uchar_t *secret, uint_t secretlen, uchar_t *label, uint_t labellen,
2N/A uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
2N/A uchar_t *result, uint_t resultlen, boolean_t xor_it)
2N/A{
2N/A uint32_t md5_ipad[MD5_HMAC_INTS_PER_BLOCK];
2N/A uint32_t md5_opad[MD5_HMAC_INTS_PER_BLOCK];
2N/A uchar_t md5_hmac[MD5_DIGEST_LENGTH];
2N/A uchar_t A[MD5_DIGEST_LENGTH];
2N/A md5_hc_ctx_t md5_hmac_ctx;
2N/A uchar_t *res, *cur;
2N/A uint_t left = resultlen;
2N/A int i;
2N/A
2N/A /* good compilers will leverage the alignment */
2N/A bzero(md5_ipad, MD5_HMAC_BLOCK_SIZE);
2N/A bzero(md5_opad, MD5_HMAC_BLOCK_SIZE);
2N/A
2N/A if (secretlen > 0) {
2N/A bcopy(secret, md5_ipad, secretlen);
2N/A bcopy(secret, md5_opad, secretlen);
2N/A }
2N/A
2N/A /* A(1) = HMAC_MD5(secret, rand1 + rand2) */
2N/A md5_hmac_ctx_init(&md5_hmac_ctx, md5_ipad, md5_opad);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, label, labellen);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand1, rand1len);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand2, rand2len);
2N/A SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, A);
2N/A
2N/A if (xor_it) {
2N/A res = md5_hmac;
2N/A cur = result;
2N/A } else {
2N/A res = result;
2N/A }
2N/A
2N/A while (left > 0) {
2N/A /*
2N/A * Compute HMAC_MD5(secret, A(i) + seed);
2N/A * The secret is already expanded in the ictx and octx, so
2N/A * we can call the SOFT_MAC_INIT_CTX() directly.
2N/A */
2N/A SOFT_MAC_INIT_CTX(MD5, &md5_hmac_ctx, md5_ipad, md5_opad,
2N/A MD5_HMAC_BLOCK_SIZE);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, A, MD5_DIGEST_LENGTH);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, label, labellen);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand1, rand1len);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, rand2, rand2len);
2N/A
2N/A if (left > MD5_DIGEST_LENGTH) {
2N/A SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, res);
2N/A if (xor_it) {
2N/A for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
2N/A *cur ^= res[i];
2N/A cur++;
2N/A }
2N/A } else {
2N/A res += MD5_DIGEST_LENGTH;
2N/A }
2N/A left -= MD5_DIGEST_LENGTH;
2N/A } else {
2N/A SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, md5_hmac);
2N/A if (xor_it) {
2N/A for (i = 0; i < left; i++) {
2N/A *cur ^= md5_hmac[i];
2N/A cur++;
2N/A }
2N/A } else {
2N/A bcopy(md5_hmac, res, left);
2N/A }
2N/A break;
2N/A }
2N/A /* A(i) = HMAC_MD5(secret, A(i-1) */
2N/A SOFT_MAC_INIT_CTX(MD5, &md5_hmac_ctx, md5_ipad, md5_opad,
2N/A MD5_HMAC_BLOCK_SIZE);
2N/A SOFT_MAC_UPDATE(MD5, &md5_hmac_ctx, A, MD5_DIGEST_LENGTH);
2N/A SOFT_MAC_FINAL(MD5, &md5_hmac_ctx, A);
2N/A }
2N/A}
2N/Astatic void
2N/AP_SHA1(uchar_t *secret, uint_t secretlen, uchar_t *label, uint_t labellen,
2N/A uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
2N/A uchar_t *result, uint_t resultlen, boolean_t xor_it)
2N/A{
2N/A uint32_t sha1_ipad[SHA1_HMAC_INTS_PER_BLOCK];
2N/A uint32_t sha1_opad[SHA1_HMAC_INTS_PER_BLOCK];
2N/A uchar_t sha1_hmac[SHA1_DIGEST_LENGTH];
2N/A uchar_t A[SHA1_DIGEST_LENGTH];
2N/A sha1_hc_ctx_t sha1_hmac_ctx;
2N/A uchar_t *res, *cur;
2N/A uint_t left = resultlen;
2N/A int i;
2N/A
2N/A /* good compilers will leverage the alignment */
2N/A bzero(sha1_ipad, SHA1_HMAC_BLOCK_SIZE);
2N/A bzero(sha1_opad, SHA1_HMAC_BLOCK_SIZE);
2N/A
2N/A if (secretlen > 0) {
2N/A bcopy(secret, sha1_ipad, secretlen);
2N/A bcopy(secret, sha1_opad, secretlen);
2N/A }
2N/A
2N/A /* A(1) = HMAC_SHA1(secret, rand1 + rand2) */
2N/A sha1_hmac_ctx_init(&sha1_hmac_ctx, sha1_ipad, sha1_opad);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, label, labellen);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand1, rand1len);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand2, rand2len);
2N/A SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, A);
2N/A
2N/A if (xor_it) {
2N/A res = sha1_hmac;
2N/A cur = result;
2N/A } else {
2N/A res = result;
2N/A }
2N/A
2N/A while (left > 0) {
2N/A /*
2N/A * Compute HMAC_SHA1(secret, A(i) + seed);
2N/A * The secret is already expanded in the ictx and octx, so
2N/A * we can call the SOFT_MAC_INIT_CTX() directly.
2N/A */
2N/A SOFT_MAC_INIT_CTX(SHA1, &sha1_hmac_ctx,
2N/A (const uchar_t *)sha1_ipad, (const uchar_t *)sha1_opad,
2N/A SHA1_HMAC_BLOCK_SIZE);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, A, SHA1_DIGEST_LENGTH);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, label, labellen);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand1, rand1len);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, rand2, rand2len);
2N/A
2N/A if (left > SHA1_DIGEST_LENGTH) {
2N/A SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, res);
2N/A if (xor_it) {
2N/A for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
2N/A *cur ^= res[i];
2N/A cur++;
2N/A }
2N/A } else {
2N/A res += SHA1_DIGEST_LENGTH;
2N/A }
2N/A left -= SHA1_DIGEST_LENGTH;
2N/A } else {
2N/A SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, sha1_hmac);
2N/A if (xor_it) {
2N/A for (i = 0; i < left; i++) {
2N/A *cur ^= sha1_hmac[i];
2N/A cur++;
2N/A }
2N/A } else {
2N/A bcopy(sha1_hmac, res, left);
2N/A }
2N/A break;
2N/A }
2N/A /* A(i) = HMAC_SHA1(secret, A(i-1) */
2N/A SOFT_MAC_INIT_CTX(SHA1, &sha1_hmac_ctx,
2N/A (const uchar_t *)sha1_ipad, (const uchar_t *)sha1_opad,
2N/A SHA1_HMAC_BLOCK_SIZE);
2N/A SOFT_MAC_UPDATE(SHA1, &sha1_hmac_ctx, A, SHA1_DIGEST_LENGTH);
2N/A SOFT_MAC_FINAL(SHA1, &sha1_hmac_ctx, A);
2N/A }
2N/A}
2N/A
2N/A/* This function handles the call from C_DeriveKey for CKM_TLS_PRF */
2N/ACK_RV
2N/Aderive_tls_prf(CK_TLS_PRF_PARAMS_PTR param, soft_object_t *basekey_p)
2N/A{
2N/A
2N/A if (param->pOutput == NULL || param->pulOutputLen == 0)
2N/A return (CKR_BUFFER_TOO_SMALL);
2N/A
2N/A (void) soft_tls_prf(OBJ_SEC_VALUE(basekey_p),
2N/A OBJ_SEC_VALUE_LEN(basekey_p), param->pLabel, param->ulLabelLen,
2N/A param->pSeed, param->ulSeedLen, NULL, 0, param->pOutput,
2N/A *param->pulOutputLen);
2N/A
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * soft_ssl_master_key_derive()
2N/A *
2N/A * Arguments:
2N/A * . session_p
2N/A * . mech_p: key derivation mechanism. the mechanism parameter carries the
2N/A * client and master random from the Hello handshake messages.
2N/A * . basekey_p: The pre-master secret key.
2N/A * . pTemplate & ulAttributeCount: Any extra attributes for the key to be
2N/A * created.
2N/A * . phKey: store for handle to the derived key.
2N/A *
2N/A * Description:
2N/A * Derive the SSL master secret from the pre-master secret, the client
2N/A * and server random.
2N/A * In SSL 3.0, master_secret =
2N/A * MD5(pre_master_secret + SHA('A' + pre_master_secret +
2N/A * ClientHello.random + ServerHello.random)) +
2N/A * MD5(pre_master_secret + SHA('BB' + pre_master_secret +
2N/A * ClientHello.random + ServerHello.random)) +
2N/A * MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
2N/A * ClientHello.random + ServerHello.random));
2N/A *
2N/A * In TLS 1.0 (a.k.a. SSL 3.1), master_secret =
2N/A * PRF(pre_master_secret, "master secret",
2N/A * ClientHello.random + ServerHello.random)
2N/A */
2N/ACK_RV
2N/Asoft_ssl_master_key_derive(soft_session_t *sp, CK_MECHANISM_PTR mech,
2N/A soft_object_t *basekey_p, CK_ATTRIBUTE_PTR pTemplate,
2N/A CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
2N/A{
2N/A uchar_t *pmsecret = OBJ_SEC_VALUE(basekey_p);
2N/A#ifdef __sparcv9
2N/A /* LINTED */
2N/A uint_t pmlen = (uint_t)OBJ_SEC_VALUE_LEN(basekey_p);
2N/A#else /* __sparcv9 */
2N/A uint_t pmlen = OBJ_SEC_VALUE_LEN(basekey_p);
2N/A#endif /* __sparcv9 */
2N/A CK_SSL3_MASTER_KEY_DERIVE_PARAMS *mkd_params;
2N/A CK_SSL3_RANDOM_DATA *random_data;
2N/A CK_VERSION_PTR pVersion;
2N/A uchar_t ssl_master_secret[48];
2N/A CK_OBJECT_CLASS class = CKO_SECRET_KEY;
2N/A CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
2N/A CK_BBOOL true = TRUE;
2N/A CK_ATTRIBUTE obj_tmpl[MAX_DEFAULT_ATTRS];
2N/A CK_ATTRIBUTE_PTR new_tmpl;
2N/A CK_ULONG newattrcount;
2N/A boolean_t new_tmpl_allocated = B_FALSE, is_tls = B_FALSE;
2N/A ulong_t i;
2N/A CK_RV rv = CKR_OK;
2N/A uint_t ClientRandomLen, ServerRandomLen;
2N/A
2N/A /* Check the validity of the mechanism's parameter */
2N/A
2N/A mkd_params = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)mech->pParameter;
2N/A
2N/A if (mkd_params == NULL ||
2N/A mech->ulParameterLen != sizeof (CK_SSL3_MASTER_KEY_DERIVE_PARAMS))
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A
2N/A pVersion = mkd_params->pVersion;
2N/A
2N/A switch (mech->mechanism) {
2N/A case CKM_TLS_MASTER_KEY_DERIVE:
2N/A is_tls = B_TRUE;
2N/A /* FALLTHRU */
2N/A case CKM_SSL3_MASTER_KEY_DERIVE:
2N/A /* Invalid pre-master key length. What else to return? */
2N/A if (pmlen != 48)
2N/A return (CKR_ARGUMENTS_BAD);
2N/A
2N/A /* Get the SSL version number from the premaster secret */
2N/A if (pVersion == NULL_PTR)
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A
2N/A bcopy(pmsecret, pVersion, sizeof (CK_VERSION));
2N/A
2N/A break;
2N/A case CKM_TLS_MASTER_KEY_DERIVE_DH:
2N/A is_tls = B_TRUE;
2N/A /* FALLTHRU */
2N/A case CKM_SSL3_MASTER_KEY_DERIVE_DH:
2N/A if (pVersion != NULL_PTR)
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A /*
2N/A * Strip leading zeroes as defined in TLS 1.1 specification
2N/A * (RFC 4346) in section 8.1.2.
2N/A */
2N/A while (pmlen != 0 && *pmsecret == 0) {
2N/A pmsecret++;
2N/A pmlen--;
2N/A }
2N/A break;
2N/A default:
2N/A return (CKR_MECHANISM_INVALID);
2N/A }
2N/A
2N/A random_data = &mkd_params->RandomInfo;
2N/A#ifdef __sparcv9
2N/A /* LINTED */
2N/A ClientRandomLen = (uint_t)random_data->ulClientRandomLen;
2N/A /* LINTED */
2N/A ServerRandomLen = (uint_t)random_data->ulServerRandomLen;
2N/A#else /* __sparcv9 */
2N/A ClientRandomLen = random_data->ulClientRandomLen;
2N/A ServerRandomLen = random_data->ulServerRandomLen;
2N/A#endif /* __sparcv9 */
2N/A
2N/A if (random_data->pClientRandom == NULL_PTR || ClientRandomLen == 0 ||
2N/A random_data->pServerRandom == NULL_PTR || ServerRandomLen == 0) {
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A }
2N/A
2N/A /* Now the actual secret derivation */
2N/A if (!is_tls) {
2N/A soft_ssl3_churn(pmsecret, pmlen, random_data->pClientRandom,
2N/A ClientRandomLen, random_data->pServerRandom,
2N/A ServerRandomLen, 3, ssl_master_secret);
2N/A } else {
2N/A soft_tls_prf(pmsecret, pmlen, TLS_MASTER_SECRET_LABEL,
2N/A TLS_MASTER_SECRET_LABEL_LEN, random_data->pClientRandom,
2N/A ClientRandomLen, random_data->pServerRandom,
2N/A ServerRandomLen, ssl_master_secret, 48);
2N/A }
2N/A
2N/A /*
2N/A * The object creation attributes need to be in one contiguous
2N/A * array. In addition to the attrs from the application supplied
2N/A * pTemplates, We need to add the class, type, value, valuelen and
2N/A * CKA_DERIVE.
2N/A * In the most likely case, the application passes between zero and
2N/A * handful of attributes, We optimize for that case by allocating
2N/A * the new template on the stack. Otherwise we malloc() it.
2N/A */
2N/A
2N/A newattrcount = ulAttributeCount + 4;
2N/A if (newattrcount > MAX_DEFAULT_ATTRS) {
2N/A new_tmpl = malloc(sizeof (CK_ATTRIBUTE) * newattrcount);
2N/A
2N/A if (new_tmpl == NULL)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A new_tmpl_allocated = B_TRUE;
2N/A } else
2N/A new_tmpl = obj_tmpl;
2N/A
2N/A /*
2N/A * Fill in the new template.
2N/A * We put the attributes contributed by the mechanism first
2N/A * so that they override the application supplied ones.
2N/A */
2N/A new_tmpl[0].type = CKA_CLASS;
2N/A new_tmpl[0].pValue = &class;
2N/A new_tmpl[0].ulValueLen = sizeof (class);
2N/A new_tmpl[1].type = CKA_KEY_TYPE;
2N/A new_tmpl[1].pValue = &keyType;
2N/A new_tmpl[1].ulValueLen = sizeof (keyType);
2N/A new_tmpl[2].type = CKA_DERIVE;
2N/A new_tmpl[2].pValue = &true;
2N/A new_tmpl[2].ulValueLen = sizeof (true);
2N/A new_tmpl[3].type = CKA_VALUE;
2N/A new_tmpl[3].pValue = ssl_master_secret;
2N/A new_tmpl[3].ulValueLen = 48;
2N/A
2N/A /* Any attributes left? */
2N/A if (ulAttributeCount > 0) {
2N/A
2N/A /* Validate the default class and type attributes */
2N/A for (i = 0; i < ulAttributeCount; i++) {
2N/A /* The caller is responsible for proper alignment */
2N/A if ((pTemplate[i].type == CKA_CLASS) &&
2N/A (*((CK_OBJECT_CLASS *)pTemplate[i].pValue) !=
2N/A CKO_SECRET_KEY)) {
2N/A rv = CKR_TEMPLATE_INCONSISTENT;
2N/A goto out;
2N/A }
2N/A if ((pTemplate[i].type == CKA_KEY_TYPE) &&
2N/A (*((CK_KEY_TYPE *)pTemplate[i].pValue) !=
2N/A CKK_GENERIC_SECRET)) {
2N/A rv = CKR_TEMPLATE_INCONSISTENT;
2N/A goto out;
2N/A }
2N/A }
2N/A bcopy(pTemplate, &new_tmpl[4],
2N/A ulAttributeCount * sizeof (CK_ATTRIBUTE));
2N/A }
2N/A
2N/A rv = soft_add_derived_key(new_tmpl, newattrcount, phKey, sp, basekey_p);
2N/Aout:
2N/A if (new_tmpl_allocated)
2N/A free(new_tmpl);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * soft_ssl3_key_and_mac_derive()
2N/A *
2N/A * Arguments:
2N/A * . session_p
2N/A * . mech_p: key derivation mechanism. the mechanism parameter carries the
2N/A * client and master random from the Hello handshake messages,
2N/A * the specification of the key and IV sizes, and the location
2N/A * for the resulting keys and IVs.
2N/A * . basekey_p: The master secret key.
2N/A * . pTemplate & ulAttributeCount: Any extra attributes for the key to be
2N/A * created.
2N/A *
2N/A * Description:
2N/A * Derive the SSL key material (Client and server MAC secrets, symmetric
2N/A * keys and IVs), from the master secret and the client
2N/A * and server random.
2N/A * First a keyblock is generated using the following formula:
2N/A * key_block =
2N/A * MD5(master_secret + SHA(`A' + master_secret +
2N/A * ServerHello.random +
2N/A * ClientHello.random)) +
2N/A * MD5(master_secret + SHA(`BB' + master_secret +
2N/A * ServerHello.random +
2N/A * ClientHello.random)) +
2N/A * MD5(master_secret + SHA(`CCC' + master_secret +
2N/A * ServerHello.random +
2N/A * ClientHello.random)) + [...];
2N/A *
2N/A * In TLS 1.0 (a.k.a. SSL 3.1), key_block =
2N/A * PRF(master_secret, "key expansion",
2N/A * ServerHello.random + ClientHello.random)
2N/A *
2N/A * Then the keys materials are taken from the keyblock.
2N/A */
2N/A
2N/ACK_RV
2N/Asoft_ssl_key_and_mac_derive(soft_session_t *sp, CK_MECHANISM_PTR mech,
2N/A soft_object_t *basekey_p, CK_ATTRIBUTE_PTR pTemplate,
2N/A CK_ULONG ulAttributeCount)
2N/A{
2N/A uchar_t *msecret = OBJ_SEC_VALUE(basekey_p);
2N/A#ifdef __sparcv9
2N/A /* LINTED */
2N/A uint_t mslen = (uint_t)OBJ_SEC_VALUE_LEN(basekey_p);
2N/A#else /* __sparcv9 */
2N/A uint_t mslen = OBJ_SEC_VALUE_LEN(basekey_p);
2N/A#endif /* __sparcv9 */
2N/A CK_SSL3_KEY_MAT_PARAMS *km_params;
2N/A CK_SSL3_RANDOM_DATA *random_data;
2N/A CK_SSL3_KEY_MAT_OUT *kmo;
2N/A uchar_t key_block[MAX_KEYBLOCK], *kb, *export_keys = NULL;
2N/A CK_OBJECT_CLASS class = CKO_SECRET_KEY;
2N/A CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
2N/A CK_BBOOL true = TRUE;
2N/A CK_ATTRIBUTE obj_tmpl[MAX_DEFAULT_ATTRS];
2N/A CK_ATTRIBUTE_PTR new_tmpl;
2N/A ulong_t newattrcount, mac_key_bytes, secret_key_bytes, iv_bytes;
2N/A ulong_t extra_attr_count;
2N/A uint_t size;
2N/A int rounds, n = 0;
2N/A boolean_t new_tmpl_allocated = B_FALSE, isExport;
2N/A CK_RV rv = CKR_OK;
2N/A uint_t ClientRandomLen, ServerRandomLen;
2N/A
2N/A /* Check the validity of the mechanism's parameter */
2N/A
2N/A km_params = (CK_SSL3_KEY_MAT_PARAMS *)mech->pParameter;
2N/A
2N/A if (km_params == NULL ||
2N/A mech->ulParameterLen != sizeof (CK_SSL3_KEY_MAT_PARAMS) ||
2N/A (kmo = km_params->pReturnedKeyMaterial) == NULL)
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A
2N/A isExport = (km_params->bIsExport == TRUE);
2N/A
2N/A random_data = &km_params->RandomInfo;
2N/A#ifdef __sparcv9
2N/A /* LINTED */
2N/A ClientRandomLen = (uint_t)random_data->ulClientRandomLen;
2N/A /* LINTED */
2N/A ServerRandomLen = (uint_t)random_data->ulServerRandomLen;
2N/A#else /* __sparcv9 */
2N/A ClientRandomLen = random_data->ulClientRandomLen;
2N/A ServerRandomLen = random_data->ulServerRandomLen;
2N/A#endif /* __sparcv9 */
2N/A
2N/A if (random_data->pClientRandom == NULL_PTR || ClientRandomLen == 0 ||
2N/A random_data->pServerRandom == NULL_PTR || ServerRandomLen == 0) {
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A }
2N/A
2N/A mac_key_bytes = km_params->ulMacSizeInBits / 8;
2N/A secret_key_bytes = km_params->ulKeySizeInBits / 8;
2N/A iv_bytes = km_params->ulIVSizeInBits / 8;
2N/A
2N/A if ((iv_bytes > 0) &&
2N/A ((kmo->pIVClient == NULL) || (kmo->pIVServer == NULL)))
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A
2N/A /*
2N/A * For exportable ciphersuites, the IV's aren't taken from the
2N/A * key block. They are directly derived from the client and
2N/A * server random data.
2N/A * For SSL3.0:
2N/A * client_write_IV = MD5(ClientHello.random + ServerHello.random);
2N/A * server_write_IV = MD5(ServerHello.random + ClientHello.random);
2N/A * For TLS1.0:
2N/A * iv_block = PRF("", "IV block", client_random +
2N/A * server_random)[0..15]
2N/A * client_write_IV = iv_block[0..7]
2N/A * server_write_IV = iv_block[8..15]
2N/A */
2N/A if ((isExport) && (iv_bytes > 0)) {
2N/A
2N/A if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE) {
2N/A MD5_CTX exp_md5_ctx;
2N/A
2N/A if (iv_bytes > MD5_DIGEST_LENGTH)
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A
2N/A MD5Init(&exp_md5_ctx);
2N/A MD5Update(&exp_md5_ctx, random_data->pClientRandom,
2N/A ClientRandomLen);
2N/A MD5Update(&exp_md5_ctx, random_data->pServerRandom,
2N/A ServerRandomLen);
2N/A
2N/A /* there's room in key_block. use it */
2N/A MD5Final(key_block, &exp_md5_ctx);
2N/A bcopy(key_block, kmo->pIVClient, iv_bytes);
2N/A
2N/A MD5Init(&exp_md5_ctx);
2N/A MD5Update(&exp_md5_ctx, random_data->pServerRandom,
2N/A ServerRandomLen);
2N/A MD5Update(&exp_md5_ctx, random_data->pClientRandom,
2N/A ClientRandomLen);
2N/A MD5Final(key_block, &exp_md5_ctx);
2N/A bcopy(key_block, kmo->pIVServer, iv_bytes);
2N/A } else {
2N/A uchar_t iv_block[16];
2N/A
2N/A if (iv_bytes != 8)
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A
2N/A soft_tls_prf(NULL, 0, TLS_IV_BLOCK_LABEL,
2N/A TLS_IV_BLOCK_LABEL_LEN,
2N/A random_data->pClientRandom, ClientRandomLen,
2N/A random_data->pServerRandom, ServerRandomLen,
2N/A iv_block, 16);
2N/A bcopy(iv_block, kmo->pIVClient, 8);
2N/A bcopy(iv_block + 8, kmo->pIVServer, 8);
2N/A }
2N/A /* so we won't allocate a key_block bigger than needed */
2N/A iv_bytes = 0;
2N/A }
2N/A
2N/A /* Now the actual secret derivation */
2N/A
2N/A#ifdef __sparcv9
2N/A /* LINTED */
2N/A size = (uint_t)((mac_key_bytes + secret_key_bytes + iv_bytes) * 2);
2N/A#else /* __sparcv9 */
2N/A size = (mac_key_bytes + secret_key_bytes + iv_bytes) * 2;
2N/A#endif /* __sparcv9 */
2N/A
2N/A /* Need to handle this better */
2N/A if (size > MAX_KEYBLOCK)
2N/A return (CKR_MECHANISM_PARAM_INVALID);
2N/A
2N/A rounds = howmany(size, MD5_DIGEST_LENGTH);
2N/A
2N/A kb = key_block;
2N/A
2N/A if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE) {
2N/A soft_ssl3_churn(msecret, mslen, random_data->pServerRandom,
2N/A ServerRandomLen, random_data->pClientRandom,
2N/A ClientRandomLen, rounds, kb);
2N/A } else {
2N/A soft_tls_prf(msecret, mslen, TLS_KEY_EXPANSION_LABEL,
2N/A TLS_KEY_EXPANSION_LABEL_LEN,
2N/A random_data->pServerRandom, ServerRandomLen,
2N/A random_data->pClientRandom, ClientRandomLen,
2N/A kb, size);
2N/A }
2N/A
2N/A /* Now create the objects */
2N/A
2N/A kmo->hClientMacSecret = CK_INVALID_HANDLE;
2N/A kmo->hServerMacSecret = CK_INVALID_HANDLE;
2N/A kmo->hClientKey = CK_INVALID_HANDLE;
2N/A kmo->hServerKey = CK_INVALID_HANDLE;
2N/A
2N/A /* First the MAC secrets */
2N/A if (mac_key_bytes > 0) {
2N/A obj_tmpl[0].type = CKA_CLASS;
2N/A obj_tmpl[0].pValue = &class; /* CKO_SECRET_KEY */
2N/A obj_tmpl[0].ulValueLen = sizeof (class);
2N/A obj_tmpl[1].type = CKA_KEY_TYPE;
2N/A obj_tmpl[1].pValue = &keyType; /* CKK_GENERIC_SECRET */
2N/A obj_tmpl[1].ulValueLen = sizeof (keyType);
2N/A obj_tmpl[2].type = CKA_DERIVE;
2N/A obj_tmpl[2].pValue = &true;
2N/A obj_tmpl[2].ulValueLen = sizeof (true);
2N/A obj_tmpl[3].type = CKA_SIGN;
2N/A obj_tmpl[3].pValue = &true;
2N/A obj_tmpl[3].ulValueLen = sizeof (true);
2N/A obj_tmpl[4].type = CKA_VERIFY;
2N/A obj_tmpl[4].pValue = &true;
2N/A obj_tmpl[4].ulValueLen = sizeof (true);
2N/A obj_tmpl[5].type = CKA_VALUE;
2N/A obj_tmpl[5].pValue = kb;
2N/A obj_tmpl[5].ulValueLen = mac_key_bytes;
2N/A
2N/A rv = soft_add_derived_key(obj_tmpl, 6,
2N/A &(kmo->hClientMacSecret), sp, basekey_p);
2N/A
2N/A if (rv != CKR_OK)
2N/A goto out_err;
2N/A
2N/A kb += mac_key_bytes;
2N/A
2N/A obj_tmpl[5].pValue = kb;
2N/A rv = soft_add_derived_key(obj_tmpl, 6,
2N/A &(kmo->hServerMacSecret), sp, basekey_p);
2N/A
2N/A if (rv != CKR_OK)
2N/A goto out_err;
2N/A
2N/A kb += mac_key_bytes;
2N/A }
2N/A
2N/A /* Then the symmetric ciphers keys */
2N/A
2N/A extra_attr_count = (secret_key_bytes == 0) ? 6 : 5;
2N/A newattrcount = ulAttributeCount + extra_attr_count;
2N/A if (newattrcount > MAX_DEFAULT_ATTRS) {
2N/A new_tmpl = malloc(sizeof (CK_ATTRIBUTE) * newattrcount);
2N/A
2N/A if (new_tmpl == NULL)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A new_tmpl_allocated = B_TRUE;
2N/A } else
2N/A new_tmpl = obj_tmpl;
2N/A
2N/A new_tmpl[n].type = CKA_CLASS;
2N/A new_tmpl[n].pValue = &class; /* CKO_SECRET_KEY */
2N/A new_tmpl[n].ulValueLen = sizeof (class);
2N/A ++n;
2N/A /*
2N/A * The keyType comes from the application's template, and depends
2N/A * on the ciphersuite. The only exception is authentication only
2N/A * ciphersuites which do not use cipher keys.
2N/A */
2N/A if (secret_key_bytes == 0) {
2N/A new_tmpl[n].type = CKA_KEY_TYPE;
2N/A new_tmpl[n].pValue = &keyType; /* CKK_GENERIC_SECRET */
2N/A new_tmpl[n].ulValueLen = sizeof (keyType);
2N/A n++;
2N/A }
2N/A new_tmpl[n].type = CKA_DERIVE;
2N/A new_tmpl[n].pValue = &true;
2N/A new_tmpl[n].ulValueLen = sizeof (true);
2N/A n++;
2N/A new_tmpl[n].type = CKA_ENCRYPT;
2N/A new_tmpl[n].pValue = &true;
2N/A new_tmpl[n].ulValueLen = sizeof (true);
2N/A n++;
2N/A new_tmpl[n].type = CKA_DECRYPT;
2N/A new_tmpl[n].pValue = &true;
2N/A new_tmpl[n].ulValueLen = sizeof (true);
2N/A n++;
2N/A new_tmpl[n].type = CKA_VALUE;
2N/A new_tmpl[n].pValue = NULL;
2N/A new_tmpl[n].ulValueLen = 0;
2N/A
2N/A if (secret_key_bytes > 0) {
2N/A if (isExport) {
2N/A if (secret_key_bytes > MD5_DIGEST_LENGTH) {
2N/A rv = CKR_MECHANISM_PARAM_INVALID;
2N/A goto out_err;
2N/A }
2N/A if ((export_keys =
2N/A malloc(2 * MD5_DIGEST_LENGTH)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto out_err;
2N/A }
2N/A soft_ssl_weaken_key(mech, kb, (uint_t)secret_key_bytes,
2N/A random_data->pClientRandom, ClientRandomLen,
2N/A random_data->pServerRandom, ServerRandomLen,
2N/A export_keys, B_TRUE);
2N/A new_tmpl[n].pValue = export_keys;
2N/A new_tmpl[n].ulValueLen = MD5_DIGEST_LENGTH;
2N/A } else {
2N/A new_tmpl[n].pValue = kb;
2N/A new_tmpl[n].ulValueLen = secret_key_bytes;
2N/A }
2N/A }
2N/A
2N/A if (ulAttributeCount > 0)
2N/A bcopy(pTemplate, &new_tmpl[extra_attr_count],
2N/A ulAttributeCount * sizeof (CK_ATTRIBUTE));
2N/A
2N/A rv = soft_add_derived_key(new_tmpl, newattrcount,
2N/A &(kmo->hClientKey), sp, basekey_p);
2N/A
2N/A if (rv != CKR_OK)
2N/A goto out_err;
2N/A
2N/A kb += secret_key_bytes;
2N/A
2N/A if (secret_key_bytes > 0) {
2N/A if (isExport) {
2N/A soft_ssl_weaken_key(mech, kb, (uint_t)secret_key_bytes,
2N/A random_data->pServerRandom, ServerRandomLen,
2N/A random_data->pClientRandom, ClientRandomLen,
2N/A export_keys + MD5_DIGEST_LENGTH, B_FALSE);
2N/A new_tmpl[n].pValue = export_keys + MD5_DIGEST_LENGTH;
2N/A } else
2N/A new_tmpl[n].pValue = kb;
2N/A }
2N/A
2N/A rv = soft_add_derived_key(new_tmpl, newattrcount,
2N/A &(kmo->hServerKey), sp, basekey_p);
2N/A
2N/A if (rv != CKR_OK)
2N/A goto out_err;
2N/A
2N/A kb += secret_key_bytes;
2N/A
2N/A /* Finally, the IVs */
2N/A if (iv_bytes > 0) {
2N/A bcopy(kb, kmo->pIVClient, iv_bytes);
2N/A kb += iv_bytes;
2N/A bcopy(kb, kmo->pIVServer, iv_bytes);
2N/A }
2N/A
2N/A if (new_tmpl_allocated)
2N/A free(new_tmpl);
2N/A
2N/A if (export_keys != NULL)
2N/A free(export_keys);
2N/A
2N/A return (rv);
2N/A
2N/Aout_err:
2N/A if (kmo->hClientMacSecret != CK_INVALID_HANDLE) {
2N/A (void) soft_delete_derived_key(sp,
2N/A (soft_object_t *)(kmo->hClientMacSecret));
2N/A kmo->hClientMacSecret = CK_INVALID_HANDLE;
2N/A }
2N/A if (kmo->hServerMacSecret != CK_INVALID_HANDLE) {
2N/A (void) soft_delete_derived_key(sp,
2N/A (soft_object_t *)(kmo->hServerMacSecret));
2N/A kmo->hServerMacSecret = CK_INVALID_HANDLE;
2N/A }
2N/A if (kmo->hClientKey != CK_INVALID_HANDLE) {
2N/A (void) soft_delete_derived_key(sp,
2N/A (soft_object_t *)(kmo->hClientKey));
2N/A kmo->hClientKey = CK_INVALID_HANDLE;
2N/A }
2N/A if (kmo->hServerKey != CK_INVALID_HANDLE) {
2N/A (void) soft_delete_derived_key(sp,
2N/A (soft_object_t *)(kmo->hServerKey));
2N/A kmo->hServerKey = CK_INVALID_HANDLE;
2N/A }
2N/A
2N/A if (new_tmpl_allocated)
2N/A free(new_tmpl);
2N/A
2N/A if (export_keys != NULL)
2N/A free(export_keys);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * Add the derived key to the session, and, if it's a token object,
2N/A * write it to the token.
2N/A */
2N/Astatic CK_RV
2N/Asoft_add_derived_key(CK_ATTRIBUTE_PTR tmpl, CK_ULONG attrcount,
2N/A CK_OBJECT_HANDLE_PTR phKey, soft_session_t *sp, soft_object_t *basekey_p)
2N/A{
2N/A CK_RV rv;
2N/A soft_object_t *secret_key;
2N/A
2N/A if ((secret_key = calloc(1, sizeof (soft_object_t))) == NULL) {
2N/A return (CKR_HOST_MEMORY);
2N/A }
2N/A
2N/A if (((rv = soft_build_secret_key_object(tmpl, attrcount, secret_key,
2N/A SOFT_CREATE_OBJ_INT, 0, (CK_KEY_TYPE)~0UL)) != CKR_OK) ||
2N/A ((rv = soft_pin_expired_check(secret_key)) != CKR_OK) ||
2N/A ((rv = soft_object_write_access_check(sp, secret_key)) != CKR_OK)) {
2N/A
2N/A free(secret_key);
2N/A return (rv);
2N/A }
2N/A
2N/A /* Set the sensitivity and extractability attributes as a needed */
2N/A soft_derive_enforce_flags(basekey_p, secret_key);
2N/A
2N/A /* Initialize the rest of stuffs in soft_object_t. */
2N/A (void) pthread_rwlock_init(&secret_key->object_rwlock, NULL);
2N/A (void) pthread_mutex_init(&secret_key->object_mutex, NULL);
2N/A secret_key->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
2N/A
2N/A /* ... and, if it needs to persist, write on the token */
2N/A if (IS_TOKEN_OBJECT(secret_key)) {
2N/A secret_key->session_handle = (CK_SESSION_HANDLE)NULL;
2N/A soft_add_token_object_to_slot(secret_key);
2N/A rv = soft_put_object_to_keystore(secret_key);
2N/A if (rv != CKR_OK) {
2N/A soft_delete_token_object(secret_key, B_FALSE, B_FALSE);
2N/A return (rv);
2N/A }
2N/A *phKey = (CK_OBJECT_HANDLE)secret_key;
2N/A
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A /* Add the new object to the session's object list. */
2N/A soft_add_object_to_session(secret_key, sp);
2N/A secret_key->session_handle = (CK_SESSION_HANDLE)sp;
2N/A
2N/A *phKey = (CK_OBJECT_HANDLE)secret_key;
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * Delete the derived key from the session, and, if it's a token object,
2N/A * remove it from the token.
2N/A */
2N/Astatic void
2N/Asoft_delete_derived_key(soft_session_t *sp, soft_object_t *key)
2N/A{
2N/A /* session_handle is the creating session. It's NULL for token objs */
2N/A
2N/A if (IS_TOKEN_OBJECT(key))
2N/A soft_delete_token_object(key, B_FALSE, B_FALSE);
2N/A else
2N/A soft_delete_object(sp, key, B_FALSE, B_FALSE);
2N/A}
2N/A
2N/A/*
2N/A * soft_ssl_weaken_key()
2N/A * Reduce the key length to an exportable size.
2N/A * For SSL3.0:
2N/A * final_client_write_key = MD5(client_write_key +
2N/A * ClientHello.random +
2N/A * ServerHello.random);
2N/A * final_server_write_key = MD5(server_write_key +
2N/A * ServerHello.random +
2N/A * ClientHello.random);
2N/A * For TLS1.0:
2N/A * final_client_write_key = PRF(SecurityParameters.client_write_key,
2N/A * "client write key",
2N/A * SecurityParameters.client_random +
2N/A * SecurityParameters.server_random)[0..15];
2N/A * final_server_write_key = PRF(SecurityParameters.server_write_key,
2N/A * "server write key",
2N/A * SecurityParameters.client_random +
2N/A * SecurityParameters.server_random)[0..15];
2N/A */
2N/Astatic void
2N/Asoft_ssl_weaken_key(CK_MECHANISM_PTR mech, uchar_t *secret, uint_t secretlen,
2N/A uchar_t *rand1, uint_t rand1len, uchar_t *rand2, uint_t rand2len,
2N/A uchar_t *result, boolean_t isclient)
2N/A{
2N/A MD5_CTX exp_md5_ctx;
2N/A uchar_t *label;
2N/A uint_t labellen;
2N/A
2N/A if (mech->mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE) {
2N/A MD5Init(&exp_md5_ctx);
2N/A MD5Update(&exp_md5_ctx, secret, secretlen);
2N/A MD5Update(&exp_md5_ctx, rand1, rand1len);
2N/A MD5Update(&exp_md5_ctx, rand2, rand2len);
2N/A MD5Final(result, &exp_md5_ctx);
2N/A } else {
2N/A if (isclient) {
2N/A label = TLS_CLIENT_KEY_LABEL;
2N/A labellen = TLS_CLIENT_KEY_LABEL_LEN;
2N/A soft_tls_prf(secret, secretlen, label, labellen,
2N/A rand1, rand1len, rand2, rand2len, result, 16);
2N/A } else {
2N/A label = TLS_SERVER_KEY_LABEL;
2N/A labellen = TLS_SERVER_KEY_LABEL_LEN;
2N/A soft_tls_prf(secret, secretlen, label, labellen,
2N/A rand2, rand2len, rand1, rand1len, result, 16);
2N/A }
2N/A }
2N/A}