/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <fcntl.h>
#include <strings.h>
#include <sys/sysmacros.h>
#include <security/cryptoki.h>
#include "softGlobal.h"
#include "softKeys.h"
#include "softKeystore.h"
#include "softMAC.h"
#include "softObject.h"
#include "softSession.h"
#include "softSSL.h"
/*
* This files contains the implementation of the following PKCS#11
* mechanisms needed by SSL:
* CKM_SSL3_MASTER_KEY_DERIVE
* CKM_SSL3_MASTER_KEY_DERIVE_DH
* CKM_SSL3_KEY_AND_DERIVE
* CKM_TLS_MASTER_KEY_DERIVE
* CKM_TLS_MASTER_KEY_DERIVE_DH
* CKM_TLS_KEY_AND_DERIVE
*
* SSL refers to common functions between SSL v3.0 and SSL v3.1 (a.k.a TLS.)
*/
static char *ssl3_const_vals[] = {
"A",
"BB",
"CCC",
"DDDD",
"EEEEE",
"FFFFFF",
"GGGGGGG",
"HHHHHHHH",
"IIIIIIIII",
"JJJJJJJJJJ",
};
/*
* soft_ssl3_churn()
* Called for derivation of the master secret from the pre-master secret,
* and for the derivation of the key_block in an SSL3 handshake
* result is assumed to be larger than rounds * MD5_HASH_SIZE.
*/
static void
{
int i;
for (i = 0; i < rounds; i++) {
ssl3_const_lens[i]);
ms += MD5_HASH_SIZE;
}
}
/*
* This TLS generic Pseudo Random Function expands a triplet
* {secret, label, seed} into any arbitrary length string of pseudo
* random bytes.
* Here, it is called for the derivation of the master secret from the
* pre-master secret, and for the derivation of the key_block in a TLS
* handshake
*/
static void
{
/* secret is NULL for IV's in exportable ciphersuites */
L_S = 0;
goto do_P_HASH;
}
/* Reduce the half secrets if bigger than the HASH's block size */
if (L_S > MD5_HMAC_BLOCK_SIZE) {
}
/*
* PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
* P_SHA-1(S2, label + seed);
* the 'seed' here is rand1 + rand2
*/
/* The first one writes directly to the result */
/* The second one XOR's with the result. */
}
/*
* These two expansion routines are very similar. (they can merge one day).
* They implement the P_HASH() function for MD5 and for SHA1, as defined in
* RFC2246:
*
* P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
* HMAC_hash(secret, A(2) + seed) +
* HMAC_hash(secret, A(3) + seed) + ...
* Where + indicates concatenation.
* A() is defined as:
* A(0) = seed
* A(i) = HMAC_hash(secret, A(i-1))
*
* The seed is the concatenation of 'babel', 'rand1', and 'rand2'.
*/
static void
{
uchar_t A[MD5_HASH_SIZE];
int i;
/* good compilers will leverage the aligment */
if (secretlen > 0) {
}
/* A(1) = HMAC_MD5(secret, rand1 + rand2) */
if (xor_it) {
} else {
}
while (left > 0) {
/*
* Compute HMAC_MD5(secret, A(i) + seed);
* The secret is already expanded in the ictx and octx, so
* we can call the SOFT_MAC_INIT_CTX() directly.
*/
if (left > MD5_HASH_SIZE) {
if (xor_it) {
for (i = 0; i < MD5_HASH_SIZE; i++) {
cur++;
}
} else {
res += MD5_HASH_SIZE;
}
left -= MD5_HASH_SIZE;
} else {
if (xor_it) {
for (i = 0; i < left; i++) {
cur++;
}
} else {
}
break;
}
/* A(i) = HMAC_MD5(secret, A(i-1) */
}
}
static void
{
int i;
/* good compilers will leverage the aligment */
if (secretlen > 0) {
}
/* A(1) = HMAC_SHA1(secret, rand1 + rand2) */
if (xor_it) {
} else {
}
while (left > 0) {
/*
* Compute HMAC_SHA1(secret, A(i) + seed);
* The secret is already expanded in the ictx and octx, so
* we can call the SOFT_MAC_INIT_CTX() directly.
*/
if (left > SHA1_HASH_SIZE) {
if (xor_it) {
for (i = 0; i < SHA1_HASH_SIZE; i++) {
cur++;
}
} else {
res += SHA1_HASH_SIZE;
}
left -= SHA1_HASH_SIZE;
} else {
if (xor_it) {
for (i = 0; i < left; i++) {
cur++;
}
} else {
}
break;
}
/* A(i) = HMAC_SHA1(secret, A(i-1) */
}
}
/* This function handles the call from C_DeriveKey for CKM_TLS_PRF */
{
return (CKR_BUFFER_TOO_SMALL);
*param->pulOutputLen);
return (CKR_OK);
}
/*
* soft_ssl_master_key_derive()
*
* Arguments:
* . session_p
* . mech_p: key derivation mechanism. the mechanism parameter carries the
* client and master random from the Hello handshake messages.
* . basekey_p: The pre-master secret key.
* . pTemplate & ulAttributeCount: Any extra attributes for the key to be
* created.
* . phKey: store for handle to the derived key.
*
* Description:
* Derive the SSL master secret from the pre-master secret, the client
* and server random.
* In SSL 3.0, master_secret =
* MD5(pre_master_secret + SHA('A' + pre_master_secret +
* ClientHello.random + ServerHello.random)) +
* MD5(pre_master_secret + SHA('BB' + pre_master_secret +
* ClientHello.random + ServerHello.random)) +
* MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
* ClientHello.random + ServerHello.random));
*
* In TLS 1.0 (a.k.a. SSL 3.1), master_secret =
* PRF(pre_master_secret, "master secret",
* ClientHello.random + ServerHello.random)
*/
{
#ifdef __sparcv9
/* LINTED */
#else /* __sparcv9 */
#endif /* __sparcv9 */
ulong_t i;
/* Check the validity of the mechanism's parameter */
if (mkd_params == NULL ||
return (CKR_MECHANISM_PARAM_INVALID);
/* FALLTHRU */
/* Invalid pre-master key length. What else to return? */
if (pmlen != 48)
return (CKR_ARGUMENTS_BAD);
/* Get the SSL version number from the premaster secret */
return (CKR_MECHANISM_PARAM_INVALID);
break;
/* FALLTHRU */
return (CKR_MECHANISM_PARAM_INVALID);
}
#ifdef __sparcv9
/* LINTED */
/* LINTED */
#else /* __sparcv9 */
#endif /* __sparcv9 */
return (CKR_MECHANISM_PARAM_INVALID);
}
/* Now the actual secret derivation */
if (!is_tls) {
} else {
}
/*
* The object creation attributes need to be in one contiguous
* array. In addition to the attrs from the application supplied
* pTemplates, We need to add the class, type, value, valuelen and
* CKA_DERIVE.
* In the most likely case, the application passes between zero and
* handful of attributes, We optimize for that case by allocating
* the new template on the stack. Oherwise we malloc() it.
*/
if (newattrcount > MAX_DEFAULT_ATTRS) {
return (CKR_HOST_MEMORY);
} else
/*
* Fill in the new template.
* We put the attributes contributed by the mechanism first
* so that they override the application supplied ones.
*/
/* Any attributes left? */
if (ulAttributeCount > 0) {
/* Validate the default class and type attributes */
for (i = 0; i < ulAttributeCount; i++) {
/* The caller is responsible for proper alignment */
CKO_SECRET_KEY)) {
goto out;
}
goto out;
}
}
ulAttributeCount * sizeof (CK_ATTRIBUTE));
}
out:
if (new_tmpl_allocated)
return (rv);
}
/*
* soft_ssl3_key_and_mac_derive()
*
* Arguments:
* . session_p
* . mech_p: key derivation mechanism. the mechanism parameter carries the
* client and mastter random from the Hello handshake messages,
* the specification of the key and IV sizes, and the location
* for the resulting keys and IVs.
* . basekey_p: The master secret key.
* . pTemplate & ulAttributeCount: Any extra attributes for the key to be
* created.
*
* Description:
* Derive the SSL key material (Client and server MAC secrets, symmetric
* keys and IVs), from the master secret and the client
* and server random.
* First a keyblock is generated usining the following formula:
* key_block =
* MD5(master_secret + SHA(`A' + master_secret +
* ServerHello.random +
* ClientHello.random)) +
* MD5(master_secret + SHA(`BB' + master_secret +
* ServerHello.random +
* ClientHello.random)) +
* MD5(master_secret + SHA(`CCC' + master_secret +
* ServerHello.random +
* ClientHello.random)) + [...];
*
* In TLS 1.0 (a.k.a. SSL 3.1), key_block =
* PRF(master_secret, "key expansion",
* ServerHello.random + ClientHello.random)
*
* Then the keys materials are taken from the keyblock.
*/
{
#ifdef __sparcv9
/* LINTED */
#else /* __sparcv9 */
#endif /* __sparcv9 */
int rounds, n = 0;
/* Check the validity of the mechanism's parameter */
return (CKR_MECHANISM_PARAM_INVALID);
#ifdef __sparcv9
/* LINTED */
/* LINTED */
#else /* __sparcv9 */
#endif /* __sparcv9 */
return (CKR_MECHANISM_PARAM_INVALID);
}
if ((iv_bytes > 0) &&
return (CKR_MECHANISM_PARAM_INVALID);
/*
* For exportable ciphersuites, the IV's aren't taken from the
* key block. They are directly derived from the client and
* server random data.
* For SSL3.0:
* client_write_IV = MD5(ClientHello.random + ServerHello.random);
* server_write_IV = MD5(ServerHello.random + ClientHello.random);
* For TLS1.0:
* iv_block = PRF("", "IV block", client_random +
* server_random)[0..15]
* client_write_IV = iv_block[0..7]
* server_write_IV = iv_block[8..15]
*/
if (iv_bytes > MD5_HASH_SIZE)
return (CKR_MECHANISM_PARAM_INVALID);
/* there's room in key_block. use it */
} else {
if (iv_bytes != 8)
return (CKR_MECHANISM_PARAM_INVALID);
iv_block, 16);
}
/* so we won't allocate a key_block bigger than needed */
iv_bytes = 0;
}
/* Now the actual secret derivation */
#ifdef __sparcv9
/* LINTED */
#else /* __sparcv9 */
#endif /* __sparcv9 */
/* Need to handle this better */
if (size > MAX_KEYBLOCK)
return (CKR_MECHANISM_PARAM_INVALID);
} else {
}
/* Now create the objects */
/* First the MAC secrets */
if (mac_key_bytes > 0) {
goto out_err;
kb += mac_key_bytes;
goto out_err;
kb += mac_key_bytes;
}
/* Then the symmetric ciphers keys */
if (newattrcount > MAX_DEFAULT_ATTRS) {
return (CKR_HOST_MEMORY);
} else
++n;
/*
* The keyType comes from the application's template, and depends
* on the ciphersuite. The only exception is authentication only
* ciphersuites which do not use cipher keys.
*/
if (secret_key_bytes == 0) {
n++;
}
new_tmpl[n].ulValueLen = sizeof (true);
n++;
new_tmpl[n].ulValueLen = sizeof (true);
n++;
new_tmpl[n].ulValueLen = sizeof (true);
n++;
new_tmpl[n].ulValueLen = 0;
if (secret_key_bytes > 0) {
if (isExport) {
if (secret_key_bytes > MD5_HASH_SIZE) {
goto out_err;
}
goto out_err;
}
#ifdef __sparcv9
/* LINTED */
#else /* __sparcv9 */
#endif /* __sparcv9 */
} else {
}
}
if (ulAttributeCount > 0)
ulAttributeCount * sizeof (CK_ATTRIBUTE));
goto out_err;
kb += secret_key_bytes;
if (secret_key_bytes > 0) {
if (isExport) {
#ifdef __sparcv9
/* LINTED */
#else /* __sparcv9 */
#endif /* __sparcv9 */
} else
}
goto out_err;
kb += secret_key_bytes;
/* Finally, the IVs */
if (iv_bytes > 0) {
}
if (new_tmpl_allocated)
if (export_keys != NULL)
return (rv);
(void) soft_delete_derived_key(sp,
}
(void) soft_delete_derived_key(sp,
}
(void) soft_delete_derived_key(sp,
}
(void) soft_delete_derived_key(sp,
}
if (new_tmpl_allocated)
if (export_keys != NULL)
return (rv);
}
/*
* Add the derived key to the session, and, if it's a token object,
* write it to the token.
*/
static CK_RV
{
return (CKR_HOST_MEMORY);
}
return (rv);
}
/* Set the sensitivity and extractability attributes as a needed */
/* Initialize the rest of stuffs in soft_object_t. */
/* ... and, if it needs to persist, write on the token */
if (IS_TOKEN_OBJECT(secret_key)) {
return (rv);
}
return (CKR_OK);
}
/* Add the new object to the session's object list. */
return (rv);
}
/*
* Delete the derived key from the session, and, if it's a token object,
* remove it from the token.
*/
static void
{
/* session_handle is the creating session. It's NULL for token objs */
if (IS_TOKEN_OBJECT(key))
else
}
/*
* soft_ssl_weaken_key()
* Reduce the key length to an exportable size.
* For SSL3.0:
* final_client_write_key = MD5(client_write_key +
* ClientHello.random +
* ServerHello.random);
* final_server_write_key = MD5(server_write_key +
* ServerHello.random +
* ClientHello.random);
* For TLS1.0:
* final_client_write_key = PRF(SecurityParameters.client_write_key,
* "client write key",
* SecurityParameters.client_random +
* SecurityParameters.server_random)[0..15];
* final_server_write_key = PRF(SecurityParameters.server_write_key,
* "server write key",
* SecurityParameters.client_random +
* SecurityParameters.server_random)[0..15];
*/
static void
{
} else {
if (isclient) {
} else {
}
}
}