PageRenderTime 141ms CodeModel.GetById 19ms app.highlight 103ms RepoModel.GetById 0ms 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

Large files files are truncated, but you can click here to view the full 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 t…

Large files files are truncated, but you can click here to view the full file