PageRenderTime 339ms CodeModel.GetById 13ms app.highlight 286ms RepoModel.GetById 1ms app.codeStats 2ms

/security/nss/lib/softoken/pkcs11c.c

http://github.com/zpao/v8monkey
C | 6575 lines | 5055 code | 667 blank | 853 comment | 1325 complexity | dc7e5c203f1d91eb1f4d216671ed2d02 MD5 | raw file
   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *   Dr Stephen Henson <stephen.henson@gemplus.com>
  23 *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
  24 *
  25 * Alternatively, the contents of this file may be used under the terms of
  26 * either the GNU General Public License Version 2 or later (the "GPL"), or
  27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28 * in which case the provisions of the GPL or the LGPL are applicable instead
  29 * of those above. If you wish to allow use of your version of this file only
  30 * under the terms of either the GPL or the LGPL, and not to allow others to
  31 * use your version of this file under the terms of the MPL, indicate your
  32 * decision by deleting the provisions above and replace them with the notice
  33 * and other provisions required by the GPL or the LGPL. If you do not delete
  34 * the provisions above, a recipient may use your version of this file under
  35 * the terms of any one of the MPL, the GPL or the LGPL.
  36 *
  37 * ***** END LICENSE BLOCK ***** */
  38/*
  39 * This file implements PKCS 11 on top of our existing security modules
  40 *
  41 * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
  42 *   This implementation has two slots:
  43 *	slot 1 is our generic crypto support. It does not require login.
  44 *   It supports Public Key ops, and all they bulk ciphers and hashes. 
  45 *   It can also support Private Key ops for imported Private keys. It does 
  46 *   not have any token storage.
  47 *	slot 2 is our private key support. It requires a login before use. It
  48 *   can store Private Keys and Certs as token objects. Currently only private
  49 *   keys and their associated Certificates are saved on the token.
  50 *
  51 *   In this implementation, session objects are only visible to the session
  52 *   that created or generated them.
  53 */
  54#include "seccomon.h"
  55#include "secitem.h"
  56#include "secport.h"
  57#include "blapi.h"
  58#include "pkcs11.h"
  59#include "pkcs11i.h"
  60#include "lowkeyi.h"
  61#include "sechash.h"
  62#include "secder.h"
  63#include "secdig.h"
  64#include "lowpbe.h"	/* We do PBE below */
  65#include "pkcs11t.h"
  66#include "secoid.h"
  67#include "alghmac.h"
  68#include "softoken.h"
  69#include "secasn1.h"
  70#include "secerr.h"
  71
  72#include "prprf.h"
  73
  74#define __PASTE(x,y)    x##y
  75
  76/*
  77 * we renamed all our internal functions, get the correct
  78 * definitions for them...
  79 */ 
  80#undef CK_PKCS11_FUNCTION_INFO
  81#undef CK_NEED_ARG_LIST
  82
  83#define CK_EXTERN extern
  84#define CK_PKCS11_FUNCTION_INFO(func) \
  85		CK_RV __PASTE(NS,func)
  86#define CK_NEED_ARG_LIST	1
  87 
  88#include "pkcs11f.h"
  89
  90typedef struct {
  91    uint8 client_version[2];
  92    uint8 random[46];
  93} SSL3RSAPreMasterSecret;
  94
  95static void sftk_Null(void *data, PRBool freeit)
  96{
  97    return;
  98} 
  99
 100#ifdef NSS_ENABLE_ECC
 101#ifdef EC_DEBUG
 102#define SEC_PRINT(str1, str2, num, sitem) \
 103    printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
 104            str1, str2, num, sitem->len); \
 105    for (i = 0; i < sitem->len; i++) { \
 106	    printf("%02x:", sitem->data[i]); \
 107    } \
 108    printf("\n") 
 109#else
 110#define SEC_PRINT(a, b, c, d) 
 111#endif
 112#endif /* NSS_ENABLE_ECC */
 113
 114/*
 115 * free routines.... Free local type  allocated data, and convert
 116 * other free routines to the destroy signature.
 117 */
 118static void
 119sftk_FreePrivKey(NSSLOWKEYPrivateKey *key, PRBool freeit)
 120{
 121    nsslowkey_DestroyPrivateKey(key);
 122}
 123
 124static void
 125sftk_Space(void *data, PRBool freeit)
 126{
 127    PORT_Free(data);
 128} 
 129
 130/*
 131 * map all the SEC_ERROR_xxx error codes that may be returned by freebl
 132 * functions to CKR_xxx.  return CKR_DEVICE_ERROR by default for backward
 133 * compatibility.
 134 */
 135static CK_RV
 136sftk_MapCryptError(int error)
 137{
 138    switch (error) {
 139	case SEC_ERROR_INVALID_ARGS:
 140	case SEC_ERROR_BAD_DATA:  /* MP_RANGE gets mapped to this */
 141	    return CKR_ARGUMENTS_BAD;
 142	case SEC_ERROR_INPUT_LEN:
 143	    return CKR_DATA_LEN_RANGE;
 144	case SEC_ERROR_OUTPUT_LEN:
 145	    return CKR_BUFFER_TOO_SMALL;
 146	case SEC_ERROR_LIBRARY_FAILURE:
 147	    return CKR_GENERAL_ERROR;
 148	case SEC_ERROR_NO_MEMORY:
 149	    return CKR_HOST_MEMORY;
 150	case SEC_ERROR_BAD_SIGNATURE:
 151	    return CKR_SIGNATURE_INVALID;
 152	case SEC_ERROR_INVALID_KEY:
 153	    return CKR_KEY_SIZE_RANGE;
 154	case SEC_ERROR_BAD_KEY:  /* an EC public key that fails validation */
 155	    return CKR_KEY_SIZE_RANGE;  /* the closest error code */
 156	case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
 157	    return CKR_TEMPLATE_INCONSISTENT;
 158	/* EC functions set this error if NSS_ENABLE_ECC is not defined */
 159	case SEC_ERROR_UNSUPPORTED_KEYALG:
 160	    return CKR_MECHANISM_INVALID;
 161	case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
 162	    return CKR_DOMAIN_PARAMS_INVALID;
 163	/* key pair generation failed after max number of attempts */
 164	case SEC_ERROR_NEED_RANDOM:
 165	    return CKR_FUNCTION_FAILED;
 166    }
 167    return CKR_DEVICE_ERROR;
 168}
 169
 170/* used by Decrypt and UnwrapKey (indirectly) */
 171static CK_RV
 172sftk_MapDecryptError(int error)
 173{
 174    switch (error) {
 175	case SEC_ERROR_BAD_DATA:
 176	    return CKR_ENCRYPTED_DATA_INVALID;
 177	default:
 178	    return sftk_MapCryptError(error);
 179    }
 180}
 181
 182/*
 183 * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for
 184 * backward compatibilty.
 185 */
 186static CK_RV
 187sftk_MapVerifyError(int error)
 188{
 189    CK_RV crv = sftk_MapCryptError(error);
 190    if (crv == CKR_DEVICE_ERROR)
 191	crv = CKR_SIGNATURE_INVALID;
 192    return crv;
 193}
 194
 195
 196/*
 197 * turn a CDMF key into a des key. CDMF is an old IBM scheme to export DES by
 198 * Deprecating a full des key to 40 bit key strenth.
 199 */
 200static CK_RV
 201sftk_cdmf2des(unsigned char *cdmfkey, unsigned char *deskey)
 202{
 203    unsigned char key1[8] = { 0xc4, 0x08, 0xb0, 0x54, 0x0b, 0xa1, 0xe0, 0xae };
 204    unsigned char key2[8] = { 0xef, 0x2c, 0x04, 0x1c, 0xe6, 0x38, 0x2f, 0xe6 };
 205    unsigned char enc_src[8];
 206    unsigned char enc_dest[8];
 207    unsigned int leng,i;
 208    DESContext *descx;
 209    SECStatus rv;
 210    
 211    
 212    /* zero the parity bits */
 213    for (i=0; i < 8; i++) {
 214	enc_src[i] = cdmfkey[i] & 0xfe;
 215    }
 216
 217    /* encrypt with key 1 */
 218    descx = DES_CreateContext(key1, NULL, NSS_DES, PR_TRUE);
 219    if (descx == NULL) return CKR_HOST_MEMORY;
 220    rv = DES_Encrypt(descx, enc_dest, &leng, 8, enc_src, 8);
 221    DES_DestroyContext(descx,PR_TRUE);
 222    if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
 223
 224    /* xor source with des, zero the parity bits and deprecate the key*/
 225    for (i=0; i < 8; i++) {
 226	if (i & 1) {
 227	    enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0xfe;
 228	} else {
 229	    enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0x0e;
 230	}
 231    }
 232
 233    /* encrypt with key 2 */
 234    descx = DES_CreateContext(key2, NULL, NSS_DES, PR_TRUE);
 235    if (descx == NULL) return CKR_HOST_MEMORY;
 236    rv = DES_Encrypt(descx, deskey, &leng, 8, enc_src, 8);
 237    DES_DestroyContext(descx,PR_TRUE);
 238    if (rv != SECSuccess) return sftk_MapCryptError(PORT_GetError());
 239
 240    /* set the corret parity on our new des key */	
 241    sftk_FormatDESKey(deskey, 8);
 242    return CKR_OK;
 243}
 244
 245
 246/* NSC_DestroyObject destroys an object. */
 247CK_RV
 248NSC_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
 249{
 250    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
 251    SFTKSession *session;
 252    SFTKObject *object;
 253    SFTKFreeStatus status;
 254
 255    CHECK_FORK();
 256
 257    if (slot == NULL) {
 258	return CKR_SESSION_HANDLE_INVALID;
 259    }
 260    /*
 261     * This whole block just makes sure we really can destroy the
 262     * requested object.
 263     */
 264    session = sftk_SessionFromHandle(hSession);
 265    if (session == NULL) {
 266        return CKR_SESSION_HANDLE_INVALID;
 267    }
 268
 269    object = sftk_ObjectFromHandle(hObject,session);
 270    if (object == NULL) {
 271	sftk_FreeSession(session);
 272	return CKR_OBJECT_HANDLE_INVALID;
 273    }
 274
 275    /* don't destroy a private object if we aren't logged in */
 276    if ((!slot->isLoggedIn) && (slot->needLogin) &&
 277				(sftk_isTrue(object,CKA_PRIVATE))) {
 278	sftk_FreeSession(session);
 279	sftk_FreeObject(object);
 280	return CKR_USER_NOT_LOGGED_IN;
 281    }
 282
 283    /* don't destroy a token object if we aren't in a rw session */
 284
 285    if (((session->info.flags & CKF_RW_SESSION) == 0) &&
 286				(sftk_isTrue(object,CKA_TOKEN))) {
 287	sftk_FreeSession(session);
 288	sftk_FreeObject(object);
 289	return CKR_SESSION_READ_ONLY;
 290    }
 291
 292    sftk_DeleteObject(session,object);
 293
 294    sftk_FreeSession(session);
 295
 296    /*
 297     * get some indication if the object is destroyed. Note: this is not
 298     * 100%. Someone may have an object reference outstanding (though that
 299     * should not be the case by here. Also note that the object is "half"
 300     * destroyed. Our internal representation is destroyed, but it may still
 301     * be in the data base.
 302     */
 303    status = sftk_FreeObject(object);
 304
 305    return (status != SFTK_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR;
 306}
 307
 308
 309/*
 310 ************** Crypto Functions:     Utilities ************************
 311 */
 312
 313
 314/* 
 315 * return a context based on the SFTKContext type.
 316 */
 317SFTKSessionContext *
 318sftk_ReturnContextByType(SFTKSession *session, SFTKContextType type)
 319{
 320    switch (type) {
 321	case SFTK_ENCRYPT:
 322	case SFTK_DECRYPT:
 323	    return session->enc_context;
 324	case SFTK_HASH:
 325	    return session->hash_context;
 326	case SFTK_SIGN:
 327	case SFTK_SIGN_RECOVER:
 328	case SFTK_VERIFY:
 329	case SFTK_VERIFY_RECOVER:
 330	    return session->hash_context;
 331    }
 332    return NULL;
 333}
 334
 335/* 
 336 * change a context based on the SFTKContext type.
 337 */
 338void
 339sftk_SetContextByType(SFTKSession *session, SFTKContextType type, 
 340						SFTKSessionContext *context)
 341{
 342    switch (type) {
 343	case SFTK_ENCRYPT:
 344	case SFTK_DECRYPT:
 345	    session->enc_context = context;
 346	    break;
 347	case SFTK_HASH:
 348	    session->hash_context = context;
 349	    break;
 350	case SFTK_SIGN:
 351	case SFTK_SIGN_RECOVER:
 352	case SFTK_VERIFY:
 353	case SFTK_VERIFY_RECOVER:
 354	    session->hash_context = context;
 355	    break;
 356    }
 357    return;
 358}
 359
 360/*
 361 * code to grab the context. Needed by every C_XXXUpdate, C_XXXFinal,
 362 * and C_XXX function. The function takes a session handle, the context type,
 363 * and wether or not the session needs to be multipart. It returns the context,
 364 * and optionally returns the session pointer (if sessionPtr != NULL) if session
 365 * pointer is returned, the caller is responsible for freeing it.
 366 */
 367static CK_RV
 368sftk_GetContext(CK_SESSION_HANDLE handle,SFTKSessionContext **contextPtr,
 369	SFTKContextType type, PRBool needMulti, SFTKSession **sessionPtr)
 370{
 371    SFTKSession *session;
 372    SFTKSessionContext *context;
 373
 374    session = sftk_SessionFromHandle(handle);
 375    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
 376    context = sftk_ReturnContextByType(session,type);
 377    /* make sure the context is valid */
 378    if((context==NULL)||(context->type!=type)||(needMulti&&!(context->multi))){
 379        sftk_FreeSession(session);
 380	return CKR_OPERATION_NOT_INITIALIZED;
 381    }
 382    *contextPtr = context;
 383    if (sessionPtr != NULL) {
 384	*sessionPtr = session;
 385    } else {
 386	sftk_FreeSession(session);
 387    }
 388    return CKR_OK;
 389}
 390
 391/** Terminate operation (in the PKCS#11 spec sense).
 392 *  Intuitive name for FreeContext/SetNullContext pair.
 393 */
 394static void
 395sftk_TerminateOp( SFTKSession *session, SFTKContextType ctype,
 396        SFTKSessionContext *context )
 397{
 398    sftk_FreeContext( context );
 399    sftk_SetContextByType( session, ctype, NULL );
 400}
 401
 402/*
 403 ************** Crypto Functions:     Encrypt ************************
 404 */
 405
 406/*
 407 * All the NSC_InitXXX functions have a set of common checks and processing they
 408 * all need to do at the beginning. This is done here.
 409 */
 410static CK_RV
 411sftk_InitGeneric(SFTKSession *session,SFTKSessionContext **contextPtr,
 412		 SFTKContextType ctype,SFTKObject **keyPtr,
 413		 CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
 414		 CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
 415{
 416    SFTKObject *key = NULL;
 417    SFTKAttribute *att;
 418    SFTKSessionContext *context;
 419
 420    /* We can only init if there is not current context active */
 421    if (sftk_ReturnContextByType(session,ctype) != NULL) {
 422	return CKR_OPERATION_ACTIVE;
 423    }
 424
 425    /* find the key */
 426    if (keyPtr) {
 427        key = sftk_ObjectFromHandle(hKey,session);
 428        if (key == NULL) {
 429	    return CKR_KEY_HANDLE_INVALID;
 430    	}
 431
 432	/* make sure it's a valid  key for this operation */
 433	if (((key->objclass != CKO_SECRET_KEY) && (key->objclass != pubKeyType))
 434					|| !sftk_isTrue(key,operation)) {
 435	    sftk_FreeObject(key);
 436	    return CKR_KEY_TYPE_INCONSISTENT;
 437	}
 438	/* get the key type */
 439	att = sftk_FindAttribute(key,CKA_KEY_TYPE);
 440	if (att == NULL) {
 441	    sftk_FreeObject(key);
 442	    return CKR_KEY_TYPE_INCONSISTENT;
 443	}
 444	PORT_Assert(att->attrib.ulValueLen == sizeof(CK_KEY_TYPE));
 445	if (att->attrib.ulValueLen != sizeof(CK_KEY_TYPE)) {
 446	    sftk_FreeAttribute(att);
 447	    sftk_FreeObject(key);
 448	    return CKR_ATTRIBUTE_VALUE_INVALID;
 449	}
 450	PORT_Memcpy(keyTypePtr, att->attrib.pValue, sizeof(CK_KEY_TYPE));
 451	sftk_FreeAttribute(att);
 452	*keyPtr = key;
 453    }
 454
 455    /* allocate the context structure */
 456    context = (SFTKSessionContext *)PORT_Alloc(sizeof(SFTKSessionContext));
 457    if (context == NULL) {
 458	if (key) sftk_FreeObject(key);
 459	return CKR_HOST_MEMORY;
 460    }
 461    context->type = ctype;
 462    context->multi = PR_TRUE;
 463    context->cipherInfo = NULL;
 464    context->hashInfo = NULL;
 465    context->doPad = PR_FALSE;
 466    context->padDataLength = 0;
 467    context->key = key;
 468    context->blockSize = 0;
 469
 470    *contextPtr = context;
 471    return CKR_OK;
 472}
 473
 474/** NSC_CryptInit initializes an encryption/Decryption operation.
 475 *
 476 * Always called by NSC_EncryptInit, NSC_DecryptInit, NSC_WrapKey,NSC_UnwrapKey.
 477 * Called by NSC_SignInit, NSC_VerifyInit (via sftk_InitCBCMac) only for block
 478 *  ciphers MAC'ing.
 479 */
 480static CK_RV
 481sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
 482     CK_OBJECT_HANDLE hKey,
 483     CK_ATTRIBUTE_TYPE mechUsage, CK_ATTRIBUTE_TYPE keyUsage,
 484		 SFTKContextType contextType, PRBool isEncrypt)
 485{
 486    SFTKSession *session;
 487    SFTKObject *key;
 488    SFTKSessionContext *context;
 489    SFTKAttribute *att;
 490    CK_RC2_CBC_PARAMS *rc2_param;
 491#if NSS_SOFTOKEN_DOES_RC5
 492    CK_RC5_CBC_PARAMS *rc5_param;
 493    SECItem rc5Key;
 494#endif
 495    CK_KEY_TYPE key_type;
 496    CK_RV crv = CKR_OK;
 497    unsigned effectiveKeyLength;
 498    unsigned char newdeskey[24];
 499    PRBool useNewKey=PR_FALSE;
 500    int t;
 501
 502    crv = sftk_MechAllowsOperation(pMechanism->mechanism, mechUsage );
 503    if (crv != CKR_OK) 
 504    	return crv;
 505
 506    session = sftk_SessionFromHandle(hSession);
 507    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
 508
 509    crv = sftk_InitGeneric(session,&context,contextType,&key,hKey,&key_type,
 510    			isEncrypt ?CKO_PUBLIC_KEY:CKO_PRIVATE_KEY, keyUsage);
 511						
 512    if (crv != CKR_OK) {
 513	sftk_FreeSession(session);
 514	return crv;
 515    }
 516
 517    context->doPad = PR_FALSE;
 518    switch(pMechanism->mechanism) {
 519    case CKM_RSA_PKCS:
 520    case CKM_RSA_X_509:
 521	if (key_type != CKK_RSA) {
 522	    crv = CKR_KEY_TYPE_INCONSISTENT;
 523	    break;
 524	}
 525	context->multi = PR_FALSE;
 526	if (isEncrypt) {
 527	    NSSLOWKEYPublicKey *pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
 528	    if (pubKey == NULL) {
 529		break;
 530	    }
 531	    context->maxLen = nsslowkey_PublicModulusLen(pubKey);
 532	    context->cipherInfo =  (void *)pubKey;
 533	    context->update = (SFTKCipher) 
 534		(pMechanism->mechanism == CKM_RSA_X_509
 535					? RSA_EncryptRaw : RSA_EncryptBlock);
 536	} else {
 537	    NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
 538	    if (privKey == NULL) {
 539		break;
 540	    }
 541	    context->maxLen = nsslowkey_PrivateModulusLen(privKey);
 542	    context->cipherInfo =  (void *)privKey;
 543	    context->update = (SFTKCipher) 
 544		(pMechanism->mechanism == CKM_RSA_X_509
 545					? RSA_DecryptRaw : RSA_DecryptBlock);
 546	}
 547	context->destroy = sftk_Null;
 548	break;
 549    case CKM_RC2_CBC_PAD:
 550	context->doPad = PR_TRUE;
 551	/* fall thru */
 552    case CKM_RC2_ECB:
 553    case CKM_RC2_CBC:
 554	context->blockSize = 8;
 555	if (key_type != CKK_RC2) {
 556	    crv = CKR_KEY_TYPE_INCONSISTENT;
 557	    break;
 558	}
 559	att = sftk_FindAttribute(key,CKA_VALUE);
 560	if (att == NULL) {
 561	    crv = CKR_KEY_HANDLE_INVALID;
 562	    break;
 563	}
 564	rc2_param = (CK_RC2_CBC_PARAMS *)pMechanism->pParameter;
 565	effectiveKeyLength = (rc2_param->ulEffectiveBits+7)/8;
 566	context->cipherInfo = 
 567	    RC2_CreateContext((unsigned char*)att->attrib.pValue,
 568			      att->attrib.ulValueLen, rc2_param->iv,
 569			      pMechanism->mechanism == CKM_RC2_ECB ? NSS_RC2 :
 570			      NSS_RC2_CBC,effectiveKeyLength);
 571	sftk_FreeAttribute(att);
 572	if (context->cipherInfo == NULL) {
 573	    crv = CKR_HOST_MEMORY;
 574	    break;
 575	}
 576	context->update = (SFTKCipher) (isEncrypt ? RC2_Encrypt : RC2_Decrypt);
 577	context->destroy = (SFTKDestroy) RC2_DestroyContext;
 578	break;
 579#if NSS_SOFTOKEN_DOES_RC5
 580    case CKM_RC5_CBC_PAD:
 581	context->doPad = PR_TRUE;
 582	/* fall thru */
 583    case CKM_RC5_ECB:
 584    case CKM_RC5_CBC:
 585	if (key_type != CKK_RC5) {
 586	    crv = CKR_KEY_TYPE_INCONSISTENT;
 587	    break;
 588	}
 589	att = sftk_FindAttribute(key,CKA_VALUE);
 590	if (att == NULL) {
 591	    crv = CKR_KEY_HANDLE_INVALID;
 592	    break;
 593	}
 594	rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
 595	context->blockSize = rc5_param->ulWordsize*2;
 596	rc5Key.data = (unsigned char*)att->attrib.pValue;
 597	rc5Key.len = att->attrib.ulValueLen;
 598	context->cipherInfo = RC5_CreateContext(&rc5Key,rc5_param->ulRounds,
 599	   rc5_param->ulWordsize,rc5_param->pIv,
 600		 pMechanism->mechanism == CKM_RC5_ECB ? NSS_RC5 : NSS_RC5_CBC);
 601	sftk_FreeAttribute(att);
 602	if (context->cipherInfo == NULL) {
 603	    crv = CKR_HOST_MEMORY;
 604	    break;
 605	}
 606	context->update = (SFTKCipher) (isEncrypt ? RC5_Encrypt : RC5_Decrypt);
 607	context->destroy = (SFTKDestroy) RC5_DestroyContext;
 608	break;
 609#endif
 610    case CKM_RC4:
 611	if (key_type != CKK_RC4) {
 612	    crv = CKR_KEY_TYPE_INCONSISTENT;
 613	    break;
 614	}
 615	att = sftk_FindAttribute(key,CKA_VALUE);
 616	if (att == NULL) {
 617	    crv = CKR_KEY_HANDLE_INVALID;
 618	    break;
 619	}
 620	context->cipherInfo = 
 621	    RC4_CreateContext((unsigned char*)att->attrib.pValue,
 622			      att->attrib.ulValueLen);
 623	sftk_FreeAttribute(att);
 624	if (context->cipherInfo == NULL) {
 625	    crv = CKR_HOST_MEMORY;  /* WRONG !!! */
 626	    break;
 627	}
 628	context->update = (SFTKCipher) (isEncrypt ? RC4_Encrypt : RC4_Decrypt);
 629	context->destroy = (SFTKDestroy) RC4_DestroyContext;
 630	break;
 631    case CKM_CDMF_CBC_PAD:
 632	context->doPad = PR_TRUE;
 633	/* fall thru */
 634    case CKM_CDMF_ECB:
 635    case CKM_CDMF_CBC:
 636	if (key_type != CKK_CDMF) {
 637	    crv = CKR_KEY_TYPE_INCONSISTENT;
 638	    break;
 639	}
 640	t = (pMechanism->mechanism == CKM_CDMF_ECB) ? NSS_DES : NSS_DES_CBC;
 641	if (crv != CKR_OK) break;
 642	goto finish_des;
 643    case CKM_DES_ECB:
 644	if (key_type != CKK_DES) {
 645	    crv = CKR_KEY_TYPE_INCONSISTENT;
 646	    break;
 647	}
 648	t = NSS_DES;
 649	goto finish_des;
 650    case CKM_DES_CBC_PAD:
 651	context->doPad = PR_TRUE;
 652	/* fall thru */
 653    case CKM_DES_CBC:
 654	if (key_type != CKK_DES) {
 655	    crv = CKR_KEY_TYPE_INCONSISTENT;
 656	    break;
 657	}
 658	t = NSS_DES_CBC;
 659	goto finish_des;
 660    case CKM_DES3_ECB:
 661	if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
 662	    crv = CKR_KEY_TYPE_INCONSISTENT;
 663	    break;
 664	}
 665	t = NSS_DES_EDE3;
 666	goto finish_des;
 667    case CKM_DES3_CBC_PAD:
 668	context->doPad = PR_TRUE;
 669	/* fall thru */
 670    case CKM_DES3_CBC:
 671	if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
 672	    crv = CKR_KEY_TYPE_INCONSISTENT;
 673	    break;
 674	}
 675	t = NSS_DES_EDE3_CBC;
 676finish_des:
 677	context->blockSize = 8;
 678	att = sftk_FindAttribute(key,CKA_VALUE);
 679	if (att == NULL) {
 680	    crv = CKR_KEY_HANDLE_INVALID;
 681	    break;
 682	}
 683	if (key_type == CKK_DES2 && 
 684            (t == NSS_DES_EDE3_CBC || t == NSS_DES_EDE3)) {
 685	    /* extend DES2 key to DES3 key. */
 686	    memcpy(newdeskey, att->attrib.pValue, 16);
 687	    memcpy(newdeskey + 16, newdeskey, 8);
 688	    useNewKey=PR_TRUE;
 689	} else if (key_type == CKK_CDMF) {
 690	    crv = sftk_cdmf2des((unsigned char*)att->attrib.pValue,newdeskey);
 691	    if (crv != CKR_OK) {
 692		sftk_FreeAttribute(att);
 693		break;
 694	    }
 695	    useNewKey=PR_TRUE;
 696	}
 697	context->cipherInfo = DES_CreateContext(
 698		useNewKey ? newdeskey : (unsigned char*)att->attrib.pValue,
 699		(unsigned char*)pMechanism->pParameter,t, isEncrypt);
 700	if (useNewKey) 
 701	    memset(newdeskey, 0, sizeof newdeskey);
 702	sftk_FreeAttribute(att);
 703	if (context->cipherInfo == NULL) {
 704	    crv = CKR_HOST_MEMORY;
 705	    break;
 706	}
 707	context->update = (SFTKCipher) (isEncrypt ? DES_Encrypt : DES_Decrypt);
 708	context->destroy = (SFTKDestroy) DES_DestroyContext;
 709	break;
 710    case CKM_SEED_CBC_PAD:
 711	context->doPad = PR_TRUE;
 712	/* fall thru */
 713    case CKM_SEED_CBC:
 714        if (!pMechanism->pParameter ||
 715	     pMechanism->ulParameterLen != 16) {
 716            crv = CKR_MECHANISM_PARAM_INVALID;
 717            break;
 718        }
 719        /* fall thru */
 720    case CKM_SEED_ECB:
 721	context->blockSize = 16;
 722	if (key_type != CKK_SEED) {
 723	    crv = CKR_KEY_TYPE_INCONSISTENT;
 724	    break;
 725	}
 726	att = sftk_FindAttribute(key,CKA_VALUE);
 727	if (att == NULL) {
 728	    crv = CKR_KEY_HANDLE_INVALID;
 729	    break;
 730	}
 731	context->cipherInfo = SEED_CreateContext(
 732	    (unsigned char*)att->attrib.pValue,
 733	    (unsigned char*)pMechanism->pParameter,
 734	    pMechanism->mechanism == CKM_SEED_ECB ? NSS_SEED : NSS_SEED_CBC,
 735	    isEncrypt);
 736	sftk_FreeAttribute(att);
 737	if (context->cipherInfo == NULL) {
 738	    crv = CKR_HOST_MEMORY;
 739	    break;
 740	}
 741	context->update = (SFTKCipher)(isEncrypt ? SEED_Encrypt : SEED_Decrypt);
 742	context->destroy = (SFTKDestroy) SEED_DestroyContext;
 743	break;
 744
 745    case CKM_CAMELLIA_CBC_PAD:
 746	context->doPad = PR_TRUE;
 747	/* fall thru */
 748    case CKM_CAMELLIA_CBC:
 749	if (!pMechanism->pParameter ||
 750		 pMechanism->ulParameterLen != 16) {
 751	    crv = CKR_MECHANISM_PARAM_INVALID;
 752	    break;
 753	}
 754	/* fall thru */
 755    case CKM_CAMELLIA_ECB:
 756	context->blockSize = 16;
 757	if (key_type != CKK_CAMELLIA) {
 758	    crv = CKR_KEY_TYPE_INCONSISTENT;
 759	    break;
 760	}
 761	att = sftk_FindAttribute(key,CKA_VALUE);
 762	if (att == NULL) {
 763	    crv = CKR_KEY_HANDLE_INVALID;
 764	    break;
 765	}
 766	context->cipherInfo = Camellia_CreateContext(
 767	    (unsigned char*)att->attrib.pValue,
 768	    (unsigned char*)pMechanism->pParameter,
 769	    pMechanism->mechanism ==
 770	    CKM_CAMELLIA_ECB ? NSS_CAMELLIA : NSS_CAMELLIA_CBC,
 771	    isEncrypt, att->attrib.ulValueLen);
 772	sftk_FreeAttribute(att);
 773	if (context->cipherInfo == NULL) {
 774	    crv = CKR_HOST_MEMORY;
 775	    break;
 776	}
 777	context->update = (SFTKCipher) (isEncrypt ?
 778					Camellia_Encrypt : Camellia_Decrypt);
 779	context->destroy = (SFTKDestroy) Camellia_DestroyContext;
 780	break;
 781
 782    case CKM_AES_CBC_PAD:
 783	context->doPad = PR_TRUE;
 784	/* fall thru */
 785    case CKM_AES_ECB:
 786    case CKM_AES_CBC:
 787	context->blockSize = 16;
 788	if (key_type != CKK_AES) {
 789	    crv = CKR_KEY_TYPE_INCONSISTENT;
 790	    break;
 791	}
 792	att = sftk_FindAttribute(key,CKA_VALUE);
 793	if (att == NULL) {
 794	    crv = CKR_KEY_HANDLE_INVALID;
 795	    break;
 796	}
 797	context->cipherInfo = AES_CreateContext(
 798	    (unsigned char*)att->attrib.pValue,
 799	    (unsigned char*)pMechanism->pParameter,
 800	    pMechanism->mechanism == CKM_AES_ECB ? NSS_AES : NSS_AES_CBC,
 801	    isEncrypt, att->attrib.ulValueLen, 16);
 802	sftk_FreeAttribute(att);
 803	if (context->cipherInfo == NULL) {
 804	    crv = CKR_HOST_MEMORY;
 805	    break;
 806	}
 807	context->update = (SFTKCipher) (isEncrypt ? AES_Encrypt : AES_Decrypt);
 808	context->destroy = (SFTKDestroy) AES_DestroyContext;
 809	break;
 810
 811    case CKM_NETSCAPE_AES_KEY_WRAP_PAD:
 812    	context->doPad = PR_TRUE;
 813	/* fall thru */
 814    case CKM_NETSCAPE_AES_KEY_WRAP:
 815	context->multi = PR_FALSE;
 816	context->blockSize = 8;
 817	if (key_type != CKK_AES) {
 818	    crv = CKR_KEY_TYPE_INCONSISTENT;
 819	    break;
 820	}
 821	att = sftk_FindAttribute(key,CKA_VALUE);
 822	if (att == NULL) {
 823	    crv = CKR_KEY_HANDLE_INVALID;
 824	    break;
 825	}
 826	context->cipherInfo = AESKeyWrap_CreateContext(
 827	    (unsigned char*)att->attrib.pValue,
 828	    (unsigned char*)pMechanism->pParameter,
 829	    isEncrypt, att->attrib.ulValueLen);
 830	sftk_FreeAttribute(att);
 831	if (context->cipherInfo == NULL) {
 832	    crv = CKR_HOST_MEMORY;
 833	    break;
 834	}
 835	context->update = (SFTKCipher) (isEncrypt ? AESKeyWrap_Encrypt 
 836	                                          : AESKeyWrap_Decrypt);
 837	context->destroy = (SFTKDestroy) AESKeyWrap_DestroyContext;
 838	break;
 839
 840    default:
 841	crv = CKR_MECHANISM_INVALID;
 842	break;
 843    }
 844
 845    if (crv != CKR_OK) {
 846        sftk_FreeContext(context);
 847	sftk_FreeSession(session);
 848	return crv;
 849    }
 850    sftk_SetContextByType(session, contextType, context);
 851    sftk_FreeSession(session);
 852    return CKR_OK;
 853}
 854
 855/* NSC_EncryptInit initializes an encryption operation. */
 856CK_RV NSC_EncryptInit(CK_SESSION_HANDLE hSession,
 857		 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
 858{
 859    CHECK_FORK();
 860    return sftk_CryptInit(hSession, pMechanism, hKey, CKA_ENCRYPT, CKA_ENCRYPT,
 861						SFTK_ENCRYPT, PR_TRUE);
 862}
 863
 864/* NSC_EncryptUpdate continues a multiple-part encryption operation. */
 865CK_RV NSC_EncryptUpdate(CK_SESSION_HANDLE hSession,
 866    CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,	
 867					CK_ULONG_PTR pulEncryptedPartLen)
 868{
 869    SFTKSessionContext *context;
 870    unsigned int outlen,i;
 871    unsigned int padoutlen = 0;
 872    unsigned int maxout = *pulEncryptedPartLen;
 873    CK_RV crv;
 874    SECStatus rv;
 875
 876    CHECK_FORK();
 877
 878    /* make sure we're legal */
 879    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,NULL);
 880    if (crv != CKR_OK) return crv;
 881
 882    if (!pEncryptedPart) {
 883	if (context->doPad) {
 884	    CK_ULONG totalDataAvailable = ulPartLen + context->padDataLength;
 885	    CK_ULONG blocksToSend = totalDataAvailable/context->blockSize;
 886
 887	    *pulEncryptedPartLen = blocksToSend * context->blockSize;
 888	    return CKR_OK;
 889	}
 890	*pulEncryptedPartLen = ulPartLen;
 891	return CKR_OK;
 892    }
 893
 894    /* do padding */
 895    if (context->doPad) {
 896	/* deal with previous buffered data */
 897	if (context->padDataLength != 0) {
 898	    /* fill in the padded to a full block size */
 899	    for (i=context->padDataLength; 
 900			(ulPartLen != 0) && i < context->blockSize; i++) {
 901		context->padBuf[i] = *pPart++;
 902		ulPartLen--;
 903		context->padDataLength++;
 904	    }
 905
 906	    /* not enough data to encrypt yet? then return */
 907	    if (context->padDataLength != context->blockSize) {
 908		*pulEncryptedPartLen = 0;
 909		return CKR_OK;
 910	    }
 911	    /* encrypt the current padded data */
 912    	    rv = (*context->update)(context->cipherInfo, pEncryptedPart, 
 913		&padoutlen, context->blockSize, context->padBuf,
 914							context->blockSize);
 915	    if (rv != SECSuccess) {
 916		return sftk_MapCryptError(PORT_GetError());
 917	    }
 918	    pEncryptedPart += padoutlen;
 919	    maxout -= padoutlen;
 920	}
 921	/* save the residual */
 922	context->padDataLength = ulPartLen % context->blockSize;
 923	if (context->padDataLength) {
 924	    PORT_Memcpy(context->padBuf,
 925			&pPart[ulPartLen-context->padDataLength],
 926							context->padDataLength);
 927	    ulPartLen -= context->padDataLength;
 928	}
 929	/* if we've exhausted our new buffer, we're done */
 930	if (ulPartLen == 0) {
 931	    *pulEncryptedPartLen = padoutlen;
 932	    return CKR_OK;
 933	}
 934    }
 935
 936
 937    /* do it: NOTE: this assumes buf size in is >= buf size out! */
 938    rv = (*context->update)(context->cipherInfo,pEncryptedPart, 
 939					&outlen, maxout, pPart, ulPartLen);
 940    *pulEncryptedPartLen = (CK_ULONG) (outlen + padoutlen);
 941    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
 942}
 943
 944
 945/* NSC_EncryptFinal finishes a multiple-part encryption operation. */
 946CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession,
 947    CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
 948{
 949    SFTKSession *session;
 950    SFTKSessionContext *context;
 951    unsigned int outlen,i;
 952    unsigned int maxout = *pulLastEncryptedPartLen;
 953    CK_RV crv;
 954    SECStatus rv = SECSuccess;
 955    PRBool contextFinished = PR_TRUE;
 956
 957    CHECK_FORK();
 958
 959    /* make sure we're legal */
 960    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,&session);
 961    if (crv != CKR_OK) return crv;
 962
 963    *pulLastEncryptedPartLen = 0;
 964    if (!pLastEncryptedPart) {
 965	/* caller is checking the amount of remaining data */
 966	if (context->blockSize > 0 && context->doPad) {
 967	    *pulLastEncryptedPartLen = context->blockSize;
 968	    contextFinished = PR_FALSE; /* still have padding to go */
 969	}
 970	goto finish;
 971    }
 972
 973    /* do padding */
 974    if (context->doPad) {
 975	unsigned char  padbyte = (unsigned char) 
 976				(context->blockSize - context->padDataLength); 
 977	/* fill out rest of pad buffer with pad magic*/
 978	for (i=context->padDataLength; i < context->blockSize; i++) {
 979	    context->padBuf[i] = padbyte;
 980	}
 981	rv = (*context->update)(context->cipherInfo,pLastEncryptedPart, 
 982			&outlen, maxout, context->padBuf, context->blockSize);
 983	if (rv == SECSuccess) *pulLastEncryptedPartLen = (CK_ULONG) outlen;
 984    }
 985
 986finish:
 987    if (contextFinished)
 988        sftk_TerminateOp( session, SFTK_ENCRYPT, context );
 989    sftk_FreeSession(session);
 990    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
 991}
 992
 993/* NSC_Encrypt encrypts single-part data. */
 994CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
 995    		   CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
 996		   CK_ULONG_PTR pulEncryptedDataLen)
 997{
 998    SFTKSession *session;
 999    SFTKSessionContext *context;
1000    unsigned int outlen;
1001    unsigned int maxoutlen = *pulEncryptedDataLen;
1002    CK_RV crv;
1003    CK_RV crv2;
1004    SECStatus rv = SECSuccess;
1005    SECItem   pText;
1006
1007    pText.type = siBuffer;
1008    pText.data = pData;
1009    pText.len  = ulDataLen;
1010
1011    CHECK_FORK();
1012
1013    /* make sure we're legal */
1014    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,&session);
1015    if (crv != CKR_OK) return crv;
1016
1017    if (!pEncryptedData) {
1018	*pulEncryptedDataLen = context->multi ? 
1019		ulDataLen + 2 * context->blockSize : context->maxLen;
1020	goto finish;
1021    }
1022
1023    if (context->doPad) {
1024	if (context->multi) {
1025	    CK_ULONG finalLen;
1026	    /* padding is fairly complicated, have the update and final 
1027	     * code deal with it */
1028	    sftk_FreeSession(session);
1029	    crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData, 
1030	                            pulEncryptedDataLen);
1031	    if (crv != CKR_OK) 
1032	    	*pulEncryptedDataLen = 0;
1033	    maxoutlen      -= *pulEncryptedDataLen;
1034	    pEncryptedData += *pulEncryptedDataLen;
1035	    finalLen = maxoutlen;
1036	    crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen);
1037	    if (crv2 == CKR_OK) 
1038	    	*pulEncryptedDataLen += finalLen;
1039	    return crv == CKR_OK ? crv2 : crv;
1040	}
1041	/* doPad without multi means that padding must be done on the first
1042	** and only update.  There will be no final.
1043	*/
1044	PORT_Assert(context->blockSize > 1);
1045	if (context->blockSize > 1) {
1046	    CK_ULONG remainder = ulDataLen % context->blockSize;
1047	    CK_ULONG padding   = context->blockSize - remainder;
1048	    pText.len += padding;
1049	    pText.data = PORT_ZAlloc(pText.len);
1050	    if (pText.data) {
1051		memcpy(pText.data, pData, ulDataLen);
1052		memset(pText.data + ulDataLen, padding, padding);
1053	    } else {
1054		crv = CKR_HOST_MEMORY;
1055		goto fail;
1056	    }
1057	}
1058    }
1059
1060    /* do it: NOTE: this assumes buf size is big enough. */
1061    rv = (*context->update)(context->cipherInfo, pEncryptedData, 
1062			    &outlen, maxoutlen, pText.data, pText.len);
1063    crv = (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
1064    *pulEncryptedDataLen = (CK_ULONG) outlen;
1065    if (pText.data != pData)
1066    	PORT_ZFree(pText.data, pText.len);
1067fail:
1068    sftk_TerminateOp( session, SFTK_ENCRYPT, context );
1069finish:
1070    sftk_FreeSession(session);
1071
1072    return crv;
1073}
1074
1075
1076/*
1077 ************** Crypto Functions:     Decrypt ************************
1078 */
1079
1080/* NSC_DecryptInit initializes a decryption operation. */
1081CK_RV NSC_DecryptInit( CK_SESSION_HANDLE hSession,
1082			 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
1083{
1084    CHECK_FORK();
1085    return sftk_CryptInit(hSession, pMechanism, hKey, CKA_DECRYPT, CKA_DECRYPT,
1086						SFTK_DECRYPT, PR_FALSE);
1087}
1088
1089/* NSC_DecryptUpdate continues a multiple-part decryption operation. */
1090CK_RV NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
1091    CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen,
1092    				CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
1093{
1094    SFTKSessionContext *context;
1095    unsigned int padoutlen = 0;
1096    unsigned int outlen;
1097    unsigned int maxout = *pulPartLen;
1098    CK_RV crv;
1099    SECStatus rv;
1100
1101    CHECK_FORK();
1102
1103    /* make sure we're legal */
1104    crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,NULL);
1105    if (crv != CKR_OK) return crv;
1106
1107    /* this can only happen on an NSS programming error */
1108    PORT_Assert((context->padDataLength == 0) 
1109		|| context->padDataLength == context->blockSize);
1110
1111
1112    if (!pPart) {
1113	if (context->doPad) {
1114	    /* we can check the data length here because if we are padding,
1115	     * then we must be using a block cipher. In the non-padding case
1116	     * the error will be returned by the underlying decryption
1117	     * function when do do the actual decrypt. We need to do the
1118	     * check here to avoid returning a negative length to the caller.
1119 	     */
1120	    if ((ulEncryptedPartLen == 0) ||
1121		(ulEncryptedPartLen % context->blockSize) != 0) {
1122		return CKR_ENCRYPTED_DATA_LEN_RANGE;
1123	    }
1124	    *pulPartLen = 
1125		ulEncryptedPartLen + context->padDataLength - context->blockSize;
1126	    return CKR_OK;
1127	}
1128	/* for stream ciphers there is are no constraints on ulEncryptedPartLen.
1129	 * for block ciphers, it must be a multiple of blockSize. The error is
1130	 * detected when this function is called again do decrypt the output.
1131	 */
1132	*pulPartLen = ulEncryptedPartLen;
1133	return CKR_OK;
1134    }
1135
1136    if (context->doPad) {
1137	/* first decrypt our saved buffer */
1138	if (context->padDataLength != 0) {
1139    	    rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
1140		 maxout, context->padBuf, context->blockSize);
1141    	    if (rv != SECSuccess) return sftk_MapDecryptError(PORT_GetError());
1142	    pPart += padoutlen;
1143	    maxout -= padoutlen;
1144	}
1145	/* now save the final block for the next decrypt or the final */
1146	PORT_Memcpy(context->padBuf,&pEncryptedPart[ulEncryptedPartLen -
1147				context->blockSize], context->blockSize);
1148	context->padDataLength = context->blockSize;
1149	ulEncryptedPartLen -= context->padDataLength;
1150    }
1151
1152    /* do it: NOTE: this assumes buf size in is >= buf size out! */
1153    rv = (*context->update)(context->cipherInfo,pPart, &outlen,
1154		 maxout, pEncryptedPart, ulEncryptedPartLen);
1155    *pulPartLen = (CK_ULONG) (outlen + padoutlen);
1156    return (rv == SECSuccess)  ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
1157}
1158
1159
1160/* NSC_DecryptFinal finishes a multiple-part decryption operation. */
1161CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
1162    CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
1163{
1164    SFTKSession *session;
1165    SFTKSessionContext *context;
1166    unsigned int outlen;
1167    unsigned int maxout = *pulLastPartLen;
1168    CK_RV crv;
1169    SECStatus rv = SECSuccess;
1170
1171    CHECK_FORK();
1172
1173    /* make sure we're legal */
1174    crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,&session);
1175    if (crv != CKR_OK) return crv;
1176
1177    *pulLastPartLen = 0;
1178    if (!pLastPart) {
1179	/* caller is checking the amount of remaining data */
1180	if (context->padDataLength > 0) {
1181	    *pulLastPartLen = context->padDataLength;
1182	}
1183	rv = SECSuccess;
1184	goto finish;
1185    }
1186
1187    if (context->doPad) {
1188	/* decrypt our saved buffer */
1189	if (context->padDataLength != 0) {
1190	    /* this assumes that pLastPart is big enough to hold the *whole*
1191	     * buffer!!! */
1192    	    rv = (*context->update)(context->cipherInfo, pLastPart, &outlen,
1193		 maxout, context->padBuf, context->blockSize);
1194    	    if (rv == SECSuccess) {
1195		unsigned int padSize = 
1196			    (unsigned int) pLastPart[context->blockSize-1];
1197		if ((padSize > context->blockSize) || (padSize == 0)) {
1198		    rv = SECFailure;
1199		} else {
1200		    *pulLastPartLen = outlen - padSize;
1201		}
1202	    }
1203	}
1204    }
1205
1206    sftk_TerminateOp( session, SFTK_DECRYPT, context );
1207finish:
1208    sftk_FreeSession(session);
1209    return (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
1210}
1211
1212/* NSC_Decrypt decrypts encrypted data in a single part. */
1213CK_RV NSC_Decrypt(CK_SESSION_HANDLE hSession,
1214    CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,
1215    						CK_ULONG_PTR pulDataLen)
1216{
1217    SFTKSession *session;
1218    SFTKSessionContext *context;
1219    unsigned int outlen;
1220    unsigned int maxoutlen = *pulDataLen;
1221    CK_RV crv;
1222    CK_RV crv2;
1223    SECStatus rv = SECSuccess;
1224
1225    CHECK_FORK();
1226
1227    /* make sure we're legal */
1228    crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_FALSE,&session);
1229    if (crv != CKR_OK) return crv;
1230
1231    if (!pData) {
1232	*pulDataLen = ulEncryptedDataLen + context->blockSize;
1233	goto finish;
1234    }
1235
1236    if (context->doPad && context->multi) {
1237	CK_ULONG finalLen;
1238	/* padding is fairly complicated, have the update and final 
1239	 * code deal with it */
1240	sftk_FreeSession(session);
1241	crv = NSC_DecryptUpdate(hSession,pEncryptedData,ulEncryptedDataLen,
1242							pData, pulDataLen);
1243	if (crv != CKR_OK) 
1244	    *pulDataLen = 0;
1245	maxoutlen -= *pulDataLen;
1246	pData     += *pulDataLen;
1247	finalLen = maxoutlen;
1248	crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
1249	if (crv2 == CKR_OK) 
1250	    *pulDataLen += finalLen;
1251	return crv == CKR_OK ? crv2 : crv;
1252    }
1253
1254    rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
1255					pEncryptedData, ulEncryptedDataLen);
1256    /* XXX need to do MUCH better error mapping than this. */
1257    crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
1258    if (rv == SECSuccess && context->doPad) {
1259    	CK_ULONG padding = pData[outlen - 1];
1260	if (padding > context->blockSize || !padding) {
1261	    crv = CKR_ENCRYPTED_DATA_INVALID;
1262	} else
1263	    outlen -= padding;
1264    }
1265    *pulDataLen = (CK_ULONG) outlen;
1266    sftk_TerminateOp( session, SFTK_DECRYPT, context );
1267finish:
1268    sftk_FreeSession(session);
1269    return crv;
1270}
1271
1272
1273
1274/*
1275 ************** Crypto Functions:     Digest (HASH)  ************************
1276 */
1277
1278/* NSC_DigestInit initializes a message-digesting operation. */
1279CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession,
1280    					CK_MECHANISM_PTR pMechanism)
1281{
1282    SFTKSession *session;
1283    SFTKSessionContext *context;
1284    CK_RV crv = CKR_OK;
1285
1286    CHECK_FORK();
1287
1288    session = sftk_SessionFromHandle(hSession);
1289    if (session == NULL) 
1290    	return CKR_SESSION_HANDLE_INVALID;
1291    crv = sftk_InitGeneric(session,&context,SFTK_HASH,NULL,0,NULL, 0, 0);
1292    if (crv != CKR_OK) {
1293	sftk_FreeSession(session);
1294	return crv;
1295    }
1296
1297
1298#define INIT_MECH(mech,mmm) \
1299    case mech: { \
1300	mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
1301	context->cipherInfo    = (void *)mmm ## _ctx; \
1302	context->cipherInfoLen = mmm ## _FlattenSize(mmm ## _ctx); \
1303	context->currentMech   = mech; \
1304	context->hashUpdate    = (SFTKHash)    mmm ## _Update; \
1305	context->end           = (SFTKEnd)     mmm ## _End; \
1306	context->destroy       = (SFTKDestroy) mmm ## _DestroyContext; \
1307	context->maxLen        = mmm ## _LENGTH; \
1308        if (mmm ## _ctx) \
1309	    mmm ## _Begin(mmm ## _ctx); \
1310	else  \
1311	    crv = CKR_HOST_MEMORY; \
1312	break; \
1313    }
1314
1315    switch(pMechanism->mechanism) {
1316    INIT_MECH(CKM_MD2,    MD2)
1317    INIT_MECH(CKM_MD5,    MD5)
1318    INIT_MECH(CKM_SHA_1,  SHA1)
1319    INIT_MECH(CKM_SHA224, SHA224)
1320    INIT_MECH(CKM_SHA256, SHA256)
1321    INIT_MECH(CKM_SHA384, SHA384)
1322    INIT_MECH(CKM_SHA512, SHA512)
1323
1324    default:
1325	crv = CKR_MECHANISM_INVALID;
1326	break;
1327    }
1328
1329    if (crv != CKR_OK) {
1330        sftk_FreeContext(context);
1331	sftk_FreeSession(session);
1332	return crv;
1333    }
1334    sftk_SetContextByType(session, SFTK_HASH, context);
1335    sftk_FreeSession(session);
1336    return CKR_OK;
1337}
1338
1339
1340/* NSC_Digest digests data in a single part. */
1341CK_RV NSC_Digest(CK_SESSION_HANDLE hSession,
1342    CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest,
1343    						CK_ULONG_PTR pulDigestLen)
1344{
1345    SFTKSession *session;
1346    SFTKSessionContext *context;
1347    unsigned int digestLen;
1348    unsigned int maxout = *pulDigestLen;
1349    CK_RV crv;
1350
1351    CHECK_FORK();
1352
1353    /* make sure we're legal */
1354    crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_FALSE,&session);
1355    if (crv != CKR_OK) return crv;
1356
1357    if (pDigest == NULL) {
1358	*pulDigestLen = context->maxLen;
1359	goto finish;
1360    }
1361
1362    /* do it: */
1363    (*context->hashUpdate)(context->cipherInfo, pData, ulDataLen);
1364    /*  NOTE: this assumes buf size is bigenough for the algorithm */
1365    (*context->end)(context->cipherInfo, pDigest, &digestLen,maxout);
1366    *pulDigestLen = digestLen;
1367
1368    sftk_TerminateOp( session, SFTK_HASH, context );
1369finish:
1370    sftk_FreeSession(session);
1371    return CKR_OK;
1372}
1373
1374
1375/* NSC_DigestUpdate continues a multiple-part message-digesting operation. */
1376CK_RV NSC_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
1377					    CK_ULONG ulPartLen)
1378{
1379    SFTKSessionContext *context;
1380    CK_RV crv;
1381
1382    CHECK_FORK();
1383
1384    /* make sure we're legal */
1385    crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_TRUE,NULL);
1386    if (crv != CKR_OK) return crv;
1387    /* do it: */
1388    (*context->hashUpdate)(context->cipherInfo, pPart, ulPartLen);
1389    return CKR_OK;
1390}
1391
1392
1393/* NSC_DigestFinal finishes a multiple-part message-digesting operation. */
1394CK_RV NSC_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,
1395    						CK_ULONG_PTR pulDigestLen)
1396{
1397    SFTKSession *session;
1398    SFTKSessionContext *context;
1399    unsigned int maxout = *pulDigestLen;
1400    unsigned int digestLen;
1401    CK_RV crv;
1402
1403    CHECK_FORK();
1404
1405    /* make sure we're legal */
1406    crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session);
1407    if (crv != CKR_OK) return crv;
1408
1409    if (pDigest != NULL) {
1410        (*context->end)(context->cipherInfo, pDigest, &digestLen, maxout);
1411        *pulDigestLen = digestLen;
1412        sftk_TerminateOp( session, SFTK_HASH, context );
1413    } else {
1414	*pulDigestLen = context->maxLen;
1415    }
1416
1417    sftk_FreeSession(session);
1418    return CKR_OK;
1419}
1420
1421/*
1422 * these helper functions are used by Generic Macing and Signing functions
1423 * that use hashes as part of their operations. 
1424 */
1425#define DOSUB(mmm) \
1426static CK_RV \
1427sftk_doSub ## mmm(SFTKSessionContext *context) { \
1428    mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
1429    context->hashInfo    = (void *)      mmm ## _ctx; \
1430    context->hashUpdate  = (SFTKHash)    mmm ## _Update; \
1431    context->end         = (SFTKEnd)     mmm ## _End; \
1432    context->hashdestroy = (SFTKDestroy) mmm ## _DestroyContext; \
1433    if (!context->hashInfo) { \
1434	return CKR_HOST_MEMORY; \
1435    } \
1436    mmm ## _Begin( mmm ## _ctx ); \
1437    return CKR_OK; \
1438}
1439
1440DOSUB(MD2)
1441DOSUB(MD5)
1442DOSUB(SHA1)
1443DOSUB(SHA224)
1444DOSUB(SHA256)
1445DOSUB(SHA384)
1446DOSUB(SHA512)
1447
1448/*
1449 * HMAC General copies only a portion of the result. This update routine likes
1450 * the final HMAC output with the signature.
1451 */
1452static SECStatus
1453sftk_HMACCopy(CK_ULONG *copyLen,unsigned char *sig,unsigned int *sigLen,
1454		unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1455{
1456    if (maxLen < *copyLen) return SECFailure;
1457    PORT_Memcpy(sig,hash,*copyLen);
1458    *sigLen = *copyLen;
1459    return SECSuccess;
1460}
1461
1462/* Verify is just a compare for HMAC */
1463static SECStatus
1464sftk_HMACCmp(CK_ULONG *copyLen,unsigned char *sig,unsigned int sigLen,
1465				unsigned char *hash, unsigned int hashLen)
1466{
1467    return (PORT_Memcmp(sig,hash,*copyLen) == 0) ? SECSuccess : SECFailure ; 
1468}
1469
1470/*
1471 * common HMAC initalization routine
1472 */
1473static CK_RV
1474sftk_doHMACInit(SFTKSessionContext *context,HASH_HashType hash,
1475					SFTKObject *key, CK_ULONG mac_size)
1476{
1477    SFTKAttribute *keyval;
1478    HMACContext *HMACcontext;
1479    CK_ULONG *intpointer;
1480    const SECHashObject *hashObj = HASH_GetRawHashObject(hash);
1481    PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
1482
1483    /* required by FIPS 198 Section 4 */
1484    if (isFIPS && (mac_size < 4 || mac_size < hashObj->length/2)) {
1485	return CKR_BUFFER_TOO_SMALL;
1486    }
1487
1488    keyval = sftk_FindAttribute(key,CKA_VALUE);
1489    if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
1490
1491    HMACcontext = HMAC_Create(hashObj, 
1492		(const unsigned char*)keyval->attrib.pValue,
1493		keyval->attrib.ulValueLen, isFIPS);
1494    context->hashInfo = HMACcontext;
1495    context->multi = PR_TRUE;
1496    sftk_FreeAttribute(keyval);
1497    if (context->hashInfo == NULL) {
1498	if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
1499	    return CKR_KEY_SIZE_RANGE;
1500	}
1501	return CKR_HOST_MEMORY;
1502    }
1503    context->hashUpdate = (SFTKHash) HMAC_Update;
1504    context->end = (SFTKEnd) HMAC_Finish;
1505
1506    context->hashdestroy = (SFTKDestroy) HMAC_Destroy;
1507    intpointer = (CK_ULONG *) PORT_Alloc(sizeof(CK_ULONG));
1508    if (intpointer == NULL) {
1509	return CKR_HOST_MEMORY;
1510    }
1511    *intpointer = mac_size;
1512    context->cipherInfo = (void *) intpointer;
1513    context->destroy = (SFTKDestroy) sftk_Space;
1514    context->update = (SFTKCipher) sftk_HMACCopy;
1515    context->verify = (SFTKVerify) sftk_HMACCmp;
1516    context->maxLen = hashObj->length;
1517    HMAC_Begin(HMACcontext);
1518    return CKR_OK;
1519}
1520
1521/*
1522 *  SSL Macing support. SSL Macs are inited, then update with the base
1523 * hashing algorithm, then finalized in sign and verify
1524 */
1525
1526/*
1527 * FROM SSL:
1528 * 60 bytes is 3 times the maximum length MAC size that is supported.
1529 * We probably should have one copy of this table. We still need this table
1530 * in ssl to 'sign' the handshake hashes.
1531 */
1532static unsigned char ssl_pad_1 [60] = {
1533    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1534    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1535    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1536    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1537    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1538    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1539    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
1540    0x36, 0x36, 0x36, 0x36
1541};
1542static unsigned char ssl_pad_2 [60] = {
1543    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1544    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1545    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1546    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1547    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1548    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1549    0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
1550    0x5c, 0x5c, 0x5c, 0x5c
1551};
1552
1553static SECStatus
1554sftk_SSLMACSign(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int *sigLen,
1555		unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1556{
1557    unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
1558    unsigned int out;
1559
1560    info->begin(info->hashContext);
1561    info->update(info->hashContext,info->key,info->keySize);
1562    info->update(info->hashContext,ssl_pad_2,info->padSize);
1563    info->update(info->hashContext,hash,hashLen);
1564    info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
1565    PORT_Memcpy(sig,tmpBuf,info->macSize);
1566    *sigLen = info->macSize;
1567    return SECSuccess;
1568}
1569
1570static SECStatus
1571sftk_SSLMACVerify(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int sigLen,
1572		unsigned char *hash, unsigned int hashLen)
1573{
1574    unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
1575    unsigned int out;
1576
1577    info->begin(info->hashContext);
1578    info->update(info->hashContext,info->key,info->keySize);
1579    info->update(info->hashContext,ssl_pad_2,info->padSize);
1580    info->update(info->hashContext,hash,hashLen);
1581    info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
1582    return (PORT_Memcmp(sig,tmpBuf,info->macSize) == 0) ? 
1583						SECSuccess : SECFailure;
1584}
1585
1586/*
1587 * common HMAC initalization routine
1588 */
1589static CK_RV
1590sftk_doSSLMACInit(SFTKSessionContext *context,SECOidTag oid,
1591					SFTKObject *key, CK_ULONG mac_size)
1592{
1593    SFTKAttribute *keyval;
1594    SFTKBegin begin;
1595    int padSize;
1596    SFTKSSLMACInfo *sslmacinfo;
1597    CK_RV crv = CKR_MECHANISM_INVALID;
1598
1599    if (oid == SEC_OID_SHA1) {
1600	crv = sftk_doSubSHA1(context);
1601	if (crv != CKR_OK) return crv;
1602	begin = (SFTKBegin) SHA1_Begin;
1603	padSize = 40;
1604    } else {
1605	crv = sftk_doSubMD5(context);
1606	if (crv != CKR_OK) return crv;
1607	begin = (SFTKBegin) MD5_Begin;
1608	padSize = 48;
1609    }
1610    context->multi = PR_TRUE;
1611
1612    keyval = sftk_FindAttribute(key,CKA_VALUE);
1613    if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
1614
1615    context->hashUpdate(context->hashInfo,keyval->attrib.pValue,
1616						 keyval->attrib.ulValueLen);
1617    context->hashUpdate(context->hashInfo,ssl_pad_1,padSize);
1618    sslmacinfo = (SFTKSSLMACInfo *) PORT_Alloc(sizeof(SFTKSSLMACInfo));
1619    if (sslmacinfo == NULL) {
1620        sftk_FreeAttribute(keyval);
1621	return CKR_HOST_MEMORY;
1622    }
1623    sslmacinfo->macSize = mac_size;
1624    sslmacinfo->hashContext = context->hashInfo;
1625    PORT_Memcpy(sslmacinfo->key,keyval->attrib.pValue,
1626					keyval->attrib.ulValueLen);
1627    sslmacinfo->keySize = keyval->attrib.ulValueLen;
1628    sslmacinfo->begin = begin;
1629    sslmacinfo->end = context->end;
1630    sslmacinfo->update = context->hashUpdate;
1631    sslmacinfo->padSize = padSize;
1632    sftk_FreeAttribute(keyval);
1633    context->cipherInfo = (void *) sslmacinfo;
1634    context->destroy = (SFTKDestroy) sftk_Space;
1635    context->update = (SFTKCipher) sftk_SSLMACSign;
1636    context->verify = (SFTKVerify) sftk_SSLMACVerify;
1637    context->maxLen = mac_size;
1638    return CKR_OK;
1639}
1640
1641/*
1642 ************** Crypto Functions:     Sign  ************************
1643 */
1644
1645/** 
1646 * Check if We're using CBCMacing and initialize the session context if we are.
1647 *  @param contextType SFTK_SIGN or SFTK_VERIFY
1648 *  @param keyUsage    check whether key allows this usage
1649 */
1650static CK_RV
1651sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1652 	CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE keyUsage,
1653						 SFTKContextType contextType)
1654	
1655{
1656    CK_MECHANISM cbc_mechanism;
1657    CK_ULONG mac_bytes = SFTK_INVALID_MAC_SIZE;
1658    CK_RC2_CBC_PARAMS rc2_params;
1659#if NSS_SOFTOKEN_DOES_RC5
1660    CK_RC5_CBC_PARAMS rc5_params;
1661    CK_RC5_MAC_GENERAL_PARAMS *rc5_mac;
1662#endif
1663    unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE];
1664    SFTKSessionContext *context;
1665    CK_RV crv;
1666    unsigned int blockSize;
1667
1668    switch (pMechanism->mechanism) {
1669    case CKM_RC2_MAC_GENERAL:
1670	mac_bytes = 
1671	    ((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
1672	/* fall through */
1673    case CKM_RC2_MAC:
1674	/* this works because ulEffectiveBits is in the same place in both the
1675	 * CK_RC2_MAC_GENERAL_PARAMS and CK_RC2_CBC_PARAMS */
1676	rc2_params.ulEffectiveBits = ((CK_RC2_MAC_GENERAL_PARAMS *)
1677				pMechanism->pParameter)->ulEffectiveBits;
1678	PORT_Memset(rc2_params.iv,0,sizeof(rc2_params.iv));
1679	cbc_mechanism.mechanism = CKM_RC2_CBC;
1680	cbc_mechanism.pParameter = &rc2_params;
1681	cbc_mechanism.ulParameterLen = sizeof(rc2_params);
1682	blockSize = 8;
1683	break;
1684#if NSS_SOFTOKEN_DOES_RC5
1685    case CKM_RC5_MAC_GENERAL:
1686	mac_bytes = 
1687	    ((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
1688	/* fall through */
1689    case CKM_RC5_MAC:
1690	/* this works because ulEffectiveBits is in the same place in both the
1691	 * CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */
1692	rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
1693	rc5_params.ulWordsize = rc5_mac->ulWordsize;
1694	rc5_params.ulRounds = rc5_mac->ulRounds;
1695	rc5_params.pIv = ivBlock;
1696	if( (blockSize = rc5_mac->ulWordsize*2) > SFTK_MAX_BLOCK_SIZE )
1697            return CKR_MECHANISM_PARAM_INVALID;
1698	rc5_params.ulIvLen = blockSize;
1699	PORT_Memset(ivBlock,0,blockSize);
1700	cbc_mechanism.mechanism = CKM_RC5_CBC;
1701	cbc_mechanism.pParameter = &rc5_params;
1702	cbc_mechanism.ulParameterLen = sizeof(rc5_params);
1703	break;
1704#endif
1705    /* add cast and idea later */
1706    case CKM_DES_MAC_GENERAL:
1707	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1708	/* fall through */
1709    case CKM_DES_MAC:
1710	blockSize = 8;
1711	PORT_Memset(ivBlock,0,blockSize);
1712	cbc_mechanism.mechanism = CKM_DES_CBC;
1713	cbc_mechanism.pParameter = &ivBlock;
1714	cbc_mechanism.ulParameterLen = blockSize;
1715	break;
1716    case CKM_DES3_MAC_GENERAL:
1717	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1718	/* fall through */
1719    case CKM_DES3_MAC:
1720	blockSize = 8;
1721	PORT_Memset(ivBlock,0,blockSize);
1722	cbc_mechanism.mechanism = CKM_DES3_CBC;
1723	cbc_mechanism.pParameter = &ivBlock;
1724	cbc_mechanism.ulParameterLen = blockSize;
1725	break;
1726    case CKM_CDMF_MAC_GENERAL:
1727	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1728	/* fall through */
1729    case CKM_CDMF_MAC:
1730	blockSize = 8;
1731	PORT_Memset(ivBlock,0,blockSize);
1732	cbc_mechanism.mechanism = CKM_CDMF_CBC;
1733	cbc_mechanism.pParameter = &ivBlock;
1734	cbc_mechanism.ulParameterLen = blockSize;
1735	break;
1736    case CKM_SEED_MAC_GENERAL:
1737	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1738	/* fall through */
1739    case CKM_SEED_MAC:
1740	blockSize = 16;
1741	PORT_Memset(ivBlock,0,blockSize);
1742	cbc_mechanism.mechanism = CKM_SEED_CBC;
1743	cbc_mechanism.pParameter = &ivBlock;
1744	cbc_mechanism.ulParameterLen = blockSize;
1745	break;
1746    case CKM_CAMELLIA_MAC_GENERAL:
1747	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1748	/* fall through */
1749    case CKM_CAMELLIA_MAC:
1750	blockSize = 16;
1751	PORT_Memset(ivBlock,0,blockSize);
1752	cbc_mechanism.mechanism = CKM_CAMELLIA_CBC;
1753	cbc_mechanism.pParameter = &ivBlock;
1754	cbc_mechanism.ulParameterLen = blockSize;
1755	break;
1756    case CKM_AES_MAC_GENERAL:
1757	mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
1758	/* fall through */
1759    case CKM_AES_MAC:
1760	blockSize = 16;
1761	PORT_Memset(ivBlock,0,blockSize);
1762	cbc_mechanism.mechanism = CKM_AES_CBC;
1763	cbc_mechanism.pParameter = &ivBlock;
1764	cbc_mechanism.ulParameterLen = blockSize;
1765	break;
1766    default:
1767	return CKR_FUNCTION_NOT_SUPPORTED;
1768    }
1769
1770    /* if MAC size is externally supplied, it should be checked.
1771     */
1772    if (mac_bytes == SFTK_INVALID_MAC_SIZE)
1773        mac_bytes = blockSize >> 1;
1774    else {
1775        if( mac_bytes > blockSize )
1776            return CKR_MECHANISM_PARAM_INVALID;
1777    }
1778
1779    crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey,
1780            CKA_ENCRYPT, /* CBC mech is able to ENCRYPT, not SIGN/VERIFY */
1781            keyUsage, contextType, PR_TRUE );
1782    if (crv != CKR_OK) return crv;
1783    crv = sftk_GetContext(hSession,&context,contextType,PR_TRUE,NULL);
1784
1785    /* this shouldn't happen! */
1786    PORT_Assert(crv == CKR_OK);
1787    if (crv != CKR_OK) return crv;
1788    context->blockSize = blockSize;
1789    context->macSize = mac_bytes;
1790    return CKR_OK;
1791}
1792
1793/*
1794 * encode RSA PKCS #1 Signature data before signing... 
1795 */
1796static SECStatus
1797sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen,
1798		unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1799{
1800    return RSA_HashSign(info->hashOid,info->key,sig,sigLen,maxLen,
1801							hash,hashLen);
1802}
1803
1804/* XXX Old template; want to expunge it eventually. */
1805static DERTemplate SECAlgorithmIDTemplate[] = {
1806    { DER_SEQUENCE,
1807	  0, NULL, sizeof(SECAlgorithmID) },
1808    { DER_OBJECT_ID,
1809	  offsetof(SECAlgorithmID,algorithm), },
1810    { DER_OPTIONAL | DER_ANY,
1811	  offsetof(SECAlgorithmID,parameters), },
1812    { 0, }
1813};
1814
1815/*
1816 * XXX OLD Template.  Once all uses have been switched over to new one,
1817 * remove this.
1818 */
1819static DERTemplate SGNDigestInfoTemplate[] = {
1820    { DER_SEQUENCE,
1821	  0, NULL, sizeof(SGNDigestInfo) },
1822    { DER_INLINE,
1823	  offsetof(SGNDigestInfo,digestAlgorithm),
1824	  SECAlgorithmIDTemplate, },
1825    { DER_OCTET_STRING,
1826	  offsetof(SGNDigestInfo,digest), },
1827    { 0, }
1828};
1829
1830SECStatus
1831RSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
1832		unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
1833		unsigned char *hash, unsigned int hashLen)
1834{
1835    
1836    SECStatus rv = SECFailure;
1837    SECItem digder;
1838    PLArenaPool *arena = NULL;
1839    SGNDigestInfo *di = NULL;
1840
1841    digder.data = NULL;
1842
1843    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1844    if ( !arena ) { goto loser; }
1845    
1846    /* Construct digest info */
1847    di = SGN_CreateDigestInfo(hashOid, hash, hashLen);
1848    if (!di) { goto loser; }
1849
1850    /* Der encode the digest as a DigestInfo */
1851    rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
1852    if (rv != SECSuccess) {
1853	goto loser;
1854    }
1855
1856    /*
1857    ** Encrypt signature after constructing appropriate PKCS#1 signature
1858    ** block
1859    */
1860    rv = RSA_Sign(key,sig,sigLen,maxLen,digder.data,digder.len);
1861
1862  loser:
1863    SGN_DestroyDigestInfo(di);
1864    if (arena != NULL) {
1865	PORT_FreeArena(arena, PR_FALSE);
1866    }
1867    return rv;
1868}
1869
1870static SECStatus
1871sftk_SignPSS(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen,
1872		unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
1873{
1874    return RSA_SignPSS(info->params,info->key,sig,sigLen,maxLen,
1875							hash,hashLen);
1876}
1877
1878static SECStatus
1879nsc_DSA_Verify_Stub(void *ctx, void *sigBuf, unsigned int sigLen,
1880                               void *dataBuf, unsigned int dataLen)
1881{
1882    SECItem signature, digest;
1883    NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
1884
1885    signature.data = (unsigned char *)sigBuf;
1886    signature.len = sigLen;
1887    digest.data = (unsigned char *)dataBuf;
1888    digest.len = dataLen;
1889    return DSA_VerifyDigest(&(key->u.dsa), &signature, &digest);
1890}
1891
1892static SECStatus
1893nsc_DSA_Sign_Stub(void *ctx, void *sigBuf,
1894                  unsigned int *sigLen, unsigned int maxSigLen,
1895                  void *dataBuf, unsigned int dataLen)
1896{
1897    SECItem signature, digest;
1898    SECStatus rv;
1899    NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
1900
1901    signature.data = (unsigned char *)sigBuf;
1902    signature.len = maxSigLen;
1903    digest.data = (unsigned char *)dataBuf;
1904    digest.len = dataLen;
1905    rv = DSA_SignDigest(&(key->u.dsa), &signature, &digest);
1906    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
1907	sftk_fatalError = PR_TRUE;
1908    }
1909    *sigLen = signature.len;
1910    return rv;
1911}
1912
1913#ifdef NSS_ENABLE_ECC
1914static SECStatus
1915nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen,
1916                    void *dataBuf, unsigned int dataLen)
1917{
1918    SECItem signature, digest;
1919    NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
1920
1921    signature.data = (unsigned char *)sigBuf;
1922    signature.len = sigLen;
1923    digest.data = (unsigned char *)dataBuf;
1924    digest.len = dataLen;
1925    return ECDSA_VerifyDigest(&(key->u.ec), &signature, &digest);
1926}
1927
1928static SECStatus
1929nsc_ECDSASignStub(void *ctx, void *sigBuf,
1930                  unsigned int *sigLen, unsigned int maxSigLen,
1931                  void *dataBuf, unsigned int dataLen)
1932{
1933    SECItem signature, digest;
1934    SECStatus rv;
1935    NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
1936
1937    signature.data = (unsigned char *)sigBuf;
1938    signature.len = maxSigLen;
1939    digest.data = (unsigned char *)dataBuf;
1940    digest.len = dataLen;
1941    rv = ECDSA_SignDigest(&(key->u.ec), &signature, &digest);
1942    if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
1943	sftk_fatalError = PR_TRUE;
1944    }
1945    *sigLen = signature.len;
1946    return rv;
1947}
1948#endif /* NSS_ENABLE_ECC */
1949
1950/* NSC_SignInit setups up the signing operations. There are three basic
1951 * types of signing:
1952 *	(1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied
1953 *  to data in a single Sign operation (which often looks a lot like an
1954 *  encrypt, with data coming in and data going out).
1955 *	(2) Hash based signing, where we continually hash the data, then apply
1956 *  some sort of signature to the end.
1957 *	(3) Block Encryption CBC MAC's, where the Data is encrypted with a key,
1958 *  and only the final block is part of the mac.
1959 *
1960 *  For case number 3, we initialize a context much like the Encryption Context
1961 *  (in fact we share code). We detect case 3 in C_SignUpdate, C_Sign, and 
1962 *  C_Final by the following method... if it's not multi-part, and it's doesn't
1963 *  have a hash context, it must be a block Encryption CBC MAC.
1964 *
1965 *  For case number 2, we initialize a hash structure, as well as make it 
1966 *  multi-part. Updates are simple calls to the hash update function. Final
1967 *  calls the hashend, then passes the result to the 'update' function (which
1968 *  operates as a final signature function). In some hash based MAC'ing (as
1969 *  opposed to hash base signatures), the update function is can be simply a 
1970 *  copy (as is the case with HMAC).
1971 */
1972CK_RV NSC_SignInit(CK_SESSION_HANDLE hSession,
1973		 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
1974{
1975    SFTKSession *session;
1976    SFTKObject *key;
1977    SFTKSessionContext *context;
1978    CK_KEY_TYPE key_type;
1979    CK_RV crv = CKR_OK;
1980    NSSLOWKEYPrivateKey *privKey;
1981    SFTKHashSignInfo *info = NULL;
1982
1983    CHECK_FORK();
1984
1985    /* Block Cipher MACing Algorithms use a different Context init method..*/
1986    crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, SFTK_SIGN);
1987    if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
1988
1989    /* we're not using a block cipher mac */
1990    session = sftk_SessionFromHandle(hSession);
1991    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
1992    crv = sftk_InitGeneric(session,&context,SFTK_SIGN,&key,hKey,&key_type,
1993						CKO_PRIVATE_KEY,CKA_SIGN);
1994    if (crv != CKR_OK) {
1995	sftk_FreeSession(session);
1996	return crv;
1997    }
1998
1999    context->multi = PR_FALSE;
2000
2001#define INIT_RSA_SIGN_MECH(mmm) \
2002    case CKM_ ## mmm ## _RSA_PKCS: \
2003        context->multi = PR_TRUE; \
2004	crv = sftk_doSub ## mmm (context); \
2005	if (crv != CKR_OK) break; \
2006	context->update = (SFTKCipher) sftk_HashSign; \
2007	info = PORT_New(SFTKHashSignInfo); \
2008	if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
2009	info->hashOid = SEC_OID_ ## mmm ; \
2010	goto finish_rsa; 
2011
2012    switch(pMechanism->mechanism) {
2013    INIT_RSA_SIGN_MECH(MD5)
2014    INIT_RSA_SIGN_MECH(MD2)
2015    INIT_RSA_SIGN_MECH(SHA1)
2016    INIT_RSA_SIGN_MECH(SHA224)
2017    INIT_RSA_SIGN_MECH(SHA256)
2018    INIT_RSA_SIGN_MECH(SHA384)
2019    INIT_RSA_SIGN_MECH(SHA512)
2020
2021    case CKM_RSA_PKCS:
2022	context->update = (SFTKCipher) RSA_Sign;
2023	goto finish_rsa;
2024    case CKM_RSA_X_509:
2025	context->update = (SFTKCipher)  RSA_SignRaw;
2026finish_rsa:
2027	if (key_type != CKK_RSA) {
2028	    crv = CKR_KEY_TYPE_INCONSISTENT;
2029	    break;
2030	}
2031	privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
2032	if (privKey == NULL) {
2033	    crv = CKR_KEY_TYPE_INCONSISTENT;
2034	    break;
2035	}
2036	/* OK, info is allocated only if we're doing hash and sign mechanism.
2037	 * It's necessary to be able to set the correct OID in the final 
2038	 * signature.
2039	 */
2040	if (info) {
2041	    info->key = privKey;
2042	    context->cipherInfo = info;
2043	    context->destroy = (SFTKDestroy)sftk_Space;
2044	} else {
2045	    context->cipherInfo = privKey;
2046	    context->destroy = (SFTKDestroy)sftk_Null;
2047	}
2048	context->maxLen = nsslowkey_PrivateModulusLen(privKey);
2049	break;
2050    case CKM_RSA_PKCS_PSS:
2051	if (key_type != CKK_RSA) {
2052	    crv = CKR_KEY_TYPE_INCONSISTENT;
2053	    break;
2054	} 
2055	if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) {
2056	    crv = CKR_MECHANISM_PARAM_INVALID;
2057	    break;
2058	}
2059	info = PORT_New(SFTKHashSignInfo);
2060	if (info == NULL) {
2061	    crv = CKR_HOST_MEMORY;
2062	    break;
2063	}
2064	info->params = pMechanism->pParameter;
2065	info->key = sftk_GetPrivKey(key,CKK_RSA,&crv);
2066	if (info->key == NULL) {
2067	    PORT_Free(info);
2068	    break;
2069	}
2070	context->cipherInfo = info;
2071	context->destroy = (SFTKDestroy) sftk_Space;
2072	context->update = (SFTKCipher) sftk_SignPSS;
2073	context->maxLen = nsslowkey_PrivateModulusLen(info->key);
2074	break;	
2075
2076    case CKM_DSA_SHA1:
2077        context->multi = PR_TRUE;
2078	crv = sftk_doSubSHA1(context);
2079	if (crv != CKR_OK) break;
2080	/* fall through */
2081    case CKM_DSA:
2082	if (key_type != CKK_DSA) {
2083	    crv = CKR_KEY_TYPE_INCONSISTENT;
2084	    break;
2085	}
2086	privKey = sftk_GetPrivKey(key,CKK_DSA,&crv);
2087	if (privKey == NULL) {
2088	    break;
2089	}
2090	context->cipherInfo = privKey;
2091	context->update     = (SFTKCipher) nsc_DSA_Sign_Stub;
2092	context->destroy    = (privKey == key->objectInfo) ?
2093		(SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
2094	context->maxLen     = DSA_SIGNATURE_LEN;
2095
2096	break;
2097
2098#ifdef NSS_ENABLE_ECC
2099    case CKM_ECDSA_SHA1:
2100	context->multi = PR_TRUE;
2101	crv = sftk_doSubSHA1(context);
2102	if (crv != CKR_OK) break;
2103	/* fall through */
2104    case CKM_ECDSA:
2105	if (key_type != CKK_EC) {
2106	    crv = CKR_KEY_TYPE_INCONSISTENT;
2107	    break;
2108	}
2109	privKey = sftk_GetPrivKey(key,CKK_EC,&crv);
2110	if (privKey == NULL) {
2111	    crv = CKR_HOST_MEMORY;
2112	    break;
2113	}
2114	context->cipherInfo = privKey;
2115	context->update     = (SFTKCipher) nsc_ECDSASignStub;
2116	context->destroy    = (privKey == key->objectInfo) ?
2117		(SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
2118	context->maxLen     = MAX_ECKEY_LEN * 2;
2119
2120	break;
2121#endif /* NSS_ENABLE_ECC */
2122
2123#define INIT_HMAC_MECH(mmm) \
2124    case CKM_ ## mmm ## _HMAC_GENERAL: \
2125	crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, \
2126				*(CK_ULONG *)pMechanism->pParameter); \
2127	break; \
2128    case CKM_ ## mmm ## _HMAC: \
2129	crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, mmm ## _LENGTH); \
2130	break; 
2131
2132    INIT_HMAC_MECH(MD2)
2133    INIT_HMAC_MECH(MD5)
2134    INIT_HMAC_MECH(SHA224)
2135    INIT_HMAC_MECH(SHA256)
2136    INIT_HMAC_MECH(SHA384)
2137    INIT_HMAC_MECH(SHA512)
2138
2139    case CKM_SHA_1_HMAC_GENERAL:
2140	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
2141				*(CK_ULONG *)pMechanism->pParameter);
2142	break;
2143    case CKM_SHA_1_HMAC:
2144	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
2145	break;
2146
2147    case CKM_SSL3_MD5_MAC:
2148	crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
2149					*(CK_ULONG *)pMechanism->pParameter);
2150	break;
2151    case CKM_SSL3_SHA1_MAC:
2152	crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
2153					*(CK_ULONG *)pMechanism->pParameter);
2154	break;
2155    case CKM_TLS_PRF_GENERAL:
2156	crv = sftk_TLSPRFInit(context, key, key_type);
2157	break;
2158    default:
2159	crv = CKR_MECHANISM_INVALID;
2160	break;
2161    }
2162
2163    if (crv != CKR_OK) {
2164	if (info) PORT_Free(info);
2165        sftk_FreeContext(context);
2166        sftk_FreeSession(session);
2167        return crv;
2168    }
2169    sftk_SetContextByType(session, SFTK_SIGN, context);
2170    sftk_FreeSession(session);
2171    return CKR_OK;
2172}
2173
2174/** MAC one block of data by block cipher
2175 */
2176static CK_RV
2177sftk_MACBlock( SFTKSessionContext *ctx, void *blk )
2178{
2179    unsigned int outlen;
2180    return ( SECSuccess == (ctx->update)( ctx->cipherInfo, ctx->macBuf, &outlen,
2181                SFTK_MAX_BLOCK_SIZE, blk, ctx->blockSize ))
2182            ? CKR_OK : sftk_MapCryptError(PORT_GetError());
2183}
2184
2185/** MAC last (incomplete) block of data by block cipher
2186 *
2187 *  Call once, then terminate MACing operation.
2188 */
2189static CK_RV
2190sftk_MACFinal( SFTKSessionContext *ctx )
2191{
2192    unsigned int padLen = ctx->padDataLength;
2193    /* pad and proceed the residual */
2194    if( padLen ) {
2195        /* shd clr ctx->padLen to make sftk_MACFinal idempotent */
2196        PORT_Memset( ctx->padBuf + padLen, 0, ctx->blockSize - padLen );
2197        return sftk_MACBlock( ctx, ctx->padBuf );
2198    } else
2199        return CKR_OK;
2200}
2201
2202/** The common implementation for {Sign,Verify}Update. (S/V only vary in their
2203 * setup and final operations).
2204 * 
2205 * A call which results in an error terminates the operation [PKCS#11,v2.11]
2206 */
2207static CK_RV
2208sftk_MACUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
2209    					CK_ULONG ulPartLen,SFTKContextType type)
2210{
2211    SFTKSession *session;
2212    SFTKSessionContext *context;
2213    CK_RV crv;
2214
2215    /* make sure we're legal */
2216    crv = sftk_GetContext(hSession,&context,type, PR_TRUE, &session );
2217    if (crv != CKR_OK) return crv;
2218
2219    if (context->hashInfo) {
2220	(*context->hashUpdate)(context->hashInfo, pPart, ulPartLen);
2221    } else {   
2222    	/* must be block cipher MACing */
2223
2224        unsigned int  blkSize   = context->blockSize;
2225        unsigned char *residual = /* free room in context->padBuf */
2226                                context->padBuf + context->padDataLength;
2227        unsigned int  minInput  = /* min input for MACing at least one block */
2228                                blkSize - context->padDataLength;
2229
2230        /* not enough data even for one block */
2231        if( ulPartLen < minInput ) {
2232            PORT_Memcpy( residual, pPart, ulPartLen );
2233            context->padDataLength += ulPartLen;
2234            goto cleanup;
2235        }
2236        /* MACing residual */
2237        if( context->padDataLength ) {
2238            PORT_Memcpy( residual, pPart, minInput );
2239            ulPartLen -= minInput;
2240            pPart     += minInput;
2241            if( CKR_OK != (crv = sftk_MACBlock( context, context->padBuf )) )
2242                goto terminate;
2243        }
2244        /* MACing full blocks */
2245        while( ulPartLen >= blkSize )
2246        {
2247            if( CKR_OK != (crv = sftk_MACBlock( context, pPart )) )
2248                goto terminate;
2249            ulPartLen -= blkSize;
2250            pPart     += blkSize;
2251        }
2252        /* save the residual */
2253        if( (context->padDataLength = ulPartLen) )
2254            PORT_Memcpy( context->padBuf, pPart, ulPartLen );
2255    } /* blk cipher MACing */
2256
2257    goto  cleanup;
2258
2259terminate:
2260    sftk_TerminateOp( session, type, context );
2261cleanup:
2262    sftk_FreeSession(session);
2263    return crv;
2264}
2265
2266/* NSC_SignUpdate continues a multiple-part signature operation,
2267 * where the signature is (will be) an appendix to the data, 
2268 * and plaintext cannot be recovered from the signature 
2269 *
2270 * A call which results in an error terminates the operation [PKCS#11,v2.11]
2271 */
2272CK_RV NSC_SignUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
2273    							CK_ULONG ulPartLen)
2274{
2275    CHECK_FORK();
2276    return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_SIGN);
2277}
2278
2279
2280/* NSC_SignFinal finishes a multiple-part signature operation, 
2281 * returning the signature. */
2282CK_RV NSC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature,
2283					    CK_ULONG_PTR pulSignatureLen)
2284{
2285    SFTKSession *session;
2286    SFTKSessionContext *context;
2287    unsigned int outlen;
2288    unsigned int maxoutlen = *pulSignatureLen;
2289    CK_RV crv;
2290
2291    CHECK_FORK();
2292
2293    /* make sure we're legal */
2294    crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_TRUE,&session);
2295    if (crv != CKR_OK) return crv;
2296
2297    if (context->hashInfo) {
2298        unsigned int digestLen;
2299        unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
2300
2301        if( !pSignature ) {
2302            outlen = context->maxLen; goto finish;
2303        }
2304        (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
2305        if( SECSuccess != (context->update)(context->cipherInfo, pSignature,
2306                    &outlen, maxoutlen, tmpbuf, digestLen))
2307            crv = sftk_MapCryptError(PORT_GetError());
2308        /* CKR_BUFFER_TOO_SMALL here isn't continuable, let operation terminate.
2309         * Keeping "too small" CK_RV intact is a standard violation, but allows
2310         * application read EXACT signature length */
2311    } else {
2312        /* must be block cipher MACing */
2313        outlen = context->macSize;
2314        /* null or "too small" buf doesn't terminate operation [PKCS#11,v2.11]*/
2315        if( !pSignature  ||  maxoutlen < outlen ) {
2316            if( pSignature ) crv = CKR_BUFFER_TOO_SMALL;
2317            goto finish;
2318        }
2319        if( CKR_OK == (crv = sftk_MACFinal( context )) )
2320	    PORT_Memcpy(pSignature, context->macBuf, outlen );
2321    }
2322
2323    sftk_TerminateOp( session, SFTK_SIGN, context );
2324finish:
2325    *pulSignatureLen = outlen;
2326    sftk_FreeSession(session);
2327    return crv;
2328}
2329
2330/* NSC_Sign signs (encrypts with private key) data in a single part,
2331 * where the signature is (will be) an appendix to the data, 
2332 * and plaintext cannot be recovered from the signature */
2333CK_RV NSC_Sign(CK_SESSION_HANDLE hSession,
2334    CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,
2335    					CK_ULONG_PTR pulSignatureLen)
2336{
2337    SFTKSession *session;
2338    SFTKSessionContext *context;
2339    CK_RV crv;
2340
2341    CHECK_FORK();
2342
2343    /* make sure we're legal */
2344    crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_FALSE,&session);
2345    if (crv != CKR_OK) return crv;
2346
2347    if (!pSignature) {
2348        /* see also how C_SignUpdate implements this */
2349	*pulSignatureLen = (!context->multi || context->hashInfo)
2350            ? context->maxLen
2351            : context->macSize; /* must be block cipher MACing */
2352	goto finish;
2353    }
2354
2355    /* multi part Signing are completely implemented by SignUpdate and
2356     * sign Final */
2357    if (context->multi) {
2358        /* SignFinal can't follow failed SignUpdate */
2359	if( CKR_OK == (crv = NSC_SignUpdate(hSession,pData,ulDataLen) ))
2360            crv = NSC_SignFinal(hSession, pSignature, pulSignatureLen);
2361    } else {   
2362    	/* single-part PKC signature (e.g. CKM_ECDSA) */
2363        unsigned int outlen;
2364        unsigned int maxoutlen = *pulSignatureLen;
2365        if( SECSuccess != (*context->update)(context->cipherInfo, pSignature,
2366                    &outlen, maxoutlen, pData, ulDataLen))
2367            crv = sftk_MapCryptError(PORT_GetError());
2368        *pulSignatureLen = (CK_ULONG) outlen;
2369        /*  "too small" here is certainly continuable */
2370        if( crv != CKR_BUFFER_TOO_SMALL )
2371            sftk_TerminateOp(session, SFTK_SIGN, context);
2372    } /* single-part */
2373
2374finish:
2375    sftk_FreeSession(session);
2376    return crv;
2377}
2378
2379
2380/*
2381 ************** Crypto Functions:     Sign Recover  ************************
2382 */
2383/* NSC_SignRecoverInit initializes a signature operation,
2384 * where the (digest) data can be recovered from the signature. 
2385 * E.g. encryption with the user's private key */
2386CK_RV NSC_SignRecoverInit(CK_SESSION_HANDLE hSession,
2387			 CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
2388{
2389    CHECK_FORK();
2390
2391    switch (pMechanism->mechanism) {
2392    case CKM_RSA_PKCS:
2393    case CKM_RSA_X_509:
2394	return NSC_SignInit(hSession,pMechanism,hKey);
2395    default:
2396	break;
2397    }
2398    return CKR_MECHANISM_INVALID;
2399}
2400
2401
2402/* NSC_SignRecover signs data in a single operation
2403 * where the (digest) data can be recovered from the signature. 
2404 * E.g. encryption with the user's private key */
2405CK_RV NSC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
2406  CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
2407{
2408    CHECK_FORK();
2409
2410    return NSC_Sign(hSession,pData,ulDataLen,pSignature,pulSignatureLen);
2411}
2412
2413/*
2414 ************** Crypto Functions:     verify  ************************
2415 */
2416
2417/* Handle RSA Signature formatting */
2418static SECStatus
2419sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, 
2420	unsigned int sigLen, unsigned char *digest, unsigned int digestLen)
2421{
2422    return RSA_HashCheckSign(info->hashOid, info->key, sig, sigLen,
2423						digest, digestLen);
2424}
2425
2426SECStatus
2427RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
2428	unsigned char *sig, unsigned int sigLen,
2429	unsigned char *digest, unsigned int digestLen)
2430{
2431
2432    SECItem it;
2433    SGNDigestInfo *di = NULL;
2434    SECStatus rv = SECSuccess;
2435    
2436    it.data = NULL;
2437
2438    if (key == NULL) goto loser;
2439
2440    it.len = nsslowkey_PublicModulusLen(key); 
2441    if (!it.len) goto loser;
2442
2443    it.data = (unsigned char *) PORT_Alloc(it.len);
2444    if (it.data == NULL) goto loser;
2445
2446    /* decrypt the block */
2447    rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen);
2448    if (rv != SECSuccess) goto loser;
2449
2450    di = SGN_DecodeDigestInfo(&it);
2451    if (di == NULL) goto loser;
2452    if (di->digest.len != digestLen)  goto loser; 
2453
2454    /* make sure the tag is OK */
2455    if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) {
2456	goto loser;
2457    }
2458    /* make sure the "parameters" are not too bogus. */
2459    if (di->digestAlgorithm.parameters.len > 2) {
2460	goto loser;
2461    }
2462    /* Now check the signature */
2463    if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) {
2464	goto done;
2465    }
2466
2467  loser:
2468    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
2469    rv = SECFailure;
2470
2471  done:
2472    if (it.data != NULL) PORT_Free(it.data);
2473    if (di != NULL) SGN_DestroyDigestInfo(di);
2474    
2475    return rv;
2476}
2477
2478static SECStatus
2479sftk_CheckSignPSS(SFTKHashVerifyInfo *info, unsigned char *sig,
2480	unsigned int sigLen, unsigned char *digest, unsigned int digestLen)
2481{
2482    return RSA_CheckSignPSS(info->params, info->key, sig, sigLen,
2483						digest, digestLen);
2484}
2485
2486/* NSC_VerifyInit initializes a verification operation, 
2487 * where the signature is an appendix to the data, 
2488 * and plaintext cannot be recovered from the signature (e.g. DSA) */
2489CK_RV NSC_VerifyInit(CK_SESSION_HANDLE hSession,
2490			   CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) 
2491{
2492    SFTKSession *session;
2493    SFTKObject *key;
2494    SFTKSessionContext *context;
2495    CK_KEY_TYPE key_type;
2496    CK_RV crv = CKR_OK;
2497    NSSLOWKEYPublicKey *pubKey;
2498    SFTKHashVerifyInfo *info = NULL;
2499
2500    CHECK_FORK();
2501
2502    /* Block Cipher MACing Algorithms use a different Context init method..*/
2503    crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_VERIFY, SFTK_VERIFY);
2504    if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
2505
2506    session = sftk_SessionFromHandle(hSession);
2507    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
2508    crv = sftk_InitGeneric(session,&context,SFTK_VERIFY,&key,hKey,&key_type,
2509						CKO_PUBLIC_KEY,CKA_VERIFY);
2510    if (crv != CKR_OK) {
2511	sftk_FreeSession(session);
2512	return crv;
2513    }
2514
2515    context->multi = PR_FALSE;
2516
2517#define INIT_RSA_VFY_MECH(mmm) \
2518    case CKM_ ## mmm ## _RSA_PKCS: \
2519        context->multi = PR_TRUE; \
2520	crv = sftk_doSub ## mmm (context); \
2521	if (crv != CKR_OK) break; \
2522	context->verify = (SFTKVerify) sftk_hashCheckSign; \
2523	info = PORT_New(SFTKHashVerifyInfo); \
2524	if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
2525	info->hashOid = SEC_OID_ ## mmm ; \
2526	goto finish_rsa; 
2527
2528    switch(pMechanism->mechanism) {
2529    INIT_RSA_VFY_MECH(MD5) 
2530    INIT_RSA_VFY_MECH(MD2) 
2531    INIT_RSA_VFY_MECH(SHA1) 
2532    INIT_RSA_VFY_MECH(SHA224)
2533    INIT_RSA_VFY_MECH(SHA256) 
2534    INIT_RSA_VFY_MECH(SHA384) 
2535    INIT_RSA_VFY_MECH(SHA512) 
2536
2537    case CKM_RSA_PKCS:
2538	context->verify = (SFTKVerify) RSA_CheckSign;
2539	goto finish_rsa;
2540    case CKM_RSA_X_509:
2541	context->verify = (SFTKVerify) RSA_CheckSignRaw;
2542finish_rsa:
2543	if (key_type != CKK_RSA) {
2544	    if (info) PORT_Free(info);
2545	    crv = CKR_KEY_TYPE_INCONSISTENT;
2546	    break;
2547	}
2548	pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
2549	if (pubKey == NULL) {
2550	    if (info) PORT_Free(info);
2551	    crv = CKR_KEY_TYPE_INCONSISTENT;
2552	    break;
2553	}
2554	if (info) {
2555	    info->key = pubKey;
2556	    context->cipherInfo = info;
2557	    context->destroy = sftk_Space;
2558	} else {
2559	    context->cipherInfo = pubKey;
2560	    context->destroy = sftk_Null;
2561	}
2562	break;
2563    case CKM_RSA_PKCS_PSS:
2564	if (key_type != CKK_RSA) {
2565	    crv = CKR_KEY_TYPE_INCONSISTENT;
2566	    break;
2567	} 
2568	if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) {
2569	    crv = CKR_MECHANISM_PARAM_INVALID;
2570	    break;
2571	}
2572	info = PORT_New(SFTKHashVerifyInfo);
2573	if (info == NULL) {
2574	    crv = CKR_HOST_MEMORY;
2575	    break;
2576	}
2577	info->params = pMechanism->pParameter;
2578	info->key = sftk_GetPubKey(key,CKK_RSA,&crv);
2579	if (info->key == NULL) {
2580	    PORT_Free(info);
2581	    break;
2582	}
2583	context->cipherInfo = info;
2584	context->destroy = (SFTKDestroy) sftk_Space;
2585	context->verify = (SFTKVerify) sftk_CheckSignPSS;
2586	break;
2587    case CKM_DSA_SHA1:
2588        context->multi = PR_TRUE;
2589	crv = sftk_doSubSHA1(context);
2590	if (crv != CKR_OK) break;
2591	/* fall through */
2592    case CKM_DSA:
2593	if (key_type != CKK_DSA) {
2594	    crv = CKR_KEY_TYPE_INCONSISTENT;
2595	    break;
2596	}
2597	pubKey = sftk_GetPubKey(key,CKK_DSA,&crv);
2598	if (pubKey == NULL) {
2599	    break;
2600	}
2601	context->cipherInfo = pubKey;
2602	context->verify     = (SFTKVerify) nsc_DSA_Verify_Stub;
2603	context->destroy    = sftk_Null;
2604	break;
2605#ifdef NSS_ENABLE_ECC
2606    case CKM_ECDSA_SHA1:
2607	context->multi = PR_TRUE;
2608	crv = sftk_doSubSHA1(context);
2609	if (crv != CKR_OK) break;
2610	/* fall through */
2611    case CKM_ECDSA:
2612	if (key_type != CKK_EC) {
2613	    crv = CKR_KEY_TYPE_INCONSISTENT;
2614	    break;
2615	}
2616	pubKey = sftk_GetPubKey(key,CKK_EC,&crv);
2617	if (pubKey == NULL) {
2618	    crv = CKR_HOST_MEMORY;
2619	    break;
2620	}
2621	context->cipherInfo = pubKey;
2622	context->verify     = (SFTKVerify) nsc_ECDSAVerifyStub;
2623	context->destroy    = sftk_Null;
2624	break;
2625#endif /* NSS_ENABLE_ECC */
2626
2627    INIT_HMAC_MECH(MD2)
2628    INIT_HMAC_MECH(MD5)
2629    INIT_HMAC_MECH(SHA224)
2630    INIT_HMAC_MECH(SHA256)
2631    INIT_HMAC_MECH(SHA384)
2632    INIT_HMAC_MECH(SHA512)
2633
2634    case CKM_SHA_1_HMAC_GENERAL:
2635	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
2636				*(CK_ULONG *)pMechanism->pParameter);
2637	break;
2638    case CKM_SHA_1_HMAC:
2639	crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
2640	break;
2641
2642    case CKM_SSL3_MD5_MAC:
2643	crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
2644					*(CK_ULONG *)pMechanism->pParameter);
2645	break;
2646    case CKM_SSL3_SHA1_MAC:
2647	crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
2648					*(CK_ULONG *)pMechanism->pParameter);
2649	break;
2650    case CKM_TLS_PRF_GENERAL:
2651	crv = sftk_TLSPRFInit(context, key, key_type);
2652	break;
2653
2654    default:
2655	crv = CKR_MECHANISM_INVALID;
2656	break;
2657    }
2658
2659    if (crv != CKR_OK) {
2660	if (info) PORT_Free(info);
2661        sftk_FreeContext(context);
2662	sftk_FreeSession(session);
2663	return crv;
2664    }
2665    sftk_SetContextByType(session, SFTK_VERIFY, context);
2666    sftk_FreeSession(session);
2667    return CKR_OK;
2668}
2669
2670/* NSC_Verify verifies a signature in a single-part operation, 
2671 * where the signature is an appendix to the data, 
2672 * and plaintext cannot be recovered from the signature */
2673CK_RV NSC_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
2674    CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
2675{
2676    SFTKSession *session;
2677    SFTKSessionContext *context;
2678    CK_RV crv;
2679
2680    CHECK_FORK();
2681
2682    /* make sure we're legal */
2683    crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_FALSE,&session);
2684    if (crv != CKR_OK) return crv;
2685
2686    /* multi part Verifying are completely implemented by VerifyUpdate and
2687     * VerifyFinal */
2688    if (context->multi) {
2689        /* VerifyFinal can't follow failed VerifyUpdate */
2690	if( CKR_OK == (crv = NSC_VerifyUpdate(hSession, pData, ulDataLen)))
2691            crv = NSC_VerifyFinal(hSession, pSignature, ulSignatureLen);
2692    } else {
2693        if (SECSuccess != (*context->verify)(context->cipherInfo,pSignature,
2694                                             ulSignatureLen, pData, ulDataLen))
2695            crv = sftk_MapCryptError(PORT_GetError());
2696
2697        sftk_TerminateOp( session, SFTK_VERIFY, context );
2698    }
2699    sftk_FreeSession(session);
2700    return crv;
2701}
2702
2703
2704/* NSC_VerifyUpdate continues a multiple-part verification operation, 
2705 * where the signature is an appendix to the data, 
2706 * and plaintext cannot be recovered from the signature
2707 *
2708 * A call which results in an error terminates the operation [PKCS#11,v2.11]
2709 */
2710CK_RV NSC_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
2711						CK_ULONG ulPartLen)
2712{
2713    CHECK_FORK();
2714    return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_VERIFY);
2715}
2716
2717
2718/* NSC_VerifyFinal finishes a multiple-part verification operation, 
2719 * checking the signature. */
2720CK_RV NSC_VerifyFinal(CK_SESSION_HANDLE hSession,
2721			CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)
2722{
2723    SFTKSession *session;
2724    SFTKSessionContext *context;
2725    CK_RV crv;
2726
2727    CHECK_FORK();
2728
2729    if (!pSignature) 
2730    	return CKR_ARGUMENTS_BAD;
2731
2732    /* make sure we're legal */
2733    crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_TRUE,&session);
2734    if (crv != CKR_OK) 
2735    	return crv;
2736    
2737    if (context->hashInfo) {
2738        unsigned int digestLen;
2739        unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
2740        
2741        (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
2742        if( SECSuccess != (context->verify)(context->cipherInfo, pSignature,
2743                                            ulSignatureLen, tmpbuf, digestLen))
2744            crv = sftk_MapCryptError(PORT_GetError());
2745    } else if (ulSignatureLen != context->macSize) {
2746	/* must be block cipher MACing */
2747	crv = CKR_SIGNATURE_LEN_RANGE;
2748    } else if (CKR_OK == (crv = sftk_MACFinal(context))) {
2749	if (PORT_Memcmp(pSignature, context->macBuf, ulSignatureLen))
2750	    crv = CKR_SIGNATURE_INVALID;
2751    }
2752
2753    sftk_TerminateOp( session, SFTK_VERIFY, context );
2754    sftk_FreeSession(session);
2755    return crv;
2756
2757}
2758
2759/*
2760 ************** Crypto Functions:     Verify  Recover ************************
2761 */
2762
2763/* NSC_VerifyRecoverInit initializes a signature verification operation, 
2764 * where the data is recovered from the signature. 
2765 * E.g. Decryption with the user's public key */
2766CK_RV NSC_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
2767			CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
2768{
2769    SFTKSession *session;
2770    SFTKObject *key;
2771    SFTKSessionContext *context;
2772    CK_KEY_TYPE key_type;
2773    CK_RV crv = CKR_OK;
2774    NSSLOWKEYPublicKey *pubKey;
2775
2776    CHECK_FORK();
2777
2778    session = sftk_SessionFromHandle(hSession);
2779    if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
2780    crv = sftk_InitGeneric(session,&context,SFTK_VERIFY_RECOVER,
2781			&key,hKey,&key_type,CKO_PUBLIC_KEY,CKA_VERIFY_RECOVER);
2782    if (crv != CKR_OK) {
2783	sftk_FreeSession(session);
2784	return crv;
2785    }
2786
2787    context->multi = PR_TRUE;
2788
2789    switch(pMechanism->mechanism) {
2790    case CKM_RSA_PKCS:
2791    case CKM_RSA_X_509:
2792	if (key_type != CKK_RSA) {
2793	    crv = CKR_KEY_TYPE_INCONSISTENT;
2794	    break;
2795	}
2796	context->multi = PR_FALSE;
2797	pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
2798	if (pubKey == NULL) {
2799	    break;
2800	}
2801	context->cipherInfo = pubKey;
2802	context->update = (SFTKCipher) (pMechanism->mechanism == CKM_RSA_X_509
2803			? RSA_CheckSignRecoverRaw : RSA_CheckSignRecover);
2804	context->destroy = sftk_Null;
2805	break;
2806    default:
2807	crv = CKR_MECHANISM_INVALID;
2808	break;
2809    }
2810
2811    if (crv != CKR_OK) {
2812        PORT_Free(context);
2813	sftk_FreeSession(session);
2814	return crv;
2815    }
2816    sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, context);
2817    sftk_FreeSession(session);
2818    return CKR_OK;
2819}
2820
2821
2822/* NSC_VerifyRecover verifies a signature in a single-part operation, 
2823 * where the data is recovered from the signature. 
2824 * E.g. Decryption with the user's public key */
2825CK_RV NSC_VerifyRecover(CK_SESSION_HANDLE hSession,
2826		 CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen,
2827    				CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)
2828{
2829    SFTKSession *session;
2830    SFTKSessionContext *context;
2831    unsigned int outlen;
2832    unsigned int maxoutlen = *pulDataLen;
2833    CK_RV crv;
2834    SECStatus rv;
2835
2836    CHECK_FORK();
2837
2838    /* make sure we're legal */
2839    crv = sftk_GetContext(hSession,&context,SFTK_VERIFY_RECOVER,
2840							PR_FALSE,&session);
2841    if (crv != CKR_OK) return crv;
2842    if (pData == NULL) {
2843	/* to return the actual size, we need  to do the decrypt, just return
2844	 * the max size, which is the size of the input signature. */
2845	*pulDataLen = ulSignatureLen;
2846	rv = SECSuccess;
2847	goto finish;
2848    }
2849
2850    rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
2851						pSignature, ulSignatureLen);
2852    *pulDataLen = (CK_ULONG) outlen;
2853
2854    sftk_TerminateOp(session, SFTK_VERIFY_RECOVER, context);
2855finish:
2856    sftk_FreeSession(session);
2857    return (rv == SECSuccess)  ? CKR_OK : sftk_MapVerifyError(PORT_GetError());
2858}
2859
2860/*
2861 **************************** Random Functions:  ************************
2862 */
2863
2864/* NSC_SeedRandom mixes additional seed material into the token's random number 
2865 * generator. */
2866CK_RV NSC_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
2867    CK_ULONG ulSeedLen) 
2868{
2869    SECStatus rv;
2870
2871    CHECK_FORK();
2872
2873    rv = RNG_RandomUpdate(pSeed, ulSeedLen);
2874    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
2875}
2876
2877/* NSC_GenerateRandom generates random data. */
2878CK_RV NSC_GenerateRandom(CK_SESSION_HANDLE hSession,
2879    CK_BYTE_PTR	pRandomData, CK_ULONG ulRandomLen)
2880{
2881    SECStatus rv;
2882
2883    CHECK_FORK();
2884
2885    rv = RNG_GenerateGlobalRandomBytes(pRandomData, ulRandomLen);
2886    /*
2887     * This may fail with SEC_ERROR_NEED_RANDOM, which means the RNG isn't
2888     * seeded with enough entropy.
2889     */
2890    return (rv == SECSuccess) ? CKR_OK : sftk_MapCryptError(PORT_GetError());
2891}
2892
2893/*
2894 **************************** Key Functions:  ************************
2895 */
2896
2897
2898/*
2899 * generate a password based encryption key. This code uses
2900 * PKCS5 to do the work.
2901 */
2902static CK_RV
2903nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
2904			void *buf, CK_ULONG *key_length, PRBool faulty3DES)
2905{
2906    SECItem *pbe_key = NULL, iv, pwitem;
2907    CK_PBE_PARAMS *pbe_params = NULL;
2908    CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
2909
2910    *key_length = 0;
2911    iv.data = NULL; iv.len = 0;
2912
2913    if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
2914	pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
2915	pwitem.data = (unsigned char *)pbkd2_params->pPassword;
2916	/* was this a typo in the PKCS #11 spec? */
2917	pwitem.len = *pbkd2_params->ulPasswordLen;
2918    } else {
2919	pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
2920	pwitem.data = (unsigned char *)pbe_params->pPassword;
2921	pwitem.len = pbe_params->ulPasswordLen;
2922    }
2923    pbe_key = nsspkcs5_ComputeKeyAndIV(pkcs5_pbe, &pwitem, &iv, faulty3DES);
2924    if (pbe_key == NULL) {
2925	return CKR_HOST_MEMORY;
2926    }
2927
2928    PORT_Memcpy(buf, pbe_key->data, pbe_key->len);
2929    *key_length = pbe_key->len;
2930    SECITEM_ZfreeItem(pbe_key, PR_TRUE);
2931    pbe_key = NULL;
2932
2933    if (iv.data) {
2934        if (pbe_params && pbe_params->pInitVector != NULL) {
2935	    PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len);
2936        }
2937        PORT_Free(iv.data);
2938    }
2939
2940    return CKR_OK;
2941}
2942static CK_RV
2943nsc_parameter_gen(CK_KEY_TYPE key_type, SFTKObject *key)
2944{
2945    SFTKAttribute *attribute;
2946    CK_ULONG counter;
2947    unsigned int seedBits = 0;
2948    unsigned int primeBits;
2949    unsigned int j;
2950    CK_RV crv = CKR_OK;
2951    PQGParams *params = NULL;
2952    PQGVerify *vfy = NULL;
2953    SECStatus rv;
2954
2955    attribute = sftk_FindAttribute(key, CKA_PRIME_BITS);
2956    if (attribute == NULL) {
2957	return CKR_TEMPLATE_INCOMPLETE;
2958    }
2959    primeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
2960    sftk_FreeAttribute(attribute);
2961    j = PQG_PBITS_TO_INDEX(primeBits);
2962    if (j == (unsigned int)-1) {
2963	return CKR_ATTRIBUTE_VALUE_INVALID;
2964    }
2965
2966    attribute = sftk_FindAttribute(key, CKA_NETSCAPE_PQG_SEED_BITS);
2967    if (attribute != NULL) {
2968	seedBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
2969	sftk_FreeAttribute(attribute);
2970    }
2971
2972    sftk_DeleteAttributeType(key,CKA_PRIME_BITS);
2973    sftk_DeleteAttributeType(key,CKA_NETSCAPE_PQG_SEED_BITS);
2974
2975    if (seedBits == 0) {
2976	rv = PQG_ParamGen(j, &params, &vfy);
2977    } else {
2978	rv = PQG_ParamGenSeedLen(j,seedBits/8, &params, &vfy);
2979    }
2980
2981    if (rv != SECSuccess) {
2982	if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
2983	    sftk_fatalError = PR_TRUE;
2984	}
2985	return sftk_MapCryptError(PORT_GetError());
2986    }
2987    crv = sftk_AddAttributeType(key,CKA_PRIME,
2988				 params->prime.data, params->prime.len);
2989    if (crv != CKR_OK) goto loser;
2990    crv = sftk_AddAttributeType(key,CKA_SUBPRIME,
2991				 params->subPrime.data, params->subPrime.len);
2992    if (crv != CKR_OK) goto loser;
2993    crv = sftk_AddAttributeType(key,CKA_BASE,
2994				 params->base.data, params->base.len);
2995    if (crv != CKR_OK) goto loser;
2996    counter = vfy->counter;
2997    crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_COUNTER,
2998				 &counter, sizeof(counter));
2999    crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_SEED,
3000				 vfy->seed.data, vfy->seed.len);
3001    if (crv != CKR_OK) goto loser;
3002    crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_H,
3003				 vfy->h.data, vfy->h.len);
3004    if (crv != CKR_OK) goto loser;
3005
3006loser:
3007    PQG_DestroyParams(params);
3008
3009    if (vfy) {
3010	PQG_DestroyVerify(vfy);
3011    }
3012    return crv;
3013}
3014
3015
3016static CK_RV
3017nsc_SetupBulkKeyGen(CK_MECHANISM_TYPE mechanism, CK_KEY_TYPE *key_type,
3018							CK_ULONG *key_length)
3019{
3020    CK_RV crv = CKR_OK;
3021
3022    switch (mechanism) {
3023    case CKM_RC2_KEY_GEN:
3024	*key_type = CKK_RC2;
3025	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3026	break;
3027#if NSS_SOFTOKEN_DOES_RC5
3028    case CKM_RC5_KEY_GEN:
3029	*key_type = CKK_RC5;
3030	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3031	break;
3032#endif
3033    case CKM_RC4_KEY_GEN:
3034	*key_type = CKK_RC4;
3035	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3036	break;
3037    case CKM_GENERIC_SECRET_KEY_GEN:
3038	*key_type = CKK_GENERIC_SECRET;
3039	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3040	break;
3041    case CKM_CDMF_KEY_GEN:
3042	*key_type = CKK_CDMF;
3043	*key_length = 8;
3044	break;
3045    case CKM_DES_KEY_GEN:
3046	*key_type = CKK_DES;
3047	*key_length = 8;
3048	break;
3049    case CKM_DES2_KEY_GEN:
3050	*key_type = CKK_DES2;
3051	*key_length = 16;
3052	break;
3053    case CKM_DES3_KEY_GEN:
3054	*key_type = CKK_DES3;
3055	*key_length = 24;
3056	break;
3057    case CKM_SEED_KEY_GEN:
3058	*key_type = CKK_SEED;
3059	*key_length = 16;
3060	break;
3061    case CKM_CAMELLIA_KEY_GEN:
3062	*key_type = CKK_CAMELLIA;
3063	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3064	break;
3065    case CKM_AES_KEY_GEN:
3066	*key_type = CKK_AES;
3067	if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
3068	break;
3069    default:
3070	PORT_Assert(0);
3071	crv = CKR_MECHANISM_INVALID;
3072	break;
3073    }
3074
3075    return crv;
3076}
3077
3078CK_RV
3079nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe)
3080{
3081    SECItem  salt;
3082    CK_PBE_PARAMS *pbe_params = NULL;
3083    NSSPKCS5PBEParameter *params;
3084    PRArenaPool *arena = NULL;
3085    SECStatus rv;
3086
3087    *pbe = NULL;
3088
3089    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
3090    if (arena == NULL) {
3091	return CKR_HOST_MEMORY;
3092    }
3093
3094    params = (NSSPKCS5PBEParameter *) PORT_ArenaZAlloc(arena,
3095				sizeof(NSSPKCS5PBEParameter));
3096    if (params == NULL) {
3097	PORT_FreeArena(arena,PR_TRUE);
3098	return CKR_HOST_MEMORY;
3099    }
3100
3101    params->poolp = arena;
3102    params->ivLen = 0;
3103    params->pbeType = NSSPKCS5_PKCS12_V2;
3104    params->hashType = HASH_AlgSHA1;
3105    params->encAlg = SEC_OID_SHA1; /* any invalid value */
3106    params->is2KeyDES = PR_FALSE;
3107    params->keyID = pbeBitGenIntegrityKey;
3108    pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
3109    params->iter = pbe_params->ulIteration;
3110
3111    salt.data = (unsigned char *)pbe_params->pSalt;
3112    salt.len = (unsigned int)pbe_params->ulSaltLen;
3113    rv = SECITEM_CopyItem(arena,&params->salt,&salt);
3114    if (rv != SECSuccess) {
3115	PORT_FreeArena(arena,PR_TRUE);
3116	return CKR_HOST_MEMORY;
3117    }
3118    switch (pMechanism->mechanism) {
3119    case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
3120    case CKM_PBA_SHA1_WITH_SHA1_HMAC:
3121	params->hashType = HASH_AlgSHA1; 
3122	params->keyLen = 20;
3123	break;
3124    case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
3125	params->hashType = HASH_AlgMD5; 
3126	params->keyLen = 16;
3127	break;
3128    case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
3129	params->hashType = HASH_AlgMD2; 
3130	params->keyLen = 16;
3131	break;
3132    default:
3133	PORT_FreeArena(arena,PR_TRUE);
3134	return CKR_MECHANISM_INVALID;
3135    }
3136    *pbe = params;
3137    return CKR_OK;
3138}
3139
3140/* maybe this should be table driven? */
3141static CK_RV
3142nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter  **pbe,
3143				CK_KEY_TYPE *key_type, CK_ULONG *key_length)
3144{
3145    CK_RV crv = CKR_OK;
3146    SECOidData *oid;
3147    CK_PBE_PARAMS *pbe_params = NULL;
3148    NSSPKCS5PBEParameter *params = NULL;
3149    CK_PKCS5_PBKD2_PARAMS *pbkd2_params = NULL;
3150    SECItem salt;
3151    CK_ULONG iteration = 0;
3152
3153    *pbe = NULL;
3154
3155    oid = SECOID_FindOIDByMechanism(pMechanism->mechanism);
3156    if (oid == NULL) {
3157	return CKR_MECHANISM_INVALID;
3158    }
3159
3160    if (pMechanism->mechanism == CKM_PKCS5_PBKD2) {
3161	pbkd2_params = (CK_PKCS5_PBKD2_PARAMS *)pMechanism->pParameter;
3162	if (pbkd2_params->saltSource != CKZ_SALT_SPECIFIED) {
3163	    return CKR_MECHANISM_PARAM_INVALID;
3164	}
3165	salt.data = (unsigned char *)pbkd2_params->pSaltSourceData;
3166	salt.len = (unsigned int)pbkd2_params->ulSaltSourceDataLen;
3167	iteration = pbkd2_params->iterations;
3168    } else {
3169	pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
3170	salt.data = (unsigned char *)pbe_params->pSalt;
3171	salt.len = (unsigned int)pbe_params->ulSaltLen;
3172	iteration = pbe_params->ulIteration;
3173    }
3174    params=nsspkcs5_NewParam(oid->offset, &salt, iteration);
3175    if (params == NULL) {
3176	return CKR_MECHANISM_INVALID;
3177    }
3178
3179    switch (params->encAlg) {
3180    case SEC_OID_DES_CBC:
3181	*key_type = CKK_DES;
3182	*key_length = params->keyLen;
3183	break;
3184    case SEC_OID_DES_EDE3_CBC:
3185	*key_type = params->is2KeyDES ? CKK_DES2 : CKK_DES3;
3186	*key_length = params->keyLen;
3187	break;
3188    case SEC_OID_RC2_CBC:
3189	*key_type = CKK_RC2;
3190	*key_length = params->keyLen;
3191	break;
3192    case SEC_OID_RC4:
3193	*key_type = CKK_RC4;
3194	*key_length = params->keyLen;
3195	break;
3196    case SEC_OID_PKCS5_PBKDF2:
3197	/* sigh, PKCS #11 currently only defines SHA1 for the KDF hash type. 
3198	 * we do the check here because this where we would handle multiple
3199	 * hash types in the future */
3200	if (pbkd2_params == NULL || 
3201		pbkd2_params->prf != CKP_PKCS5_PBKD2_HMAC_SHA1) {
3202	    crv = CKR_MECHANISM_PARAM_INVALID;
3203	    break;
3204	}
3205	/* key type must already be set */
3206	if (*key_type == CKK_INVALID_KEY_TYPE) {
3207	    crv = CKR_TEMPLATE_INCOMPLETE;
3208	    break;
3209	}
3210	/* PBKDF2 needs to calculate the key length from the other parameters
3211	 */
3212	if (*key_length == 0) {
3213	    *key_length = sftk_MapKeySize(*key_type);
3214	}
3215	if (*key_length == 0) {
3216	    crv = CKR_TEMPLATE_INCOMPLETE;
3217	    break;
3218	}
3219	params->keyLen = *key_length;
3220	break;
3221    default:
3222	crv = CKR_MECHANISM_INVALID;
3223	nsspkcs5_DestroyPBEParameter(params);
3224	break;
3225    }
3226    if (crv == CKR_OK) {
3227    	*pbe = params;
3228    }
3229    return crv;
3230}
3231
3232/* NSC_GenerateKey generates a secret key, creating a new key object. */
3233CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession,
3234    CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,
3235    						CK_OBJECT_HANDLE_PTR phKey)
3236{
3237    SFTKObject *key;
3238    SFTKSession *session;
3239    PRBool checkWeak = PR_FALSE;
3240    CK_ULONG key_length = 0;
3241    CK_KEY_TYPE key_type = CKK_INVALID_KEY_TYPE;
3242    CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
3243    CK_RV crv = CKR_OK;
3244    CK_BBOOL cktrue = CK_TRUE;
3245    int i;
3246    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
3247    unsigned char buf[MAX_KEY_LEN];
3248    enum {nsc_pbe, nsc_ssl, nsc_bulk, nsc_param, nsc_jpake} key_gen_type;
3249    NSSPKCS5PBEParameter *pbe_param;
3250    SSL3RSAPreMasterSecret *rsa_pms;
3251    CK_VERSION *version;
3252    /* in very old versions of NSS, there were implementation errors with key 
3253     * generation methods.  We want to beable to read these, but not 
3254     * produce them any more.  The affected algorithm was 3DES.
3255     */
3256    PRBool faultyPBE3DES = PR_FALSE;
3257    HASH_HashType hashType;
3258
3259    CHECK_FORK();
3260
3261    if (!slot) {
3262        return CKR_SESSION_HANDLE_INVALID;
3263    }
3264    /*
3265     * now lets create an object to hang the attributes off of
3266     */
3267    key = sftk_NewObject(slot); /* fill in the handle later */
3268    if (key == NULL) {
3269	return CKR_HOST_MEMORY;
3270    }
3271
3272    /*
3273     * load the template values into the object
3274     */
3275    for (i=0; i < (int) ulCount; i++) {
3276	if (pTemplate[i].type == CKA_VALUE_LEN) {
3277	    key_length = *(CK_ULONG *)pTemplate[i].pValue;
3278	    continue;
3279	}
3280	/* some algorithms need keytype specified */
3281	if (pTemplate[i].type == CKA_KEY_TYPE) {
3282	    key_type = *(CK_ULONG *)pTemplate[i].pValue;
3283	    continue;
3284	}
3285
3286	crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
3287	if (crv != CKR_OK) break;
3288    }
3289    if (crv != CKR_OK) {
3290	sftk_FreeObject(key);
3291	return crv;
3292    }
3293
3294    /* make sure we don't have any class, key_type, or value fields */
3295    sftk_DeleteAttributeType(key,CKA_CLASS);
3296    sftk_DeleteAttributeType(key,CKA_KEY_TYPE);
3297    sftk_DeleteAttributeType(key,CKA_VALUE);
3298
3299    /* Now Set up the parameters to generate the key (based on mechanism) */
3300    key_gen_type = nsc_bulk; /* bulk key by default */
3301    switch (pMechanism->mechanism) {
3302    case CKM_CDMF_KEY_GEN:
3303    case CKM_DES_KEY_GEN:
3304    case CKM_DES2_KEY_GEN:
3305    case CKM_DES3_KEY_GEN:
3306	checkWeak = PR_TRUE;
3307    case CKM_RC2_KEY_GEN:
3308    case CKM_RC4_KEY_GEN:
3309    case CKM_GENERIC_SECRET_KEY_GEN:
3310    case CKM_SEED_KEY_GEN:
3311    case CKM_CAMELLIA_KEY_GEN:
3312    case CKM_AES_KEY_GEN:
3313#if NSS_SOFTOKEN_DOES_RC5
3314    case CKM_RC5_KEY_GEN:
3315#endif
3316	crv = nsc_SetupBulkKeyGen(pMechanism->mechanism,&key_type,&key_length);
3317	break;
3318    case CKM_SSL3_PRE_MASTER_KEY_GEN:
3319	key_type = CKK_GENERIC_SECRET;
3320	key_length = 48;
3321	key_gen_type = nsc_ssl;
3322	break;
3323    case CKM_PBA_SHA1_WITH_SHA1_HMAC:
3324    case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
3325    case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
3326    case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
3327	key_gen_type = nsc_pbe;
3328	key_type = CKK_GENERIC_SECRET;
3329	crv = nsc_SetupHMACKeyGen(pMechanism, &pbe_param);
3330	break;
3331    case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
3332	faultyPBE3DES = PR_TRUE;
3333    case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
3334    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
3335    case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
3336    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
3337    case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
3338    case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
3339    case CKM_PBE_SHA1_DES3_EDE_CBC:
3340    case CKM_PBE_SHA1_DES2_EDE_CBC:
3341    case CKM_PBE_SHA1_RC2_128_CBC:
3342    case CKM_PBE_SHA1_RC2_40_CBC:
3343    case CKM_PBE_SHA1_RC4_128:
3344    case CKM_PBE_SHA1_RC4_40:
3345    case CKM_PBE_MD5_DES_CBC:
3346    case CKM_PBE_MD2_DES_CBC:
3347    case CKM_PKCS5_PBKD2:
3348	key_gen_type = nsc_pbe;
3349	crv = nsc_SetupPBEKeyGen(pMechanism,&pbe_param, &key_type, &key_length);
3350	break;
3351    case CKM_DSA_PARAMETER_GEN:
3352	key_gen_type = nsc_param;
3353	key_type = CKK_DSA;
3354	objclass = CKO_KG_PARAMETERS;
3355	crv = CKR_OK;
3356	break;
3357    case CKM_NSS_JPAKE_ROUND1_SHA1:   hashType = HASH_AlgSHA1;   goto jpake1;
3358    case CKM_NSS_JPAKE_ROUND1_SHA256: hashType = HASH_AlgSHA256; goto jpake1;
3359    case CKM_NSS_JPAKE_ROUND1_SHA384: hashType = HASH_AlgSHA384; goto jpake1;
3360    case CKM_NSS_JPAKE_ROUND1_SHA512: hashType = HASH_AlgSHA512; goto jpake1;
3361jpake1:
3362	key_gen_type = nsc_jpake;
3363	key_type = CKK_NSS_JPAKE_ROUND1;
3364        objclass = CKO_PRIVATE_KEY;
3365        if (pMechanism->pParameter == NULL ||
3366            pMechanism->ulParameterLen != sizeof(CK_NSS_JPAKERound1Params)) {
3367            crv = CKR_MECHANISM_PARAM_INVALID;
3368            break;
3369        }
3370        if (sftk_isTrue(key, CKA_TOKEN)) {
3371            crv = CKR_TEMPLATE_INCONSISTENT;
3372        }
3373        crv = CKR_OK;
3374        break;
3375    default:
3376	crv = CKR_MECHANISM_INVALID;
3377	break;
3378    }
3379
3380    /* make sure we aren't going to overflow the buffer */
3381    if (sizeof(buf) < key_length) {
3382	/* someone is getting pretty optimistic about how big their key can
3383	 * be... */
3384        crv = CKR_TEMPLATE_INCONSISTENT;
3385    }
3386
3387    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3388
3389    /* if there was no error,
3390     * key_type *MUST* be set in the switch statement above */
3391    PORT_Assert( key_type != CKK_INVALID_KEY_TYPE );
3392
3393    /*
3394     * now to the actual key gen.
3395     */
3396    switch (key_gen_type) {
3397    case nsc_pbe:
3398	crv = nsc_pbe_key_gen(pbe_param, pMechanism, buf, &key_length,
3399			       faultyPBE3DES);
3400	nsspkcs5_DestroyPBEParameter(pbe_param);
3401	break;
3402    case nsc_ssl:
3403	rsa_pms = (SSL3RSAPreMasterSecret *)buf;
3404	version = (CK_VERSION *)pMechanism->pParameter;
3405	rsa_pms->client_version[0] = version->major;
3406        rsa_pms->client_version[1] = version->minor;
3407        crv = 
3408	    NSC_GenerateRandom(0,&rsa_pms->random[0], sizeof(rsa_pms->random));
3409	break;
3410    case nsc_bulk:
3411	/* get the key, check for weak keys and repeat if found */
3412	do {
3413            crv = NSC_GenerateRandom(0, buf, key_length);
3414	} while (crv == CKR_OK && checkWeak && sftk_IsWeakKey(buf,key_type));
3415	break;
3416    case nsc_param:
3417	/* generate parameters */
3418	*buf = 0;
3419	crv = nsc_parameter_gen(key_type,key);
3420	break;
3421    case nsc_jpake:
3422        crv = jpake_Round1(hashType,
3423                           (CK_NSS_JPAKERound1Params *) pMechanism->pParameter,
3424                           key);
3425        break;
3426    }
3427
3428    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3429
3430    /* Add the class, key_type, and value */
3431    crv = sftk_AddAttributeType(key,CKA_CLASS,&objclass,sizeof(CK_OBJECT_CLASS));
3432    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3433    crv = sftk_AddAttributeType(key,CKA_KEY_TYPE,&key_type,sizeof(CK_KEY_TYPE));
3434    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3435    if (key_length != 0) {
3436	crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
3437	if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
3438    }
3439
3440    /* get the session */
3441    session = sftk_SessionFromHandle(hSession);
3442    if (session == NULL) {
3443	sftk_FreeObject(key);
3444        return CKR_SESSION_HANDLE_INVALID;
3445    }
3446
3447    /*
3448     * handle the base object stuff
3449     */
3450    crv = sftk_handleObject(key,session);
3451    sftk_FreeSession(session);
3452    if (sftk_isTrue(key,CKA_SENSITIVE)) {
3453	sftk_forceAttribute(key,CKA_ALWAYS_SENSITIVE,&cktrue,sizeof(CK_BBOOL));
3454    }
3455    if (!sftk_isTrue(key,CKA_EXTRACTABLE)) {
3456	sftk_forceAttribute(key,CKA_NEVER_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL));
3457    }
3458
3459    *phKey = key->handle;
3460    sftk_FreeObject(key);
3461    return crv;
3462}
3463
3464#define PAIRWISE_DIGEST_LENGTH			SHA1_LENGTH /* 160-bits */
3465#define PAIRWISE_MESSAGE_LENGTH			20          /* 160-bits */
3466
3467/*
3468 * FIPS 140-2 pairwise consistency check utilized to validate key pair.
3469 *
3470 * This function returns
3471 *   CKR_OK               if pairwise consistency check passed
3472 *   CKR_GENERAL_ERROR    if pairwise consistency check failed
3473 *   other error codes    if paiswise consistency check could not be
3474 *                        performed, for example, CKR_HOST_MEMORY.
3475 */
3476static CK_RV
3477sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession,
3478    SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType)
3479{
3480    /*
3481     *                      Key type    Mechanism type
3482     *                      --------------------------------
3483     * For encrypt/decrypt: CKK_RSA  => CKM_RSA_PKCS
3484     *                      others   => CKM_INVALID_MECHANISM
3485     *
3486     * For sign/verify:     CKK_RSA  => CKM_RSA_PKCS
3487     *                      CKK_DSA  => CKM_DSA
3488     *                      CKK_EC   => CKM_ECDSA
3489     *                      others   => CKM_INVALID_MECHANISM
3490     *
3491     * None of these mechanisms has a parameter.
3492     */
3493    CK_MECHANISM mech = {0, NULL, 0};
3494
3495    CK_ULONG modulusLen;
3496    PRBool isEncryptable = PR_FALSE;
3497    PRBool canSignVerify = PR_FALSE;
3498    PRBool isDerivable = PR_FALSE;
3499    CK_RV crv;
3500
3501    /* Variables used for Encrypt/Decrypt functions. */
3502    unsigned char *known_message = (unsigned char *)"Known Crypto Message";
3503    unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH];
3504    CK_ULONG bytes_decrypted;
3505    unsigned char *ciphertext;
3506    unsigned char *text_compared;
3507    CK_ULONG bytes_encrypted;
3508    CK_ULONG bytes_compared;
3509
3510    /* Variables used for Signature/Verification functions. */
3511    /* always uses SHA-1 digest */
3512    unsigned char *known_digest = (unsigned char *)"Mozilla Rules World!";
3513    unsigned char *signature;
3514    CK_ULONG signature_length;
3515
3516    if (keyType == CKK_RSA) {
3517	SFTKAttribute *attribute;
3518
3519	/* Get modulus length of private key. */
3520	attribute = sftk_FindAttribute(privateKey, CKA_MODULUS);
3521	if (attribute == NULL) {
3522	    return CKR_DEVICE_ERROR;
3523	}
3524	modulusLen = attribute->attrib.ulValueLen;
3525	if (*(unsigned char *)attribute->attrib.pValue == 0) {
3526	    modulusLen--;
3527	}
3528	sftk_FreeAttribute(attribute);
3529    }
3530
3531    /**************************************************/
3532    /* Pairwise Consistency Check of Encrypt/Decrypt. */
3533    /**************************************************/
3534
3535    isEncryptable = sftk_isTrue(privateKey, CKA_DECRYPT); 
3536
3537    /*
3538     * If the decryption attribute is set, attempt to encrypt
3539     * with the public key and decrypt with the private key.
3540     */
3541    if (isEncryptable) {
3542	if (keyType != CKK_RSA) {
3543	    return CKR_DEVICE_ERROR;
3544	}
3545	bytes_encrypted = modulusLen;
3546	mech.mechanism = CKM_RSA_PKCS;
3547
3548	/* Allocate space for ciphertext. */
3549	ciphertext = (unsigned char *) PORT_ZAlloc(bytes_encrypted);
3550	if (ciphertext == NULL) {
3551	    return CKR_HOST_MEMORY;
3552	}
3553
3554	/* Prepare for encryption using the public key. */
3555	crv = NSC_EncryptInit(hSession, &mech, publicKey->handle);
3556	if (crv != CKR_OK) {
3557	    PORT_Free(ciphertext);
3558	    return crv;
3559	}
3560
3561	/* Encrypt using the public key. */
3562	crv = NSC_Encrypt(hSession,
3563			  known_message,
3564			  PAIRWISE_MESSAGE_LENGTH,
3565			  ciphertext,
3566			  &bytes_encrypted);
3567	if (crv != CKR_OK) {
3568	    PORT_Free(ciphertext);
3569	    return crv;
3570	}
3571
3572	/* Always use the smaller of these two values . . . */
3573	bytes_compared = PR_MIN(bytes_encrypted, PAIRWISE_MESSAGE_LENGTH);
3574
3575	/*
3576	 * If there was a failure, the plaintext
3577	 * goes at the end, therefore . . .
3578	 */
3579	text_compared = ciphertext + bytes_encrypted - bytes_compared;
3580
3581	/*
3582	 * Check to ensure that ciphertext does
3583	 * NOT EQUAL known input message text
3584	 * per FIPS PUB 140-2 directive.
3585	 */
3586	if (PORT_Memcmp(text_compared, known_message,
3587			bytes_compared) == 0) {
3588	    /* Set error to Invalid PRIVATE Key. */
3589	    PORT_SetError(SEC_ERROR_INVALID_KEY);
3590	    PORT_Free(ciphertext);
3591	    return CKR_GENERAL_ERROR;
3592	}
3593
3594	/* Prepare for decryption using the private key. */
3595	crv = NSC_DecryptInit(hSession, &mech, privateKey->handle);
3596	if (crv != CKR_OK) {
3597	    PORT_Free(ciphertext);
3598	    return crv;
3599	}
3600
3601	memset(plaintext, 0, PAIRWISE_MESSAGE_LENGTH);
3602
3603	/*
3604	 * Initialize bytes decrypted to be the
3605	 * expected PAIRWISE_MESSAGE_LENGTH.
3606	 */
3607	bytes_decrypted = PAIRWISE_MESSAGE_LENGTH;
3608
3609	/*
3610	 * Decrypt using the private key.
3611	 * NOTE:  No need to reset the
3612	 *        value of bytes_encrypted.
3613	 */
3614	crv = NSC_Decrypt(hSession,
3615			  ciphertext,
3616			  bytes_encrypted,
3617			  plaintext,
3618			  &bytes_decrypted);
3619
3620	/* Finished with ciphertext; free it. */
3621	PORT_Free(ciphertext);
3622
3623	if (crv != CKR_OK) {
3624	    return crv;
3625	}
3626
3627	/*
3628	 * Check to ensure that the output plaintext
3629	 * does EQUAL known input message text.
3630	 */
3631	if ((bytes_decrypted != PAIRWISE_MESSAGE_LENGTH) ||
3632	    (PORT_Memcmp(plaintext, known_message,
3633			 PAIRWISE_MESSAGE_LENGTH) != 0)) {
3634	    /* Set error to Bad PUBLIC Key. */
3635	    PORT_SetError(SEC_ERROR_BAD_KEY);
3636	    return CKR_GENERAL_ERROR;
3637	}
3638    }
3639
3640    /**********************************************/
3641    /* Pairwise Consistency Check of Sign/Verify. */
3642    /**********************************************/
3643
3644    canSignVerify = sftk_isTrue(privateKey, CKA_SIGN);
3645    
3646    if (canSignVerify) {
3647	/* Determine length of signature. */
3648	switch (keyType) {
3649	case CKK_RSA:
3650	    signature_length = modulusLen;
3651	    mech.mechanism = CKM_RSA_PKCS;
3652	    break;
3653	case CKK_DSA:
3654	    signature_length = DSA_SIGNATURE_LEN;
3655	    mech.mechanism = CKM_DSA;
3656	    break;
3657#ifdef NSS_ENABLE_ECC
3658	case CKK_EC:
3659	    signature_length = MAX_ECKEY_LEN * 2;
3660	    mech.mechanism = CKM_ECDSA;
3661	    break;
3662#endif
3663	default:
3664	    return CKR_DEVICE_ERROR;
3665	}
3666	
3667	/* Allocate space for signature data. */
3668	signature = (unsigned char *) PORT_ZAlloc(signature_length);
3669	if (signature == NULL) {
3670	    return CKR_HOST_MEMORY;
3671	}
3672	
3673	/* Sign the known hash using the private key. */
3674	crv = NSC_SignInit(hSession, &mech, privateKey->handle);
3675	if (crv != CKR_OK) {
3676	    PORT_Free(signature);
3677	    return crv;
3678	}
3679
3680	crv = NSC_Sign(hSession,
3681		       known_digest,
3682		       PAIRWISE_DIGEST_LENGTH,
3683		       signature,
3684		       &signature_length);
3685	if (crv != CKR_OK) {
3686	    PORT_Free(signature);
3687	    return crv;
3688	}
3689	
3690	/* Verify the known hash using the public key. */
3691	crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
3692	if (crv != CKR_OK) {
3693	    PORT_Free(signature);
3694	    return crv;
3695	}
3696
3697	crv = NSC_Verify(hSession,
3698			 known_digest,
3699			 PAIRWISE_DIGEST_LENGTH,
3700			 signature,
3701			 signature_length);
3702
3703	/* Free signature data. */
3704	PORT_Free(signature);
3705
3706	if ((crv == CKR_SIGNATURE_LEN_RANGE) ||
3707		(crv == CKR_SIGNATURE_INVALID)) {
3708	    return CKR_GENERAL_ERROR;
3709	}
3710	if (crv != CKR_OK) {
3711	    return crv;
3712	}
3713    }
3714
3715    /**********************************************/
3716    /* Pairwise Consistency Check for Derivation  */
3717    /**********************************************/
3718
3719    isDerivable = sftk_isTrue(privateKey, CKA_DERIVE);
3720    
3721    if (isDerivable) {
3722	/* 
3723	 * We are not doing consistency check for Diffie-Hellman Key - 
3724	 * otherwise it would be here
3725	 * This is also true for Elliptic Curve Diffie-Hellman keys
3726	 * NOTE: EC keys are currently subjected to pairwise
3727	 * consistency check for signing/verification.
3728	 */
3729	/*
3730	 * FIPS 140-2 had the following pairwise consistency test for
3731	 * public and private keys used for key agreement:
3732	 *   If the keys are used to perform key agreement, then the
3733	 *   cryptographic module shall create a second, compatible
3734	 *   key pair.  The cryptographic module shall perform both
3735	 *   sides of the key agreement algorithm and shall compare
3736	 *   the resulting shared values.  If the shared values are
3737	 *   not equal, the test shall fail.
3738	 * This test was removed in Change Notice 3.
3739	 */
3740
3741    }
3742
3743    return CKR_OK;
3744}
3745
3746/* NSC_GenerateKeyPair generates a public-key/private-key pair, 
3747 * creating new key objects. */
3748CK_RV NSC_GenerateKeyPair (CK_SESSION_HANDLE hSession,
3749    CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate,
3750    CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
3751    CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey,
3752    					CK_OBJECT_HANDLE_PTR phPrivateKey)
3753{
3754    SFTKObject *	publicKey,*privateKey;
3755    SFTKSession *	session;
3756    CK_KEY_TYPE 	key_type;
3757    CK_RV 		crv 	= CKR_OK;
3758    CK_BBOOL 		cktrue 	= CK_TRUE;
3759    SECStatus 		rv;
3760    CK_OBJECT_CLASS 	pubClass = CKO_PUBLIC_KEY;
3761    CK_OBJECT_CLASS 	privClass = CKO_PRIVATE_KEY;
3762    int 		i;
3763    SFTKSlot *		slot 	= sftk_SlotFromSessionHandle(hSession);
3764    unsigned int bitSize;
3765
3766    /* RSA */
3767    int 		public_modulus_bits = 0;
3768    SECItem 		pubExp;
3769    RSAPrivateKey *	rsaPriv;
3770
3771    /* DSA */
3772    PQGParams 		pqgParam;
3773    DHParams  		dhParam;
3774    DSAPrivateKey *	dsaPriv;
3775
3776    /* Diffie Hellman */
3777    int 		private_value_bits = 0;
3778    DHPrivateKey *	dhPriv;
3779
3780#ifdef NSS_ENABLE_ECC
3781    /* Elliptic Curve Cryptography */
3782    SECItem  		ecEncodedParams;  /* DER Encoded parameters */
3783    ECPrivateKey *	ecPriv;
3784    ECParams *          ecParams;
3785#endif /* NSS_ENABLE_ECC */
3786
3787    CHECK_FORK();
3788
3789    if (!slot) {
3790        return CKR_SESSION_HANDLE_INVALID;
3791    }
3792    /*
3793     * now lets create an object to hang the attributes off of
3794     */
3795    publicKey = sftk_NewObject(slot); /* fill in the handle later */
3796    if (publicKey == NULL) {
3797	return CKR_HOST_MEMORY;
3798    }
3799
3800    /*
3801     * load the template values into the publicKey
3802     */
3803    for (i=0; i < (int) ulPublicKeyAttributeCount; i++) {
3804	if (pPublicKeyTemplate[i].type == CKA_MODULUS_BITS) {
3805	    public_modulus_bits = *(CK_ULONG *)pPublicKeyTemplate[i].pValue;
3806	    continue;
3807	}
3808
3809	crv = sftk_AddAttributeType(publicKey,
3810				    sftk_attr_expand(&pPublicKeyTemplate[i]));
3811	if (crv != CKR_OK) break;
3812    }
3813
3814    if (crv != CKR_OK) {
3815	sftk_FreeObject(publicKey);
3816	return CKR_HOST_MEMORY;
3817    }
3818
3819    privateKey = sftk_NewObject(slot); /* fill in the handle later */
3820    if (privateKey == NULL) {
3821	sftk_FreeObject(publicKey);
3822	return CKR_HOST_MEMORY;
3823    }
3824    /*
3825     * now load the private key template
3826     */
3827    for (i=0; i < (int) ulPrivateKeyAttributeCount; i++) {
3828	if (pPrivateKeyTemplate[i].type == CKA_VALUE_BITS) {
3829	    private_value_bits = *(CK_ULONG *)pPrivateKeyTemplate[i].pValue;
3830	    continue;
3831	}
3832
3833	crv = sftk_AddAttributeType(privateKey,
3834				    sftk_attr_expand(&pPrivateKeyTemplate[i]));
3835	if (crv != CKR_OK) break;
3836    }
3837
3838    if (crv != CKR_OK) {
3839	sftk_FreeObject(publicKey);
3840	sftk_FreeObject(privateKey);
3841	return CKR_HOST_MEMORY;
3842    }
3843    sftk_DeleteAttributeType(privateKey,CKA_CLASS);
3844    sftk_DeleteAttributeType(privateKey,CKA_KEY_TYPE);
3845    sftk_DeleteAttributeType(privateKey,CKA_VALUE);
3846    sftk_DeleteAttributeType(publicKey,CKA_CLASS);
3847    sftk_DeleteAttributeType(publicKey,CKA_KEY_TYPE);
3848    sftk_DeleteAttributeType(publicKey,CKA_VALUE);
3849
3850    /* Now Set up the parameters to generate the key (based on mechanism) */
3851    switch (pMechanism->mechanism) {
3852    case CKM_RSA_PKCS_KEY_PAIR_GEN:
3853	/* format the keys */
3854    	sftk_DeleteAttributeType(publicKey,CKA_MODULUS);
3855    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
3856    	sftk_DeleteAttributeType(privateKey,CKA_MODULUS);
3857    	sftk_DeleteAttributeType(privateKey,CKA_PRIVATE_EXPONENT);
3858    	sftk_DeleteAttributeType(privateKey,CKA_PUBLIC_EXPONENT);
3859    	sftk_DeleteAttributeType(privateKey,CKA_PRIME_1);
3860    	sftk_DeleteAttributeType(privateKey,CKA_PRIME_2);
3861    	sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_1);
3862    	sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_2);
3863    	sftk_DeleteAttributeType(privateKey,CKA_COEFFICIENT);
3864	key_type = CKK_RSA;
3865	if (public_modulus_bits == 0) {
3866	    crv = CKR_TEMPLATE_INCOMPLETE;
3867	    break;
3868	}
3869	if (public_modulus_bits < RSA_MIN_MODULUS_BITS) {
3870	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
3871	    break;
3872	}
3873	if (public_modulus_bits % 2 != 0) {
3874	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
3875	    break;
3876	}
3877
3878	/* extract the exponent */
3879	crv=sftk_Attribute2SSecItem(NULL,&pubExp,publicKey,CKA_PUBLIC_EXPONENT);
3880	if (crv != CKR_OK) break;
3881        bitSize = sftk_GetLengthInBits(pubExp.data, pubExp.len);
3882	if (bitSize < 2) {
3883	    crv = CKR_ATTRIBUTE_VALUE_INVALID;
3884	    break;
3885	}
3886        crv = sftk_AddAttributeType(privateKey,CKA_PUBLIC_EXPONENT,
3887				    		    sftk_item_expand(&pubExp));
3888	if (crv != CKR_OK) {
3889	    PORT_Free(pubExp.data);
3890	    break;
3891	}
3892
3893	rsaPriv = RSA_NewKey(public_modulus_bits, &pubExp);
3894	PORT_Free(pubExp.data);
3895	if (rsaPriv == NULL) {
3896	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
3897		sftk_fatalError = PR_TRUE;
3898	    }
3899	    crv = sftk_MapCryptError(PORT_GetError());
3900	    break;
3901	}
3902        /* now fill in the RSA dependent paramenters in the public key */
3903        crv = sftk_AddAttributeType(publicKey,CKA_MODULUS,
3904			   sftk_item_expand(&rsaPriv->modulus));
3905	if (crv != CKR_OK) goto kpg_done;
3906        /* now fill in the RSA dependent paramenters in the private key */
3907        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
3908			   sftk_item_expand(&rsaPriv->modulus));
3909	if (crv != CKR_OK) goto kpg_done;
3910        crv = sftk_AddAttributeType(privateKey,CKA_MODULUS,
3911			   sftk_item_expand(&rsaPriv->modulus));
3912	if (crv != CKR_OK) goto kpg_done;
3913        crv = sftk_AddAttributeType(privateKey,CKA_PRIVATE_EXPONENT,
3914			   sftk_item_expand(&rsaPriv->privateExponent));
3915	if (crv != CKR_OK) goto kpg_done;
3916        crv = sftk_AddAttributeType(privateKey,CKA_PRIME_1,
3917			   sftk_item_expand(&rsaPriv->prime1));
3918	if (crv != CKR_OK) goto kpg_done;
3919        crv = sftk_AddAttributeType(privateKey,CKA_PRIME_2,
3920			   sftk_item_expand(&rsaPriv->prime2));
3921	if (crv != CKR_OK) goto kpg_done;
3922        crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_1,
3923			   sftk_item_expand(&rsaPriv->exponent1));
3924	if (crv != CKR_OK) goto kpg_done;
3925        crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_2,
3926			   sftk_item_expand(&rsaPriv->exponent2));
3927	if (crv != CKR_OK) goto kpg_done;
3928        crv = sftk_AddAttributeType(privateKey,CKA_COEFFICIENT,
3929			   sftk_item_expand(&rsaPriv->coefficient));
3930kpg_done:
3931	/* Should zeroize the contents first, since this func doesn't. */
3932	PORT_FreeArena(rsaPriv->arena, PR_TRUE);
3933	break;
3934    case CKM_DSA_KEY_PAIR_GEN:
3935    	sftk_DeleteAttributeType(publicKey,CKA_VALUE);
3936    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
3937	sftk_DeleteAttributeType(privateKey,CKA_PRIME);
3938	sftk_DeleteAttributeType(privateKey,CKA_SUBPRIME);
3939	sftk_DeleteAttributeType(privateKey,CKA_BASE);
3940	key_type = CKK_DSA;
3941
3942	/* extract the necessary parameters and copy them to the private key */
3943	crv=sftk_Attribute2SSecItem(NULL,&pqgParam.prime,publicKey,CKA_PRIME);
3944	if (crv != CKR_OK) break;
3945	crv=sftk_Attribute2SSecItem(NULL,&pqgParam.subPrime,publicKey,
3946	                            CKA_SUBPRIME);
3947	if (crv != CKR_OK) {
3948	    PORT_Free(pqgParam.prime.data);
3949	    break;
3950	}
3951	crv=sftk_Attribute2SSecItem(NULL,&pqgParam.base,publicKey,CKA_BASE);
3952	if (crv != CKR_OK) {
3953	    PORT_Free(pqgParam.prime.data);
3954	    PORT_Free(pqgParam.subPrime.data);
3955	    break;
3956	}
3957        crv = sftk_AddAttributeType(privateKey,CKA_PRIME,
3958				    sftk_item_expand(&pqgParam.prime));
3959	if (crv != CKR_OK) {
3960	    PORT_Free(pqgParam.prime.data);
3961	    PORT_Free(pqgParam.subPrime.data);
3962	    PORT_Free(pqgParam.base.data);
3963	    break;
3964	}
3965        crv = sftk_AddAttributeType(privateKey,CKA_SUBPRIME,
3966			    	    sftk_item_expand(&pqgParam.subPrime));
3967	if (crv != CKR_OK) {
3968	    PORT_Free(pqgParam.prime.data);
3969	    PORT_Free(pqgParam.subPrime.data);
3970	    PORT_Free(pqgParam.base.data);
3971	    break;
3972	}
3973        crv = sftk_AddAttributeType(privateKey,CKA_BASE,
3974			    	    sftk_item_expand(&pqgParam.base));
3975	if (crv != CKR_OK) {
3976	    PORT_Free(pqgParam.prime.data);
3977	    PORT_Free(pqgParam.subPrime.data);
3978	    PORT_Free(pqgParam.base.data);
3979	    break;
3980	}
3981
3982        bitSize = sftk_GetLengthInBits(pqgParam.subPrime.data, 
3983							pqgParam.subPrime.len);
3984        if (bitSize != DSA_Q_BITS)  {
3985	    crv = CKR_TEMPLATE_INCOMPLETE;
3986	    PORT_Free(pqgParam.prime.data);
3987	    PORT_Free(pqgParam.subPrime.data);
3988	    PORT_Free(pqgParam.base.data);
3989	    break;
3990	}
3991        bitSize = sftk_GetLengthInBits(pqgParam.prime.data,pqgParam.prime.len);
3992        if ((bitSize <  DSA_MIN_P_BITS) || (bitSize > DSA_MAX_P_BITS)) {
3993	    crv = CKR_TEMPLATE_INCOMPLETE;
3994	    PORT_Free(pqgParam.prime.data);
3995	    PORT_Free(pqgParam.subPrime.data);
3996	    PORT_Free(pqgParam.base.data);
3997	    break;
3998	}
3999        bitSize = sftk_GetLengthInBits(pqgParam.base.data,pqgParam.base.len);
4000        if ((bitSize <  1) || (bitSize > DSA_MAX_P_BITS)) {
4001	    crv = CKR_TEMPLATE_INCOMPLETE;
4002	    PORT_Free(pqgParam.prime.data);
4003	    PORT_Free(pqgParam.subPrime.data);
4004	    PORT_Free(pqgParam.base.data);
4005	    break;
4006	}
4007	    
4008	/* Generate the key */
4009	rv = DSA_NewKey(&pqgParam, &dsaPriv);
4010
4011	PORT_Free(pqgParam.prime.data);
4012	PORT_Free(pqgParam.subPrime.data);
4013	PORT_Free(pqgParam.base.data);
4014
4015	if (rv != SECSuccess) {
4016	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
4017		sftk_fatalError = PR_TRUE;
4018	    }
4019	    crv = sftk_MapCryptError(PORT_GetError());
4020	    break;
4021	}
4022
4023	/* store the generated key into the attributes */
4024        crv = sftk_AddAttributeType(publicKey,CKA_VALUE,
4025			   sftk_item_expand(&dsaPriv->publicValue));
4026	if (crv != CKR_OK) goto dsagn_done;
4027
4028        /* now fill in the RSA dependent paramenters in the private key */
4029        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
4030			   sftk_item_expand(&dsaPriv->publicValue));
4031	if (crv != CKR_OK) goto dsagn_done;
4032        crv = sftk_AddAttributeType(privateKey,CKA_VALUE,
4033			   sftk_item_expand(&dsaPriv->privateValue));
4034
4035dsagn_done:
4036	/* should zeroize, since this function doesn't. */
4037	PORT_FreeArena(dsaPriv->params.arena, PR_TRUE);
4038	break;
4039
4040    case CKM_DH_PKCS_KEY_PAIR_GEN:
4041	sftk_DeleteAttributeType(privateKey,CKA_PRIME);
4042	sftk_DeleteAttributeType(privateKey,CKA_BASE);
4043	sftk_DeleteAttributeType(privateKey,CKA_VALUE);
4044    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
4045	key_type = CKK_DH;
4046
4047	/* extract the necessary parameters and copy them to private keys */
4048        crv = sftk_Attribute2SSecItem(NULL, &dhParam.prime, publicKey, 
4049				      CKA_PRIME);
4050	if (crv != CKR_OK) break;
4051	crv = sftk_Attribute2SSecItem(NULL, &dhParam.base, publicKey, CKA_BASE);
4052	if (crv != CKR_OK) {
4053	    PORT_Free(dhParam.prime.data);
4054	    break;
4055	}
4056	crv = sftk_AddAttributeType(privateKey, CKA_PRIME, 
4057				    sftk_item_expand(&dhParam.prime));
4058	if (crv != CKR_OK) {
4059	    PORT_Free(dhParam.prime.data);
4060	    PORT_Free(dhParam.base.data);
4061	    break;
4062	}
4063	crv = sftk_AddAttributeType(privateKey, CKA_BASE, 
4064				    sftk_item_expand(&dhParam.base));
4065	if (crv != CKR_OK) {
4066	    PORT_Free(dhParam.prime.data);
4067	    PORT_Free(dhParam.base.data);
4068	    break;
4069	}
4070        bitSize = sftk_GetLengthInBits(dhParam.prime.data,dhParam.prime.len);
4071        if ((bitSize <  DH_MIN_P_BITS) || (bitSize > DH_MAX_P_BITS)) {
4072	    crv = CKR_TEMPLATE_INCOMPLETE;
4073	    PORT_Free(dhParam.prime.data);
4074	    PORT_Free(dhParam.base.data);
4075	    break;
4076	}
4077        bitSize = sftk_GetLengthInBits(dhParam.base.data,dhParam.base.len);
4078        if ((bitSize <  1) || (bitSize > DH_MAX_P_BITS)) {
4079	    crv = CKR_TEMPLATE_INCOMPLETE;
4080	    PORT_Free(dhParam.prime.data);
4081	    PORT_Free(dhParam.base.data);
4082	    break;
4083	}
4084
4085	rv = DH_NewKey(&dhParam, &dhPriv);
4086	PORT_Free(dhParam.prime.data);
4087	PORT_Free(dhParam.base.data);
4088	if (rv != SECSuccess) { 
4089	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
4090		sftk_fatalError = PR_TRUE;
4091	    }
4092	    crv = sftk_MapCryptError(PORT_GetError());
4093	    break;
4094	}
4095
4096	crv=sftk_AddAttributeType(publicKey, CKA_VALUE, 
4097				sftk_item_expand(&dhPriv->publicValue));
4098	if (crv != CKR_OK) goto dhgn_done;
4099
4100        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
4101			   sftk_item_expand(&dhPriv->publicValue));
4102	if (crv != CKR_OK) goto dhgn_done;
4103
4104	crv=sftk_AddAttributeType(privateKey, CKA_VALUE, 
4105			      sftk_item_expand(&dhPriv->privateValue));
4106
4107dhgn_done:
4108	/* should zeroize, since this function doesn't. */
4109	PORT_FreeArena(dhPriv->arena, PR_TRUE);
4110	break;
4111
4112#ifdef NSS_ENABLE_ECC
4113    case CKM_EC_KEY_PAIR_GEN:
4114	sftk_DeleteAttributeType(privateKey,CKA_EC_PARAMS);
4115	sftk_DeleteAttributeType(privateKey,CKA_VALUE);
4116    	sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
4117	key_type = CKK_EC;
4118
4119	/* extract the necessary parameters and copy them to private keys */
4120	crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey, 
4121				      CKA_EC_PARAMS);
4122	if (crv != CKR_OK) break;
4123
4124	crv = sftk_AddAttributeType(privateKey, CKA_EC_PARAMS, 
4125				    sftk_item_expand(&ecEncodedParams));
4126	if (crv != CKR_OK) {
4127	  PORT_Free(ecEncodedParams.data);
4128	  break;
4129	}
4130
4131	/* Decode ec params before calling EC_NewKey */
4132	rv = EC_DecodeParams(&ecEncodedParams, &ecParams);
4133	PORT_Free(ecEncodedParams.data);
4134	if (rv != SECSuccess) {
4135	    crv = sftk_MapCryptError(PORT_GetError());
4136	    break;
4137	}
4138	rv = EC_NewKey(ecParams, &ecPriv);
4139	PORT_FreeArena(ecParams->arena, PR_TRUE);
4140	if (rv != SECSuccess) { 
4141	    if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
4142		sftk_fatalError = PR_TRUE;
4143	    }
4144	    crv = sftk_MapCryptError(PORT_GetError());
4145	    break;
4146	}
4147
4148	if (getenv("NSS_USE_DECODED_CKA_EC_POINT")) {
4149	    crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, 
4150				sftk_item_expand(&ecPriv->publicValue));
4151	} else {
4152	    SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL, 
4153					&ecPriv->publicValue, 
4154					SEC_ASN1_GET(SEC_OctetStringTemplate));
4155	    if (!pubValue) {
4156		crv = CKR_ARGUMENTS_BAD;
4157		goto ecgn_done;
4158	    }
4159	    crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, 
4160				sftk_item_expand(pubValue));
4161	    SECITEM_FreeItem(pubValue, PR_TRUE);
4162	}
4163	if (crv != CKR_OK) goto ecgn_done;
4164
4165	crv = sftk_AddAttributeType(privateKey, CKA_VALUE, 
4166			      sftk_item_expand(&ecPriv->privateValue));
4167	if (crv != CKR_OK) goto ecgn_done;
4168
4169        crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
4170			   sftk_item_expand(&ecPriv->publicValue));
4171ecgn_done:
4172	/* should zeroize, since this function doesn't. */
4173	PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
4174	break;
4175#endif /* NSS_ENABLE_ECC */
4176
4177    default:
4178	crv = CKR_MECHANISM_INVALID;
4179    }
4180
4181    if (crv != CKR_OK) {
4182	sftk_FreeObject(privateKey);
4183	sftk_FreeObject(publicKey);
4184	return crv;
4185    }
4186
4187
4188    /* Add the class, key_type The loop lets us check errors blow out
4189     *  on errors and clean up at the bottom */
4190    session = NULL; /* make pedtantic happy... session cannot leave the*/
4191		    /* loop below NULL unless an error is set... */
4192    do {
4193	crv = sftk_AddAttributeType(privateKey,CKA_CLASS,&privClass,
4194						sizeof(CK_OBJECT_CLASS));
4195        if (crv != CKR_OK) break;
4196	crv = sftk_AddAttributeType(publicKey,CKA_CLASS,&pubClass,
4197						sizeof(CK_OBJECT_CLASS));
4198        if (crv != CKR_OK) break;
4199	crv = sftk_AddAttributeType(privateKey,CKA_KEY_TYPE,&key_type,
4200						sizeof(CK_KEY_TYPE));
4201        if (crv != CKR_OK) break;
4202	crv = sftk_AddAttributeType(publicKey,CKA_KEY_TYPE,&key_type,
4203						sizeof(CK_KEY_TYPE));
4204        if (crv != CKR_OK) break;
4205        session = sftk_SessionFromHandle(hSession);
4206        if (session == NULL) crv = CKR_SESSION_HANDLE_INVALID;
4207    } while (0);
4208
4209    if (crv != CKR_OK) {
4210	 sftk_FreeObject(privateKey);
4211	 sftk_FreeObject(publicKey);
4212	 return crv;
4213    }
4214
4215    /*
4216     * handle the base object cleanup for the public Key
4217     */
4218    crv = sftk_handleObject(privateKey,session);
4219    if (crv != CKR_OK) {
4220        sftk_FreeSession(session);
4221	sftk_FreeObject(privateKey);
4222	sftk_FreeObject(publicKey);
4223	return crv;
4224    }
4225
4226    /*
4227     * handle the base object cleanup for the private Key
4228     * If we have any problems, we destroy the public Key we've
4229     * created and linked.
4230     */
4231    crv = sftk_handleObject(publicKey,session);
4232    sftk_FreeSession(session);
4233    if (crv != CKR_OK) {
4234	sftk_FreeObject(publicKey);
4235	NSC_DestroyObject(hSession,privateKey->handle);
4236	sftk_FreeObject(privateKey);
4237	return crv;
4238    }
4239    if (sftk_isTrue(privateKey,CKA_SENSITIVE)) {
4240	sftk_forceAttribute(privateKey,CKA_ALWAYS_SENSITIVE,
4241						&cktrue,sizeof(CK_BBOOL));
4242    }
4243    if (sftk_isTrue(publicKey,CKA_SENSITIVE)) {
4244	sftk_forceAttribute(publicKey,CKA_ALWAYS_SENSITIVE,
4245						&cktrue,sizeof(CK_BBOOL));
4246    }
4247    if (!sftk_isTrue(privateKey,CKA_EXTRACTABLE)) {
4248	sftk_forceAttribute(privateKey,CKA_NEVER_EXTRACTABLE,
4249						&cktrue,sizeof(CK_BBOOL));
4250    }
4251    if (!sftk_isTrue(publicKey,CKA_EXTRACTABLE)) {
4252	sftk_forceAttribute(publicKey,CKA_NEVER_EXTRACTABLE,
4253						&cktrue,sizeof(CK_BBOOL));
4254    }
4255
4256    /* Perform FIPS 140-2 pairwise consistency check. */
4257    crv = sftk_PairwiseConsistencyCheck(hSession,
4258					publicKey, privateKey, key_type);
4259    if (crv != CKR_OK) {
4260	NSC_DestroyObject(hSession,publicKey->handle);
4261	sftk_FreeObject(publicKey);
4262	NSC_DestroyObject(hSession,privateKey->handle);
4263	sftk_FreeObject(privateKey);
4264	if (sftk_audit_enabled) {
4265	    char msg[128];
4266	    PR_snprintf(msg,sizeof msg,
4267			"C_GenerateKeyPair(hSession=0x%08lX, "
4268			"pMechanism->mechanism=0x%08lX)=0x%08lX "
4269			"self-test: pair-wise consistency test failed",
4270			(PRUint32)hSession,(PRUint32)pMechanism->mechanism,
4271			(PRUint32)crv);
4272	    sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
4273	}
4274	return crv;
4275    }
4276
4277    *phPrivateKey = privateKey->handle;
4278    *phPublicKey = publicKey->handle;
4279    sftk_FreeObject(publicKey);
4280    sftk_FreeObject(privateKey);
4281
4282    return CKR_OK;
4283}
4284
4285static SECItem *sftk_PackagePrivateKey(SFTKObject *key, CK_RV *crvp)
4286{
4287    NSSLOWKEYPrivateKey *lk = NULL;
4288    NSSLOWKEYPrivateKeyInfo *pki = NULL;
4289    SFTKAttribute *attribute = NULL;
4290    PLArenaPool *arena = NULL;
4291    SECOidTag algorithm = SEC_OID_UNKNOWN;
4292    void *dummy, *param = NULL;
4293    SECStatus rv = SECSuccess;
4294    SECItem *encodedKey = NULL;
4295#ifdef NSS_ENABLE_ECC
4296    SECItem *fordebug;
4297    int savelen;
4298#endif
4299
4300    if(!key) {
4301	*crvp = CKR_KEY_HANDLE_INVALID; /* really can't happen */
4302	return NULL;
4303    }
4304
4305    attribute = sftk_FindAttribute(key, CKA_KEY_TYPE);
4306    if(!attribute) {
4307	*crvp = CKR_KEY_TYPE_INCONSISTENT;
4308	return NULL;
4309    }
4310
4311    lk = sftk_GetPrivKey(key, *(CK_KEY_TYPE *)attribute->attrib.pValue, crvp);
4312    sftk_FreeAttribute(attribute);
4313    if(!lk) {
4314	return NULL;
4315    }
4316
4317    arena = PORT_NewArena(2048); 	/* XXX different size? */
4318    if(!arena) {
4319	*crvp = CKR_HOST_MEMORY;
4320	rv = SECFailure;
4321	goto loser;
4322    }
4323
4324    pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
4325					sizeof(NSSLOWKEYPrivateKeyInfo));
4326    if(!pki) {
4327	*crvp = CKR_HOST_MEMORY;
4328	rv = SECFailure;
4329	goto loser;
4330    }
4331    pki->arena = arena;
4332
4333    param = NULL;
4334    switch(lk->keyType) {
4335	case NSSLOWKEYRSAKey:
4336	    prepare_low_rsa_priv_key_for_asn1(lk);
4337	    dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
4338				       nsslowkey_RSAPrivateKeyTemplate);
4339	    algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
4340	    break;
4341	case NSSLOWKEYDSAKey:
4342            prepare_low_dsa_priv_key_export_for_asn1(lk);
4343	    dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
4344				       nsslowkey_DSAPrivateKeyExportTemplate);
4345	    prepare_low_pqg_params_for_asn1(&lk->u.dsa.params);
4346	    param = SEC_ASN1EncodeItem(NULL, NULL, &(lk->u.dsa.params),
4347				       nsslowkey_PQGParamsTemplate);
4348	    algorithm = SEC_OID_ANSIX9_DSA_SIGNATURE;
4349	    break;
4350#ifdef NSS_ENABLE_ECC	    
4351        case NSSLOWKEYECKey:
4352            prepare_low_ec_priv_key_for_asn1(lk);
4353	    /* Public value is encoded as a bit string so adjust length
4354	     * to be in bits before ASN encoding and readjust 
4355	     * immediately after.
4356	     *
4357	     * Since the SECG specification recommends not including the
4358	     * parameters as part of ECPrivateKey, we zero out the curveOID
4359	     * length before encoding and restore it later.
4360	     */
4361	    lk->u.ec.publicValue.len <<= 3;
4362	    savelen = lk->u.ec.ecParams.curveOID.len;
4363	    lk->u.ec.ecParams.curveOID.len = 0;
4364	    dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
4365				       nsslowkey_ECPrivateKeyTemplate);
4366	    lk->u.ec.ecParams.curveOID.len = savelen;
4367	    lk->u.ec.publicValue.len >>= 3;
4368
4369	    fordebug = &pki->privateKey;
4370	    SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKey", lk->keyType,
4371		      fordebug);
4372
4373	    param = SECITEM_DupItem(&lk->u.ec.ecParams.DEREncoding);
4374
4375	    algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
4376	    break;
4377#endif /* NSS_ENABLE_ECC */
4378	case NSSLOWKEYDHKey:
4379	default:
4380	    dummy = NULL;
4381	    break;
4382    }
4383 
4384    if(!dummy || ((lk->keyType == NSSLOWKEYDSAKey) && !param)) {
4385	*crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
4386	rv = SECFailure;
4387	goto loser;
4388    }
4389    
4390    rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, 
4391			       (SECItem*)param);
4392    if(rv != SECSuccess) {
4393	*crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
4394	rv = SECFailure;
4395	goto loser;
4396    }
4397
4398    dummy = SEC_ASN1EncodeInteger(arena, &pki->version,
4399				  NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
4400    if(!dummy) {
4401	*crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
4402	rv = SECFailure;
4403	goto loser;
4404    }
4405
4406    encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, 
4407				    nsslowkey_PrivateKeyInfoTemplate);
4408    *crvp = encodedKey ? CKR_OK : CKR_DEVICE_ERROR;
4409
4410#ifdef NSS_ENABLE_ECC
4411    fordebug = encodedKey;
4412    SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKeyInfo", lk->keyType,
4413	      fordebug);
4414#endif
4415loser:
4416    if(arena) {
4417	PORT_FreeArena(arena, PR_TRUE);
4418    }
4419
4420    if(lk && (lk != key->objectInfo)) {
4421	nsslowkey_DestroyPrivateKey(lk);
4422    }
4423 
4424    if(param) {
4425	SECITEM_ZfreeItem((SECItem*)param, PR_TRUE);
4426    }
4427
4428    if(rv != SECSuccess) {
4429	return NULL;
4430    }
4431
4432    return encodedKey;
4433}
4434    
4435/* it doesn't matter yet, since we colapse error conditions in the
4436 * level above, but we really should map those few key error differences */
4437static CK_RV 
4438sftk_mapWrap(CK_RV crv) 
4439{ 
4440    switch (crv) {
4441    case CKR_ENCRYPTED_DATA_INVALID:  crv = CKR_WRAPPED_KEY_INVALID; break;
4442    }
4443    return crv; 
4444}
4445
4446/* NSC_WrapKey wraps (i.e., encrypts) a key. */
4447CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession,
4448    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey,
4449    CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey,
4450					 CK_ULONG_PTR pulWrappedKeyLen)
4451{
4452    SFTKSession *session;
4453    SFTKAttribute *attribute;
4454    SFTKObject *key;
4455    CK_RV crv;
4456
4457    CHECK_FORK();
4458
4459    session = sftk_SessionFromHandle(hSession);
4460    if (session == NULL) {
4461    	return CKR_SESSION_HANDLE_INVALID;
4462    }
4463
4464    key = sftk_ObjectFromHandle(hKey,session);
4465    sftk_FreeSession(session);
4466    if (key == NULL) {
4467	return CKR_KEY_HANDLE_INVALID;
4468    }
4469
4470    switch(key->objclass) {
4471	case CKO_SECRET_KEY:
4472	  {
4473	    SFTKSessionContext *context = NULL;
4474	    SECItem pText;
4475
4476	    attribute = sftk_FindAttribute(key,CKA_VALUE);
4477
4478	    if (attribute == NULL) {
4479		crv = CKR_KEY_TYPE_INCONSISTENT;
4480		break;
4481	    }
4482	    crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey, 
4483				CKA_WRAP, CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
4484	    if (crv != CKR_OK) {
4485		sftk_FreeAttribute(attribute);
4486		break;
4487	    }
4488
4489	    pText.type = siBuffer;
4490	    pText.data = (unsigned char *)attribute->attrib.pValue;
4491	    pText.len  = attribute->attrib.ulValueLen;
4492
4493	    /* Find out if this is a block cipher. */
4494	    crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,NULL);
4495	    if (crv != CKR_OK || !context) 
4496	        break;
4497	    if (context->blockSize > 1) {
4498		unsigned int remainder = pText.len % context->blockSize;
4499	        if (!context->doPad && remainder) {
4500		    /* When wrapping secret keys with unpadded block ciphers, 
4501		    ** the keys are zero padded, if necessary, to fill out 
4502		    ** a full block.
4503		    */
4504		    pText.len += context->blockSize - remainder;
4505		    pText.data = PORT_ZAlloc(pText.len);
4506		    if (pText.data)
4507			memcpy(pText.data, attribute->attrib.pValue,
4508			                   attribute->attrib.ulValueLen);
4509		    else {
4510			crv = CKR_HOST_MEMORY;
4511			break;
4512		    }
4513		}
4514	    }
4515
4516	    crv = NSC_Encrypt(hSession, (CK_BYTE_PTR)pText.data, 
4517		              pText.len, pWrappedKey, pulWrappedKeyLen);
4518	    /* always force a finalize, both on errors and when
4519	     * we are just getting the size */
4520	    if (crv != CKR_OK || pWrappedKey == NULL) {
4521	    	CK_RV lcrv ;
4522		lcrv = sftk_GetContext(hSession,&context,
4523				       SFTK_ENCRYPT,PR_FALSE,NULL);
4524		sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
4525	    	if (lcrv == CKR_OK && context) {
4526		    sftk_FreeContext(context);
4527		}
4528    	    }
4529
4530	    if (pText.data != (unsigned char *)attribute->attrib.pValue) 
4531	    	PORT_ZFree(pText.data, pText.len);
4532	    sftk_FreeAttribute(attribute);
4533	    break;
4534	  }
4535
4536	case CKO_PRIVATE_KEY:
4537	    {
4538		SECItem *bpki = sftk_PackagePrivateKey(key, &crv);
4539		SFTKSessionContext *context = NULL;
4540
4541		if(!bpki) {
4542		    break;
4543		}
4544
4545		crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey,
4546				CKA_WRAP, CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
4547		if(crv != CKR_OK) {
4548		    SECITEM_ZfreeItem(bpki, PR_TRUE);
4549		    crv = CKR_KEY_TYPE_INCONSISTENT;
4550		    break;
4551		}
4552
4553		crv = NSC_Encrypt(hSession, bpki->data, bpki->len,
4554					pWrappedKey, pulWrappedKeyLen);
4555		/* always force a finalize */
4556		if (crv != CKR_OK || pWrappedKey == NULL) {
4557	    	    CK_RV lcrv ;
4558		    lcrv = sftk_GetContext(hSession,&context,
4559					   SFTK_ENCRYPT,PR_FALSE,NULL);
4560		    sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
4561	    	    if (lcrv == CKR_OK && context)  {
4562			sftk_FreeContext(context);
4563		    }
4564		}
4565		SECITEM_ZfreeItem(bpki, PR_TRUE);
4566		break;
4567	    }
4568
4569	default:
4570	    crv = CKR_KEY_TYPE_INCONSISTENT;
4571	    break;
4572    }
4573    sftk_FreeObject(key);
4574
4575    return sftk_mapWrap(crv);
4576}
4577
4578/*
4579 * import a pprivate key info into the desired slot
4580 */
4581static SECStatus
4582sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki)
4583{
4584    CK_BBOOL cktrue = CK_TRUE; 
4585    CK_KEY_TYPE keyType = CKK_RSA;
4586    SECStatus rv = SECFailure;
4587    const SEC_ASN1Template *keyTemplate, *paramTemplate;
4588    void *paramDest = NULL;
4589    PLArenaPool *arena;
4590    NSSLOWKEYPrivateKey *lpk = NULL;
4591    NSSLOWKEYPrivateKeyInfo *pki = NULL;
4592    CK_RV crv = CKR_KEY_TYPE_INCONSISTENT;
4593
4594    arena = PORT_NewArena(2048);
4595    if(!arena) {
4596	return SECFailure;
4597    }
4598
4599    pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
4600					sizeof(NSSLOWKEYPrivateKeyInfo));
4601    if(!pki) {
4602	PORT_FreeArena(arena, PR_FALSE);
4603	return SECFailure;
4604    }
4605
4606    if(SEC_ASN1DecodeItem(arena, pki, nsslowkey_PrivateKeyInfoTemplate, bpki) 
4607				!= SECSuccess) {
4608	PORT_FreeArena(arena, PR_TRUE);
4609	return SECFailure;
4610    }
4611
4612    lpk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(arena,
4613						  sizeof(NSSLOWKEYPrivateKey));
4614    if(lpk == NULL) {
4615	goto loser;
4616    }
4617    lpk->arena = arena;
4618
4619    switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
4620	case SEC_OID_PKCS1_RSA_ENCRYPTION:
4621	    keyTemplate = nsslowkey_RSAPrivateKeyTemplate;
4622	    paramTemplate = NULL;
4623	    paramDest = NULL;
4624	    lpk->keyType = NSSLOWKEYRSAKey;
4625	    prepare_low_rsa_priv_key_for_asn1(lpk);
4626	    break;
4627	case SEC_OID_ANSIX9_DSA_SIGNATURE:
4628	    keyTemplate = nsslowkey_DSAPrivateKeyExportTemplate;
4629	    paramTemplate = nsslowkey_PQGParamsTemplate;
4630	    paramDest = &(lpk->u.dsa.params);
4631	    lpk->keyType = NSSLOWKEYDSAKey;
4632	    prepare_low_dsa_priv_key_export_for_asn1(lpk);
4633	    prepare_low_pqg_params_for_asn1(&lpk->u.dsa.params);
4634	    break;
4635	/* case NSSLOWKEYDHKey: */
4636#ifdef NSS_ENABLE_ECC
4637        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
4638	    keyTemplate = nsslowkey_ECPrivateKeyTemplate;
4639	    paramTemplate = NULL;
4640	    paramDest = &(lpk->u.ec.ecParams.DEREncoding);
4641	    lpk->keyType = NSSLOWKEYECKey;
4642	    prepare_low_ec_priv_key_for_asn1(lpk);
4643	    prepare_low_ecparams_for_asn1(&lpk->u.ec.ecParams);
4644	    break;
4645#endif /* NSS_ENABLE_ECC */
4646	default:
4647	    keyTemplate = NULL;
4648	    paramTemplate = NULL;
4649	    paramDest = NULL;
4650	    break;
4651    }
4652
4653    if(!keyTemplate) {
4654	goto loser;
4655    }
4656
4657    /* decode the private key and any algorithm parameters */
4658    rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
4659
4660#ifdef NSS_ENABLE_ECC
4661    if (lpk->keyType == NSSLOWKEYECKey) {
4662        /* convert length in bits to length in bytes */
4663	lpk->u.ec.publicValue.len >>= 3;
4664        rv = SECITEM_CopyItem(arena, 
4665			      &(lpk->u.ec.ecParams.DEREncoding),
4666	                      &(pki->algorithm.parameters));
4667	if(rv != SECSuccess) {
4668	    goto loser;
4669	}
4670    }
4671#endif /* NSS_ENABLE_ECC */
4672
4673    if(rv != SECSuccess) {
4674	goto loser;
4675    }
4676    if(paramDest && paramTemplate) {
4677	rv = SEC_QuickDERDecodeItem(arena, paramDest, paramTemplate, 
4678				 &(pki->algorithm.parameters));
4679	if(rv != SECSuccess) {
4680	    goto loser;
4681	}
4682    }
4683
4684    rv = SECFailure;
4685
4686    switch (lpk->keyType) {
4687        case NSSLOWKEYRSAKey:
4688	    keyType = CKK_RSA;
4689	    if(sftk_hasAttribute(key, CKA_NETSCAPE_DB)) {
4690		sftk_DeleteAttributeType(key, CKA_NETSCAPE_DB);
4691	    }
4692	    crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
4693					sizeof(keyType));
4694	    if(crv != CKR_OK) break;
4695	    crv = sftk_AddAttributeType(key, CKA_UNWRAP, &cktrue, 
4696					sizeof(CK_BBOOL));
4697	    if(crv != CKR_OK) break;
4698	    crv = sftk_AddAttributeType(key, CKA_DECRYPT, &cktrue, 
4699					sizeof(CK_BBOOL));
4700	    if(crv != CKR_OK) break;
4701	    crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
4702					sizeof(CK_BBOOL));
4703	    if(crv != CKR_OK) break;
4704	    crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
4705				    sizeof(CK_BBOOL));
4706	    if(crv != CKR_OK) break;
4707	    crv = sftk_AddAttributeType(key, CKA_MODULUS, 
4708				sftk_item_expand(&lpk->u.rsa.modulus));
4709	    if(crv != CKR_OK) break;
4710	    crv = sftk_AddAttributeType(key, CKA_PUBLIC_EXPONENT, 
4711	     			sftk_item_expand(&lpk->u.rsa.publicExponent));
4712	    if(crv != CKR_OK) break;
4713	    crv = sftk_AddAttributeType(key, CKA_PRIVATE_EXPONENT, 
4714	     			sftk_item_expand(&lpk->u.rsa.privateExponent));
4715	    if(crv != CKR_OK) break;
4716	    crv = sftk_AddAttributeType(key, CKA_PRIME_1, 
4717				sftk_item_expand(&lpk->u.rsa.prime1));
4718	    if(crv != CKR_OK) break;
4719	    crv = sftk_AddAttributeType(key, CKA_PRIME_2, 
4720	     			sftk_item_expand(&lpk->u.rsa.prime2));
4721	    if(crv != CKR_OK) break;
4722	    crv = sftk_AddAttributeType(key, CKA_EXPONENT_1, 
4723	     			sftk_item_expand(&lpk->u.rsa.exponent1));
4724	    if(crv != CKR_OK) break;
4725	    crv = sftk_AddAttributeType(key, CKA_EXPONENT_2, 
4726	     			sftk_item_expand(&lpk->u.rsa.exponent2));
4727	    if(crv != CKR_OK) break;
4728	    crv = sftk_AddAttributeType(key, CKA_COEFFICIENT, 
4729	     			sftk_item_expand(&lpk->u.rsa.coefficient));
4730	    break;
4731        case NSSLOWKEYDSAKey:
4732	    keyType = CKK_DSA;
4733	    crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
4734						CKR_KEY_TYPE_INCONSISTENT;
4735	    if(crv != CKR_OK) break;
4736	    crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
4737						sizeof(keyType));
4738	    if(crv != CKR_OK) break;
4739	    crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
4740						sizeof(CK_BBOOL));
4741	    if(crv != CKR_OK) break;
4742	    crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
4743						sizeof(CK_BBOOL)); 
4744	    if(crv != CKR_OK) break;
4745	    crv = sftk_AddAttributeType(key, CKA_PRIME,    
4746				    sftk_item_expand(&lpk->u.dsa.params.prime));
4747	    if(crv != CKR_OK) break;
4748	    crv = sftk_AddAttributeType(key, CKA_SUBPRIME,
4749				 sftk_item_expand(&lpk->u.dsa.params.subPrime));
4750	    if(crv != CKR_OK) break;
4751	    crv = sftk_AddAttributeType(key, CKA_BASE,  
4752				    sftk_item_expand(&lpk->u.dsa.params.base));
4753	    if(crv != CKR_OK) break;
4754	    crv = sftk_AddAttributeType(key, CKA_VALUE, 
4755			sftk_item_expand(&lpk->u.dsa.privateValue));
4756	    if(crv != CKR_OK) break;
4757	    break;
4758#ifdef notdef
4759        case NSSLOWKEYDHKey:
4760	    template = dhTemplate;
4761	    templateCount = sizeof(dhTemplate)/sizeof(CK_ATTRIBUTE);
4762	    keyType = CKK_DH;
4763	    break;
4764#endif
4765	/* what about fortezza??? */
4766#ifdef NSS_ENABLE_ECC
4767        case NSSLOWKEYECKey:
4768	    keyType = CKK_EC;
4769	    crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
4770						CKR_KEY_TYPE_INCONSISTENT;
4771	    if(crv != CKR_OK) break;
4772	    crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
4773						sizeof(keyType));
4774	    if(crv != CKR_OK) break;
4775	    crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
4776						sizeof(CK_BBOOL));
4777	    if(crv != CKR_OK) break;
4778	    crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
4779						sizeof(CK_BBOOL)); 
4780	    if(crv != CKR_OK) break;
4781	    crv = sftk_AddAttributeType(key, CKA_DERIVE, &cktrue, 
4782						sizeof(CK_BBOOL)); 
4783	    if(crv != CKR_OK) break;
4784	    crv = sftk_AddAttributeType(key, CKA_EC_PARAMS,
4785				 sftk_item_expand(&lpk->u.ec.ecParams.DEREncoding));
4786	    if(crv != CKR_OK) break;
4787	    crv = sftk_AddAttributeType(key, CKA_VALUE, 
4788			sftk_item_expand(&lpk->u.ec.privateValue));
4789	    if(crv != CKR_OK) break;
4790	    /* XXX Do we need to decode the EC Params here ?? */
4791	    break;
4792#endif /* NSS_ENABLE_ECC */
4793	default:
4794	    crv = CKR_KEY_TYPE_INCONSISTENT;
4795	    break;
4796    }
4797
4798loser:
4799    if(lpk) {
4800	nsslowkey_DestroyPrivateKey(lpk);
4801    }
4802
4803    if(crv != CKR_OK) {
4804	return SECFailure;
4805    }
4806
4807    return SECSuccess;
4808}
4809
4810
4811/* NSC_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */
4812CK_RV NSC_UnwrapKey(CK_SESSION_HANDLE hSession,
4813    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,
4814    CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,
4815    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
4816						 CK_OBJECT_HANDLE_PTR phKey)
4817{
4818    SFTKObject *key = NULL;
4819    SFTKSession *session;
4820    CK_ULONG key_length = 0;
4821    unsigned char * buf = NULL;
4822    CK_RV crv = CKR_OK;
4823    int i;
4824    CK_ULONG bsize = ulWrappedKeyLen;
4825    SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4826    SECItem bpki;
4827    CK_OBJECT_CLASS target_type = CKO_SECRET_KEY;
4828
4829    CHECK_FORK();
4830
4831    if (!slot) {
4832        return CKR_SESSION_HANDLE_INVALID;
4833    }
4834    /*
4835     * now lets create an object to hang the attributes off of
4836     */
4837    key = sftk_NewObject(slot); /* fill in the handle later */
4838    if (key == NULL) {
4839	return CKR_HOST_MEMORY;
4840    }
4841
4842    /*
4843     * load the template values into the object
4844     */
4845    for (i=0; i < (int) ulAttributeCount; i++) {
4846	if (pTemplate[i].type == CKA_VALUE_LEN) {
4847	    key_length = *(CK_ULONG *)pTemplate[i].pValue;
4848	    continue;
4849	}
4850        if (pTemplate[i].type == CKA_CLASS) {
4851	    target_type = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
4852	}
4853	crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
4854	if (crv != CKR_OK) break;
4855    }
4856    if (crv != CKR_OK) {
4857	sftk_FreeObject(key);
4858	return crv;
4859    }
4860
4861    crv = sftk_CryptInit(hSession,pMechanism,hUnwrappingKey,CKA_UNWRAP,
4862					CKA_UNWRAP, SFTK_DECRYPT, PR_FALSE);
4863    if (crv != CKR_OK) {
4864	sftk_FreeObject(key);
4865	return sftk_mapWrap(crv);
4866    }
4867
4868    /* allocate the buffer to decrypt into 
4869     * this assumes the unwrapped key is never larger than the
4870     * wrapped key. For all the mechanisms we support this is true */
4871    buf = (unsigned char *)PORT_Alloc( ulWrappedKeyLen);
4872    bsize = ulWrappedKeyLen;
4873
4874    crv = NSC_Decrypt(hSession, pWrappedKey, ulWrappedKeyLen, buf, &bsize);
4875    if (crv != CKR_OK) {
4876	sftk_FreeObject(key);
4877	PORT_Free(buf);
4878	return sftk_mapWrap(crv);
4879    }
4880
4881    switch(target_type) {
4882	case CKO_SECRET_KEY:
4883	    if (!sftk_hasAttribute(key,CKA_KEY_TYPE)) {
4884		crv = CKR_TEMPLATE_INCOMPLETE;
4885		break;
4886	    }
4887
4888	    if (key_length == 0 || key_length > bsize) {
4889		key_length = bsize;
4890	    }
4891	    if (key_length > MAX_KEY_LEN) {
4892		crv = CKR_TEMPLATE_INCONSISTENT;
4893		break;
4894	    }
4895    
4896	    /* add the value */
4897	    crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
4898	    break;
4899	case CKO_PRIVATE_KEY:
4900	    bpki.data = (unsigned char *)buf;
4901	    bpki.len = bsize;
4902	    crv = CKR_OK;
4903	    if(sftk_unwrapPrivateKey(key, &bpki) != SECSuccess) {
4904		crv = CKR_TEMPLATE_INCOMPLETE;
4905	    }
4906	    break;
4907	default:
4908	    crv = CKR_TEMPLATE_INCONSISTENT;
4909	    break;
4910    }
4911
4912    PORT_ZFree(buf, bsize);
4913    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
4914
4915    /* get the session */
4916    session = sftk_SessionFromHandle(hSession);
4917    if (session == NULL) {
4918	sftk_FreeObject(key);
4919        return CKR_SESSION_HANDLE_INVALID;
4920    }
4921
4922    /*
4923     * handle the base object stuff
4924     */
4925    crv = sftk_handleObject(key,session);
4926    *phKey = key->handle;
4927    sftk_FreeSession(session);
4928    sftk_FreeObject(key);
4929
4930    return crv;
4931
4932}
4933
4934/*
4935 * The SSL key gen mechanism create's lots of keys. This function handles the
4936 * details of each of these key creation.
4937 */
4938static CK_RV
4939sftk_buildSSLKey(CK_SESSION_HANDLE hSession, SFTKObject *baseKey, 
4940    PRBool isMacKey, unsigned char *keyBlock, unsigned int keySize,
4941						 CK_OBJECT_HANDLE *keyHandle)
4942{
4943    SFTKObject *key;
4944    SFTKSession *session;
4945    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
4946    CK_BBOOL cktrue = CK_TRUE;
4947    CK_BBOOL ckfalse = CK_FALSE;
4948    CK_RV crv = CKR_HOST_MEMORY;
4949
4950    /*
4951     * now lets create an object to hang the attributes off of
4952     */
4953    *keyHandle = CK_INVALID_HANDLE;
4954    key = sftk_NewObject(baseKey->slot); 
4955    if (key == NULL) return CKR_HOST_MEMORY;
4956    sftk_narrowToSessionObject(key)->wasDerived = PR_TRUE;
4957
4958    crv = sftk_CopyObject(key,baseKey);
4959    if (crv != CKR_OK) goto loser;
4960    if (isMacKey) {
4961	crv = sftk_forceAttribute(key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
4962	if (crv != CKR_OK) goto loser;
4963	crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
4964	if (crv != CKR_OK) goto loser;
4965	crv = sftk_forceAttribute(key,CKA_ENCRYPT,&ckfalse,sizeof(CK_BBOOL));
4966	if (crv != CKR_OK) goto loser;
4967	crv = sftk_forceAttribute(key,CKA_DECRYPT,&ckfalse,sizeof(CK_BBOOL));
4968	if (crv != CKR_OK) goto loser;
4969	crv = sftk_forceAttribute(key,CKA_SIGN,&cktrue,sizeof(CK_BBOOL));
4970	if (crv != CKR_OK) goto loser;
4971	crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
4972	if (crv != CKR_OK) goto loser;
4973	crv = sftk_forceAttribute(key,CKA_WRAP,&ckfalse,sizeof(CK_BBOOL));
4974	if (crv != CKR_OK) goto loser;
4975	crv = sftk_forceAttribute(key,CKA_UNWRAP,&ckfalse,sizeof(CK_BBOOL));
4976	if (crv != CKR_OK) goto loser;
4977    }
4978    crv = sftk_forceAttribute(key,CKA_VALUE,keyBlock,keySize);
4979    if (crv != CKR_OK) goto loser;
4980
4981    /* get the session */
4982    crv = CKR_HOST_MEMORY;
4983    session = sftk_SessionFromHandle(hSession);
4984    if (session == NULL) { goto loser; }
4985
4986    crv = sftk_handleObject(key,session);
4987    sftk_FreeSession(session);
4988    *keyHandle = key->handle;
4989loser:
4990    if (key) sftk_FreeObject(key);
4991    return crv;
4992}
4993
4994/*
4995 * if there is an error, we need to free the keys we already created in SSL
4996 * This is the routine that will do it..
4997 */
4998static void
4999sftk_freeSSLKeys(CK_SESSION_HANDLE session,
5000				CK_SSL3_KEY_MAT_OUT *returnedMaterial ) 
5001{
5002	if (returnedMaterial->hClientMacSecret != CK_INVALID_HANDLE) {
5003	   NSC_DestroyObject(session,returnedMaterial->hClientMacSecret);
5004	}
5005	if (returnedMaterial->hServerMacSecret != CK_INVALID_HANDLE) {
5006	   NSC_DestroyObject(session, returnedMaterial->hServerMacSecret);
5007	}
5008	if (returnedMaterial->hClientKey != CK_INVALID_HANDLE) {
5009	   NSC_DestroyObject(session, returnedMaterial->hClientKey);
5010	}
5011	if (returnedMaterial->hServerKey != CK_INVALID_HANDLE) {
5012	   NSC_DestroyObject(session, returnedMaterial->hServerKey);
5013	}
5014}
5015
5016/*
5017 * when deriving from sensitive and extractable keys, we need to preserve some
5018 * of the semantics in the derived key. This helper routine maintains these
5019 * semantics.
5020 */
5021static CK_RV
5022sftk_DeriveSensitiveCheck(SFTKObject *baseKey,SFTKObject *destKey) 
5023{
5024    PRBool hasSensitive;
5025    PRBool sensitive = PR_FALSE;
5026    PRBool hasExtractable;
5027    PRBool extractable = PR_TRUE;
5028    CK_RV crv = CKR_OK;
5029    SFTKAttribute *att;
5030
5031    hasSensitive = PR_FALSE;
5032    att = sftk_FindAttribute(destKey,CKA_SENSITIVE);
5033    if (att) {
5034        hasSensitive = PR_TRUE;
5035	sensitive = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
5036	sftk_FreeAttribute(att);
5037    }
5038
5039    hasExtractable = PR_FALSE;
5040    att = sftk_FindAttribute(destKey,CKA_EXTRACTABLE);
5041    if (att) {
5042        hasExtractable = PR_TRUE;
5043	extractable = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
5044	sftk_FreeAttribute(att);
5045    }
5046
5047
5048    /* don't make a key more accessible */
5049    if (sftk_isTrue(baseKey,CKA_SENSITIVE) && hasSensitive && 
5050						(sensitive == PR_FALSE)) {
5051	return CKR_KEY_FUNCTION_NOT_PERMITTED;
5052    }
5053    if (!sftk_isTrue(baseKey,CKA_EXTRACTABLE) && hasExtractable && 
5054						(extractable == PR_TRUE)) {
5055	return CKR_KEY_FUNCTION_NOT_PERMITTED;
5056    }
5057
5058    /* inherit parent's sensitivity */
5059    if (!hasSensitive) {
5060        att = sftk_FindAttribute(baseKey,CKA_SENSITIVE);
5061	if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
5062	crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
5063	sftk_FreeAttribute(att);
5064	if (crv != CKR_OK) return crv;
5065    }
5066    if (!hasExtractable) {
5067        att = sftk_FindAttribute(baseKey,CKA_EXTRACTABLE);
5068	if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
5069	crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
5070	sftk_FreeAttribute(att);
5071	if (crv != CKR_OK) return crv;
5072    }
5073
5074    /* we should inherit the parent's always extractable/ never sensitive info,
5075     * but handleObject always forces this attributes, so we would need to do
5076     * something special. */
5077    return CKR_OK;
5078}
5079
5080/*
5081 * make known fixed PKCS #11 key types to their sizes in bytes
5082 */	
5083unsigned long
5084sftk_MapKeySize(CK_KEY_TYPE keyType) 
5085{
5086    switch (keyType) {
5087    case CKK_CDMF:
5088	return 8;
5089    case CKK_DES:
5090	return 8;
5091    case CKK_DES2:
5092	return 16;
5093    case CKK_DES3:
5094	return 24;
5095    /* IDEA and CAST need to be added */
5096    default:
5097	break;
5098    }
5099    return 0;
5100}
5101
5102/*
5103 * SSL Key generation given pre master secret
5104 */
5105#define NUM_MIXERS 9
5106static const char * const mixers[NUM_MIXERS] = { 
5107    "A", 
5108    "BB", 
5109    "CCC", 
5110    "DDDD", 
5111    "EEEEE", 
5112    "FFFFFF", 
5113    "GGGGGGG",
5114    "HHHHHHHH",
5115    "IIIIIIIII" };
5116#define SSL3_PMS_LENGTH 48
5117#define SSL3_MASTER_SECRET_LENGTH 48
5118#define SSL3_RANDOM_LENGTH 32
5119
5120
5121/* NSC_DeriveKey derives a key from a base key, creating a new key object. */
5122CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession,
5123	 CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey,
5124	 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, 
5125						CK_OBJECT_HANDLE_PTR phKey)
5126{
5127    SFTKSession *   session;
5128    SFTKSlot    *   slot	= sftk_SlotFromSessionHandle(hSession);
5129    SFTKObject  *   key;
5130    SFTKObject  *   sourceKey;
5131    SFTKAttribute * att = NULL;
5132    SFTKAttribute * att2 = NULL;
5133    unsigned char * buf;
5134    SHA1Context *   sha;
5135    MD5Context *    md5;
5136    MD2Context *    md2;
5137    CK_ULONG        macSize;
5138    CK_ULONG        tmpKeySize;
5139    CK_ULONG        IVSize;
5140    CK_ULONG        keySize	= 0;
5141    CK_RV           crv 	= CKR_OK;
5142    CK_BBOOL        cktrue	= CK_TRUE;
5143    CK_KEY_TYPE     keyType	= CKK_GENERIC_SECRET;
5144    CK_OBJECT_CLASS classType	= CKO_SECRET_KEY;
5145    CK_KEY_DERIVATION_STRING_DATA *stringPtr;
5146    PRBool          isTLS = PR_FALSE;
5147    PRBool          isDH = PR_FALSE;
5148    SECStatus       rv;
5149    int             i;
5150    unsigned int    outLen;
5151    unsigned char   sha_out[SHA1_LENGTH];
5152    unsigned char   key_block[NUM_MIXERS * MD5_LENGTH];
5153    unsigned char   key_block2[MD5_LENGTH];
5154    PRBool          isFIPS;		
5155    HASH_HashType   hashType;
5156    PRBool          extractValue = PR_TRUE;
5157
5158    CHECK_FORK();
5159
5160    if (!slot) {
5161        return CKR_SESSION_HANDLE_INVALID;
5162    }
5163    /*
5164     * now lets create an object to hang the attributes off of
5165     */
5166    if (phKey) *phKey = CK_INVALID_HANDLE;
5167
5168    key = sftk_NewObject(slot); /* fill in the handle later */
5169    if (key == NULL) {
5170	return CKR_HOST_MEMORY;
5171    }
5172    isFIPS = (slot->slotID == FIPS_SLOT_ID);
5173
5174    /*
5175     * load the template values into the object
5176     */
5177    for (i=0; i < (int) ulAttributeCount; i++) {
5178	crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
5179	if (crv != CKR_OK) break;
5180
5181	if (pTemplate[i].type == CKA_KEY_TYPE) {
5182	    keyType = *(CK_KEY_TYPE *)pTemplate[i].pValue;
5183	}
5184	if (pTemplate[i].type == CKA_VALUE_LEN) {
5185	    keySize = *(CK_ULONG *)pTemplate[i].pValue;
5186	}
5187    }
5188    if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
5189
5190    if (keySize == 0) {
5191	keySize = sftk_MapKeySize(keyType);
5192    }
5193
5194    switch (pMechanism->mechanism) {
5195      case CKM_NSS_JPAKE_ROUND2_SHA1:   /* fall through */
5196      case CKM_NSS_JPAKE_ROUND2_SHA256: /* fall through */
5197      case CKM_NSS_JPAKE_ROUND2_SHA384: /* fall through */
5198      case CKM_NSS_JPAKE_ROUND2_SHA512:
5199          extractValue = PR_FALSE;
5200          classType = CKO_PRIVATE_KEY;
5201          break;
5202      case CKM_NSS_JPAKE_FINAL_SHA1:   /* fall through */
5203      case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */
5204      case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */
5205      case CKM_NSS_JPAKE_FINAL_SHA512:
5206          extractValue = PR_FALSE;
5207          /* fall through */
5208      default:
5209          classType = CKO_SECRET_KEY;
5210    }
5211    
5212    crv = sftk_forceAttribute (key,CKA_CLASS,&classType,sizeof(classType));
5213    if (crv != CKR_OK) {
5214	sftk_FreeObject(key);
5215	return crv;
5216    }
5217
5218    /* look up the base key we're deriving with */ 
5219    session = sftk_SessionFromHandle(hSession);
5220    if (session == NULL) {
5221	sftk_FreeObject(key);
5222        return CKR_SESSION_HANDLE_INVALID;
5223    }
5224
5225    sourceKey = sftk_ObjectFromHandle(hBaseKey,session);
5226    sftk_FreeSession(session);
5227    if (sourceKey == NULL) {
5228	sftk_FreeObject(key);
5229        return CKR_KEY_HANDLE_INVALID;
5230    }
5231
5232    if (extractValue) {
5233        /* get the value of the base key */
5234        att = sftk_FindAttribute(sourceKey,CKA_VALUE);
5235        if (att == NULL) {
5236            sftk_FreeObject(key);
5237            sftk_FreeObject(sourceKey);
5238            return CKR_KEY_HANDLE_INVALID;
5239        }
5240    }
5241
5242    switch (pMechanism->mechanism) {
5243    /*
5244     * generate the master secret 
5245     */
5246    case CKM_TLS_MASTER_KEY_DERIVE:
5247    case CKM_TLS_MASTER_KEY_DERIVE_DH:
5248	isTLS = PR_TRUE;
5249	/* fall thru */
5250    case CKM_SSL3_MASTER_KEY_DERIVE:
5251    case CKM_SSL3_MASTER_KEY_DERIVE_DH:
5252      {
5253	CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master;
5254	SSL3RSAPreMasterSecret *          rsa_pms;
5255	unsigned char                     crsrdata[SSL3_RANDOM_LENGTH * 2];
5256
5257        if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) ||
5258            (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH))
5259		isDH = PR_TRUE;
5260
5261	/* first do the consistancy checks */
5262	if (!isDH && (att->attrib.ulValueLen != SSL3_PMS_LENGTH)) {
5263	    crv = CKR_KEY_TYPE_INCONSISTENT;
5264	    break;
5265	}
5266	att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
5267	if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
5268					CKK_GENERIC_SECRET)) {
5269	    if (att2) sftk_FreeAttribute(att2);
5270	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5271	    break;
5272	}
5273	sftk_FreeAttribute(att2);
5274	if (keyType != CKK_GENERIC_SECRET) {
5275	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5276	    break;
5277	}
5278	if ((keySize != 0) && (keySize != SSL3_MASTER_SECRET_LENGTH)) {
5279	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5280	    break;
5281	}
5282
5283	/* finally do the key gen */
5284	ssl3_master = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)
5285					pMechanism->pParameter;
5286
5287	PORT_Memcpy(crsrdata, 
5288	            ssl3_master->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
5289	PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
5290	            ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
5291
5292	if (ssl3_master->pVersion) {
5293	    SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
5294	    rsa_pms = (SSL3RSAPreMasterSecret *) att->attrib.pValue;
5295	    /* don't leak more key material then necessary for SSL to work */
5296	    if ((sessKey == NULL) || sessKey->wasDerived) {
5297		ssl3_master->pVersion->major = 0xff;
5298		ssl3_master->pVersion->minor = 0xff;
5299	    } else {
5300		ssl3_master->pVersion->major = rsa_pms->client_version[0];
5301		ssl3_master->pVersion->minor = rsa_pms->client_version[1];
5302	    }
5303	}
5304	if (ssl3_master->RandomInfo.ulClientRandomLen != SSL3_RANDOM_LENGTH) {
5305	   crv = CKR_MECHANISM_PARAM_INVALID;
5306	   break;
5307	}
5308	if (ssl3_master->RandomInfo.ulServerRandomLen != SSL3_RANDOM_LENGTH) {
5309	   crv = CKR_MECHANISM_PARAM_INVALID;
5310	   break;
5311	}
5312
5313        if (isTLS) {
5314	    SECStatus status;
5315 	    SECItem crsr   = { siBuffer, NULL, 0 };
5316 	    SECItem master = { siBuffer, NULL, 0 };
5317 	    SECItem pms    = { siBuffer, NULL, 0 };
5318
5319 	    crsr.data   = crsrdata;
5320	    crsr.len    = sizeof crsrdata;
5321 	    master.data = key_block;
5322	    master.len  = SSL3_MASTER_SECRET_LENGTH;
5323 	    pms.data    = (unsigned char*)att->attrib.pValue;
5324	    pms.len     =                 att->attrib.ulValueLen;
5325
5326	    status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
5327	    if (status != SECSuccess) {
5328	    	crv = CKR_FUNCTION_FAILED;
5329		break;
5330	    }
5331	} else {
5332	    /* now allocate the hash contexts */
5333	    md5 = MD5_NewContext();
5334	    if (md5 == NULL) { 
5335		crv = CKR_HOST_MEMORY;
5336		break;
5337	    }
5338	    sha = SHA1_NewContext();
5339	    if (sha == NULL) { 
5340		PORT_Free(md5);
5341		crv = CKR_HOST_MEMORY;
5342		break;
5343	    }
5344            for (i = 0; i < 3; i++) {
5345              SHA1_Begin(sha);
5346              SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
5347              SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
5348			  att->attrib.ulValueLen);
5349              SHA1_Update(sha, crsrdata, sizeof crsrdata);
5350              SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
5351              PORT_Assert(outLen == SHA1_LENGTH);
5352
5353              MD5_Begin(md5);
5354              MD5_Update(md5, (const unsigned char*)att->attrib.pValue, 
5355			 att->attrib.ulValueLen);
5356              MD5_Update(md5, sha_out, outLen);
5357              MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
5358              PORT_Assert(outLen == MD5_LENGTH);
5359            }
5360	    PORT_Free(md5);
5361	    PORT_Free(sha);
5362	}
5363
5364	/* store the results */
5365	crv = sftk_forceAttribute
5366			(key,CKA_VALUE,key_block,SSL3_MASTER_SECRET_LENGTH);
5367	if (crv != CKR_OK) break;
5368	keyType = CKK_GENERIC_SECRET;
5369	crv = sftk_forceAttribute (key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
5370	if (isTLS) {
5371	    /* TLS's master secret is used to "sign" finished msgs with PRF. */
5372	    /* XXX This seems like a hack.   But SFTK_Derive only accepts 
5373	     * one "operation" argument. */
5374	    crv = sftk_forceAttribute(key,CKA_SIGN,  &cktrue,sizeof(CK_BBOOL));
5375	    if (crv != CKR_OK) break;
5376	    crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
5377	    if (crv != CKR_OK) break;
5378	    /* While we're here, we might as well force this, too. */
5379	    crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
5380	    if (crv != CKR_OK) break;
5381	}
5382	break;
5383      }
5384
5385    case CKM_TLS_KEY_AND_MAC_DERIVE:
5386	isTLS = PR_TRUE;
5387	/* fall thru */
5388    case CKM_SSL3_KEY_AND_MAC_DERIVE:
5389      {
5390	CK_SSL3_KEY_MAT_PARAMS *ssl3_keys;
5391	CK_SSL3_KEY_MAT_OUT *   ssl3_keys_out;
5392	CK_ULONG                effKeySize;
5393	unsigned int            block_needed;
5394	unsigned char           srcrdata[SSL3_RANDOM_LENGTH * 2];
5395	unsigned char           crsrdata[SSL3_RANDOM_LENGTH * 2];
5396
5397	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5398	if (crv != CKR_OK) break;
5399
5400	if (att->attrib.ulValueLen != SSL3_MASTER_SECRET_LENGTH) {
5401	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5402	    break;
5403	}
5404	att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
5405	if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
5406					CKK_GENERIC_SECRET)) {
5407	    if (att2) sftk_FreeAttribute(att2);
5408	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
5409	    break;
5410	}
5411	sftk_FreeAttribute(att2);
5412	md5 = MD5_NewContext();
5413	if (md5 == NULL) { 
5414	    crv = CKR_HOST_MEMORY;
5415	    break;
5416	}
5417	sha = SHA1_NewContext();
5418	if (sha == NULL) { 
5419	    PORT_Free(md5);
5420	    crv = CKR_HOST_MEMORY;
5421	    break;
5422	}
5423	ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter;
5424
5425	PORT_Memcpy(srcrdata, 
5426	            ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
5427	PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, 
5428		    ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
5429
5430	PORT_Memcpy(crsrdata, 
5431		    ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
5432	PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
5433		    ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
5434
5435	/*
5436	 * clear out our returned keys so we can recover on failure
5437	 */
5438	ssl3_keys_out = ssl3_keys->pReturnedKeyMaterial;
5439	ssl3_keys_out->hClientMacSecret = CK_INVALID_HANDLE;
5440	ssl3_keys_out->hServerMacSecret = CK_INVALID_HANDLE;
5441	ssl3_keys_out->hClientKey       = CK_INVALID_HANDLE;
5442	ssl3_keys_out->hServerKey       = CK_INVALID_HANDLE;
5443
5444	/*
5445	 * How much key material do we need?
5446	 */
5447	macSize    = ssl3_keys->ulMacSizeInBits/8;
5448	effKeySize = ssl3_keys->ulKeySizeInBits/8;
5449	IVSize     = ssl3_keys->ulIVSizeInBits/8;
5450	if (keySize == 0) {
5451	    effKeySize = keySize;
5452	}
5453	block_needed = 2 * (macSize + effKeySize + 
5454	                    ((!ssl3_keys->bIsExport) * IVSize));
5455	PORT_Assert(block_needed <= sizeof key_block);
5456	if (block_needed > sizeof key_block)
5457	    block_needed = sizeof key_block;
5458
5459	/*
5460	 * generate the key material: This looks amazingly similar to the
5461	 * PMS code, and is clearly crying out for a function to provide it.
5462	 */
5463	if (isTLS) {
5464	    SECStatus     status;
5465	    SECItem       srcr   = { siBuffer, NULL, 0 };
5466	    SECItem       keyblk = { siBuffer, NULL, 0 };
5467	    SECItem       master = { siBuffer, NULL, 0 }; 
5468
5469	    srcr.data   = srcrdata;
5470	    srcr.len    = sizeof srcrdata;
5471	    keyblk.data = key_block;
5472	    keyblk.len  = block_needed;
5473	    master.data = (unsigned char*)att->attrib.pValue;
5474	    master.len  =                 att->attrib.ulValueLen;
5475
5476	    status = TLS_PRF(&master, "key expansion", &srcr, &keyblk,
5477			      isFIPS);
5478	    if (status != SECSuccess) {
5479		goto key_and_mac_derive_fail;
5480	    }
5481	} else {
5482	    unsigned int block_bytes = 0;
5483	    /* key_block = 
5484	     *     MD5(master_secret + SHA('A' + master_secret + 
5485	     *                      ServerHello.random + ClientHello.random)) +
5486	     *     MD5(master_secret + SHA('BB' + master_secret + 
5487	     *                      ServerHello.random + ClientHello.random)) +
5488	     *     MD5(master_secret + SHA('CCC' + master_secret + 
5489	     *                      ServerHello.random + ClientHello.random)) +
5490	     *     [...];
5491	     */
5492	    for (i = 0; i < NUM_MIXERS && block_bytes < block_needed; i++) {
5493	      SHA1_Begin(sha);
5494	      SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
5495	      SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
5496			  att->attrib.ulValueLen);
5497	      SHA1_Update(sha, srcrdata, sizeof srcrdata);
5498	      SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
5499	      PORT_Assert(outLen == SHA1_LENGTH);
5500	      MD5_Begin(md5);
5501	      MD5_Update(md5, (const unsigned char*)att->attrib.pValue,
5502			 att->attrib.ulValueLen);
5503	      MD5_Update(md5, sha_out, outLen);
5504	      MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
5505	      PORT_Assert(outLen == MD5_LENGTH);
5506	      block_bytes += outLen;
5507	    }
5508	}
5509
5510	/*
5511	 * Put the key material where it goes.
5512	 */
5513	i = 0;			/* now shows how much consumed */
5514
5515	/* 
5516	 * The key_block is partitioned as follows:
5517	 * client_write_MAC_secret[CipherSpec.hash_size]
5518	 */
5519	crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
5520					 &ssl3_keys_out->hClientMacSecret);
5521	if (crv != CKR_OK)
5522	    goto key_and_mac_derive_fail;
5523
5524	i += macSize;
5525
5526	/* 
5527	 * server_write_MAC_secret[CipherSpec.hash_size]
5528	 */
5529	crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
5530					    &ssl3_keys_out->hServerMacSecret);
5531	if (crv != CKR_OK) {
5532	    goto key_and_mac_derive_fail;
5533	}
5534	i += macSize;
5535
5536	if (keySize) {
5537	    if (!ssl3_keys->bIsExport) {
5538		/* 
5539		** Generate Domestic write keys and IVs.
5540		** client_write_key[CipherSpec.key_material]
5541		*/
5542		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
5543					keySize, &ssl3_keys_out->hClientKey);
5544		if (crv != CKR_OK) {
5545		    goto key_and_mac_derive_fail;
5546		}
5547		i += keySize;
5548
5549		/* 
5550		** server_write_key[CipherSpec.key_material]
5551		*/
5552		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
5553					keySize, &ssl3_keys_out->hServerKey);
5554		if (crv != CKR_OK) {
5555		    goto key_and_mac_derive_fail;
5556		}
5557		i += keySize;
5558
5559		/* 
5560		** client_write_IV[CipherSpec.IV_size]
5561		*/
5562		if (IVSize > 0) {
5563		    PORT_Memcpy(ssl3_keys_out->pIVClient, 
5564		                &key_block[i], IVSize);
5565		    i += IVSize;
5566		}
5567
5568		/* 
5569		** server_write_IV[CipherSpec.IV_size]
5570		*/
5571		if (IVSize > 0) {
5572		    PORT_Memcpy(ssl3_keys_out->pIVServer, 
5573		                &key_block[i], IVSize);
5574		    i += IVSize;
5575		}
5576		PORT_Assert(i <= sizeof key_block);
5577
5578	    } else if (!isTLS) {
5579
5580		/*
5581		** Generate SSL3 Export write keys and IVs.
5582		** client_write_key[CipherSpec.key_material]
5583		** final_client_write_key = MD5(client_write_key +
5584		**                   ClientHello.random + ServerHello.random);
5585		*/
5586		MD5_Begin(md5);
5587		MD5_Update(md5, &key_block[i], effKeySize);
5588            	MD5_Update(md5, crsrdata, sizeof crsrdata);
5589		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5590		i += effKeySize;
5591		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
5592				 	keySize,&ssl3_keys_out->hClientKey);
5593		if (crv != CKR_OK) {
5594		    goto key_and_mac_derive_fail;
5595		}
5596
5597		/*
5598		** server_write_key[CipherSpec.key_material]
5599		** final_server_write_key = MD5(server_write_key +
5600		**                    ServerHello.random + ClientHello.random);
5601		*/
5602		MD5_Begin(md5);
5603		MD5_Update(md5, &key_block[i], effKeySize);
5604            	MD5_Update(md5, srcrdata, sizeof srcrdata);
5605		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5606		i += effKeySize;
5607		crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
5608					 keySize,&ssl3_keys_out->hServerKey);
5609		if (crv != CKR_OK) {
5610		    goto key_and_mac_derive_fail;
5611		}
5612
5613		/*
5614		** client_write_IV = 
5615		**	MD5(ClientHello.random + ServerHello.random);
5616		*/
5617		MD5_Begin(md5);
5618            	MD5_Update(md5, crsrdata, sizeof crsrdata);
5619		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5620		PORT_Memcpy(ssl3_keys_out->pIVClient, key_block2, IVSize);
5621
5622		/*
5623		** server_write_IV = 
5624		**	MD5(ServerHello.random + ClientHello.random);
5625		*/
5626		MD5_Begin(md5);
5627            	MD5_Update(md5, srcrdata, sizeof srcrdata);
5628		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
5629		PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize);
5630
5631	    } else {
5632
5633		/*
5634		** Generate TLS Export write keys and IVs.
5635		*/
5636		SECStatus     status;
5637		SECItem       secret = { siBuffer, NULL, 0 };
5638		SECItem       crsr   = { siBuffer, NULL, 0 };
5639		SECItem       keyblk = { siBuffer, NULL, 0 };
5640
5641		/*
5642		** client_write_key[CipherSpec.key_material]
5643		** final_client_write_key = PRF(client_write_key, 
5644		**                              "client write key",
5645		**                              client_random + server_random);
5646		*/
5647		secret.data = &key_block[i];
5648		secret.len  = effKeySize;
5649		i          += effKeySize;
5650		crsr.data   = crsrdata;
5651		crsr.len    = sizeof crsrdata;
5652		keyblk.data = key_block2;
5653		keyblk.len  = sizeof key_block2;
5654		status = TLS_PRF(&secret, "client write key", &crsr, &keyblk,
5655				  isFIPS);
5656		if (status != SECSuccess) {
5657		    goto key_and_mac_derive_fail;
5658		}
5659		crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
5660				       keySize, &ssl3_keys_out->hClientKey);
5661		if (crv != CKR_OK) {
5662		    goto key_and_mac_derive_fail;
5663		}
5664
5665		/*
5666		** server_write_key[CipherSpec.key_material]
5667		** final_server_write_key = PRF(server_write_key,
5668		**                              "server write key",
5669		**                              client_random + server_random);
5670		*/
5671		secret.data = &key_block[i];
5672		secret.len  = effKeySize;
5673		i          += effKeySize;
5674		keyblk.data = key_block2;
5675		keyblk.len  = sizeof key_block2;
5676		status = TLS_PRF(&secret, "server write key", &crsr, &keyblk,
5677				  isFIPS);
5678		if (status != SECSuccess) {
5679		    goto key_and_mac_derive_fail;
5680		}
5681		crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
5682				       keySize, &ssl3_keys_out->hServerKey);
5683		if (crv != CKR_OK) {
5684		    goto key_and_mac_derive_fail;
5685		}
5686
5687		/*
5688		** iv_block = PRF("", "IV block", 
5689		**                    client_random + server_random);
5690		** client_write_IV[SecurityParameters.IV_size]
5691		** server_write_IV[SecurityParameters.IV_size]
5692		*/
5693		if (IVSize) {
5694		    secret.data = NULL;
5695		    secret.len  = 0;
5696		    keyblk.data = &key_block[i];
5697		    keyblk.len  = 2 * IVSize;
5698		    status = TLS_PRF(&secret, "IV block", &crsr, &keyblk,
5699				      isFIPS);
5700		    if (status != SECSuccess) {
5701			goto key_and_mac_derive_fail;
5702		    }
5703		    PORT_Memcpy(ssl3_keys_out->pIVClient, keyblk.data, IVSize);
5704		    PORT_Memcpy(ssl3_keys_out->pIVServer, keyblk.data + IVSize,
5705                                IVSize);
5706		}
5707	    }
5708	}
5709
5710	crv = CKR_OK;
5711
5712	if (0) {
5713key_and_mac_derive_fail:
5714	    if (crv == CKR_OK)
5715	    	crv = CKR_FUNCTION_FAILED;
5716	    sftk_freeSSLKeys(hSession, ssl3_keys_out);
5717	}
5718	MD5_DestroyContext(md5, PR_TRUE);
5719	SHA1_DestroyContext(sha, PR_TRUE);
5720	sftk_FreeObject(key);
5721	key = NULL;
5722	break;
5723      }
5724
5725    case CKM_CONCATENATE_BASE_AND_KEY:
5726      {
5727	SFTKObject *newKey;
5728
5729	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5730	if (crv != CKR_OK) break;
5731
5732	session = sftk_SessionFromHandle(hSession);
5733	if (session == NULL) {
5734            crv = CKR_SESSION_HANDLE_INVALID;
5735	    break;
5736    	}
5737
5738	newKey = sftk_ObjectFromHandle(*(CK_OBJECT_HANDLE *)
5739					pMechanism->pParameter,session);
5740	sftk_FreeSession(session);
5741	if ( newKey == NULL) {
5742            crv = CKR_KEY_HANDLE_INVALID;
5743	    break;
5744	}
5745
5746	if (sftk_isTrue(newKey,CKA_SENSITIVE)) {
5747	    crv = sftk_forceAttribute(newKey,CKA_SENSITIVE,&cktrue,
5748							sizeof(CK_BBOOL));
5749	    if (crv != CKR_OK) {
5750		sftk_FreeObject(newKey);
5751		break;
5752	    }
5753	}
5754
5755	att2 = sftk_FindAttribute(newKey,CKA_VALUE);
5756	if (att2 == NULL) {
5757	    sftk_FreeObject(newKey);
5758            crv = CKR_KEY_HANDLE_INVALID;
5759	    break;
5760	}
5761	tmpKeySize = att->attrib.ulValueLen+att2->attrib.ulValueLen;
5762	if (keySize == 0) keySize = tmpKeySize;
5763	if (keySize > tmpKeySize) {
5764	    sftk_FreeObject(newKey);
5765	    sftk_FreeAttribute(att2);
5766	    crv = CKR_TEMPLATE_INCONSISTENT;
5767	    break;
5768	}
5769	buf = (unsigned char*)PORT_Alloc(tmpKeySize);
5770	if (buf == NULL) {
5771	    sftk_FreeAttribute(att2);
5772	    sftk_FreeObject(newKey);
5773	    crv = CKR_HOST_MEMORY;	
5774	    break;
5775	}
5776
5777	PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
5778	PORT_Memcpy(buf+att->attrib.ulValueLen,
5779				att2->attrib.pValue,att2->attrib.ulValueLen);
5780
5781	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5782	PORT_ZFree(buf,tmpKeySize);
5783	sftk_FreeAttribute(att2);
5784	sftk_FreeObject(newKey);
5785	break;
5786      }
5787
5788    case CKM_CONCATENATE_BASE_AND_DATA:
5789	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5790	if (crv != CKR_OK) break;
5791
5792	stringPtr = (CK_KEY_DERIVATION_STRING_DATA *) pMechanism->pParameter;
5793	tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
5794	if (keySize == 0) keySize = tmpKeySize;
5795	if (keySize > tmpKeySize) {
5796	    crv = CKR_TEMPLATE_INCONSISTENT;
5797	    break;
5798	}
5799	buf = (unsigned char*)PORT_Alloc(tmpKeySize);
5800	if (buf == NULL) {
5801	    crv = CKR_HOST_MEMORY;
5802	    break;
5803	}
5804
5805	PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
5806	PORT_Memcpy(buf+att->attrib.ulValueLen,stringPtr->pData,
5807							stringPtr->ulLen);
5808
5809	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5810	PORT_ZFree(buf,tmpKeySize);
5811	break;
5812    case CKM_CONCATENATE_DATA_AND_BASE:
5813	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5814	if (crv != CKR_OK) break;
5815
5816	stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
5817	tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
5818	if (keySize == 0) keySize = tmpKeySize;
5819	if (keySize > tmpKeySize) {
5820	    crv = CKR_TEMPLATE_INCONSISTENT;
5821	    break;
5822	}
5823	buf = (unsigned char*)PORT_Alloc(tmpKeySize);
5824	if (buf == NULL) {
5825	    crv = CKR_HOST_MEMORY;
5826	    break;
5827	}
5828
5829	PORT_Memcpy(buf,stringPtr->pData,stringPtr->ulLen);
5830	PORT_Memcpy(buf+stringPtr->ulLen,att->attrib.pValue,
5831							att->attrib.ulValueLen);
5832
5833	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5834	PORT_ZFree(buf,tmpKeySize);
5835	break;
5836    case CKM_XOR_BASE_AND_DATA:
5837	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5838	if (crv != CKR_OK) break;
5839
5840	stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
5841	tmpKeySize = PR_MIN(att->attrib.ulValueLen,stringPtr->ulLen);
5842	if (keySize == 0) keySize = tmpKeySize;
5843	if (keySize > tmpKeySize) {
5844	    crv = CKR_TEMPLATE_INCONSISTENT;
5845	    break;
5846	}
5847	buf = (unsigned char*)PORT_Alloc(keySize);
5848	if (buf == NULL) {
5849	    crv = CKR_HOST_MEMORY;
5850	    break;
5851	}
5852
5853	
5854	PORT_Memcpy(buf,att->attrib.pValue,keySize);
5855	for (i=0; i < (int)keySize; i++) {
5856	    buf[i] ^= stringPtr->pData[i];
5857	}
5858
5859	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5860	PORT_ZFree(buf,keySize);
5861	break;
5862
5863    case CKM_EXTRACT_KEY_FROM_KEY:
5864      {
5865	/* the following assumes 8 bits per byte */
5866	CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter;
5867	CK_ULONG shift   = extract & 0x7;      /* extract mod 8 the fast way */
5868	CK_ULONG offset  = extract >> 3;       /* extract div 8 the fast way */
5869
5870	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
5871	if (crv != CKR_OK) break;
5872
5873	if (keySize == 0)  {
5874	    crv = CKR_TEMPLATE_INCOMPLETE;
5875	    break;
5876	}
5877	/* make sure we have enough bits in the original key */
5878	if (att->attrib.ulValueLen < 
5879			(offset + keySize + ((shift != 0)? 1 :0)) ) {
5880	    crv = CKR_MECHANISM_PARAM_INVALID;
5881	    break;
5882	}
5883	buf = (unsigned char*)PORT_Alloc(keySize);
5884	if (buf == NULL) {
5885	    crv = CKR_HOST_MEMORY;
5886	    break;
5887	}
5888
5889	/* copy the bits we need into the new key */	
5890	for (i=0; i < (int)keySize; i++) {
5891	    unsigned char *value =
5892			 ((unsigned char *)att->attrib.pValue)+offset+i;
5893	    if (shift) {
5894	        buf[i] = (value[0] << (shift)) | (value[1] >> (8 - shift));
5895	    } else {
5896		buf[i] = value[0];
5897	    }
5898	}
5899
5900	crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
5901	PORT_ZFree(buf,keySize);
5902	break;
5903      }
5904    case CKM_MD2_KEY_DERIVATION:
5905	if (keySize == 0) keySize = MD2_LENGTH;
5906	if (keySize > MD2_LENGTH) {
5907	    crv = CKR_TEMPLATE_INCONSISTENT;
5908	    break;
5909	}
5910	/* now allocate the hash contexts */
5911	md2 = MD2_NewContext();
5912	if (md2 == NULL) { 
5913	    crv = CKR_HOST_MEMORY;
5914	    break;
5915	}
5916	MD2_Begin(md2);
5917	MD2_Update(md2,(const unsigned char*)att->attrib.pValue,
5918		   att->attrib.ulValueLen);
5919	MD2_End(md2,key_block,&outLen,MD2_LENGTH);
5920	MD2_DestroyContext(md2, PR_TRUE);
5921
5922	crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
5923	break;
5924    case CKM_MD5_KEY_DERIVATION:
5925	if (keySize == 0) keySize = MD5_LENGTH;
5926	if (keySize > MD5_LENGTH) {
5927	    crv = CKR_TEMPLATE_INCONSISTENT;
5928	    break;
5929	}
5930	/* now allocate the hash contexts */
5931	md5 = MD5_NewContext();
5932	if (md5 == NULL) { 
5933	    crv = CKR_HOST_MEMORY;
5934	    break;
5935	}
5936	MD5_Begin(md5);
5937	MD5_Update(md5,(const unsigned char*)att->attrib.pValue,
5938		   att->attrib.ulValueLen);
5939	MD5_End(md5,key_block,&outLen,MD5_LENGTH);
5940	MD5_DestroyContext(md5, PR_TRUE);
5941
5942	crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
5943	break;
5944     case CKM_SHA1_KEY_DERIVATION:
5945	if (keySize == 0) keySize = SHA1_LENGTH;
5946	if (keySize > SHA1_LENGTH) {
5947	    crv = CKR_TEMPLATE_INCONSISTENT;
5948	    break;
5949	}
5950	/* now allocate the hash contexts */
5951	sha = SHA1_NewContext();
5952	if (sha == NULL) { 
5953	    crv = CKR_HOST_MEMORY;
5954	    break;
5955	}
5956	SHA1_Begin(sha);
5957	SHA1_Update(sha,(const unsigned char*)att->attrib.pValue,
5958		    att->attrib.ulValueLen);
5959	SHA1_End(sha,key_block,&outLen,SHA1_LENGTH);
5960	SHA1_DestroyContext(sha, PR_TRUE);
5961
5962	crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize);
5963	break;
5964
5965    case CKM_DH_PKCS_DERIVE:
5966      {
5967	SECItem  derived,  dhPublic;
5968	SECItem  dhPrime,  dhValue;
5969	/* sourceKey - values for the local existing low key */
5970	/* get prime and value attributes */
5971	crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME); 
5972	if (crv != SECSuccess) break;
5973	crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE); 
5974	if (crv != SECSuccess) {
5975 	    PORT_Free(dhPrime.data);
5976	    break;
5977	}
5978
5979	dhPublic.data = pMechanism->pParameter;
5980	dhPublic.len  = pMechanism->ulParameterLen;
5981
5982	/* calculate private value - oct */
5983	rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize); 
5984
5985	PORT_Free(dhPrime.data);
5986	PORT_Free(dhValue.data);
5987     
5988	if (rv == SECSuccess) {
5989	    sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
5990	    PORT_ZFree(derived.data, derived.len);
5991	} else
5992	    crv = CKR_HOST_MEMORY;
5993	    
5994	break;
5995      }
5996
5997#ifdef NSS_ENABLE_ECC
5998    case CKM_ECDH1_DERIVE:
5999    case CKM_ECDH1_COFACTOR_DERIVE:
6000      {
6001	SECItem  ecScalar, ecPoint;
6002	SECItem  tmp;
6003	PRBool   withCofactor = PR_FALSE;
6004	unsigned char secret_hash[20];
6005	unsigned char *secret;
6006	unsigned char *keyData = NULL;
6007	int secretlen, curveLen, pubKeyLen;
6008	CK_ECDH1_DERIVE_PARAMS *mechParams;
6009	NSSLOWKEYPrivateKey *privKey;
6010	PLArenaPool *arena = NULL;
6011
6012	/* Check mechanism parameters */
6013	mechParams = (CK_ECDH1_DERIVE_PARAMS *) pMechanism->pParameter;
6014	if ((pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) ||
6015	    ((mechParams->kdf == CKD_NULL) &&
6016		((mechParams->ulSharedDataLen != 0) || 
6017		    (mechParams->pSharedData != NULL)))) {
6018	    crv = CKR_MECHANISM_PARAM_INVALID;
6019	    break;
6020	}
6021
6022	privKey = sftk_GetPrivKey(sourceKey, CKK_EC, &crv);
6023	if (privKey == NULL) {
6024	    break;
6025	}
6026
6027	/* Now we are working with a non-NULL private key */
6028	SECITEM_CopyItem(NULL, &ecScalar, &privKey->u.ec.privateValue);
6029
6030	ecPoint.data = mechParams->pPublicData;
6031	ecPoint.len  = mechParams->ulPublicDataLen;
6032
6033	curveLen = (privKey->u.ec.ecParams.fieldID.size +7)/8;
6034	pubKeyLen = (2*curveLen) + 1;
6035
6036	/* if the len is too small, can't be a valid point */
6037	if (ecPoint.len < pubKeyLen) {
6038	    goto ec_loser;
6039	}
6040	/* if the len is too large, must be an encoded point (length is
6041	 * equal case just falls through */
6042	if (ecPoint.len > pubKeyLen) {
6043	    SECItem newPoint;
6044
6045	    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
6046	    if (arena == NULL) {
6047		goto ec_loser;
6048	    }
6049
6050	    rv = SEC_QuickDERDecodeItem(arena, &newPoint, 
6051					SEC_ASN1_GET(SEC_OctetStringTemplate), 
6052					&ecPoint);
6053	    if (rv != SECSuccess) {
6054		goto ec_loser;
6055	    }
6056	    ecPoint = newPoint;
6057	}
6058
6059	if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
6060	    withCofactor = PR_TRUE;
6061	} else {
6062	    /* When not using cofactor derivation, one should
6063	     * validate the public key to avoid small subgroup
6064	     * attacks.
6065	     */
6066	    if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint) 
6067		!= SECSuccess) {
6068		goto ec_loser;
6069	    }
6070	}
6071
6072	rv =