Back to index

lightning-sunbird  0.9+nobinonly
pkcs11c.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Stephen Henson <stephen.henson@gemplus.com>
00023  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 /*
00039  * This file implements PKCS 11 on top of our existing security modules
00040  *
00041  * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
00042  *   This implementation has two slots:
00043  *     slot 1 is our generic crypto support. It does not require login.
00044  *   It supports Public Key ops, and all they bulk ciphers and hashes. 
00045  *   It can also support Private Key ops for imported Private keys. It does 
00046  *   not have any token storage.
00047  *     slot 2 is our private key support. It requires a login before use. It
00048  *   can store Private Keys and Certs as token objects. Currently only private
00049  *   keys and their associated Certificates are saved on the token.
00050  *
00051  *   In this implementation, session objects are only visible to the session
00052  *   that created or generated them.
00053  */
00054 #include "seccomon.h"
00055 #include "secitem.h"
00056 #include "secport.h"
00057 #include "blapi.h"
00058 #include "pqgutil.h"
00059 #include "pkcs11.h"
00060 #include "pkcs11i.h"
00061 #include "lowkeyi.h"
00062 #include "pcert.h"
00063 #include "sechash.h"
00064 #include "secder.h"
00065 #include "secdig.h"
00066 #include "lowpbe.h"  /* We do PBE below */
00067 #include "pkcs11t.h"
00068 #include "secoid.h"
00069 #include "alghmac.h"
00070 #include "softoken.h"
00071 #include "secasn1.h"
00072 #include "secerr.h"
00073 
00074 #include "pcert.h"
00075 #include "ssl3prot.h"       /* for SSL3_RANDOM_LENGTH */
00076 #include "prprf.h"
00077 
00078 #define __PASTE(x,y)    x##y
00079 
00080 /*
00081  * we renamed all our internal functions, get the correct
00082  * definitions for them...
00083  */ 
00084 #undef CK_PKCS11_FUNCTION_INFO
00085 #undef CK_NEED_ARG_LIST
00086 
00087 #define CK_EXTERN extern
00088 #define CK_PKCS11_FUNCTION_INFO(func) \
00089               CK_RV __PASTE(NS,func)
00090 #define CK_NEED_ARG_LIST    1
00091  
00092 #include "pkcs11f.h"
00093 
00094 static void sftk_Null(void *data, PRBool freeit)
00095 {
00096     return;
00097 } 
00098 
00099 #ifdef NSS_ENABLE_ECC
00100 extern SECStatus EC_DecodeParams(const SECItem *encodedParams, 
00101                              ECParams **ecparams);
00102 #ifdef EC_DEBUG
00103 #define SEC_PRINT(str1, str2, num, sitem) \
00104     printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
00105             str1, str2, num, sitem->len); \
00106     for (i = 0; i < sitem->len; i++) { \
00107            printf("%02x:", sitem->data[i]); \
00108     } \
00109     printf("\n") 
00110 #else
00111 #define SEC_PRINT(a, b, c, d) 
00112 #endif
00113 #endif /* NSS_ENABLE_ECC */
00114 
00115 /*
00116  * free routines.... Free local type  allocated data, and convert
00117  * other free routines to the destroy signature.
00118  */
00119 static void
00120 sftk_FreePrivKey(NSSLOWKEYPrivateKey *key, PRBool freeit)
00121 {
00122     nsslowkey_DestroyPrivateKey(key);
00123 }
00124 
00125 static void
00126 sftk_Space(void *data, PRBool freeit)
00127 {
00128     PORT_Free(data);
00129 } 
00130 
00131 
00132 /*
00133  * turn a CDMF key into a des key. CDMF is an old IBM scheme to export DES by
00134  * Deprecating a full des key to 40 bit key strenth.
00135  */
00136 static CK_RV
00137 sftk_cdmf2des(unsigned char *cdmfkey, unsigned char *deskey)
00138 {
00139     unsigned char key1[8] = { 0xc4, 0x08, 0xb0, 0x54, 0x0b, 0xa1, 0xe0, 0xae };
00140     unsigned char key2[8] = { 0xef, 0x2c, 0x04, 0x1c, 0xe6, 0x38, 0x2f, 0xe6 };
00141     unsigned char enc_src[8];
00142     unsigned char enc_dest[8];
00143     unsigned int leng,i;
00144     DESContext *descx;
00145     SECStatus rv;
00146     
00147     
00148     /* zero the parity bits */
00149     for (i=0; i < 8; i++) {
00150        enc_src[i] = cdmfkey[i] & 0xfe;
00151     }
00152 
00153     /* encrypt with key 1 */
00154     descx = DES_CreateContext(key1, NULL, NSS_DES, PR_TRUE);
00155     if (descx == NULL) return CKR_HOST_MEMORY;
00156     rv = DES_Encrypt(descx, enc_dest, &leng, 8, enc_src, 8);
00157     DES_DestroyContext(descx,PR_TRUE);
00158     if (rv != SECSuccess) return CKR_DEVICE_ERROR;
00159 
00160     /* xor source with des, zero the parity bits and depricate the key*/
00161     for (i=0; i < 8; i++) {
00162        if (i & 1) {
00163            enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0xfe;
00164        } else {
00165            enc_src[i] = (enc_src[i] ^ enc_dest[i]) & 0x0e;
00166        }
00167     }
00168 
00169     /* encrypt with key 2 */
00170     descx = DES_CreateContext(key2, NULL, NSS_DES, PR_TRUE);
00171     if (descx == NULL) return CKR_HOST_MEMORY;
00172     rv = DES_Encrypt(descx, deskey, &leng, 8, enc_src, 8);
00173     DES_DestroyContext(descx,PR_TRUE);
00174     if (rv != SECSuccess) return CKR_DEVICE_ERROR;
00175 
00176     /* set the corret parity on our new des key */      
00177     sftk_FormatDESKey(deskey, 8);
00178     return CKR_OK;
00179 }
00180 
00181 
00182 /* NSC_DestroyObject destroys an object. */
00183 CK_RV
00184 NSC_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
00185 {
00186     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
00187     SFTKSession *session;
00188     SFTKObject *object;
00189     SFTKFreeStatus status;
00190 
00191     /*
00192      * This whole block just makes sure we really can destroy the
00193      * requested object.
00194      */
00195     session = sftk_SessionFromHandle(hSession);
00196     if (session == NULL) {
00197         return CKR_SESSION_HANDLE_INVALID;
00198     }
00199 
00200     object = sftk_ObjectFromHandle(hObject,session);
00201     if (object == NULL) {
00202        sftk_FreeSession(session);
00203        return CKR_OBJECT_HANDLE_INVALID;
00204     }
00205 
00206     /* don't destroy a private object if we aren't logged in */
00207     if ((!slot->isLoggedIn) && (slot->needLogin) &&
00208                             (sftk_isTrue(object,CKA_PRIVATE))) {
00209        sftk_FreeSession(session);
00210        sftk_FreeObject(object);
00211        return CKR_USER_NOT_LOGGED_IN;
00212     }
00213 
00214     /* don't destroy a token object if we aren't in a rw session */
00215 
00216     if (((session->info.flags & CKF_RW_SESSION) == 0) &&
00217                             (sftk_isTrue(object,CKA_TOKEN))) {
00218        sftk_FreeSession(session);
00219        sftk_FreeObject(object);
00220        return CKR_SESSION_READ_ONLY;
00221     }
00222 
00223     sftk_DeleteObject(session,object);
00224 
00225     sftk_FreeSession(session);
00226 
00227     /*
00228      * get some indication if the object is destroyed. Note: this is not
00229      * 100%. Someone may have an object reference outstanding (though that
00230      * should not be the case by here. Also note that the object is "half"
00231      * destroyed. Our internal representation is destroyed, but it may still
00232      * be in the data base.
00233      */
00234     status = sftk_FreeObject(object);
00235 
00236     return (status != SFTK_DestroyFailure) ? CKR_OK : CKR_DEVICE_ERROR;
00237 }
00238 
00239 
00240 /*
00241  ************** Crypto Functions:     Utilities ************************
00242  */
00243 
00244 
00245 /* 
00246  * return a context based on the SFTKContext type.
00247  */
00248 SFTKSessionContext *
00249 sftk_ReturnContextByType(SFTKSession *session, SFTKContextType type)
00250 {
00251     switch (type) {
00252        case SFTK_ENCRYPT:
00253        case SFTK_DECRYPT:
00254            return session->enc_context;
00255        case SFTK_HASH:
00256            return session->hash_context;
00257        case SFTK_SIGN:
00258        case SFTK_SIGN_RECOVER:
00259        case SFTK_VERIFY:
00260        case SFTK_VERIFY_RECOVER:
00261            return session->hash_context;
00262     }
00263     return NULL;
00264 }
00265 
00266 /* 
00267  * change a context based on the SFTKContext type.
00268  */
00269 void
00270 sftk_SetContextByType(SFTKSession *session, SFTKContextType type, 
00271                                           SFTKSessionContext *context)
00272 {
00273     switch (type) {
00274        case SFTK_ENCRYPT:
00275        case SFTK_DECRYPT:
00276            session->enc_context = context;
00277            break;
00278        case SFTK_HASH:
00279            session->hash_context = context;
00280            break;
00281        case SFTK_SIGN:
00282        case SFTK_SIGN_RECOVER:
00283        case SFTK_VERIFY:
00284        case SFTK_VERIFY_RECOVER:
00285            session->hash_context = context;
00286            break;
00287     }
00288     return;
00289 }
00290 
00291 /*
00292  * code to grab the context. Needed by every C_XXXUpdate, C_XXXFinal,
00293  * and C_XXX function. The function takes a session handle, the context type,
00294  * and wether or not the session needs to be multipart. It returns the context,
00295  * and optionally returns the session pointer (if sessionPtr != NULL) if session
00296  * pointer is returned, the caller is responsible for freeing it.
00297  */
00298 static CK_RV
00299 sftk_GetContext(CK_SESSION_HANDLE handle,SFTKSessionContext **contextPtr,
00300        SFTKContextType type, PRBool needMulti, SFTKSession **sessionPtr)
00301 {
00302     SFTKSession *session;
00303     SFTKSessionContext *context;
00304 
00305     session = sftk_SessionFromHandle(handle);
00306     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
00307     context = sftk_ReturnContextByType(session,type);
00308     /* make sure the context is valid */
00309     if((context==NULL)||(context->type!=type)||(needMulti&&!(context->multi))){
00310         sftk_FreeSession(session);
00311        return CKR_OPERATION_NOT_INITIALIZED;
00312     }
00313     *contextPtr = context;
00314     if (sessionPtr != NULL) {
00315        *sessionPtr = session;
00316     } else {
00317        sftk_FreeSession(session);
00318     }
00319     return CKR_OK;
00320 }
00321 
00322 /*
00323  ************** Crypto Functions:     Encrypt ************************
00324  */
00325 
00326 /*
00327  * All the NSC_InitXXX functions have a set of common checks and processing they
00328  * all need to do at the beginning. This is done here.
00329  */
00330 static CK_RV
00331 sftk_InitGeneric(SFTKSession *session,SFTKSessionContext **contextPtr,
00332                SFTKContextType ctype,SFTKObject **keyPtr,
00333                CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
00334                CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
00335 {
00336     SFTKObject *key = NULL;
00337     SFTKAttribute *att;
00338     SFTKSessionContext *context;
00339 
00340     /* We can only init if there is not current context active */
00341     if (sftk_ReturnContextByType(session,ctype) != NULL) {
00342        return CKR_OPERATION_ACTIVE;
00343     }
00344 
00345     /* find the key */
00346     if (keyPtr) {
00347         key = sftk_ObjectFromHandle(hKey,session);
00348         if (key == NULL) {
00349            return CKR_KEY_HANDLE_INVALID;
00350        }
00351 
00352        /* make sure it's a valid  key for this operation */
00353        if (((key->objclass != CKO_SECRET_KEY) && (key->objclass != pubKeyType))
00354                                    || !sftk_isTrue(key,operation)) {
00355            sftk_FreeObject(key);
00356            return CKR_KEY_TYPE_INCONSISTENT;
00357        }
00358        /* get the key type */
00359        att = sftk_FindAttribute(key,CKA_KEY_TYPE);
00360        if (att == NULL) {
00361            sftk_FreeObject(key);
00362            return CKR_KEY_TYPE_INCONSISTENT;
00363        }
00364        PORT_Assert(att->attrib.ulValueLen == sizeof(CK_KEY_TYPE));
00365        if (att->attrib.ulValueLen != sizeof(CK_KEY_TYPE)) {
00366            sftk_FreeAttribute(att);
00367            sftk_FreeObject(key);
00368            return CKR_ATTRIBUTE_VALUE_INVALID;
00369        }
00370        PORT_Memcpy(keyTypePtr, att->attrib.pValue, sizeof(CK_KEY_TYPE));
00371        sftk_FreeAttribute(att);
00372        *keyPtr = key;
00373     }
00374 
00375     /* allocate the context structure */
00376     context = (SFTKSessionContext *)PORT_Alloc(sizeof(SFTKSessionContext));
00377     if (context == NULL) {
00378        if (key) sftk_FreeObject(key);
00379        return CKR_HOST_MEMORY;
00380     }
00381     context->type = ctype;
00382     context->multi = PR_TRUE;
00383     context->cipherInfo = NULL;
00384     context->hashInfo = NULL;
00385     context->doPad = PR_FALSE;
00386     context->padDataLength = 0;
00387     context->key = key;
00388     context->blockSize = 0;
00389 
00390     *contextPtr = context;
00391     return CKR_OK;
00392 }
00393 
00394 /* NSC_CryptInit initializes an encryption/Decryption operation. */
00395 /* This function is used by NSC_EncryptInit, NSC_DecryptInit, 
00396  *                          NSC_WrapKey, NSC_UnwrapKey, 
00397  *                          NSC_SignInit, NSC_VerifyInit (via sftk_InitCBCMac),
00398  * The only difference in their uses is the value of etype.
00399  */
00400 static CK_RV
00401 sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
00402                CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE etype,
00403                SFTKContextType contextType, PRBool isEncrypt)
00404 {
00405     SFTKSession *session;
00406     SFTKObject *key;
00407     SFTKSessionContext *context;
00408     SFTKAttribute *att;
00409     CK_RC2_CBC_PARAMS *rc2_param;
00410 #if NSS_SOFTOKEN_DOES_RC5
00411     CK_RC5_CBC_PARAMS *rc5_param;
00412     SECItem rc5Key;
00413 #endif
00414     CK_KEY_TYPE key_type;
00415     CK_RV crv = CKR_OK;
00416     unsigned effectiveKeyLength;
00417     unsigned char newdeskey[24];
00418     PRBool useNewKey=PR_FALSE;
00419     int t;
00420 
00421     crv = sftk_MechAllowsOperation(pMechanism->mechanism, etype);
00422     if (crv != CKR_OK) 
00423        return crv;
00424 
00425     session = sftk_SessionFromHandle(hSession);
00426     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
00427 
00428     crv = sftk_InitGeneric(session,&context,contextType,&key,hKey,&key_type,
00429                      isEncrypt ?CKO_PUBLIC_KEY:CKO_PRIVATE_KEY, etype);
00430                                           
00431     if (crv != CKR_OK) {
00432        sftk_FreeSession(session);
00433        return crv;
00434     }
00435 
00436     context->doPad = PR_FALSE;
00437     switch(pMechanism->mechanism) {
00438     case CKM_RSA_PKCS:
00439     case CKM_RSA_X_509:
00440        if (key_type != CKK_RSA) {
00441            crv = CKR_KEY_TYPE_INCONSISTENT;
00442            break;
00443        }
00444        context->multi = PR_FALSE;
00445        if (isEncrypt) {
00446            NSSLOWKEYPublicKey *pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
00447            if (pubKey == NULL) {
00448               break;
00449            }
00450            context->maxLen = nsslowkey_PublicModulusLen(pubKey);
00451            context->cipherInfo =  (void *)pubKey;
00452            context->update = (SFTKCipher) 
00453               (pMechanism->mechanism == CKM_RSA_X_509
00454                                    ? RSA_EncryptRaw : RSA_EncryptBlock);
00455        } else {
00456            NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
00457            if (privKey == NULL) {
00458               break;
00459            }
00460            context->maxLen = nsslowkey_PrivateModulusLen(privKey);
00461            context->cipherInfo =  (void *)privKey;
00462            context->update = (SFTKCipher) 
00463               (pMechanism->mechanism == CKM_RSA_X_509
00464                                    ? RSA_DecryptRaw : RSA_DecryptBlock);
00465        }
00466        context->destroy = sftk_Null;
00467        break;
00468     case CKM_RC2_CBC_PAD:
00469        context->doPad = PR_TRUE;
00470        /* fall thru */
00471     case CKM_RC2_ECB:
00472     case CKM_RC2_CBC:
00473        context->blockSize = 8;
00474        if (key_type != CKK_RC2) {
00475            crv = CKR_KEY_TYPE_INCONSISTENT;
00476            break;
00477        }
00478        att = sftk_FindAttribute(key,CKA_VALUE);
00479        if (att == NULL) {
00480            crv = CKR_KEY_HANDLE_INVALID;
00481            break;
00482        }
00483        rc2_param = (CK_RC2_CBC_PARAMS *)pMechanism->pParameter;
00484        effectiveKeyLength = (rc2_param->ulEffectiveBits+7)/8;
00485        context->cipherInfo = 
00486            RC2_CreateContext((unsigned char*)att->attrib.pValue,
00487                            att->attrib.ulValueLen, rc2_param->iv,
00488                            pMechanism->mechanism == CKM_RC2_ECB ? NSS_RC2 :
00489                            NSS_RC2_CBC,effectiveKeyLength);
00490        sftk_FreeAttribute(att);
00491        if (context->cipherInfo == NULL) {
00492            crv = CKR_HOST_MEMORY;
00493            break;
00494        }
00495        context->update = (SFTKCipher) (isEncrypt ? RC2_Encrypt : RC2_Decrypt);
00496        context->destroy = (SFTKDestroy) RC2_DestroyContext;
00497        break;
00498 #if NSS_SOFTOKEN_DOES_RC5
00499     case CKM_RC5_CBC_PAD:
00500        context->doPad = PR_TRUE;
00501        /* fall thru */
00502     case CKM_RC5_ECB:
00503     case CKM_RC5_CBC:
00504        if (key_type != CKK_RC5) {
00505            crv = CKR_KEY_TYPE_INCONSISTENT;
00506            break;
00507        }
00508        att = sftk_FindAttribute(key,CKA_VALUE);
00509        if (att == NULL) {
00510            crv = CKR_KEY_HANDLE_INVALID;
00511            break;
00512        }
00513        rc5_param = (CK_RC5_CBC_PARAMS *)pMechanism->pParameter;
00514        context->blockSize = rc5_param->ulWordsize*2;
00515        rc5Key.data = (unsigned char*)att->attrib.pValue;
00516        rc5Key.len = att->attrib.ulValueLen;
00517        context->cipherInfo = RC5_CreateContext(&rc5Key,rc5_param->ulRounds,
00518           rc5_param->ulWordsize,rc5_param->pIv,
00519                pMechanism->mechanism == CKM_RC5_ECB ? NSS_RC5 : NSS_RC5_CBC);
00520        sftk_FreeAttribute(att);
00521        if (context->cipherInfo == NULL) {
00522            crv = CKR_HOST_MEMORY;
00523            break;
00524        }
00525        context->update = (SFTKCipher) (isEncrypt ? RC5_Encrypt : RC5_Decrypt);
00526        context->destroy = (SFTKDestroy) RC5_DestroyContext;
00527        break;
00528 #endif
00529     case CKM_RC4:
00530        if (key_type != CKK_RC4) {
00531            crv = CKR_KEY_TYPE_INCONSISTENT;
00532            break;
00533        }
00534        att = sftk_FindAttribute(key,CKA_VALUE);
00535        if (att == NULL) {
00536            crv = CKR_KEY_HANDLE_INVALID;
00537            break;
00538        }
00539        context->cipherInfo = 
00540            RC4_CreateContext((unsigned char*)att->attrib.pValue,
00541                            att->attrib.ulValueLen);
00542        sftk_FreeAttribute(att);
00543        if (context->cipherInfo == NULL) {
00544            crv = CKR_HOST_MEMORY;  /* WRONG !!! */
00545            break;
00546        }
00547        context->update = (SFTKCipher) (isEncrypt ? RC4_Encrypt : RC4_Decrypt);
00548        context->destroy = (SFTKDestroy) RC4_DestroyContext;
00549        break;
00550     case CKM_CDMF_CBC_PAD:
00551        context->doPad = PR_TRUE;
00552        /* fall thru */
00553     case CKM_CDMF_ECB:
00554     case CKM_CDMF_CBC:
00555        if (key_type != CKK_CDMF) {
00556            crv = CKR_KEY_TYPE_INCONSISTENT;
00557            break;
00558        }
00559        t = (pMechanism->mechanism == CKM_CDMF_ECB) ? NSS_DES : NSS_DES_CBC;
00560        if (crv != CKR_OK) break;
00561        goto finish_des;
00562     case CKM_DES_ECB:
00563        if (key_type != CKK_DES) {
00564            crv = CKR_KEY_TYPE_INCONSISTENT;
00565            break;
00566        }
00567        t = NSS_DES;
00568        goto finish_des;
00569     case CKM_DES_CBC_PAD:
00570        context->doPad = PR_TRUE;
00571        /* fall thru */
00572     case CKM_DES_CBC:
00573        if (key_type != CKK_DES) {
00574            crv = CKR_KEY_TYPE_INCONSISTENT;
00575            break;
00576        }
00577        t = NSS_DES_CBC;
00578        goto finish_des;
00579     case CKM_DES3_ECB:
00580        if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
00581            crv = CKR_KEY_TYPE_INCONSISTENT;
00582            break;
00583        }
00584        t = NSS_DES_EDE3;
00585        goto finish_des;
00586     case CKM_DES3_CBC_PAD:
00587        context->doPad = PR_TRUE;
00588        /* fall thru */
00589     case CKM_DES3_CBC:
00590        if ((key_type != CKK_DES2) && (key_type != CKK_DES3)) {
00591            crv = CKR_KEY_TYPE_INCONSISTENT;
00592            break;
00593        }
00594        t = NSS_DES_EDE3_CBC;
00595 finish_des:
00596        context->blockSize = 8;
00597        att = sftk_FindAttribute(key,CKA_VALUE);
00598        if (att == NULL) {
00599            crv = CKR_KEY_HANDLE_INVALID;
00600            break;
00601        }
00602        if (key_type == CKK_DES2 && 
00603             (t == NSS_DES_EDE3_CBC || t == NSS_DES_EDE3)) {
00604            /* extend DES2 key to DES3 key. */
00605            memcpy(newdeskey, att->attrib.pValue, 16);
00606            memcpy(newdeskey + 16, newdeskey, 8);
00607            useNewKey=PR_TRUE;
00608        } else if (key_type == CKK_CDMF) {
00609            crv = sftk_cdmf2des((unsigned char*)att->attrib.pValue,newdeskey);
00610            if (crv != CKR_OK) {
00611               sftk_FreeAttribute(att);
00612               break;
00613            }
00614            useNewKey=PR_TRUE;
00615        }
00616        context->cipherInfo = DES_CreateContext(
00617               useNewKey ? newdeskey : (unsigned char*)att->attrib.pValue,
00618               (unsigned char*)pMechanism->pParameter,t, isEncrypt);
00619        if (useNewKey) 
00620            memset(newdeskey, 0, sizeof newdeskey);
00621        sftk_FreeAttribute(att);
00622        if (context->cipherInfo == NULL) {
00623            crv = CKR_HOST_MEMORY;
00624            break;
00625        }
00626        context->update = (SFTKCipher) (isEncrypt ? DES_Encrypt : DES_Decrypt);
00627        context->destroy = (SFTKDestroy) DES_DestroyContext;
00628        break;
00629 
00630     case CKM_AES_CBC_PAD:
00631        context->doPad = PR_TRUE;
00632        /* fall thru */
00633     case CKM_AES_ECB:
00634     case CKM_AES_CBC:
00635        context->blockSize = 16;
00636        if (key_type != CKK_AES) {
00637            crv = CKR_KEY_TYPE_INCONSISTENT;
00638            break;
00639        }
00640        att = sftk_FindAttribute(key,CKA_VALUE);
00641        if (att == NULL) {
00642            crv = CKR_KEY_HANDLE_INVALID;
00643            break;
00644        }
00645        context->cipherInfo = AES_CreateContext(
00646            (unsigned char*)att->attrib.pValue,
00647            (unsigned char*)pMechanism->pParameter,
00648            pMechanism->mechanism == CKM_AES_ECB ? NSS_AES : NSS_AES_CBC,
00649            isEncrypt, att->attrib.ulValueLen, 16);
00650        sftk_FreeAttribute(att);
00651        if (context->cipherInfo == NULL) {
00652            crv = CKR_HOST_MEMORY;
00653            break;
00654        }
00655        context->update = (SFTKCipher) (isEncrypt ? AES_Encrypt : AES_Decrypt);
00656        context->destroy = (SFTKDestroy) AES_DestroyContext;
00657        break;
00658 
00659     case CKM_NETSCAPE_AES_KEY_WRAP_PAD:
00660        context->doPad = PR_TRUE;
00661        /* fall thru */
00662     case CKM_NETSCAPE_AES_KEY_WRAP:
00663        context->multi = PR_FALSE;
00664        context->blockSize = 8;
00665        if (key_type != CKK_AES) {
00666            crv = CKR_KEY_TYPE_INCONSISTENT;
00667            break;
00668        }
00669        att = sftk_FindAttribute(key,CKA_VALUE);
00670        if (att == NULL) {
00671            crv = CKR_KEY_HANDLE_INVALID;
00672            break;
00673        }
00674        context->cipherInfo = AESKeyWrap_CreateContext(
00675            (unsigned char*)att->attrib.pValue,
00676            (unsigned char*)pMechanism->pParameter,
00677            isEncrypt, att->attrib.ulValueLen);
00678        sftk_FreeAttribute(att);
00679        if (context->cipherInfo == NULL) {
00680            crv = CKR_HOST_MEMORY;
00681            break;
00682        }
00683        context->update = (SFTKCipher) (isEncrypt ? AESKeyWrap_Encrypt 
00684                                                  : AESKeyWrap_Decrypt);
00685        context->destroy = (SFTKDestroy) AESKeyWrap_DestroyContext;
00686        break;
00687 
00688     default:
00689        crv = CKR_MECHANISM_INVALID;
00690        break;
00691     }
00692 
00693     if (crv != CKR_OK) {
00694         sftk_FreeContext(context);
00695        sftk_FreeSession(session);
00696        return crv;
00697     }
00698     sftk_SetContextByType(session, contextType, context);
00699     sftk_FreeSession(session);
00700     return CKR_OK;
00701 }
00702 
00703 /* NSC_EncryptInit initializes an encryption operation. */
00704 CK_RV NSC_EncryptInit(CK_SESSION_HANDLE hSession,
00705                CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
00706 {
00707     return sftk_CryptInit(hSession, pMechanism, hKey, CKA_ENCRYPT, 
00708                                           SFTK_ENCRYPT, PR_TRUE);
00709 }
00710 
00711 /* NSC_EncryptUpdate continues a multiple-part encryption operation. */
00712 CK_RV NSC_EncryptUpdate(CK_SESSION_HANDLE hSession,
00713     CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,       
00714                                    CK_ULONG_PTR pulEncryptedPartLen)
00715 {
00716     SFTKSessionContext *context;
00717     unsigned int outlen,i;
00718     unsigned int padoutlen = 0;
00719     unsigned int maxout = *pulEncryptedPartLen;
00720     CK_RV crv;
00721     SECStatus rv;
00722 
00723     /* make sure we're legal */
00724     crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,NULL);
00725     if (crv != CKR_OK) return crv;
00726 
00727     if (!pEncryptedPart) {
00728        if (context->doPad) {
00729            CK_ULONG totalDataAvailable = ulPartLen + context->padDataLength;
00730            CK_ULONG blocksToSend = totalDataAvailable/context->blockSize;
00731 
00732            *pulEncryptedPartLen = blocksToSend * context->blockSize;
00733            return CKR_OK;
00734        }
00735        *pulEncryptedPartLen = ulPartLen;
00736        return CKR_OK;
00737     }
00738 
00739     /* do padding */
00740     if (context->doPad) {
00741        /* deal with previous buffered data */
00742        if (context->padDataLength != 0) {
00743            /* fill in the padded to a full block size */
00744            for (i=context->padDataLength; 
00745                      (ulPartLen != 0) && i < context->blockSize; i++) {
00746               context->padBuf[i] = *pPart++;
00747               ulPartLen--;
00748               context->padDataLength++;
00749            }
00750 
00751            /* not enough data to encrypt yet? then return */
00752            if (context->padDataLength != context->blockSize) {
00753               *pulEncryptedPartLen = 0;
00754               return CKR_OK;
00755            }
00756            /* encrypt the current padded data */
00757            rv = (*context->update)(context->cipherInfo, pEncryptedPart, 
00758               &padoutlen, context->blockSize, context->padBuf,
00759                                                  context->blockSize);
00760            if (rv != SECSuccess) return CKR_DEVICE_ERROR;
00761            pEncryptedPart += padoutlen;
00762            maxout -= padoutlen;
00763        }
00764        /* save the residual */
00765        context->padDataLength = ulPartLen % context->blockSize;
00766        if (context->padDataLength) {
00767            PORT_Memcpy(context->padBuf,
00768                      &pPart[ulPartLen-context->padDataLength],
00769                                                  context->padDataLength);
00770            ulPartLen -= context->padDataLength;
00771        }
00772        /* if we've exhausted our new buffer, we're done */
00773        if (ulPartLen == 0) {
00774            *pulEncryptedPartLen = padoutlen;
00775            return CKR_OK;
00776        }
00777     }
00778 
00779 
00780     /* do it: NOTE: this assumes buf size in is >= buf size out! */
00781     rv = (*context->update)(context->cipherInfo,pEncryptedPart, 
00782                                    &outlen, maxout, pPart, ulPartLen);
00783     *pulEncryptedPartLen = (CK_ULONG) (outlen + padoutlen);
00784     return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
00785 }
00786 
00787 
00788 /* NSC_EncryptFinal finishes a multiple-part encryption operation. */
00789 CK_RV NSC_EncryptFinal(CK_SESSION_HANDLE hSession,
00790     CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen)
00791 {
00792     SFTKSession *session;
00793     SFTKSessionContext *context;
00794     unsigned int outlen,i;
00795     unsigned int maxout = *pulLastEncryptedPartLen;
00796     CK_RV crv;
00797     SECStatus rv = SECSuccess;
00798     PRBool contextFinished = PR_TRUE;
00799 
00800     /* make sure we're legal */
00801     crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,&session);
00802     if (crv != CKR_OK) return crv;
00803 
00804     *pulLastEncryptedPartLen = 0;
00805     if (!pLastEncryptedPart) {
00806        /* caller is checking the amount of remaining data */
00807        if (context->blockSize > 0 && context->doPad) {
00808            *pulLastEncryptedPartLen = context->blockSize;
00809            contextFinished = PR_FALSE; /* still have padding to go */
00810        }
00811        goto finish;
00812     }
00813 
00814     /* do padding */
00815     if (context->doPad) {
00816        unsigned char  padbyte = (unsigned char) 
00817                             (context->blockSize - context->padDataLength); 
00818        /* fill out rest of pad buffer with pad magic*/
00819        for (i=context->padDataLength; i < context->blockSize; i++) {
00820            context->padBuf[i] = padbyte;
00821        }
00822        rv = (*context->update)(context->cipherInfo,pLastEncryptedPart, 
00823                      &outlen, maxout, context->padBuf, context->blockSize);
00824        if (rv == SECSuccess) *pulLastEncryptedPartLen = (CK_ULONG) outlen;
00825     }
00826 
00827 finish:
00828     if (contextFinished) {
00829        sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
00830        sftk_FreeContext(context);
00831     }
00832     sftk_FreeSession(session);
00833     return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
00834 }
00835 
00836 /* NSC_Encrypt encrypts single-part data. */
00837 CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
00838                  CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
00839                  CK_ULONG_PTR pulEncryptedDataLen)
00840 {
00841     SFTKSession *session;
00842     SFTKSessionContext *context;
00843     unsigned int outlen;
00844     unsigned int maxoutlen = *pulEncryptedDataLen;
00845     CK_RV crv;
00846     CK_RV crv2;
00847     SECStatus rv = SECSuccess;
00848     SECItem   pText;
00849 
00850     pText.type = siBuffer;
00851     pText.data = pData;
00852     pText.len  = ulDataLen;
00853 
00854     /* make sure we're legal */
00855     crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,&session);
00856     if (crv != CKR_OK) return crv;
00857 
00858     if (!pEncryptedData) {
00859        *pulEncryptedDataLen = context->multi ? 
00860               ulDataLen + 2 * context->blockSize : context->maxLen;
00861        goto finish;
00862     }
00863 
00864     if (context->doPad) {
00865        if (context->multi) {
00866            CK_ULONG finalLen;
00867            /* padding is fairly complicated, have the update and final 
00868             * code deal with it */
00869            sftk_FreeSession(session);
00870            crv = NSC_EncryptUpdate(hSession, pData, ulDataLen, pEncryptedData, 
00871                                    pulEncryptedDataLen);
00872            if (crv != CKR_OK) 
00873               *pulEncryptedDataLen = 0;
00874            maxoutlen      -= *pulEncryptedDataLen;
00875            pEncryptedData += *pulEncryptedDataLen;
00876            finalLen = maxoutlen;
00877            crv2 = NSC_EncryptFinal(hSession, pEncryptedData, &finalLen);
00878            if (crv2 == CKR_OK) 
00879               *pulEncryptedDataLen += finalLen;
00880            return crv == CKR_OK ? crv2 : crv;
00881        }
00882        /* doPad without multi means that padding must be done on the first
00883        ** and only update.  There will be no final.
00884        */
00885        PORT_Assert(context->blockSize > 1);
00886        if (context->blockSize > 1) {
00887            CK_ULONG remainder = ulDataLen % context->blockSize;
00888            CK_ULONG padding   = context->blockSize - remainder;
00889            pText.len += padding;
00890            pText.data = PORT_ZAlloc(pText.len);
00891            if (pText.data) {
00892               memcpy(pText.data, pData, ulDataLen);
00893               memset(pText.data + ulDataLen, padding, padding);
00894            } else {
00895               crv = CKR_HOST_MEMORY;
00896               goto fail;
00897            }
00898        }
00899     }
00900 
00901     /* do it: NOTE: this assumes buf size is big enough. */
00902     rv = (*context->update)(context->cipherInfo, pEncryptedData, 
00903                          &outlen, maxoutlen, pText.data, pText.len);
00904     crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
00905     *pulEncryptedDataLen = (CK_ULONG) outlen;
00906     if (pText.data != pData)
00907        PORT_ZFree(pText.data, pText.len);
00908 fail:
00909     sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
00910     sftk_FreeContext(context);
00911 finish:
00912     sftk_FreeSession(session);
00913 
00914     return crv;
00915 }
00916 
00917 
00918 /*
00919  ************** Crypto Functions:     Decrypt ************************
00920  */
00921 
00922 /* NSC_DecryptInit initializes a decryption operation. */
00923 CK_RV NSC_DecryptInit( CK_SESSION_HANDLE hSession,
00924                       CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
00925 {
00926     return sftk_CryptInit(hSession, pMechanism, hKey, CKA_DECRYPT,
00927                                           SFTK_DECRYPT, PR_FALSE);
00928 }
00929 
00930 /* NSC_DecryptUpdate continues a multiple-part decryption operation. */
00931 CK_RV NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
00932     CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen,
00933                             CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
00934 {
00935     SFTKSessionContext *context;
00936     unsigned int padoutlen = 0;
00937     unsigned int outlen;
00938     unsigned int maxout = *pulPartLen;
00939     CK_RV crv;
00940     SECStatus rv;
00941 
00942     /* make sure we're legal */
00943     crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,NULL);
00944     if (crv != CKR_OK) return crv;
00945 
00946     /* this can only happen on an NSS programming error */
00947     PORT_Assert((context->padDataLength == 0) 
00948               || context->padDataLength == context->blockSize);
00949 
00950 
00951     if (!pPart) {
00952        if (context->doPad) {
00953            /* we can check the data length here because if we are padding,
00954             * then we must be using a block cipher. In the non-padding case
00955             * the error will be returned by the underlying decryption
00956             * function when do do the actual decrypt. We need to do the
00957             * check here to avoid returning a negative length to the caller.
00958             */
00959            if ((ulEncryptedPartLen == 0) ||
00960               (ulEncryptedPartLen % context->blockSize) != 0) {
00961               return CKR_ENCRYPTED_DATA_LEN_RANGE;
00962            }
00963            *pulPartLen = 
00964               ulEncryptedPartLen + context->padDataLength - context->blockSize;
00965            return CKR_OK;
00966        }
00967        /* for stream ciphers there is are no constraints on ulEncryptedPartLen.
00968         * for block ciphers, it must be a multiple of blockSize. The error is
00969         * detected when this function is called again do decrypt the output.
00970         */
00971        *pulPartLen = ulEncryptedPartLen;
00972        return CKR_OK;
00973     }
00974 
00975     if (context->doPad) {
00976        /* first decrypt our saved buffer */
00977        if (context->padDataLength != 0) {
00978            rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
00979                maxout, context->padBuf, context->blockSize);
00980            if (rv != SECSuccess)  return CKR_DEVICE_ERROR;
00981            pPart += padoutlen;
00982            maxout -= padoutlen;
00983        }
00984        /* now save the final block for the next decrypt or the final */
00985        PORT_Memcpy(context->padBuf,&pEncryptedPart[ulEncryptedPartLen -
00986                             context->blockSize], context->blockSize);
00987        context->padDataLength = context->blockSize;
00988        ulEncryptedPartLen -= context->padDataLength;
00989     }
00990 
00991     /* do it: NOTE: this assumes buf size in is >= buf size out! */
00992     rv = (*context->update)(context->cipherInfo,pPart, &outlen,
00993                maxout, pEncryptedPart, ulEncryptedPartLen);
00994     *pulPartLen = (CK_ULONG) (outlen + padoutlen);
00995     return (rv == SECSuccess)  ? CKR_OK : CKR_DEVICE_ERROR;
00996 }
00997 
00998 
00999 /* NSC_DecryptFinal finishes a multiple-part decryption operation. */
01000 CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
01001     CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
01002 {
01003     SFTKSession *session;
01004     SFTKSessionContext *context;
01005     unsigned int outlen;
01006     unsigned int maxout = *pulLastPartLen;
01007     CK_RV crv;
01008     SECStatus rv = SECSuccess;
01009 
01010     /* make sure we're legal */
01011     crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,&session);
01012     if (crv != CKR_OK) return crv;
01013 
01014     *pulLastPartLen = 0;
01015     if (!pLastPart) {
01016        /* caller is checking the amount of remaining data */
01017        if (context->padDataLength > 0) {
01018            *pulLastPartLen = context->padDataLength;
01019        }
01020        rv = SECSuccess;
01021        goto finish;
01022     }
01023 
01024     if (context->doPad) {
01025        /* decrypt our saved buffer */
01026        if (context->padDataLength != 0) {
01027            /* this assumes that pLastPart is big enough to hold the *whole*
01028             * buffer!!! */
01029            rv = (*context->update)(context->cipherInfo, pLastPart, &outlen,
01030                maxout, context->padBuf, context->blockSize);
01031            if (rv == SECSuccess) {
01032               unsigned int padSize = 
01033                          (unsigned int) pLastPart[context->blockSize-1];
01034               if ((padSize > context->blockSize) || (padSize == 0)) {
01035                   rv = SECFailure;
01036               } else {
01037                   *pulLastPartLen = outlen - padSize;
01038               }
01039            }
01040        }
01041     }
01042 
01043     sftk_SetContextByType(session, SFTK_DECRYPT, NULL);
01044     sftk_FreeContext(context);
01045 finish:
01046     sftk_FreeSession(session);
01047     return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
01048 }
01049 
01050 /* NSC_Decrypt decrypts encrypted data in a single part. */
01051 CK_RV NSC_Decrypt(CK_SESSION_HANDLE hSession,
01052     CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,
01053                                           CK_ULONG_PTR pulDataLen)
01054 {
01055     SFTKSession *session;
01056     SFTKSessionContext *context;
01057     unsigned int outlen;
01058     unsigned int maxoutlen = *pulDataLen;
01059     CK_RV crv;
01060     CK_RV crv2;
01061     SECStatus rv = SECSuccess;
01062 
01063     /* make sure we're legal */
01064     crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_FALSE,&session);
01065     if (crv != CKR_OK) return crv;
01066 
01067     if (!pData) {
01068        *pulDataLen = ulEncryptedDataLen + context->blockSize;
01069        goto finish;
01070     }
01071 
01072     if (context->doPad && context->multi) {
01073        CK_ULONG finalLen;
01074        /* padding is fairly complicated, have the update and final 
01075         * code deal with it */
01076        sftk_FreeSession(session);
01077        crv = NSC_DecryptUpdate(hSession,pEncryptedData,ulEncryptedDataLen,
01078                                                  pData, pulDataLen);
01079        if (crv != CKR_OK) 
01080            *pulDataLen = 0;
01081        maxoutlen -= *pulDataLen;
01082        pData     += *pulDataLen;
01083        finalLen = maxoutlen;
01084        crv2 = NSC_DecryptFinal(hSession, pData, &finalLen);
01085        if (crv2 == CKR_OK) 
01086            *pulDataLen += finalLen;
01087        return crv == CKR_OK ? crv2 : crv;
01088     }
01089 
01090     rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
01091                                    pEncryptedData, ulEncryptedDataLen);
01092     /* XXX need to do MUCH better error mapping than this. */
01093     crv = (rv == SECSuccess)  ? CKR_OK : CKR_DEVICE_ERROR;
01094     if (rv == SECSuccess && context->doPad) {
01095        CK_ULONG padding = pData[outlen - 1];
01096        if (padding > context->blockSize || !padding) {
01097            crv = CKR_ENCRYPTED_DATA_INVALID;
01098        } else
01099            outlen -= padding;
01100     }
01101     *pulDataLen = (CK_ULONG) outlen;
01102     sftk_SetContextByType(session, SFTK_DECRYPT, NULL);
01103     sftk_FreeContext(context);
01104 finish:
01105     sftk_FreeSession(session);
01106     return crv;
01107 }
01108 
01109 
01110 
01111 /*
01112  ************** Crypto Functions:     Digest (HASH)  ************************
01113  */
01114 
01115 /* NSC_DigestInit initializes a message-digesting operation. */
01116 CK_RV NSC_DigestInit(CK_SESSION_HANDLE hSession,
01117                                    CK_MECHANISM_PTR pMechanism)
01118 {
01119     SFTKSession *session;
01120     SFTKSessionContext *context;
01121     CK_RV crv = CKR_OK;
01122 
01123     session = sftk_SessionFromHandle(hSession);
01124     if (session == NULL) 
01125        return CKR_SESSION_HANDLE_INVALID;
01126     crv = sftk_InitGeneric(session,&context,SFTK_HASH,NULL,0,NULL, 0, 0);
01127     if (crv != CKR_OK) {
01128        sftk_FreeSession(session);
01129        return crv;
01130     }
01131 
01132 
01133 #define INIT_MECH(mech,mmm) \
01134     case mech: { \
01135        mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
01136        context->cipherInfo    = (void *)mmm ## _ctx; \
01137        context->cipherInfoLen = mmm ## _FlattenSize(mmm ## _ctx); \
01138        context->currentMech   = mech; \
01139        context->hashUpdate    = (SFTKHash)    mmm ## _Update; \
01140        context->end           = (SFTKEnd)     mmm ## _End; \
01141        context->destroy       = (SFTKDestroy) mmm ## _DestroyContext; \
01142        context->maxLen        = mmm ## _LENGTH; \
01143         if (mmm ## _ctx) \
01144            mmm ## _Begin(mmm ## _ctx); \
01145        else  \
01146            crv = CKR_HOST_MEMORY; \
01147        break; \
01148     }
01149 
01150     switch(pMechanism->mechanism) {
01151     INIT_MECH(CKM_MD2,    MD2)
01152     INIT_MECH(CKM_MD5,    MD5)
01153     INIT_MECH(CKM_SHA_1,  SHA1)
01154     INIT_MECH(CKM_SHA256, SHA256)
01155     INIT_MECH(CKM_SHA384, SHA384)
01156     INIT_MECH(CKM_SHA512, SHA512)
01157 
01158     default:
01159        crv = CKR_MECHANISM_INVALID;
01160        break;
01161     }
01162 
01163     if (crv != CKR_OK) {
01164         sftk_FreeContext(context);
01165        sftk_FreeSession(session);
01166        return crv;
01167     }
01168     sftk_SetContextByType(session, SFTK_HASH, context);
01169     sftk_FreeSession(session);
01170     return CKR_OK;
01171 }
01172 
01173 
01174 /* NSC_Digest digests data in a single part. */
01175 CK_RV NSC_Digest(CK_SESSION_HANDLE hSession,
01176     CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest,
01177                                           CK_ULONG_PTR pulDigestLen)
01178 {
01179     SFTKSession *session;
01180     SFTKSessionContext *context;
01181     unsigned int digestLen;
01182     unsigned int maxout = *pulDigestLen;
01183     CK_RV crv;
01184 
01185     /* make sure we're legal */
01186     crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_FALSE,&session);
01187     if (crv != CKR_OK) return crv;
01188 
01189     if (pDigest == NULL) {
01190        *pulDigestLen = context->maxLen;
01191        goto finish;
01192     }
01193 
01194     /* do it: */
01195     (*context->hashUpdate)(context->cipherInfo, pData, ulDataLen);
01196     /*  NOTE: this assumes buf size is bigenough for the algorithm */
01197     (*context->end)(context->cipherInfo, pDigest, &digestLen,maxout);
01198     *pulDigestLen = digestLen;
01199 
01200     sftk_SetContextByType(session, SFTK_HASH, NULL);
01201     sftk_FreeContext(context);
01202 finish:
01203     sftk_FreeSession(session);
01204     return CKR_OK;
01205 }
01206 
01207 
01208 /* NSC_DigestUpdate continues a multiple-part message-digesting operation. */
01209 CK_RV NSC_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
01210                                        CK_ULONG ulPartLen)
01211 {
01212     SFTKSessionContext *context;
01213     CK_RV crv;
01214 
01215     /* make sure we're legal */
01216     crv = sftk_GetContext(hSession,&context,SFTK_HASH,PR_TRUE,NULL);
01217     if (crv != CKR_OK) return crv;
01218     /* do it: */
01219     (*context->hashUpdate)(context->cipherInfo, pPart, ulPartLen);
01220     return CKR_OK;
01221 }
01222 
01223 
01224 /* NSC_DigestFinal finishes a multiple-part message-digesting operation. */
01225 CK_RV NSC_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,
01226                                           CK_ULONG_PTR pulDigestLen)
01227 {
01228     SFTKSession *session;
01229     SFTKSessionContext *context;
01230     unsigned int maxout = *pulDigestLen;
01231     unsigned int digestLen;
01232     CK_RV crv;
01233 
01234     /* make sure we're legal */
01235     crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session);
01236     if (crv != CKR_OK) return crv;
01237 
01238     if (pDigest != NULL) {
01239         (*context->end)(context->cipherInfo, pDigest, &digestLen, maxout);
01240         *pulDigestLen = digestLen;
01241        sftk_SetContextByType(session, SFTK_HASH, NULL);
01242        sftk_FreeContext(context);
01243     } else {
01244        *pulDigestLen = context->maxLen;
01245     }
01246 
01247     sftk_FreeSession(session);
01248     return CKR_OK;
01249 }
01250 
01251 /*
01252  * these helper functions are used by Generic Macing and Signing functions
01253  * that use hashes as part of their operations. 
01254  */
01255 #define DOSUB(mmm) \
01256 static CK_RV \
01257 sftk_doSub ## mmm(SFTKSessionContext *context) { \
01258     mmm ## Context * mmm ## _ctx = mmm ## _NewContext(); \
01259     context->hashInfo    = (void *)      mmm ## _ctx; \
01260     context->hashUpdate  = (SFTKHash)    mmm ## _Update; \
01261     context->end         = (SFTKEnd)     mmm ## _End; \
01262     context->hashdestroy = (SFTKDestroy) mmm ## _DestroyContext; \
01263     if (!context->hashInfo) { \
01264        return CKR_HOST_MEMORY; \
01265     } \
01266     mmm ## _Begin( mmm ## _ctx ); \
01267     return CKR_OK; \
01268 }
01269 
01270 DOSUB(MD2)
01271 DOSUB(MD5)
01272 DOSUB(SHA1)
01273 DOSUB(SHA256)
01274 DOSUB(SHA384)
01275 DOSUB(SHA512)
01276 
01277 /*
01278  * HMAC General copies only a portion of the result. This update routine likes
01279  * the final HMAC output with the signature.
01280  */
01281 static SECStatus
01282 sftk_HMACCopy(CK_ULONG *copyLen,unsigned char *sig,unsigned int *sigLen,
01283               unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
01284 {
01285     if (maxLen < *copyLen) return SECFailure;
01286     PORT_Memcpy(sig,hash,*copyLen);
01287     *sigLen = *copyLen;
01288     return SECSuccess;
01289 }
01290 
01291 /* Verify is just a compare for HMAC */
01292 static SECStatus
01293 sftk_HMACCmp(CK_ULONG *copyLen,unsigned char *sig,unsigned int sigLen,
01294                             unsigned char *hash, unsigned int hashLen)
01295 {
01296     return (PORT_Memcmp(sig,hash,*copyLen) == 0) ? SECSuccess : SECFailure ; 
01297 }
01298 
01299 /*
01300  * common HMAC initalization routine
01301  */
01302 static CK_RV
01303 sftk_doHMACInit(SFTKSessionContext *context,HASH_HashType hash,
01304                                    SFTKObject *key, CK_ULONG mac_size)
01305 {
01306     SFTKAttribute *keyval;
01307     HMACContext *HMACcontext;
01308     CK_ULONG *intpointer;
01309     const SECHashObject *hashObj = HASH_GetRawHashObject(hash);
01310     PRBool isFIPS = (key->slot->slotID == FIPS_SLOT_ID);
01311 
01312     /* required by FIPS 198 Section 4 */
01313     if (isFIPS && (mac_size < 4 || mac_size < hashObj->length/2)) {
01314        return CKR_BUFFER_TOO_SMALL;
01315     }
01316 
01317     keyval = sftk_FindAttribute(key,CKA_VALUE);
01318     if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
01319 
01320     HMACcontext = HMAC_Create(hashObj, 
01321               (const unsigned char*)keyval->attrib.pValue,
01322               keyval->attrib.ulValueLen, isFIPS);
01323     context->hashInfo = HMACcontext;
01324     context->multi = PR_TRUE;
01325     sftk_FreeAttribute(keyval);
01326     if (context->hashInfo == NULL) {
01327        if (PORT_GetError() == SEC_ERROR_INVALID_ARGS) {
01328            return CKR_KEY_SIZE_RANGE;
01329        }
01330        return CKR_HOST_MEMORY;
01331     }
01332     context->hashUpdate = (SFTKHash) HMAC_Update;
01333     context->end = (SFTKEnd) HMAC_Finish;
01334 
01335     context->hashdestroy = (SFTKDestroy) HMAC_Destroy;
01336     intpointer = (CK_ULONG *) PORT_Alloc(sizeof(CK_ULONG));
01337     if (intpointer == NULL) {
01338        return CKR_HOST_MEMORY;
01339     }
01340     *intpointer = mac_size;
01341     context->cipherInfo = (void *) intpointer;
01342     context->destroy = (SFTKDestroy) sftk_Space;
01343     context->update = (SFTKCipher) sftk_HMACCopy;
01344     context->verify = (SFTKVerify) sftk_HMACCmp;
01345     context->maxLen = hashObj->length;
01346     HMAC_Begin(HMACcontext);
01347     return CKR_OK;
01348 }
01349 
01350 /*
01351  *  SSL Macing support. SSL Macs are inited, then update with the base
01352  * hashing algorithm, then finalized in sign and verify
01353  */
01354 
01355 /*
01356  * FROM SSL:
01357  * 60 bytes is 3 times the maximum length MAC size that is supported.
01358  * We probably should have one copy of this table. We still need this table
01359  * in ssl to 'sign' the handshake hashes.
01360  */
01361 static unsigned char ssl_pad_1 [60] = {
01362     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
01363     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
01364     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
01365     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
01366     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
01367     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
01368     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
01369     0x36, 0x36, 0x36, 0x36
01370 };
01371 static unsigned char ssl_pad_2 [60] = {
01372     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
01373     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
01374     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
01375     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
01376     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
01377     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
01378     0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
01379     0x5c, 0x5c, 0x5c, 0x5c
01380 };
01381 
01382 static SECStatus
01383 sftk_SSLMACSign(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int *sigLen,
01384               unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
01385 {
01386     unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
01387     unsigned int out;
01388 
01389     info->begin(info->hashContext);
01390     info->update(info->hashContext,info->key,info->keySize);
01391     info->update(info->hashContext,ssl_pad_2,info->padSize);
01392     info->update(info->hashContext,hash,hashLen);
01393     info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
01394     PORT_Memcpy(sig,tmpBuf,info->macSize);
01395     *sigLen = info->macSize;
01396     return SECSuccess;
01397 }
01398 
01399 static SECStatus
01400 sftk_SSLMACVerify(SFTKSSLMACInfo *info,unsigned char *sig,unsigned int sigLen,
01401               unsigned char *hash, unsigned int hashLen)
01402 {
01403     unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
01404     unsigned int out;
01405 
01406     info->begin(info->hashContext);
01407     info->update(info->hashContext,info->key,info->keySize);
01408     info->update(info->hashContext,ssl_pad_2,info->padSize);
01409     info->update(info->hashContext,hash,hashLen);
01410     info->end(info->hashContext,tmpBuf,&out,SFTK_MAX_MAC_LENGTH);
01411     return (PORT_Memcmp(sig,tmpBuf,info->macSize) == 0) ? 
01412                                           SECSuccess : SECFailure;
01413 }
01414 
01415 /*
01416  * common HMAC initalization routine
01417  */
01418 static CK_RV
01419 sftk_doSSLMACInit(SFTKSessionContext *context,SECOidTag oid,
01420                                    SFTKObject *key, CK_ULONG mac_size)
01421 {
01422     SFTKAttribute *keyval;
01423     SFTKBegin begin;
01424     int padSize;
01425     SFTKSSLMACInfo *sslmacinfo;
01426     CK_RV crv = CKR_MECHANISM_INVALID;
01427 
01428     if (oid == SEC_OID_SHA1) {
01429        crv = sftk_doSubSHA1(context);
01430        if (crv != CKR_OK) return crv;
01431        begin = (SFTKBegin) SHA1_Begin;
01432        padSize = 40;
01433     } else {
01434        crv = sftk_doSubMD5(context);
01435        if (crv != CKR_OK) return crv;
01436        begin = (SFTKBegin) MD5_Begin;
01437        padSize = 48;
01438     }
01439     context->multi = PR_TRUE;
01440 
01441     keyval = sftk_FindAttribute(key,CKA_VALUE);
01442     if (keyval == NULL) return CKR_KEY_SIZE_RANGE;
01443 
01444     context->hashUpdate(context->hashInfo,keyval->attrib.pValue,
01445                                            keyval->attrib.ulValueLen);
01446     context->hashUpdate(context->hashInfo,ssl_pad_1,padSize);
01447     sslmacinfo = (SFTKSSLMACInfo *) PORT_Alloc(sizeof(SFTKSSLMACInfo));
01448     if (sslmacinfo == NULL) {
01449         sftk_FreeAttribute(keyval);
01450        return CKR_HOST_MEMORY;
01451     }
01452     sslmacinfo->macSize = mac_size;
01453     sslmacinfo->hashContext = context->hashInfo;
01454     PORT_Memcpy(sslmacinfo->key,keyval->attrib.pValue,
01455                                    keyval->attrib.ulValueLen);
01456     sslmacinfo->keySize = keyval->attrib.ulValueLen;
01457     sslmacinfo->begin = begin;
01458     sslmacinfo->end = context->end;
01459     sslmacinfo->update = context->hashUpdate;
01460     sslmacinfo->padSize = padSize;
01461     sftk_FreeAttribute(keyval);
01462     context->cipherInfo = (void *) sslmacinfo;
01463     context->destroy = (SFTKDestroy) sftk_Space;
01464     context->update = (SFTKCipher) sftk_SSLMACSign;
01465     context->verify = (SFTKVerify) sftk_SSLMACVerify;
01466     context->maxLen = mac_size;
01467     return CKR_OK;
01468 }
01469 
01470 /*
01471  ************** Crypto Functions:     Sign  ************************
01472  */
01473 
01474 /*
01475  * Check if We're using CBCMacing and initialize the session context if we are.
01476  */
01477 static CK_RV
01478 sftk_InitCBCMac(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
01479        CK_OBJECT_HANDLE hKey, CK_ATTRIBUTE_TYPE keyUsage,
01480                                            SFTKContextType contextType)
01481        
01482 {
01483     CK_MECHANISM cbc_mechanism;
01484     CK_ULONG mac_bytes = SFTK_INVALID_MAC_SIZE;
01485     CK_RC2_CBC_PARAMS rc2_params;
01486 #if NSS_SOFTOKEN_DOES_RC5
01487     CK_RC5_CBC_PARAMS rc5_params;
01488     CK_RC5_MAC_GENERAL_PARAMS *rc5_mac;
01489 #endif
01490     unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE];
01491     SFTKSessionContext *context;
01492     CK_RV crv;
01493     int blockSize;
01494 
01495     switch (pMechanism->mechanism) {
01496     case CKM_RC2_MAC_GENERAL:
01497        mac_bytes = 
01498            ((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
01499        /* fall through */
01500     case CKM_RC2_MAC:
01501        /* this works because ulEffectiveBits is in the same place in both the
01502         * CK_RC2_MAC_GENERAL_PARAMS and CK_RC2_CBC_PARAMS */
01503        rc2_params.ulEffectiveBits = ((CK_RC2_MAC_GENERAL_PARAMS *)
01504                             pMechanism->pParameter)->ulEffectiveBits;
01505        PORT_Memset(rc2_params.iv,0,sizeof(rc2_params.iv));
01506        cbc_mechanism.mechanism = CKM_RC2_CBC;
01507        cbc_mechanism.pParameter = &rc2_params;
01508        cbc_mechanism.ulParameterLen = sizeof(rc2_params);
01509        blockSize = 8;
01510        break;
01511 #if NSS_SOFTOKEN_DOES_RC5
01512     case CKM_RC5_MAC_GENERAL:
01513        mac_bytes = 
01514            ((CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
01515        /* fall through */
01516     case CKM_RC5_MAC:
01517        /* this works because ulEffectiveBits is in the same place in both the
01518         * CK_RC5_MAC_GENERAL_PARAMS and CK_RC5_CBC_PARAMS */
01519        rc5_mac = (CK_RC5_MAC_GENERAL_PARAMS *)pMechanism->pParameter;
01520        rc5_params.ulWordsize = rc5_mac->ulWordsize;
01521        rc5_params.ulRounds = rc5_mac->ulRounds;
01522        rc5_params.pIv = ivBlock;
01523        blockSize = rc5_mac->ulWordsize*2;
01524        rc5_params.ulIvLen = blockSize;
01525        PORT_Memset(ivBlock,0,blockSize);
01526        cbc_mechanism.mechanism = CKM_RC5_CBC;
01527        cbc_mechanism.pParameter = &rc5_params;
01528        cbc_mechanism.ulParameterLen = sizeof(rc5_params);
01529        break;
01530 #endif
01531     /* add cast and idea later */
01532     case CKM_DES_MAC_GENERAL:
01533        mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
01534        /* fall through */
01535     case CKM_DES_MAC:
01536        blockSize = 8;
01537        PORT_Memset(ivBlock,0,blockSize);
01538        cbc_mechanism.mechanism = CKM_DES_CBC;
01539        cbc_mechanism.pParameter = &ivBlock;
01540        cbc_mechanism.ulParameterLen = blockSize;
01541        break;
01542     case CKM_DES3_MAC_GENERAL:
01543        mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
01544        /* fall through */
01545     case CKM_DES3_MAC:
01546        blockSize = 8;
01547        PORT_Memset(ivBlock,0,blockSize);
01548        cbc_mechanism.mechanism = CKM_DES3_CBC;
01549        cbc_mechanism.pParameter = &ivBlock;
01550        cbc_mechanism.ulParameterLen = blockSize;
01551        break;
01552     case CKM_CDMF_MAC_GENERAL:
01553        mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
01554        /* fall through */
01555     case CKM_CDMF_MAC:
01556        blockSize = 8;
01557        PORT_Memset(ivBlock,0,blockSize);
01558        cbc_mechanism.mechanism = CKM_CDMF_CBC;
01559        cbc_mechanism.pParameter = &ivBlock;
01560        cbc_mechanism.ulParameterLen = blockSize;
01561        break;
01562     case CKM_AES_MAC_GENERAL:
01563        mac_bytes = *(CK_ULONG *)pMechanism->pParameter;
01564        /* fall through */
01565     case CKM_AES_MAC:
01566        blockSize = 16;
01567        PORT_Memset(ivBlock,0,blockSize);
01568        cbc_mechanism.mechanism = CKM_AES_CBC;
01569        cbc_mechanism.pParameter = &ivBlock;
01570        cbc_mechanism.ulParameterLen = blockSize;
01571        break;
01572     default:
01573        return CKR_FUNCTION_NOT_SUPPORTED;
01574     }
01575 
01576     crv = sftk_CryptInit(hSession, &cbc_mechanism, hKey, keyUsage,
01577                                                  contextType, PR_TRUE);
01578     if (crv != CKR_OK) return crv;
01579     crv = sftk_GetContext(hSession,&context,contextType,PR_TRUE,NULL);
01580 
01581     /* this shouldn't happen! */
01582     PORT_Assert(crv == CKR_OK);
01583     if (crv != CKR_OK) return crv;
01584     context->blockSize = blockSize;
01585     if (mac_bytes == SFTK_INVALID_MAC_SIZE) mac_bytes = blockSize/2;
01586     context->macSize = mac_bytes;
01587     return CKR_OK;
01588 }
01589 
01590 /*
01591  * encode RSA PKCS #1 Signature data before signing... 
01592  */
01593 static SECStatus
01594 sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen,
01595               unsigned int maxLen,unsigned char *hash, unsigned int hashLen)
01596 {
01597     return RSA_HashSign(info->hashOid,info->key,sig,sigLen,maxLen,
01598                                                  hash,hashLen);
01599 }
01600 
01601 SECStatus
01602 RSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key,
01603               unsigned char *sig, unsigned int *sigLen, unsigned int maxLen,
01604               unsigned char *hash, unsigned int hashLen)
01605 {
01606     
01607     SECStatus rv = SECFailure;
01608     SECItem digder;
01609     PLArenaPool *arena = NULL;
01610     SGNDigestInfo *di = NULL;
01611 
01612     digder.data = NULL;
01613 
01614     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01615     if ( !arena ) { goto loser; }
01616     
01617     /* Construct digest info */
01618     di = SGN_CreateDigestInfo(hashOid, hash, hashLen);
01619     if (!di) { goto loser; }
01620 
01621     /* Der encode the digest as a DigestInfo */
01622     rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di);
01623     if (rv != SECSuccess) {
01624        goto loser;
01625     }
01626 
01627     /*
01628     ** Encrypt signature after constructing appropriate PKCS#1 signature
01629     ** block
01630     */
01631     rv = RSA_Sign(key,sig,sigLen,maxLen,digder.data,digder.len);
01632 
01633   loser:
01634     SGN_DestroyDigestInfo(di);
01635     if (arena != NULL) {
01636        PORT_FreeArena(arena, PR_FALSE);
01637     }
01638     return rv;
01639 }
01640 
01641 static SECStatus
01642 nsc_DSA_Verify_Stub(void *ctx, void *sigBuf, unsigned int sigLen,
01643                                void *dataBuf, unsigned int dataLen)
01644 {
01645     SECItem signature, digest;
01646     NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
01647 
01648     signature.data = (unsigned char *)sigBuf;
01649     signature.len = sigLen;
01650     digest.data = (unsigned char *)dataBuf;
01651     digest.len = dataLen;
01652     return DSA_VerifyDigest(&(key->u.dsa), &signature, &digest);
01653 }
01654 
01655 static SECStatus
01656 nsc_DSA_Sign_Stub(void *ctx, void *sigBuf,
01657                   unsigned int *sigLen, unsigned int maxSigLen,
01658                   void *dataBuf, unsigned int dataLen)
01659 {
01660     SECItem signature, digest;
01661     SECStatus rv;
01662     NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
01663 
01664     signature.data = (unsigned char *)sigBuf;
01665     signature.len = maxSigLen;
01666     digest.data = (unsigned char *)dataBuf;
01667     digest.len = dataLen;
01668     rv = DSA_SignDigest(&(key->u.dsa), &signature, &digest);
01669     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
01670        sftk_fatalError = PR_TRUE;
01671     }
01672     *sigLen = signature.len;
01673     return rv;
01674 }
01675 
01676 #ifdef NSS_ENABLE_ECC
01677 static SECStatus
01678 nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen,
01679                     void *dataBuf, unsigned int dataLen)
01680 {
01681     SECItem signature, digest;
01682     NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx;
01683 
01684     signature.data = (unsigned char *)sigBuf;
01685     signature.len = sigLen;
01686     digest.data = (unsigned char *)dataBuf;
01687     digest.len = dataLen;
01688     return ECDSA_VerifyDigest(&(key->u.ec), &signature, &digest);
01689 }
01690 
01691 static SECStatus
01692 nsc_ECDSASignStub(void *ctx, void *sigBuf,
01693                   unsigned int *sigLen, unsigned int maxSigLen,
01694                   void *dataBuf, unsigned int dataLen)
01695 {
01696     SECItem signature, digest;
01697     SECStatus rv;
01698     NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx;
01699 
01700     signature.data = (unsigned char *)sigBuf;
01701     signature.len = maxSigLen;
01702     digest.data = (unsigned char *)dataBuf;
01703     digest.len = dataLen;
01704     rv = ECDSA_SignDigest(&(key->u.ec), &signature, &digest);
01705     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
01706        sftk_fatalError = PR_TRUE;
01707     }
01708     *sigLen = signature.len;
01709     return rv;
01710 }
01711 #endif /* NSS_ENABLE_ECC */
01712 
01713 /* NSC_SignInit setups up the signing operations. There are three basic
01714  * types of signing:
01715  *     (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied
01716  *  to data in a single Sign operation (which often looks a lot like an
01717  *  encrypt, with data coming in and data going out).
01718  *     (2) Hash based signing, where we continually hash the data, then apply
01719  *  some sort of signature to the end.
01720  *     (3) Block Encryption CBC MAC's, where the Data is encrypted with a key,
01721  *  and only the final block is part of the mac.
01722  *
01723  *  For case number 3, we initialize a context much like the Encryption Context
01724  *  (in fact we share code). We detect case 3 in C_SignUpdate, C_Sign, and 
01725  *  C_Final by the following method... if it's not multi-part, and it's doesn't
01726  *  have a hash context, it must be a block Encryption CBC MAC.
01727  *
01728  *  For case number 2, we initialize a hash structure, as well as make it 
01729  *  multi-part. Updates are simple calls to the hash update function. Final
01730  *  calls the hashend, then passes the result to the 'update' function (which
01731  *  operates as a final signature function). In some hash based MAC'ing (as
01732  *  opposed to hash base signatures), the update function is can be simply a 
01733  *  copy (as is the case with HMAC).
01734  */
01735 CK_RV NSC_SignInit(CK_SESSION_HANDLE hSession,
01736                CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey)
01737 {
01738     SFTKSession *session;
01739     SFTKObject *key;
01740     SFTKSessionContext *context;
01741     CK_KEY_TYPE key_type;
01742     CK_RV crv = CKR_OK;
01743     NSSLOWKEYPrivateKey *privKey;
01744     SFTKHashSignInfo *info = NULL;
01745 
01746     /* Block Cipher MACing Algorithms use a different Context init method..*/
01747     crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, SFTK_SIGN);
01748     if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
01749 
01750     /* we're not using a block cipher mac */
01751     session = sftk_SessionFromHandle(hSession);
01752     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
01753     crv = sftk_InitGeneric(session,&context,SFTK_SIGN,&key,hKey,&key_type,
01754                                           CKO_PRIVATE_KEY,CKA_SIGN);
01755     if (crv != CKR_OK) {
01756        sftk_FreeSession(session);
01757        return crv;
01758     }
01759 
01760     context->multi = PR_FALSE;
01761 
01762 #define INIT_RSA_SIGN_MECH(mmm) \
01763     case CKM_ ## mmm ## _RSA_PKCS: \
01764         context->multi = PR_TRUE; \
01765        crv = sftk_doSub ## mmm (context); \
01766        if (crv != CKR_OK) break; \
01767        context->update = (SFTKCipher) sftk_HashSign; \
01768        info = PORT_New(SFTKHashSignInfo); \
01769        if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
01770        info->hashOid = SEC_OID_ ## mmm ; \
01771        goto finish_rsa; 
01772 
01773     switch(pMechanism->mechanism) {
01774     INIT_RSA_SIGN_MECH(MD5)
01775     INIT_RSA_SIGN_MECH(MD2)
01776     INIT_RSA_SIGN_MECH(SHA1)
01777     INIT_RSA_SIGN_MECH(SHA256)
01778     INIT_RSA_SIGN_MECH(SHA384)
01779     INIT_RSA_SIGN_MECH(SHA512)
01780 
01781     case CKM_RSA_PKCS:
01782        context->update = (SFTKCipher) RSA_Sign;
01783        goto finish_rsa;
01784     case CKM_RSA_X_509:
01785        context->update = (SFTKCipher)  RSA_SignRaw;
01786 finish_rsa:
01787        if (key_type != CKK_RSA) {
01788            if (info) PORT_Free(info);
01789            crv = CKR_KEY_TYPE_INCONSISTENT;
01790            break;
01791        }
01792        privKey = sftk_GetPrivKey(key,CKK_RSA,&crv);
01793        if (privKey == NULL) {
01794            if (info) PORT_Free(info);
01795            break;
01796        }
01797        /* OK, info is allocated only if we're doing hash and sign mechanism.
01798         * It's necessary to be able to set the correct OID in the final 
01799         * signature.
01800         */
01801        if (info) {
01802            info->key = privKey;
01803            context->cipherInfo = info;
01804            context->destroy = (SFTKDestroy)sftk_Space;
01805        } else {
01806            context->cipherInfo = privKey;
01807            context->destroy = (SFTKDestroy)sftk_Null;
01808        }
01809        context->maxLen = nsslowkey_PrivateModulusLen(privKey);
01810        break;
01811 
01812     case CKM_DSA_SHA1:
01813         context->multi = PR_TRUE;
01814        crv = sftk_doSubSHA1(context);
01815        if (crv != CKR_OK) break;
01816        /* fall through */
01817     case CKM_DSA:
01818        if (key_type != CKK_DSA) {
01819            crv = CKR_KEY_TYPE_INCONSISTENT;
01820            break;
01821        }
01822        privKey = sftk_GetPrivKey(key,CKK_DSA,&crv);
01823        if (privKey == NULL) {
01824            break;
01825        }
01826        context->cipherInfo = privKey;
01827        context->update     = (SFTKCipher) nsc_DSA_Sign_Stub;
01828        context->destroy    = (privKey == key->objectInfo) ?
01829               (SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
01830        context->maxLen     = DSA_SIGNATURE_LEN;
01831 
01832        break;
01833 
01834 #ifdef NSS_ENABLE_ECC
01835     case CKM_ECDSA_SHA1:
01836        context->multi = PR_TRUE;
01837        crv = sftk_doSubSHA1(context);
01838        if (crv != CKR_OK) break;
01839        /* fall through */
01840     case CKM_ECDSA:
01841        if (key_type != CKK_EC) {
01842            crv = CKR_KEY_TYPE_INCONSISTENT;
01843            break;
01844        }
01845        privKey = sftk_GetPrivKey(key,CKK_EC,&crv);
01846        if (privKey == NULL) {
01847            crv = CKR_HOST_MEMORY;
01848            break;
01849        }
01850        context->cipherInfo = privKey;
01851        context->update     = (SFTKCipher) nsc_ECDSASignStub;
01852        context->destroy    = (privKey == key->objectInfo) ?
01853               (SFTKDestroy) sftk_Null:(SFTKDestroy)sftk_FreePrivKey;
01854        context->maxLen     = MAX_ECKEY_LEN * 2;
01855 
01856        break;
01857 #endif /* NSS_ENABLE_ECC */
01858 
01859 #define INIT_HMAC_MECH(mmm) \
01860     case CKM_ ## mmm ## _HMAC_GENERAL: \
01861        crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, \
01862                             *(CK_ULONG *)pMechanism->pParameter); \
01863        break; \
01864     case CKM_ ## mmm ## _HMAC: \
01865        crv = sftk_doHMACInit(context, HASH_Alg ## mmm ,key, mmm ## _LENGTH); \
01866        break; 
01867 
01868     INIT_HMAC_MECH(MD2)
01869     INIT_HMAC_MECH(MD5)
01870     INIT_HMAC_MECH(SHA256)
01871     INIT_HMAC_MECH(SHA384)
01872     INIT_HMAC_MECH(SHA512)
01873 
01874     case CKM_SHA_1_HMAC_GENERAL:
01875        crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
01876                             *(CK_ULONG *)pMechanism->pParameter);
01877        break;
01878     case CKM_SHA_1_HMAC:
01879        crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
01880        break;
01881 
01882     case CKM_SSL3_MD5_MAC:
01883        crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
01884                                    *(CK_ULONG *)pMechanism->pParameter);
01885        break;
01886     case CKM_SSL3_SHA1_MAC:
01887        crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
01888                                    *(CK_ULONG *)pMechanism->pParameter);
01889        break;
01890     case CKM_TLS_PRF_GENERAL:
01891        crv = sftk_TLSPRFInit(context, key, key_type);
01892        break;
01893     default:
01894        crv = CKR_MECHANISM_INVALID;
01895        break;
01896     }
01897 
01898     if (crv != CKR_OK) {
01899         sftk_FreeContext(context);
01900        sftk_FreeSession(session);
01901        return crv;
01902     }
01903     sftk_SetContextByType(session, SFTK_SIGN, context);
01904     sftk_FreeSession(session);
01905     return CKR_OK;
01906 }
01907 
01908 
01909 /* MACUpdate is the common implementation for SignUpdate and VerifyUpdate.
01910  * (sign and verify only very in their setup and final operations) */
01911 static CK_RV 
01912 sftk_MACUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
01913                                    CK_ULONG ulPartLen,SFTKContextType type)
01914 {
01915     unsigned int outlen;
01916     SFTKSessionContext *context;
01917     CK_RV crv;
01918     SECStatus rv;
01919 
01920     /* make sure we're legal */
01921     crv = sftk_GetContext(hSession,&context,type,PR_TRUE,NULL);
01922     if (crv != CKR_OK) return crv;
01923 
01924     if (context->hashInfo) {
01925        (*context->hashUpdate)(context->hashInfo, pPart, ulPartLen);
01926        return CKR_OK;
01927     }
01928 
01929     /* must be block cipher macing */
01930 
01931     /* deal with previous buffered data */
01932     if (context->padDataLength != 0) {
01933        int i;
01934        /* fill in the padded to a full block size */
01935        for (i=context->padDataLength; (ulPartLen != 0) && 
01936                                    i < (int)context->blockSize; i++) {
01937            context->padBuf[i] = *pPart++;
01938            ulPartLen--;
01939            context->padDataLength++;
01940        }
01941 
01942        /* not enough data to encrypt yet? then return */
01943        if (context->padDataLength != context->blockSize)  return CKR_OK;
01944        /* encrypt the current padded data */
01945        rv = (*context->update)(context->cipherInfo,context->macBuf,&outlen,
01946                      SFTK_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
01947        if (rv != SECSuccess) return CKR_DEVICE_ERROR;
01948     }
01949 
01950     /* save the residual */
01951     context->padDataLength = ulPartLen % context->blockSize;
01952     if (context->padDataLength) {
01953        PORT_Memcpy(context->padBuf,
01954                   &pPart[ulPartLen-context->padDataLength],
01955                   context->padDataLength);
01956        ulPartLen -= context->padDataLength;
01957     }
01958 
01959     /* if we've exhausted our new buffer, we're done */
01960     if (ulPartLen == 0) { return CKR_OK; }
01961 
01962     /* run the data through out encrypter */     
01963     while (ulPartLen) {
01964        rv = (*context->update)(context->cipherInfo, context->padBuf, &outlen, 
01965                      SFTK_MAX_BLOCK_SIZE, pPart, context->blockSize);
01966        if (rv != SECSuccess) return CKR_DEVICE_ERROR;
01967        /* paranoia.. make sure we exit the loop */
01968        PORT_Assert(ulPartLen >= context->blockSize);
01969        if (ulPartLen < context->blockSize) break;
01970        ulPartLen -= context->blockSize;
01971     }
01972 
01973     return CKR_OK;
01974        
01975 }
01976 
01977 /* NSC_SignUpdate continues a multiple-part signature operation,
01978  * where the signature is (will be) an appendix to the data, 
01979  * and plaintext cannot be recovered from the signature */
01980 CK_RV NSC_SignUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,
01981                                                  CK_ULONG ulPartLen)
01982 {
01983     return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_SIGN);
01984 }
01985 
01986 
01987 /* NSC_SignFinal finishes a multiple-part signature operation, 
01988  * returning the signature. */
01989 CK_RV NSC_SignFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature,
01990                                        CK_ULONG_PTR pulSignatureLen)
01991 {
01992     SFTKSession *session;
01993     SFTKSessionContext *context;
01994     unsigned int outlen;
01995     unsigned int digestLen;
01996     unsigned int maxoutlen = *pulSignatureLen;
01997     unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
01998     CK_RV crv;
01999     SECStatus rv = SECSuccess;
02000 
02001     /* make sure we're legal */
02002     *pulSignatureLen = 0;
02003     crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_TRUE,&session);
02004     if (crv != CKR_OK) return crv;
02005 
02006     if (!pSignature) {
02007        *pulSignatureLen = context->maxLen;
02008        goto finish;
02009     } else if (context->hashInfo) {
02010         (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
02011        rv = (*context->update)(context->cipherInfo, pSignature,
02012                                    &outlen, maxoutlen, tmpbuf, digestLen);
02013         *pulSignatureLen = (CK_ULONG) outlen;
02014     } else {
02015        /* deal with the last block if any residual */
02016        if (context->padDataLength) {
02017            /* fill out rest of pad buffer with pad magic*/
02018            int i;
02019            for (i=context->padDataLength; i < (int)context->blockSize; i++) {
02020               context->padBuf[i] = 0;
02021            }
02022            rv = (*context->update)(context->cipherInfo,context->macBuf,
02023               &outlen,SFTK_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
02024        }
02025        if (rv == SECSuccess) {
02026            PORT_Memcpy(pSignature,context->macBuf,context->macSize);
02027            *pulSignatureLen = context->macSize;
02028        }
02029     }
02030 
02031     sftk_FreeContext(context);
02032     sftk_SetContextByType(session, SFTK_SIGN, NULL);
02033 
02034 finish:
02035     sftk_FreeSession(session);
02036 
02037     return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
02038 }
02039 
02040 /* NSC_Sign signs (encrypts with private key) data in a single part,
02041  * where the signature is (will be) an appendix to the data, 
02042  * and plaintext cannot be recovered from the signature */
02043 CK_RV NSC_Sign(CK_SESSION_HANDLE hSession,
02044     CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,
02045                                    CK_ULONG_PTR pulSignatureLen)
02046 {
02047     SFTKSession *session;
02048     SFTKSessionContext *context;
02049     unsigned int outlen;
02050     unsigned int maxoutlen = *pulSignatureLen;
02051     CK_RV crv,crv2;
02052     SECStatus rv = SECSuccess;
02053 
02054     /* make sure we're legal */
02055     crv = sftk_GetContext(hSession,&context,SFTK_SIGN,PR_FALSE,&session);
02056     if (crv != CKR_OK) return crv;
02057 
02058     if (!pSignature) {
02059        *pulSignatureLen = context->maxLen;
02060        goto finish;
02061     }
02062 
02063     /* multi part Signing are completely implemented by SignUpdate and
02064      * sign Final */
02065     if (context->multi) {
02066         sftk_FreeSession(session);
02067        crv = NSC_SignUpdate(hSession,pData,ulDataLen);
02068        if (crv != CKR_OK) *pulSignatureLen = 0;
02069        crv2 = NSC_SignFinal(hSession, pSignature, pulSignatureLen);
02070        return crv == CKR_OK ? crv2 :crv;
02071     }
02072 
02073     rv = (*context->update)(context->cipherInfo, pSignature,
02074                                    &outlen, maxoutlen, pData, ulDataLen);
02075     *pulSignatureLen = (CK_ULONG) outlen;
02076     sftk_FreeContext(context);
02077     sftk_SetContextByType(session, SFTK_SIGN, NULL);
02078 
02079 finish:
02080     sftk_FreeSession(session);
02081 
02082     return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
02083 }
02084 
02085 
02086 /*
02087  ************** Crypto Functions:     Sign Recover  ************************
02088  */
02089 /* NSC_SignRecoverInit initializes a signature operation,
02090  * where the (digest) data can be recovered from the signature. 
02091  * E.g. encryption with the user's private key */
02092 CK_RV NSC_SignRecoverInit(CK_SESSION_HANDLE hSession,
02093                       CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
02094 {
02095     switch (pMechanism->mechanism) {
02096     case CKM_RSA_PKCS:
02097     case CKM_RSA_X_509:
02098        return NSC_SignInit(hSession,pMechanism,hKey);
02099     default:
02100        break;
02101     }
02102     return CKR_MECHANISM_INVALID;
02103 }
02104 
02105 
02106 /* NSC_SignRecover signs data in a single operation
02107  * where the (digest) data can be recovered from the signature. 
02108  * E.g. encryption with the user's private key */
02109 CK_RV NSC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
02110   CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
02111 {
02112     return NSC_Sign(hSession,pData,ulDataLen,pSignature,pulSignatureLen);
02113 }
02114 
02115 /*
02116  ************** Crypto Functions:     verify  ************************
02117  */
02118 
02119 /* Handle RSA Signature formatting */
02120 static SECStatus
02121 sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, 
02122        unsigned int sigLen, unsigned char *digest, unsigned int digestLen)
02123 {
02124     return RSA_HashCheckSign(info->hashOid, info->key, sig, sigLen,
02125                                           digest, digestLen);
02126 }
02127 
02128 SECStatus
02129 RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
02130        unsigned char *sig, unsigned int sigLen,
02131        unsigned char *digest, unsigned int digestLen)
02132 {
02133 
02134     SECItem it;
02135     SGNDigestInfo *di = NULL;
02136     SECStatus rv = SECSuccess;
02137     
02138     it.data = NULL;
02139 
02140     if (key == NULL) goto loser;
02141 
02142     it.len = nsslowkey_PublicModulusLen(key); 
02143     if (!it.len) goto loser;
02144 
02145     it.data = (unsigned char *) PORT_Alloc(it.len);
02146     if (it.data == NULL) goto loser;
02147 
02148     /* decrypt the block */
02149     rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen);
02150     if (rv != SECSuccess) goto loser;
02151 
02152     di = SGN_DecodeDigestInfo(&it);
02153     if (di == NULL) goto loser;
02154     if (di->digest.len != digestLen)  goto loser; 
02155 
02156     /* make sure the tag is OK */
02157     if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) {
02158        goto loser;
02159     }
02160     /* make sure the "parameters" are not too bogus. */
02161     if (di->digestAlgorithm.parameters.len > 2) {
02162        goto loser;
02163     }
02164     /* Now check the signature */
02165     if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) {
02166        goto done;
02167     }
02168 
02169   loser:
02170     PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
02171     rv = SECFailure;
02172 
02173   done:
02174     if (it.data != NULL) PORT_Free(it.data);
02175     if (di != NULL) SGN_DestroyDigestInfo(di);
02176     
02177     return rv;
02178 }
02179 
02180 /* NSC_VerifyInit initializes a verification operation, 
02181  * where the signature is an appendix to the data, 
02182  * and plaintext cannot be recovered from the signature (e.g. DSA) */
02183 CK_RV NSC_VerifyInit(CK_SESSION_HANDLE hSession,
02184                         CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey) 
02185 {
02186     SFTKSession *session;
02187     SFTKObject *key;
02188     SFTKSessionContext *context;
02189     CK_KEY_TYPE key_type;
02190     CK_RV crv = CKR_OK;
02191     NSSLOWKEYPublicKey *pubKey;
02192     SFTKHashVerifyInfo *info = NULL;
02193 
02194     /* Block Cipher MACing Algorithms use a different Context init method..*/
02195     crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_VERIFY, SFTK_VERIFY);
02196     if (crv != CKR_FUNCTION_NOT_SUPPORTED) return crv;
02197 
02198     session = sftk_SessionFromHandle(hSession);
02199     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
02200     crv = sftk_InitGeneric(session,&context,SFTK_VERIFY,&key,hKey,&key_type,
02201                                           CKO_PUBLIC_KEY,CKA_VERIFY);
02202     if (crv != CKR_OK) {
02203        sftk_FreeSession(session);
02204        return crv;
02205     }
02206 
02207     context->multi = PR_FALSE;
02208 
02209 #define INIT_RSA_VFY_MECH(mmm) \
02210     case CKM_ ## mmm ## _RSA_PKCS: \
02211         context->multi = PR_TRUE; \
02212        crv = sftk_doSub ## mmm (context); \
02213        if (crv != CKR_OK) break; \
02214        context->verify = (SFTKVerify) sftk_hashCheckSign; \
02215        info = PORT_New(SFTKHashVerifyInfo); \
02216        if (info == NULL) { crv = CKR_HOST_MEMORY; break; } \
02217        info->hashOid = SEC_OID_ ## mmm ; \
02218        goto finish_rsa; 
02219 
02220     switch(pMechanism->mechanism) {
02221     INIT_RSA_VFY_MECH(MD5) 
02222     INIT_RSA_VFY_MECH(MD2) 
02223     INIT_RSA_VFY_MECH(SHA1) 
02224     INIT_RSA_VFY_MECH(SHA256) 
02225     INIT_RSA_VFY_MECH(SHA384) 
02226     INIT_RSA_VFY_MECH(SHA512) 
02227 
02228     case CKM_RSA_PKCS:
02229        context->verify = (SFTKVerify) RSA_CheckSign;
02230        goto finish_rsa;
02231     case CKM_RSA_X_509:
02232        context->verify = (SFTKVerify) RSA_CheckSignRaw;
02233 finish_rsa:
02234        if (key_type != CKK_RSA) {
02235            crv = CKR_KEY_TYPE_INCONSISTENT;
02236            break;
02237        }
02238        pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
02239        if (pubKey == NULL) {
02240            break;
02241        }
02242        if (info) {
02243            info->key = pubKey;
02244            context->cipherInfo = info;
02245            context->destroy = sftk_Space;
02246        } else {
02247            context->cipherInfo = pubKey;
02248            context->destroy = sftk_Null;
02249        }
02250        break;
02251     case CKM_DSA_SHA1:
02252         context->multi = PR_TRUE;
02253        crv = sftk_doSubSHA1(context);
02254        if (crv != CKR_OK) break;
02255        /* fall through */
02256     case CKM_DSA:
02257        if (key_type != CKK_DSA) {
02258            crv = CKR_KEY_TYPE_INCONSISTENT;
02259            break;
02260        }
02261        pubKey = sftk_GetPubKey(key,CKK_DSA,&crv);
02262        if (pubKey == NULL) {
02263            break;
02264        }
02265        context->cipherInfo = pubKey;
02266        context->verify     = (SFTKVerify) nsc_DSA_Verify_Stub;
02267        context->destroy    = sftk_Null;
02268        break;
02269 #ifdef NSS_ENABLE_ECC
02270     case CKM_ECDSA_SHA1:
02271        context->multi = PR_TRUE;
02272        crv = sftk_doSubSHA1(context);
02273        if (crv != CKR_OK) break;
02274        /* fall through */
02275     case CKM_ECDSA:
02276        if (key_type != CKK_EC) {
02277            crv = CKR_KEY_TYPE_INCONSISTENT;
02278            break;
02279        }
02280        pubKey = sftk_GetPubKey(key,CKK_EC,&crv);
02281        if (pubKey == NULL) {
02282            crv = CKR_HOST_MEMORY;
02283            break;
02284        }
02285        context->cipherInfo = pubKey;
02286        context->verify     = (SFTKVerify) nsc_ECDSAVerifyStub;
02287        context->destroy    = sftk_Null;
02288        break;
02289 #endif /* NSS_ENABLE_ECC */
02290 
02291     INIT_HMAC_MECH(MD2)
02292     INIT_HMAC_MECH(MD5)
02293     INIT_HMAC_MECH(SHA256)
02294     INIT_HMAC_MECH(SHA384)
02295     INIT_HMAC_MECH(SHA512)
02296 
02297     case CKM_SHA_1_HMAC_GENERAL:
02298        crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,
02299                             *(CK_ULONG *)pMechanism->pParameter);
02300        break;
02301     case CKM_SHA_1_HMAC:
02302        crv = sftk_doHMACInit(context,HASH_AlgSHA1,key,SHA1_LENGTH);
02303        break;
02304 
02305     case CKM_SSL3_MD5_MAC:
02306        crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
02307                                    *(CK_ULONG *)pMechanism->pParameter);
02308        break;
02309     case CKM_SSL3_SHA1_MAC:
02310        crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
02311                                    *(CK_ULONG *)pMechanism->pParameter);
02312        break;
02313     case CKM_TLS_PRF_GENERAL:
02314        crv = sftk_TLSPRFInit(context, key, key_type);
02315        break;
02316 
02317     default:
02318        crv = CKR_MECHANISM_INVALID;
02319        break;
02320     }
02321 
02322     if (crv != CKR_OK) {
02323        if (info) PORT_Free(info);
02324         PORT_Free(context);
02325        sftk_FreeSession(session);
02326        return crv;
02327     }
02328     sftk_SetContextByType(session, SFTK_VERIFY, context);
02329     sftk_FreeSession(session);
02330     return CKR_OK;
02331 }
02332 
02333 /* NSC_Verify verifies a signature in a single-part operation, 
02334  * where the signature is an appendix to the data, 
02335  * and plaintext cannot be recovered from the signature */
02336 CK_RV NSC_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
02337     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
02338 {
02339     SFTKSession *session;
02340     SFTKSessionContext *context;
02341     CK_RV crv, crv2;
02342     SECStatus rv;
02343 
02344     /* make sure we're legal */
02345     crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_FALSE,&session);
02346     if (crv != CKR_OK) return crv;
02347 
02348     /* multi part Verifying are completely implemented by VerifyUpdate and
02349      * VerifyFinal */
02350     if (context->multi) {
02351        sftk_FreeSession(session);
02352        crv = NSC_VerifyUpdate(hSession, pData, ulDataLen);
02353        crv2 = NSC_VerifyFinal(hSession, pSignature, ulSignatureLen);
02354        return crv == CKR_OK ? crv2 :crv;
02355     }
02356 
02357     rv = (*context->verify)(context->cipherInfo,pSignature, ulSignatureLen,
02358                                                   pData, ulDataLen);
02359     sftk_FreeContext(context);
02360     sftk_SetContextByType(session, SFTK_VERIFY, NULL);
02361     sftk_FreeSession(session);
02362 
02363     return (rv == SECSuccess) ? CKR_OK : CKR_SIGNATURE_INVALID;
02364 
02365 }
02366 
02367 
02368 /* NSC_VerifyUpdate continues a multiple-part verification operation, 
02369  * where the signature is an appendix to the data, 
02370  * and plaintext cannot be recovered from the signature */
02371 CK_RV NSC_VerifyUpdate( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
02372                                           CK_ULONG ulPartLen)
02373 {
02374     return sftk_MACUpdate(hSession, pPart, ulPartLen, SFTK_VERIFY);
02375 }
02376 
02377 
02378 /* NSC_VerifyFinal finishes a multiple-part verification operation, 
02379  * checking the signature. */
02380 CK_RV NSC_VerifyFinal(CK_SESSION_HANDLE hSession,
02381                      CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)
02382 {
02383     SFTKSession *session;
02384     SFTKSessionContext *context;
02385     unsigned int outlen;
02386     unsigned int digestLen;
02387     unsigned char tmpbuf[SFTK_MAX_MAC_LENGTH];
02388     CK_RV crv;
02389     SECStatus rv = SECSuccess;
02390 
02391     /* make sure we're legal */
02392     crv = sftk_GetContext(hSession,&context,SFTK_VERIFY,PR_TRUE,&session);
02393     if (crv != CKR_OK) return crv;
02394 
02395     if (context->hashInfo) {
02396         (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
02397        rv = (*context->verify)(context->cipherInfo, pSignature, 
02398                                    ulSignatureLen, tmpbuf, digestLen);
02399     } else {
02400        if (context->padDataLength) {
02401            /* fill out rest of pad buffer with pad magic*/
02402            int i;
02403            for (i=context->padDataLength; i < (int)context->blockSize; i++) {
02404               context->padBuf[i] = 0;
02405            }
02406            rv = (*context->update)(context->cipherInfo,context->macBuf, 
02407               &outlen,SFTK_MAX_BLOCK_SIZE,context->padBuf,context->blockSize);
02408        }
02409        if (rv == SECSuccess) {
02410            rv =(PORT_Memcmp(pSignature,context->macBuf,context->macSize) == 0)
02411                              ? SECSuccess : SECFailure;
02412        }
02413     }
02414 
02415     sftk_FreeContext(context);
02416     sftk_SetContextByType(session, SFTK_VERIFY, NULL);
02417     sftk_FreeSession(session);
02418     return (rv == SECSuccess) ? CKR_OK : CKR_SIGNATURE_INVALID;
02419 
02420 }
02421 
02422 /*
02423  ************** Crypto Functions:     Verify  Recover ************************
02424  */
02425 
02426 /* NSC_VerifyRecoverInit initializes a signature verification operation, 
02427  * where the data is recovered from the signature. 
02428  * E.g. Decryption with the user's public key */
02429 CK_RV NSC_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
02430                      CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)
02431 {
02432     SFTKSession *session;
02433     SFTKObject *key;
02434     SFTKSessionContext *context;
02435     CK_KEY_TYPE key_type;
02436     CK_RV crv = CKR_OK;
02437     NSSLOWKEYPublicKey *pubKey;
02438 
02439     session = sftk_SessionFromHandle(hSession);
02440     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
02441     crv = sftk_InitGeneric(session,&context,SFTK_VERIFY_RECOVER,
02442                      &key,hKey,&key_type,CKO_PUBLIC_KEY,CKA_VERIFY_RECOVER);
02443     if (crv != CKR_OK) {
02444        sftk_FreeSession(session);
02445        return crv;
02446     }
02447 
02448     context->multi = PR_TRUE;
02449 
02450     switch(pMechanism->mechanism) {
02451     case CKM_RSA_PKCS:
02452     case CKM_RSA_X_509:
02453        if (key_type != CKK_RSA) {
02454            crv = CKR_KEY_TYPE_INCONSISTENT;
02455            break;
02456        }
02457        context->multi = PR_FALSE;
02458        pubKey = sftk_GetPubKey(key,CKK_RSA,&crv);
02459        if (pubKey == NULL) {
02460            break;
02461        }
02462        context->cipherInfo = pubKey;
02463        context->update = (SFTKCipher) (pMechanism->mechanism == CKM_RSA_X_509
02464                      ? RSA_CheckSignRecoverRaw : RSA_CheckSignRecover);
02465        context->destroy = sftk_Null;
02466        break;
02467     default:
02468        crv = CKR_MECHANISM_INVALID;
02469        break;
02470     }
02471 
02472     if (crv != CKR_OK) {
02473         PORT_Free(context);
02474        sftk_FreeSession(session);
02475        return crv;
02476     }
02477     sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, context);
02478     sftk_FreeSession(session);
02479     return CKR_OK;
02480 }
02481 
02482 
02483 /* NSC_VerifyRecover verifies a signature in a single-part operation, 
02484  * where the data is recovered from the signature. 
02485  * E.g. Decryption with the user's public key */
02486 CK_RV NSC_VerifyRecover(CK_SESSION_HANDLE hSession,
02487                CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen,
02488                             CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)
02489 {
02490     SFTKSession *session;
02491     SFTKSessionContext *context;
02492     unsigned int outlen;
02493     unsigned int maxoutlen = *pulDataLen;
02494     CK_RV crv;
02495     SECStatus rv;
02496 
02497     /* make sure we're legal */
02498     crv = sftk_GetContext(hSession,&context,SFTK_VERIFY_RECOVER,
02499                                                  PR_FALSE,&session);
02500     if (crv != CKR_OK) return crv;
02501     if (pData == NULL) {
02502        /* to return the actual size, we need  to do the decrypt, just return
02503         * the max size, which is the size of the input signature. */
02504        *pulDataLen = ulSignatureLen;
02505        rv = SECSuccess;
02506        goto finish;
02507     }
02508 
02509     rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, 
02510                                           pSignature, ulSignatureLen);
02511     *pulDataLen = (CK_ULONG) outlen;
02512 
02513     sftk_FreeContext(context);
02514     sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, NULL);
02515 finish:
02516     sftk_FreeSession(session);
02517     return (rv == SECSuccess)  ? CKR_OK : CKR_SIGNATURE_INVALID;
02518 }
02519 
02520 /*
02521  **************************** Random Functions:  ************************
02522  */
02523 
02524 /* NSC_SeedRandom mixes additional seed material into the token's random number 
02525  * generator. */
02526 CK_RV NSC_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
02527     CK_ULONG ulSeedLen) 
02528 {
02529     SECStatus rv;
02530 
02531     rv = RNG_RandomUpdate(pSeed, ulSeedLen);
02532     return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
02533 }
02534 
02535 /* NSC_GenerateRandom generates random data. */
02536 CK_RV NSC_GenerateRandom(CK_SESSION_HANDLE hSession,
02537     CK_BYTE_PTR      pRandomData, CK_ULONG ulRandomLen)
02538 {
02539     SECStatus rv;
02540 
02541     rv = RNG_GenerateGlobalRandomBytes(pRandomData, ulRandomLen);
02542     return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
02543 }
02544 
02545 /*
02546  **************************** Key Functions:  ************************
02547  */
02548 
02549 
02550 /*
02551  * generate a password based encryption key. This code uses
02552  * PKCS5 to do the work.
02553  */
02554 static CK_RV
02555 nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism,
02556                      char *buf, CK_ULONG *key_length, PRBool faulty3DES)
02557 {
02558     SECItem *pbe_key = NULL, iv, pwitem;
02559     CK_PBE_PARAMS *pbe_params = NULL;
02560 
02561     *key_length = 0;
02562     iv.data = NULL; iv.len = 0;
02563 
02564     pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
02565 
02566     pwitem.data = (unsigned char *)pbe_params->pPassword;
02567     pwitem.len = (unsigned int)pbe_params->ulPasswordLen;
02568     pbe_key = nsspkcs5_ComputeKeyAndIV(pkcs5_pbe, &pwitem, &iv, faulty3DES);
02569     if (pbe_key == NULL) {
02570        return CKR_HOST_MEMORY;
02571     }
02572 
02573     PORT_Memcpy(buf, pbe_key->data, pbe_key->len);
02574     *key_length = pbe_key->len;
02575     SECITEM_ZfreeItem(pbe_key, PR_TRUE);
02576     pbe_key = NULL;
02577 
02578     if (iv.data) {
02579         if (pbe_params->pInitVector != NULL) {
02580            PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len);
02581         }
02582         PORT_Free(iv.data);
02583     }
02584 
02585     return CKR_OK;
02586 }
02587 static CK_RV
02588 nsc_parameter_gen(CK_KEY_TYPE key_type, SFTKObject *key)
02589 {
02590     SFTKAttribute *attribute;
02591     CK_ULONG counter;
02592     unsigned int seedBits = 0;
02593     unsigned int primeBits;
02594     unsigned int j;
02595     CK_RV crv = CKR_OK;
02596     PQGParams *params = NULL;
02597     PQGVerify *vfy = NULL;
02598     SECStatus rv;
02599 
02600     attribute = sftk_FindAttribute(key, CKA_PRIME_BITS);
02601     if (attribute == NULL) {
02602        return CKR_TEMPLATE_INCOMPLETE;
02603     }
02604     primeBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
02605     sftk_FreeAttribute(attribute);
02606     j = PQG_PBITS_TO_INDEX(primeBits);
02607     if (j == (unsigned int)-1) {
02608        return CKR_ATTRIBUTE_VALUE_INVALID;
02609     }
02610 
02611     attribute = sftk_FindAttribute(key, CKA_NETSCAPE_PQG_SEED_BITS);
02612     if (attribute != NULL) {
02613        seedBits = (unsigned int) *(CK_ULONG *)attribute->attrib.pValue;
02614        sftk_FreeAttribute(attribute);
02615     }
02616 
02617     sftk_DeleteAttributeType(key,CKA_PRIME_BITS);
02618     sftk_DeleteAttributeType(key,CKA_NETSCAPE_PQG_SEED_BITS);
02619 
02620     if (seedBits == 0) {
02621        rv = PQG_ParamGen(j, &params, &vfy);
02622     } else {
02623        rv = PQG_ParamGenSeedLen(j,seedBits/8, &params, &vfy);
02624     }
02625 
02626     if (rv != SECSuccess) {
02627        if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
02628            sftk_fatalError = PR_TRUE;
02629        }
02630        return CKR_DEVICE_ERROR;
02631     }
02632     crv = sftk_AddAttributeType(key,CKA_PRIME,
02633                              params->prime.data, params->prime.len);
02634     if (crv != CKR_OK) goto loser;
02635     crv = sftk_AddAttributeType(key,CKA_SUBPRIME,
02636                              params->subPrime.data, params->subPrime.len);
02637     if (crv != CKR_OK) goto loser;
02638     crv = sftk_AddAttributeType(key,CKA_BASE,
02639                              params->base.data, params->base.len);
02640     if (crv != CKR_OK) goto loser;
02641     counter = vfy->counter;
02642     crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_COUNTER,
02643                              &counter, sizeof(counter));
02644     crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_SEED,
02645                              vfy->seed.data, vfy->seed.len);
02646     if (crv != CKR_OK) goto loser;
02647     crv = sftk_AddAttributeType(key,CKA_NETSCAPE_PQG_H,
02648                              vfy->h.data, vfy->h.len);
02649     if (crv != CKR_OK) goto loser;
02650 
02651 loser:
02652     if (params) {
02653        PQG_DestroyParams(params);
02654     }
02655     if (vfy) {
02656        PQG_DestroyVerify(vfy);
02657     }
02658     return crv;
02659 }
02660 
02661     
02662 
02663     
02664 
02665 
02666 
02667 static CK_RV
02668 nsc_SetupBulkKeyGen(CK_MECHANISM_TYPE mechanism, CK_KEY_TYPE *key_type,
02669                                                  CK_ULONG *key_length)
02670 {
02671     CK_RV crv = CKR_OK;
02672 
02673     switch (mechanism) {
02674     case CKM_RC2_KEY_GEN:
02675        *key_type = CKK_RC2;
02676        if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
02677        break;
02678 #if NSS_SOFTOKEN_DOES_RC5
02679     case CKM_RC5_KEY_GEN:
02680        *key_type = CKK_RC5;
02681        if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
02682        break;
02683 #endif
02684     case CKM_RC4_KEY_GEN:
02685        *key_type = CKK_RC4;
02686        if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
02687        break;
02688     case CKM_GENERIC_SECRET_KEY_GEN:
02689        *key_type = CKK_GENERIC_SECRET;
02690        if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
02691        break;
02692     case CKM_CDMF_KEY_GEN:
02693        *key_type = CKK_CDMF;
02694        *key_length = 8;
02695        break;
02696     case CKM_DES_KEY_GEN:
02697        *key_type = CKK_DES;
02698        *key_length = 8;
02699        break;
02700     case CKM_DES2_KEY_GEN:
02701        *key_type = CKK_DES2;
02702        *key_length = 16;
02703        break;
02704     case CKM_DES3_KEY_GEN:
02705        *key_type = CKK_DES3;
02706        *key_length = 24;
02707        break;
02708     case CKM_AES_KEY_GEN:
02709        *key_type = CKK_AES;
02710        if (*key_length == 0) crv = CKR_TEMPLATE_INCOMPLETE;
02711        break;
02712     default:
02713        PORT_Assert(0);
02714        crv = CKR_MECHANISM_INVALID;
02715        break;
02716     }
02717 
02718     return crv;
02719 }
02720 
02721 CK_RV
02722 nsc_SetupHMACKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter **pbe)
02723 {
02724     SECItem  salt;
02725     CK_PBE_PARAMS *pbe_params = NULL;
02726     NSSPKCS5PBEParameter *params;
02727     PRArenaPool *arena = NULL;
02728     SECStatus rv;
02729 
02730     *pbe = NULL;
02731 
02732     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
02733     if (arena == NULL) {
02734        return CKR_HOST_MEMORY;
02735     }
02736 
02737     params = (NSSPKCS5PBEParameter *) PORT_ArenaZAlloc(arena,
02738                             sizeof(NSSPKCS5PBEParameter));
02739     if (params == NULL) {
02740        PORT_FreeArena(arena,PR_TRUE);
02741        return CKR_HOST_MEMORY;
02742     }
02743 
02744     params->poolp = arena;
02745     params->ivLen = 0;
02746     params->pbeType = NSSPKCS5_PKCS12_V2;
02747     params->hashType = HASH_AlgSHA1;
02748     params->encAlg = SEC_OID_SHA1; /* any invalid value */
02749     params->is2KeyDES = PR_FALSE;
02750     params->keyID = pbeBitGenIntegrityKey;
02751     pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
02752     params->iter = pbe_params->ulIteration;
02753 
02754     salt.data = (unsigned char *)pbe_params->pSalt;
02755     salt.len = (unsigned int)pbe_params->ulSaltLen;
02756     rv = SECITEM_CopyItem(arena,&params->salt,&salt);
02757     if (rv != SECSuccess) {
02758        PORT_FreeArena(arena,PR_TRUE);
02759        return CKR_HOST_MEMORY;
02760     }
02761     switch (pMechanism->mechanism) {
02762     case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
02763     case CKM_PBA_SHA1_WITH_SHA1_HMAC:
02764        params->hashType = HASH_AlgSHA1; 
02765        params->keyLen = 20;
02766        break;
02767     case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
02768        params->hashType = HASH_AlgMD5; 
02769        params->keyLen = 16;
02770        break;
02771     case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
02772        params->hashType = HASH_AlgMD2; 
02773        params->keyLen = 16;
02774        break;
02775     default:
02776        PORT_FreeArena(arena,PR_TRUE);
02777        return CKR_MECHANISM_INVALID;
02778     }
02779     *pbe = params;
02780     return CKR_OK;
02781 }
02782 /* maybe this should be table driven? */
02783 static CK_RV
02784 nsc_SetupPBEKeyGen(CK_MECHANISM_PTR pMechanism, NSSPKCS5PBEParameter  **pbe,
02785                                                  CK_KEY_TYPE *key_type)
02786 {
02787     CK_RV crv = CKR_OK;
02788     SECOidData *oid;
02789     CK_PBE_PARAMS *pbe_params;
02790     NSSPKCS5PBEParameter *params;
02791     SECItem salt;
02792 
02793     *pbe = NULL;
02794 
02795     oid = SECOID_FindOIDByMechanism(pMechanism->mechanism);
02796     if (oid == NULL) {
02797        return CKR_MECHANISM_INVALID;
02798     }
02799 
02800     pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter;
02801     salt.data = (unsigned char *)pbe_params->pSalt;
02802     salt.len = (unsigned int)pbe_params->ulSaltLen;
02803 
02804     params=nsspkcs5_NewParam(oid->offset, &salt, pbe_params->ulIteration);
02805     if (params == NULL) {
02806        return CKR_MECHANISM_INVALID;
02807     }
02808 
02809 
02810     switch (params->encAlg) {
02811     case SEC_OID_DES_CBC:
02812        *key_type = CKK_DES;
02813        break;
02814     case SEC_OID_DES_EDE3_CBC:
02815        *key_type = params->is2KeyDES ? CKK_DES2 : CKK_DES3;
02816        break;
02817     case SEC_OID_RC2_CBC:
02818        *key_type = CKK_RC2;
02819        break;
02820     case SEC_OID_RC4:
02821        *key_type = CKK_RC4;
02822        break;
02823     default:
02824        crv = CKR_MECHANISM_INVALID;
02825        nsspkcs5_DestroyPBEParameter(params);
02826        break;
02827     }
02828     if (crv == CKR_OK) {
02829        *pbe = params;
02830     }
02831     return crv;
02832 }
02833 
02834 /* NSC_GenerateKey generates a secret key, creating a new key object. */
02835 CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession,
02836     CK_MECHANISM_PTR pMechanism,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,
02837                                           CK_OBJECT_HANDLE_PTR phKey)
02838 {
02839     SFTKObject *key;
02840     SFTKSession *session;
02841     PRBool checkWeak = PR_FALSE;
02842     CK_ULONG key_length = 0;
02843     CK_KEY_TYPE key_type = CKK_INVALID_KEY_TYPE;
02844     CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
02845     CK_RV crv = CKR_OK;
02846     CK_BBOOL cktrue = CK_TRUE;
02847     int i;
02848     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
02849     char buf[MAX_KEY_LEN];
02850     enum {nsc_pbe, nsc_ssl, nsc_bulk, nsc_param} key_gen_type;
02851     NSSPKCS5PBEParameter *pbe_param;
02852     SSL3RSAPreMasterSecret *rsa_pms;
02853     CK_VERSION *version;
02854     /* in very old versions of NSS, there were implementation errors with key 
02855      * generation methods.  We want to beable to read these, but not 
02856      * produce them any more.  The affected algorithm was 3DES.
02857      */
02858     PRBool faultyPBE3DES = PR_FALSE;
02859 
02860 
02861     /*
02862      * now lets create an object to hang the attributes off of
02863      */
02864     key = sftk_NewObject(slot); /* fill in the handle later */
02865     if (key == NULL) {
02866        return CKR_HOST_MEMORY;
02867     }
02868 
02869     /*
02870      * load the template values into the object
02871      */
02872     for (i=0; i < (int) ulCount; i++) {
02873        if (pTemplate[i].type == CKA_VALUE_LEN) {
02874            key_length = *(CK_ULONG *)pTemplate[i].pValue;
02875            continue;
02876        }
02877 
02878        crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
02879        if (crv != CKR_OK) break;
02880     }
02881     if (crv != CKR_OK) {
02882        sftk_FreeObject(key);
02883        return crv;
02884     }
02885 
02886     /* make sure we don't have any class, key_type, or value fields */
02887     sftk_DeleteAttributeType(key,CKA_CLASS);
02888     sftk_DeleteAttributeType(key,CKA_KEY_TYPE);
02889     sftk_DeleteAttributeType(key,CKA_VALUE);
02890 
02891     /* Now Set up the parameters to generate the key (based on mechanism) */
02892     key_gen_type = nsc_bulk; /* bulk key by default */
02893     switch (pMechanism->mechanism) {
02894     case CKM_CDMF_KEY_GEN:
02895     case CKM_DES_KEY_GEN:
02896     case CKM_DES2_KEY_GEN:
02897     case CKM_DES3_KEY_GEN:
02898        checkWeak = PR_TRUE;
02899     case CKM_RC2_KEY_GEN:
02900     case CKM_RC4_KEY_GEN:
02901     case CKM_GENERIC_SECRET_KEY_GEN:
02902     case CKM_AES_KEY_GEN:
02903 #if NSS_SOFTOKEN_DOES_RC5
02904     case CKM_RC5_KEY_GEN:
02905 #endif
02906        crv = nsc_SetupBulkKeyGen(pMechanism->mechanism,&key_type,&key_length);
02907        break;
02908     case CKM_SSL3_PRE_MASTER_KEY_GEN:
02909        key_type = CKK_GENERIC_SECRET;
02910        key_length = 48;
02911        key_gen_type = nsc_ssl;
02912        break;
02913     case CKM_PBA_SHA1_WITH_SHA1_HMAC:
02914     case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
02915     case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
02916     case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
02917        key_gen_type = nsc_pbe;
02918        key_type = CKK_GENERIC_SECRET;
02919        crv = nsc_SetupHMACKeyGen(pMechanism, &pbe_param);
02920        break;
02921     case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC:
02922        faultyPBE3DES = PR_TRUE;
02923     case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC:
02924     case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC:
02925     case CKM_NETSCAPE_PBE_SHA1_DES_CBC:
02926     case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC:
02927     case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4:
02928     case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4:
02929     case CKM_PBE_SHA1_DES3_EDE_CBC:
02930     case CKM_PBE_SHA1_DES2_EDE_CBC:
02931     case CKM_PBE_SHA1_RC2_128_CBC:
02932     case CKM_PBE_SHA1_RC2_40_CBC:
02933     case CKM_PBE_SHA1_RC4_128:
02934     case CKM_PBE_SHA1_RC4_40:
02935     case CKM_PBE_MD5_DES_CBC:
02936     case CKM_PBE_MD2_DES_CBC:
02937        key_gen_type = nsc_pbe;
02938        crv = nsc_SetupPBEKeyGen(pMechanism,&pbe_param, &key_type);
02939        break;
02940     case CKM_DSA_PARAMETER_GEN:
02941        key_gen_type = nsc_param;
02942        key_type = CKK_DSA;
02943        objclass = CKO_KG_PARAMETERS;
02944        crv = CKR_OK;
02945        break;
02946     default:
02947        crv = CKR_MECHANISM_INVALID;
02948        break;
02949     }
02950 
02951     /* make sure we aren't going to overflow the buffer */
02952     if (sizeof(buf) < key_length) {
02953        /* someone is getting pretty optimistic about how big their key can
02954         * be... */
02955         crv = CKR_TEMPLATE_INCONSISTENT;
02956     }
02957 
02958     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
02959 
02960     /* if there was no error,
02961      * key_type *MUST* be set in the switch statement above */
02962     PORT_Assert( key_type != CKK_INVALID_KEY_TYPE );
02963 
02964     /*
02965      * now to the actual key gen.
02966      */
02967     switch (key_gen_type) {
02968     case nsc_pbe:
02969        crv = nsc_pbe_key_gen(pbe_param, pMechanism, buf, &key_length,
02970                             faultyPBE3DES);
02971        nsspkcs5_DestroyPBEParameter(pbe_param);
02972        break;
02973     case nsc_ssl:
02974        rsa_pms = (SSL3RSAPreMasterSecret *)buf;
02975        version = (CK_VERSION *)pMechanism->pParameter;
02976        rsa_pms->client_version[0] = version->major;
02977         rsa_pms->client_version[1] = version->minor;
02978         crv = 
02979            NSC_GenerateRandom(0,&rsa_pms->random[0], sizeof(rsa_pms->random));
02980        break;
02981     case nsc_bulk:
02982        /* get the key, check for weak keys and repeat if found */
02983        do {
02984             crv = NSC_GenerateRandom(0, (unsigned char *)buf, key_length);
02985        } while (crv == CKR_OK && checkWeak && 
02986                      sftk_IsWeakKey((unsigned char *)buf,key_type));
02987        break;
02988     case nsc_param:
02989        /* generate parameters */
02990        *buf = 0;
02991        crv = nsc_parameter_gen(key_type,key);
02992        break;
02993     }
02994 
02995     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
02996 
02997     /* Add the class, key_type, and value */
02998     crv = sftk_AddAttributeType(key,CKA_CLASS,&objclass,sizeof(CK_OBJECT_CLASS));
02999     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
03000     crv = sftk_AddAttributeType(key,CKA_KEY_TYPE,&key_type,sizeof(CK_KEY_TYPE));
03001     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
03002     if (key_length != 0) {
03003        crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
03004        if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
03005     }
03006 
03007     /* get the session */
03008     session = sftk_SessionFromHandle(hSession);
03009     if (session == NULL) {
03010        sftk_FreeObject(key);
03011         return CKR_SESSION_HANDLE_INVALID;
03012     }
03013 
03014     /*
03015      * handle the base object stuff
03016      */
03017     crv = sftk_handleObject(key,session);
03018     sftk_FreeSession(session);
03019     if (sftk_isTrue(key,CKA_SENSITIVE)) {
03020        sftk_forceAttribute(key,CKA_ALWAYS_SENSITIVE,&cktrue,sizeof(CK_BBOOL));
03021     }
03022     if (!sftk_isTrue(key,CKA_EXTRACTABLE)) {
03023        sftk_forceAttribute(key,CKA_NEVER_EXTRACTABLE,&cktrue,sizeof(CK_BBOOL));
03024     }
03025 
03026     *phKey = key->handle;
03027     sftk_FreeObject(key);
03028     return crv;
03029 }
03030 
03031 #define PAIRWISE_DIGEST_LENGTH                   SHA1_LENGTH /* 160-bits */
03032 #define PAIRWISE_MESSAGE_LENGTH                  20          /* 160-bits */
03033 
03034 /*
03035  * FIPS 140-2 pairwise consistency check utilized to validate key pair.
03036  *
03037  * This function returns
03038  *   CKR_OK               if pairwise consistency check passed
03039  *   CKR_GENERAL_ERROR    if pairwise consistency check failed
03040  *   other error codes    if paiswise consistency check could not be
03041  *                        performed, for example, CKR_HOST_MEMORY.
03042  */
03043 static CK_RV
03044 sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession,
03045     SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType)
03046 {
03047     /*
03048      *                      Key type    Mechanism type
03049      *                      --------------------------------
03050      * For encrypt/decrypt: CKK_RSA  => CKM_RSA_PKCS
03051      *                      others   => CKM_INVALID_MECHANISM
03052      *
03053      * For sign/verify:     CKK_RSA  => CKM_RSA_PKCS
03054      *                      CKK_DSA  => CKM_DSA
03055      *                      CKK_EC   => CKM_ECDSA
03056      *                      others   => CKM_INVALID_MECHANISM
03057      *
03058      * None of these mechanisms has a parameter.
03059      */
03060     CK_MECHANISM mech = {0, NULL, 0};
03061 
03062     CK_ULONG modulusLen;
03063     PRBool isEncryptable = PR_FALSE;
03064     PRBool canSignVerify = PR_FALSE;
03065     PRBool isDerivable = PR_FALSE;
03066     CK_RV crv;
03067 
03068     /* Variables used for Encrypt/Decrypt functions. */
03069     unsigned char *known_message = (unsigned char *)"Known Crypto Message";
03070     unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH];
03071     CK_ULONG bytes_decrypted;
03072     unsigned char *ciphertext;
03073     unsigned char *text_compared;
03074     CK_ULONG bytes_encrypted;
03075     CK_ULONG bytes_compared;
03076 
03077     /* Variables used for Signature/Verification functions. */
03078     /* always uses SHA-1 digest */
03079     unsigned char *known_digest = (unsigned char *)"Mozilla Rules World!";
03080     unsigned char *signature;
03081     CK_ULONG signature_length;
03082 
03083     if (keyType == CKK_RSA) {
03084        SFTKAttribute *attribute;
03085 
03086        /* Get modulus length of private key. */
03087        attribute = sftk_FindAttribute(privateKey, CKA_MODULUS);
03088        if (attribute == NULL) {
03089            return CKR_DEVICE_ERROR;
03090        }
03091        modulusLen = attribute->attrib.ulValueLen;
03092        if (*(unsigned char *)attribute->attrib.pValue == 0) {
03093            modulusLen--;
03094        }
03095        sftk_FreeAttribute(attribute);
03096     }
03097 
03098     /**************************************************/
03099     /* Pairwise Consistency Check of Encrypt/Decrypt. */
03100     /**************************************************/
03101 
03102     isEncryptable = sftk_isTrue(privateKey, CKA_DECRYPT); 
03103 
03104     /*
03105      * If the decryption attribute is set, attempt to encrypt
03106      * with the public key and decrypt with the private key.
03107      */
03108     if (isEncryptable) {
03109        if (keyType != CKK_RSA) {
03110            return CKR_DEVICE_ERROR;
03111        }
03112        bytes_encrypted = modulusLen;
03113        mech.mechanism = CKM_RSA_PKCS;
03114 
03115        /* Allocate space for ciphertext. */
03116        ciphertext = (unsigned char *) PORT_ZAlloc(bytes_encrypted);
03117        if (ciphertext == NULL) {
03118            return CKR_HOST_MEMORY;
03119        }
03120 
03121        /* Prepare for encryption using the public key. */
03122        crv = NSC_EncryptInit(hSession, &mech, publicKey->handle);
03123        if (crv != CKR_OK) {
03124            PORT_Free(ciphertext);
03125            return crv;
03126        }
03127 
03128        /* Encrypt using the public key. */
03129        crv = NSC_Encrypt(hSession,
03130                        known_message,
03131                        PAIRWISE_MESSAGE_LENGTH,
03132                        ciphertext,
03133                        &bytes_encrypted);
03134        if (crv != CKR_OK) {
03135            PORT_Free(ciphertext);
03136            return crv;
03137        }
03138 
03139        /* Always use the smaller of these two values . . . */
03140        bytes_compared = PR_MIN(bytes_encrypted, PAIRWISE_MESSAGE_LENGTH);
03141 
03142        /*
03143         * If there was a failure, the plaintext
03144         * goes at the end, therefore . . .
03145         */
03146        text_compared = ciphertext + bytes_encrypted - bytes_compared;
03147 
03148        /*
03149         * Check to ensure that ciphertext does
03150         * NOT EQUAL known input message text
03151         * per FIPS PUB 140-2 directive.
03152         */
03153        if (PORT_Memcmp(text_compared, known_message,
03154                      bytes_compared) == 0) {
03155            /* Set error to Invalid PRIVATE Key. */
03156            PORT_SetError(SEC_ERROR_INVALID_KEY);
03157            PORT_Free(ciphertext);
03158            return CKR_GENERAL_ERROR;
03159        }
03160 
03161        /* Prepare for decryption using the private key. */
03162        crv = NSC_DecryptInit(hSession, &mech, privateKey->handle);
03163        if (crv != CKR_OK) {
03164            PORT_Free(ciphertext);
03165            return crv;
03166        }
03167 
03168        memset(plaintext, 0, PAIRWISE_MESSAGE_LENGTH);
03169 
03170        /*
03171         * Initialize bytes decrypted to be the
03172         * expected PAIRWISE_MESSAGE_LENGTH.
03173         */
03174        bytes_decrypted = PAIRWISE_MESSAGE_LENGTH;
03175 
03176        /*
03177         * Decrypt using the private key.
03178         * NOTE:  No need to reset the
03179         *        value of bytes_encrypted.
03180         */
03181        crv = NSC_Decrypt(hSession,
03182                        ciphertext,
03183                        bytes_encrypted,
03184                        plaintext,
03185                        &bytes_decrypted);
03186 
03187        /* Finished with ciphertext; free it. */
03188        PORT_Free(ciphertext);
03189 
03190        if (crv != CKR_OK) {
03191            return crv;
03192        }
03193 
03194        /*
03195         * Check to ensure that the output plaintext
03196         * does EQUAL known input message text.
03197         */
03198        if ((bytes_decrypted != PAIRWISE_MESSAGE_LENGTH) ||
03199            (PORT_Memcmp(plaintext, known_message,
03200                       PAIRWISE_MESSAGE_LENGTH) != 0)) {
03201            /* Set error to Bad PUBLIC Key. */
03202            PORT_SetError(SEC_ERROR_BAD_KEY);
03203            return CKR_GENERAL_ERROR;
03204        }
03205     }
03206 
03207     /**********************************************/
03208     /* Pairwise Consistency Check of Sign/Verify. */
03209     /**********************************************/
03210 
03211     canSignVerify = sftk_isTrue(privateKey, CKA_SIGN);
03212     
03213     if (canSignVerify) {
03214        /* Determine length of signature. */
03215        switch (keyType) {
03216        case CKK_RSA:
03217            signature_length = modulusLen;
03218            mech.mechanism = CKM_RSA_PKCS;
03219            break;
03220        case CKK_DSA:
03221            signature_length = DSA_SIGNATURE_LEN;
03222            mech.mechanism = CKM_DSA;
03223            break;
03224 #ifdef NSS_ENABLE_ECC
03225        case CKK_EC:
03226            signature_length = MAX_ECKEY_LEN * 2;
03227            mech.mechanism = CKM_ECDSA;
03228            break;
03229 #endif
03230        default:
03231            return CKR_DEVICE_ERROR;
03232        }
03233        
03234        /* Allocate space for signature data. */
03235        signature = (unsigned char *) PORT_ZAlloc(signature_length);
03236        if (signature == NULL) {
03237            return CKR_HOST_MEMORY;
03238        }
03239        
03240        /* Sign the known hash using the private key. */
03241        crv = NSC_SignInit(hSession, &mech, privateKey->handle);
03242        if (crv != CKR_OK) {
03243            PORT_Free(signature);
03244            return crv;
03245        }
03246 
03247        crv = NSC_Sign(hSession,
03248                      known_digest,
03249                      PAIRWISE_DIGEST_LENGTH,
03250                      signature,
03251                      &signature_length);
03252        if (crv != CKR_OK) {
03253            PORT_Free(signature);
03254            return crv;
03255        }
03256        
03257        /* Verify the known hash using the public key. */
03258        crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
03259        if (crv != CKR_OK) {
03260            PORT_Free(signature);
03261            return crv;
03262        }
03263 
03264        crv = NSC_Verify(hSession,
03265                       known_digest,
03266                       PAIRWISE_DIGEST_LENGTH,
03267                       signature,
03268                       signature_length);
03269 
03270        /* Free signature data. */
03271        PORT_Free(signature);
03272 
03273        if ((crv == CKR_SIGNATURE_LEN_RANGE) ||
03274               (crv == CKR_SIGNATURE_INVALID)) {
03275            return CKR_GENERAL_ERROR;
03276        }
03277        if (crv != CKR_OK) {
03278            return crv;
03279        }
03280     }
03281 
03282     /**********************************************/
03283     /* Pairwise Consistency Check for Derivation  */
03284     /**********************************************/
03285 
03286     isDerivable = sftk_isTrue(privateKey, CKA_DERIVE);
03287     
03288     if (isDerivable) {
03289        /* 
03290         * We are not doing consistency check for Diffie-Hellman Key - 
03291         * otherwise it would be here
03292         * This is also true for Elliptic Curve Diffie-Hellman keys
03293         * NOTE: EC keys are currently subjected to pairwise
03294         * consistency check for signing/verification.
03295         */
03296        /*
03297         * FIPS 140-2 had the following pairwise consistency test for
03298         * public and private keys used for key agreement:
03299         *   If the keys are used to perform key agreement, then the
03300         *   cryptographic module shall create a second, compatible
03301         *   key pair.  The cryptographic module shall perform both
03302         *   sides of the key agreement algorithm and shall compare
03303         *   the resulting shared values.  If the shared values are
03304         *   not equal, the test shall fail.
03305         * This test was removed in Change Notice 3.
03306         */
03307 
03308     }
03309 
03310     return CKR_OK;
03311 }
03312 
03313 /* NSC_GenerateKeyPair generates a public-key/private-key pair, 
03314  * creating new key objects. */
03315 CK_RV NSC_GenerateKeyPair (CK_SESSION_HANDLE hSession,
03316     CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate,
03317     CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
03318     CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey,
03319                                    CK_OBJECT_HANDLE_PTR phPrivateKey)
03320 {
03321     SFTKObject *     publicKey,*privateKey;
03322     SFTKSession *    session;
03323     CK_KEY_TYPE      key_type;
03324     CK_RV            crv    = CKR_OK;
03325     CK_BBOOL         cktrue        = CK_TRUE;
03326     SECStatus               rv;
03327     CK_OBJECT_CLASS  pubClass = CKO_PUBLIC_KEY;
03328     CK_OBJECT_CLASS  privClass = CKO_PRIVATE_KEY;
03329     int              i;
03330     SFTKSlot *              slot   = sftk_SlotFromSessionHandle(hSession);
03331     unsigned int bitSize;
03332 
03333     /* RSA */
03334     int              public_modulus_bits = 0;
03335     SECItem          pubExp;
03336     RSAPrivateKey *  rsaPriv;
03337 
03338     /* DSA */
03339     PQGParams               pqgParam;
03340     DHParams                dhParam;
03341     DSAPrivateKey *  dsaPriv;
03342 
03343     /* Diffie Hellman */
03344     int              private_value_bits = 0;
03345     DHPrivateKey *   dhPriv;
03346 
03347 #ifdef NSS_ENABLE_ECC
03348     /* Elliptic Curve Cryptography */
03349     SECItem          ecEncodedParams;  /* DER Encoded parameters */
03350     ECPrivateKey *   ecPriv;
03351     ECParams *          ecParams;
03352 #endif /* NSS_ENABLE_ECC */
03353 
03354     /*
03355      * now lets create an object to hang the attributes off of
03356      */
03357     publicKey = sftk_NewObject(slot); /* fill in the handle later */
03358     if (publicKey == NULL) {
03359        return CKR_HOST_MEMORY;
03360     }
03361 
03362     /*
03363      * load the template values into the publicKey
03364      */
03365     for (i=0; i < (int) ulPublicKeyAttributeCount; i++) {
03366        if (pPublicKeyTemplate[i].type == CKA_MODULUS_BITS) {
03367            public_modulus_bits = *(CK_ULONG *)pPublicKeyTemplate[i].pValue;
03368            continue;
03369        }
03370 
03371        crv = sftk_AddAttributeType(publicKey,
03372                                 sftk_attr_expand(&pPublicKeyTemplate[i]));
03373        if (crv != CKR_OK) break;
03374     }
03375 
03376     if (crv != CKR_OK) {
03377        sftk_FreeObject(publicKey);
03378        return CKR_HOST_MEMORY;
03379     }
03380 
03381     privateKey = sftk_NewObject(slot); /* fill in the handle later */
03382     if (privateKey == NULL) {
03383        sftk_FreeObject(publicKey);
03384        return CKR_HOST_MEMORY;
03385     }
03386     /*
03387      * now load the private key template
03388      */
03389     for (i=0; i < (int) ulPrivateKeyAttributeCount; i++) {
03390        if (pPrivateKeyTemplate[i].type == CKA_VALUE_BITS) {
03391            private_value_bits = *(CK_ULONG *)pPrivateKeyTemplate[i].pValue;
03392            continue;
03393        }
03394 
03395        crv = sftk_AddAttributeType(privateKey,
03396                                 sftk_attr_expand(&pPrivateKeyTemplate[i]));
03397        if (crv != CKR_OK) break;
03398     }
03399 
03400     if (crv != CKR_OK) {
03401        sftk_FreeObject(publicKey);
03402        sftk_FreeObject(privateKey);
03403        return CKR_HOST_MEMORY;
03404     }
03405     sftk_DeleteAttributeType(privateKey,CKA_CLASS);
03406     sftk_DeleteAttributeType(privateKey,CKA_KEY_TYPE);
03407     sftk_DeleteAttributeType(privateKey,CKA_VALUE);
03408     sftk_DeleteAttributeType(publicKey,CKA_CLASS);
03409     sftk_DeleteAttributeType(publicKey,CKA_KEY_TYPE);
03410     sftk_DeleteAttributeType(publicKey,CKA_VALUE);
03411 
03412     /* Now Set up the parameters to generate the key (based on mechanism) */
03413     switch (pMechanism->mechanism) {
03414     case CKM_RSA_PKCS_KEY_PAIR_GEN:
03415        /* format the keys */
03416        sftk_DeleteAttributeType(publicKey,CKA_MODULUS);
03417        sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
03418        sftk_DeleteAttributeType(privateKey,CKA_MODULUS);
03419        sftk_DeleteAttributeType(privateKey,CKA_PRIVATE_EXPONENT);
03420        sftk_DeleteAttributeType(privateKey,CKA_PUBLIC_EXPONENT);
03421        sftk_DeleteAttributeType(privateKey,CKA_PRIME_1);
03422        sftk_DeleteAttributeType(privateKey,CKA_PRIME_2);
03423        sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_1);
03424        sftk_DeleteAttributeType(privateKey,CKA_EXPONENT_2);
03425        sftk_DeleteAttributeType(privateKey,CKA_COEFFICIENT);
03426        key_type = CKK_RSA;
03427        if (public_modulus_bits == 0) {
03428            crv = CKR_TEMPLATE_INCOMPLETE;
03429            break;
03430        }
03431        if (public_modulus_bits < RSA_MIN_MODULUS_BITS) {
03432            crv = CKR_ATTRIBUTE_VALUE_INVALID;
03433            break;
03434        }
03435        if (public_modulus_bits % 2 != 0) {
03436            crv = CKR_ATTRIBUTE_VALUE_INVALID;
03437            break;
03438        }
03439 
03440        /* extract the exponent */
03441        crv=sftk_Attribute2SSecItem(NULL,&pubExp,publicKey,CKA_PUBLIC_EXPONENT);
03442        if (crv != CKR_OK) break;
03443         bitSize = sftk_GetLengthInBits(pubExp.data, pubExp.len);
03444        if (bitSize < 2) {
03445            crv = CKR_ATTRIBUTE_VALUE_INVALID;
03446            break;
03447        }
03448         crv = sftk_AddAttributeType(privateKey,CKA_PUBLIC_EXPONENT,
03449                                               sftk_item_expand(&pubExp));
03450        if (crv != CKR_OK) {
03451            PORT_Free(pubExp.data);
03452            break;
03453        }
03454 
03455        rsaPriv = RSA_NewKey(public_modulus_bits, &pubExp);
03456        PORT_Free(pubExp.data);
03457        if (rsaPriv == NULL) {
03458            if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
03459               sftk_fatalError = PR_TRUE;
03460            }
03461            crv = CKR_DEVICE_ERROR;
03462            break;
03463        }
03464         /* now fill in the RSA dependent paramenters in the public key */
03465         crv = sftk_AddAttributeType(publicKey,CKA_MODULUS,
03466                         sftk_item_expand(&rsaPriv->modulus));
03467        if (crv != CKR_OK) goto kpg_done;
03468         /* now fill in the RSA dependent paramenters in the private key */
03469         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
03470                         sftk_item_expand(&rsaPriv->modulus));
03471        if (crv != CKR_OK) goto kpg_done;
03472         crv = sftk_AddAttributeType(privateKey,CKA_MODULUS,
03473                         sftk_item_expand(&rsaPriv->modulus));
03474        if (crv != CKR_OK) goto kpg_done;
03475         crv = sftk_AddAttributeType(privateKey,CKA_PRIVATE_EXPONENT,
03476                         sftk_item_expand(&rsaPriv->privateExponent));
03477        if (crv != CKR_OK) goto kpg_done;
03478         crv = sftk_AddAttributeType(privateKey,CKA_PRIME_1,
03479                         sftk_item_expand(&rsaPriv->prime1));
03480        if (crv != CKR_OK) goto kpg_done;
03481         crv = sftk_AddAttributeType(privateKey,CKA_PRIME_2,
03482                         sftk_item_expand(&rsaPriv->prime2));
03483        if (crv != CKR_OK) goto kpg_done;
03484         crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_1,
03485                         sftk_item_expand(&rsaPriv->exponent1));
03486        if (crv != CKR_OK) goto kpg_done;
03487         crv = sftk_AddAttributeType(privateKey,CKA_EXPONENT_2,
03488                         sftk_item_expand(&rsaPriv->exponent2));
03489        if (crv != CKR_OK) goto kpg_done;
03490         crv = sftk_AddAttributeType(privateKey,CKA_COEFFICIENT,
03491                         sftk_item_expand(&rsaPriv->coefficient));
03492 kpg_done:
03493        /* Should zeroize the contents first, since this func doesn't. */
03494        PORT_FreeArena(rsaPriv->arena, PR_TRUE);
03495        break;
03496     case CKM_DSA_KEY_PAIR_GEN:
03497        sftk_DeleteAttributeType(publicKey,CKA_VALUE);
03498        sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
03499        sftk_DeleteAttributeType(privateKey,CKA_PRIME);
03500        sftk_DeleteAttributeType(privateKey,CKA_SUBPRIME);
03501        sftk_DeleteAttributeType(privateKey,CKA_BASE);
03502        key_type = CKK_DSA;
03503 
03504        /* extract the necessary paramters and copy them to the private key */
03505        crv=sftk_Attribute2SSecItem(NULL,&pqgParam.prime,publicKey,CKA_PRIME);
03506        if (crv != CKR_OK) break;
03507        crv=sftk_Attribute2SSecItem(NULL,&pqgParam.subPrime,publicKey,
03508                                    CKA_SUBPRIME);
03509        if (crv != CKR_OK) {
03510            PORT_Free(pqgParam.prime.data);
03511            break;
03512        }
03513        crv=sftk_Attribute2SSecItem(NULL,&pqgParam.base,publicKey,CKA_BASE);
03514        if (crv != CKR_OK) {
03515            PORT_Free(pqgParam.prime.data);
03516            PORT_Free(pqgParam.subPrime.data);
03517            break;
03518        }
03519         crv = sftk_AddAttributeType(privateKey,CKA_PRIME,
03520                                 sftk_item_expand(&pqgParam.prime));
03521        if (crv != CKR_OK) {
03522            PORT_Free(pqgParam.prime.data);
03523            PORT_Free(pqgParam.subPrime.data);
03524            PORT_Free(pqgParam.base.data);
03525            break;
03526        }
03527         crv = sftk_AddAttributeType(privateKey,CKA_SUBPRIME,
03528                                 sftk_item_expand(&pqgParam.subPrime));
03529        if (crv != CKR_OK) {
03530            PORT_Free(pqgParam.prime.data);
03531            PORT_Free(pqgParam.subPrime.data);
03532            PORT_Free(pqgParam.base.data);
03533            break;
03534        }
03535         crv = sftk_AddAttributeType(privateKey,CKA_BASE,
03536                                 sftk_item_expand(&pqgParam.base));
03537        if (crv != CKR_OK) {
03538            PORT_Free(pqgParam.prime.data);
03539            PORT_Free(pqgParam.subPrime.data);
03540            PORT_Free(pqgParam.base.data);
03541            break;
03542        }
03543 
03544         bitSize = sftk_GetLengthInBits(pqgParam.subPrime.data, 
03545                                                  pqgParam.subPrime.len);
03546         if (bitSize != DSA_Q_BITS)  {
03547            crv = CKR_TEMPLATE_INCOMPLETE;
03548            PORT_Free(pqgParam.prime.data);
03549            PORT_Free(pqgParam.subPrime.data);
03550            PORT_Free(pqgParam.base.data);
03551            break;
03552        }
03553         bitSize = sftk_GetLengthInBits(pqgParam.prime.data,pqgParam.prime.len);
03554         if ((bitSize <  DSA_MIN_P_BITS) || (bitSize > DSA_MAX_P_BITS)) {
03555            crv = CKR_TEMPLATE_INCOMPLETE;
03556            PORT_Free(pqgParam.prime.data);
03557            PORT_Free(pqgParam.subPrime.data);
03558            PORT_Free(pqgParam.base.data);
03559            break;
03560        }
03561         bitSize = sftk_GetLengthInBits(pqgParam.base.data,pqgParam.base.len);
03562         if ((bitSize <  1) || (bitSize > DSA_MAX_P_BITS)) {
03563            crv = CKR_TEMPLATE_INCOMPLETE;
03564            PORT_Free(pqgParam.prime.data);
03565            PORT_Free(pqgParam.subPrime.data);
03566            PORT_Free(pqgParam.base.data);
03567            break;
03568        }
03569            
03570        /* Generate the key */
03571        rv = DSA_NewKey(&pqgParam, &dsaPriv);
03572 
03573        PORT_Free(pqgParam.prime.data);
03574        PORT_Free(pqgParam.subPrime.data);
03575        PORT_Free(pqgParam.base.data);
03576 
03577        if (rv != SECSuccess) {
03578            if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
03579               sftk_fatalError = PR_TRUE;
03580            }
03581            crv = CKR_DEVICE_ERROR;
03582            break;
03583        }
03584 
03585        /* store the generated key into the attributes */
03586         crv = sftk_AddAttributeType(publicKey,CKA_VALUE,
03587                         sftk_item_expand(&dsaPriv->publicValue));
03588        if (crv != CKR_OK) goto dsagn_done;
03589 
03590         /* now fill in the RSA dependent paramenters in the private key */
03591         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
03592                         sftk_item_expand(&dsaPriv->publicValue));
03593        if (crv != CKR_OK) goto dsagn_done;
03594         crv = sftk_AddAttributeType(privateKey,CKA_VALUE,
03595                         sftk_item_expand(&dsaPriv->privateValue));
03596 
03597 dsagn_done:
03598        /* should zeroize, since this function doesn't. */
03599        PORT_FreeArena(dsaPriv->params.arena, PR_TRUE);
03600        break;
03601 
03602     case CKM_DH_PKCS_KEY_PAIR_GEN:
03603        sftk_DeleteAttributeType(privateKey,CKA_PRIME);
03604        sftk_DeleteAttributeType(privateKey,CKA_BASE);
03605        sftk_DeleteAttributeType(privateKey,CKA_VALUE);
03606        sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
03607        key_type = CKK_DH;
03608 
03609        /* extract the necessary parameters and copy them to private keys */
03610         crv = sftk_Attribute2SSecItem(NULL, &dhParam.prime, publicKey, 
03611                                   CKA_PRIME);
03612        if (crv != CKR_OK) break;
03613        crv = sftk_Attribute2SSecItem(NULL, &dhParam.base, publicKey, CKA_BASE);
03614        if (crv != CKR_OK) {
03615            PORT_Free(dhParam.prime.data);
03616            break;
03617        }
03618        crv = sftk_AddAttributeType(privateKey, CKA_PRIME, 
03619                                 sftk_item_expand(&dhParam.prime));
03620        if (crv != CKR_OK) {
03621            PORT_Free(dhParam.prime.data);
03622            PORT_Free(dhParam.base.data);
03623            break;
03624        }
03625        crv = sftk_AddAttributeType(privateKey, CKA_BASE, 
03626                                 sftk_item_expand(&dhParam.base));
03627        if (crv != CKR_OK) {
03628            PORT_Free(dhParam.prime.data);
03629            PORT_Free(dhParam.base.data);
03630            break;
03631        }
03632         bitSize = sftk_GetLengthInBits(dhParam.prime.data,dhParam.prime.len);
03633         if ((bitSize <  DH_MIN_P_BITS) || (bitSize > DH_MAX_P_BITS)) {
03634            crv = CKR_TEMPLATE_INCOMPLETE;
03635            PORT_Free(dhParam.prime.data);
03636            PORT_Free(dhParam.base.data);
03637            break;
03638        }
03639         bitSize = sftk_GetLengthInBits(dhParam.base.data,dhParam.base.len);
03640         if ((bitSize <  1) || (bitSize > DH_MAX_P_BITS)) {
03641            crv = CKR_TEMPLATE_INCOMPLETE;
03642            PORT_Free(dhParam.prime.data);
03643            PORT_Free(dhParam.base.data);
03644            break;
03645        }
03646 
03647        rv = DH_NewKey(&dhParam, &dhPriv);
03648        PORT_Free(dhParam.prime.data);
03649        PORT_Free(dhParam.base.data);
03650        if (rv != SECSuccess) { 
03651            if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
03652               sftk_fatalError = PR_TRUE;
03653            }
03654            crv = CKR_DEVICE_ERROR;
03655            break;
03656        }
03657 
03658        crv=sftk_AddAttributeType(publicKey, CKA_VALUE, 
03659                             sftk_item_expand(&dhPriv->publicValue));
03660        if (crv != CKR_OK) goto dhgn_done;
03661 
03662         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
03663                         sftk_item_expand(&dhPriv->publicValue));
03664        if (crv != CKR_OK) goto dhgn_done;
03665 
03666        crv=sftk_AddAttributeType(privateKey, CKA_VALUE, 
03667                            sftk_item_expand(&dhPriv->privateValue));
03668 
03669 dhgn_done:
03670        /* should zeroize, since this function doesn't. */
03671        PORT_FreeArena(dhPriv->arena, PR_TRUE);
03672        break;
03673 
03674 #ifdef NSS_ENABLE_ECC
03675     case CKM_EC_KEY_PAIR_GEN:
03676        sftk_DeleteAttributeType(privateKey,CKA_EC_PARAMS);
03677        sftk_DeleteAttributeType(privateKey,CKA_VALUE);
03678        sftk_DeleteAttributeType(privateKey,CKA_NETSCAPE_DB);
03679        key_type = CKK_EC;
03680 
03681        /* extract the necessary parameters and copy them to private keys */
03682        crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey, 
03683                                   CKA_EC_PARAMS);
03684        if (crv != CKR_OK) break;
03685 
03686        crv = sftk_AddAttributeType(privateKey, CKA_EC_PARAMS, 
03687                                 sftk_item_expand(&ecEncodedParams));
03688        if (crv != CKR_OK) {
03689          PORT_Free(ecEncodedParams.data);
03690          break;
03691        }
03692 
03693        /* Decode ec params before calling EC_NewKey */
03694        rv = EC_DecodeParams(&ecEncodedParams, &ecParams);
03695        PORT_Free(ecEncodedParams.data);
03696        if (rv != SECSuccess) {
03697            crv = CKR_DEVICE_ERROR;
03698            break;
03699        }
03700        rv = EC_NewKey(ecParams, &ecPriv);
03701        PORT_FreeArena(ecParams->arena, PR_TRUE);
03702        if (rv != SECSuccess) { 
03703            if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
03704               sftk_fatalError = PR_TRUE;
03705            }
03706            crv = CKR_DEVICE_ERROR;
03707            break;
03708        }
03709 
03710        crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, 
03711                             sftk_item_expand(&ecPriv->publicValue));
03712        if (crv != CKR_OK) goto ecgn_done;
03713 
03714        crv = sftk_AddAttributeType(privateKey, CKA_VALUE, 
03715                            sftk_item_expand(&ecPriv->privateValue));
03716        if (crv != CKR_OK) goto ecgn_done;
03717 
03718         crv = sftk_AddAttributeType(privateKey,CKA_NETSCAPE_DB,
03719                         sftk_item_expand(&ecPriv->publicValue));
03720 ecgn_done:
03721        /* should zeroize, since this function doesn't. */
03722        PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
03723        break;
03724 #endif /* NSS_ENABLE_ECC */
03725 
03726     default:
03727        crv = CKR_MECHANISM_INVALID;
03728     }
03729 
03730     if (crv != CKR_OK) {
03731        sftk_FreeObject(privateKey);
03732        sftk_FreeObject(publicKey);
03733        return crv;
03734     }
03735 
03736 
03737     /* Add the class, key_type The loop lets us check errors blow out
03738      *  on errors and clean up at the bottom */
03739     session = NULL; /* make pedtantic happy... session cannot leave the*/
03740                   /* loop below NULL unless an error is set... */
03741     do {
03742        crv = sftk_AddAttributeType(privateKey,CKA_CLASS,&privClass,
03743                                           sizeof(CK_OBJECT_CLASS));
03744         if (crv != CKR_OK) break;
03745        crv = sftk_AddAttributeType(publicKey,CKA_CLASS,&pubClass,
03746                                           sizeof(CK_OBJECT_CLASS));
03747         if (crv != CKR_OK) break;
03748        crv = sftk_AddAttributeType(privateKey,CKA_KEY_TYPE,&key_type,
03749                                           sizeof(CK_KEY_TYPE));
03750         if (crv != CKR_OK) break;
03751        crv = sftk_AddAttributeType(publicKey,CKA_KEY_TYPE,&key_type,
03752                                           sizeof(CK_KEY_TYPE));
03753         if (crv != CKR_OK) break;
03754         session = sftk_SessionFromHandle(hSession);
03755         if (session == NULL) crv = CKR_SESSION_HANDLE_INVALID;
03756     } while (0);
03757 
03758     if (crv != CKR_OK) {
03759         sftk_FreeObject(privateKey);
03760         sftk_FreeObject(publicKey);
03761         return crv;
03762     }
03763 
03764     /*
03765      * handle the base object cleanup for the public Key
03766      */
03767     crv = sftk_handleObject(privateKey,session);
03768     if (crv != CKR_OK) {
03769         sftk_FreeSession(session);
03770        sftk_FreeObject(privateKey);
03771        sftk_FreeObject(publicKey);
03772        return crv;
03773     }
03774 
03775     /*
03776      * handle the base object cleanup for the private Key
03777      * If we have any problems, we destroy the public Key we've
03778      * created and linked.
03779      */
03780     crv = sftk_handleObject(publicKey,session);
03781     sftk_FreeSession(session);
03782     if (crv != CKR_OK) {
03783        sftk_FreeObject(publicKey);
03784        NSC_DestroyObject(hSession,privateKey->handle);
03785        sftk_FreeObject(privateKey);
03786        return crv;
03787     }
03788     if (sftk_isTrue(privateKey,CKA_SENSITIVE)) {
03789        sftk_forceAttribute(privateKey,CKA_ALWAYS_SENSITIVE,
03790                                           &cktrue,sizeof(CK_BBOOL));
03791     }
03792     if (sftk_isTrue(publicKey,CKA_SENSITIVE)) {
03793        sftk_forceAttribute(publicKey,CKA_ALWAYS_SENSITIVE,
03794                                           &cktrue,sizeof(CK_BBOOL));
03795     }
03796     if (!sftk_isTrue(privateKey,CKA_EXTRACTABLE)) {
03797        sftk_forceAttribute(privateKey,CKA_NEVER_EXTRACTABLE,
03798                                           &cktrue,sizeof(CK_BBOOL));
03799     }
03800     if (!sftk_isTrue(publicKey,CKA_EXTRACTABLE)) {
03801        sftk_forceAttribute(publicKey,CKA_NEVER_EXTRACTABLE,
03802                                           &cktrue,sizeof(CK_BBOOL));
03803     }
03804 
03805     /* Perform FIPS 140-2 pairwise consistency check. */
03806     crv = sftk_PairwiseConsistencyCheck(hSession,
03807                                    publicKey, privateKey, key_type);
03808     if (crv != CKR_OK) {
03809        NSC_DestroyObject(hSession,publicKey->handle);
03810        sftk_FreeObject(publicKey);
03811        NSC_DestroyObject(hSession,privateKey->handle);
03812        sftk_FreeObject(privateKey);
03813        if (sftk_audit_enabled) {
03814            char msg[128];
03815            PR_snprintf(msg,sizeof msg,
03816                      "C_GenerateKeyPair(hSession=0x%08lX, "
03817                      "pMechanism->mechanism=0x%08lX)=0x%08lX "
03818                      "self-test: pair-wise consistency test failed",
03819                      (PRUint32)hSession,(PRUint32)pMechanism->mechanism,
03820                      (PRUint32)crv);
03821            sftk_LogAuditMessage(NSS_AUDIT_ERROR, msg);
03822        }
03823        return crv;
03824     }
03825 
03826     *phPrivateKey = privateKey->handle;
03827     *phPublicKey = publicKey->handle;
03828     sftk_FreeObject(publicKey);
03829     sftk_FreeObject(privateKey);
03830 
03831     return CKR_OK;
03832 }
03833 
03834 static SECItem *sftk_PackagePrivateKey(SFTKObject *key, CK_RV *crvp)
03835 {
03836     NSSLOWKEYPrivateKey *lk = NULL;
03837     NSSLOWKEYPrivateKeyInfo *pki = NULL;
03838     SFTKAttribute *attribute = NULL;
03839     PLArenaPool *arena = NULL;
03840     SECOidTag algorithm = SEC_OID_UNKNOWN;
03841     void *dummy, *param = NULL;
03842     SECStatus rv = SECSuccess;
03843     SECItem *encodedKey = NULL;
03844 #ifdef NSS_ENABLE_ECC
03845     SECItem *fordebug;
03846     int savelen;
03847 #endif
03848 
03849     if(!key) {
03850        *crvp = CKR_KEY_HANDLE_INVALID; /* really can't happen */
03851        return NULL;
03852     }
03853 
03854     attribute = sftk_FindAttribute(key, CKA_KEY_TYPE);
03855     if(!attribute) {
03856        *crvp = CKR_KEY_TYPE_INCONSISTENT;
03857        return NULL;
03858     }
03859 
03860     lk = sftk_GetPrivKey(key, *(CK_KEY_TYPE *)attribute->attrib.pValue, crvp);
03861     sftk_FreeAttribute(attribute);
03862     if(!lk) {
03863        return NULL;
03864     }
03865 
03866     arena = PORT_NewArena(2048);   /* XXX different size? */
03867     if(!arena) {
03868        *crvp = CKR_HOST_MEMORY;
03869        rv = SECFailure;
03870        goto loser;
03871     }
03872 
03873     pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
03874                                    sizeof(NSSLOWKEYPrivateKeyInfo));
03875     if(!pki) {
03876        *crvp = CKR_HOST_MEMORY;
03877        rv = SECFailure;
03878        goto loser;
03879     }
03880     pki->arena = arena;
03881 
03882     param = NULL;
03883     switch(lk->keyType) {
03884        case NSSLOWKEYRSAKey:
03885            prepare_low_rsa_priv_key_for_asn1(lk);
03886            dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
03887                                    nsslowkey_RSAPrivateKeyTemplate);
03888            algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
03889            break;
03890        case NSSLOWKEYDSAKey:
03891             prepare_low_dsa_priv_key_export_for_asn1(lk);
03892            dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
03893                                    nsslowkey_DSAPrivateKeyExportTemplate);
03894            prepare_low_pqg_params_for_asn1(&lk->u.dsa.params);
03895            param = SEC_ASN1EncodeItem(NULL, NULL, &(lk->u.dsa.params),
03896                                    nsslowkey_PQGParamsTemplate);
03897            algorithm = SEC_OID_ANSIX9_DSA_SIGNATURE;
03898            break;
03899 #ifdef NSS_ENABLE_ECC           
03900         case NSSLOWKEYECKey:
03901             prepare_low_ec_priv_key_for_asn1(lk);
03902            /* Public value is encoded as a bit string so adjust length
03903             * to be in bits before ASN encoding and readjust 
03904             * immediately after.
03905             *
03906             * Since the SECG specification recommends not including the
03907             * parameters as part of ECPrivateKey, we zero out the curveOID
03908             * length before encoding and restore it later.
03909             */
03910            lk->u.ec.publicValue.len <<= 3;
03911            savelen = lk->u.ec.ecParams.curveOID.len;
03912            lk->u.ec.ecParams.curveOID.len = 0;
03913            dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
03914                                    nsslowkey_ECPrivateKeyTemplate);
03915            lk->u.ec.ecParams.curveOID.len = savelen;
03916            lk->u.ec.publicValue.len >>= 3;
03917 
03918            fordebug = &pki->privateKey;
03919            SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKey", lk->keyType,
03920                     fordebug);
03921 
03922            param = SECITEM_DupItem(&lk->u.ec.ecParams.DEREncoding);
03923 
03924            algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
03925            break;
03926 #endif /* NSS_ENABLE_ECC */
03927        case NSSLOWKEYDHKey:
03928        default:
03929            dummy = NULL;
03930            break;
03931     }
03932  
03933     if(!dummy || ((lk->keyType == NSSLOWKEYDSAKey) && !param)) {
03934        *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
03935        rv = SECFailure;
03936        goto loser;
03937     }
03938     
03939     rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, 
03940                             (SECItem*)param);
03941     if(rv != SECSuccess) {
03942        *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
03943        rv = SECFailure;
03944        goto loser;
03945     }
03946 
03947     dummy = SEC_ASN1EncodeInteger(arena, &pki->version,
03948                               NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
03949     if(!dummy) {
03950        *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
03951        rv = SECFailure;
03952        goto loser;
03953     }
03954 
03955     encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, 
03956                                 nsslowkey_PrivateKeyInfoTemplate);
03957     *crvp = encodedKey ? CKR_OK : CKR_DEVICE_ERROR;
03958 
03959 #ifdef NSS_ENABLE_ECC
03960     fordebug = encodedKey;
03961     SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKeyInfo", lk->keyType,
03962              fordebug);
03963 #endif
03964 loser:
03965     if(arena) {
03966        PORT_FreeArena(arena, PR_TRUE);
03967     }
03968 
03969     if(lk && (lk != key->objectInfo)) {
03970        nsslowkey_DestroyPrivateKey(lk);
03971     }
03972  
03973     if(param) {
03974        SECITEM_ZfreeItem((SECItem*)param, PR_TRUE);
03975     }
03976 
03977     if(rv != SECSuccess) {
03978        return NULL;
03979     }
03980 
03981     return encodedKey;
03982 }
03983     
03984 /* it doesn't matter yet, since we colapse error conditions in the
03985  * level above, but we really should map those few key error differences */
03986 static CK_RV 
03987 sftk_mapWrap(CK_RV crv) 
03988 { 
03989     switch (crv) {
03990     case CKR_ENCRYPTED_DATA_INVALID:  crv = CKR_WRAPPED_KEY_INVALID; break;
03991     }
03992     return crv; 
03993 }
03994 
03995 /* NSC_WrapKey wraps (i.e., encrypts) a key. */
03996 CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession,
03997     CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey,
03998     CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey,
03999                                     CK_ULONG_PTR pulWrappedKeyLen)
04000 {
04001     SFTKSession *session;
04002     SFTKAttribute *attribute;
04003     SFTKObject *key;
04004     CK_RV crv;
04005 
04006     session = sftk_SessionFromHandle(hSession);
04007     if (session == NULL) {
04008        return CKR_SESSION_HANDLE_INVALID;
04009     }
04010 
04011     key = sftk_ObjectFromHandle(hKey,session);
04012     sftk_FreeSession(session);
04013     if (key == NULL) {
04014        return CKR_KEY_HANDLE_INVALID;
04015     }
04016 
04017     switch(key->objclass) {
04018        case CKO_SECRET_KEY:
04019          {
04020            SFTKSessionContext *context = NULL;
04021            SECItem pText;
04022 
04023            attribute = sftk_FindAttribute(key,CKA_VALUE);
04024 
04025            if (attribute == NULL) {
04026               crv = CKR_KEY_TYPE_INCONSISTENT;
04027               break;
04028            }
04029            crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey, 
04030                                    CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
04031            if (crv != CKR_OK) {
04032               sftk_FreeAttribute(attribute);
04033               break;
04034            }
04035 
04036            pText.type = siBuffer;
04037            pText.data = (unsigned char *)attribute->attrib.pValue;
04038            pText.len  = attribute->attrib.ulValueLen;
04039 
04040            /* Find out if this is a block cipher. */
04041            crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_FALSE,NULL);
04042            if (crv != CKR_OK || !context) 
04043                break;
04044            if (context->blockSize > 1) {
04045               unsigned int remainder = pText.len % context->blockSize;
04046                if (!context->doPad && remainder) {
04047                   /* When wrapping secret keys with unpadded block ciphers, 
04048                   ** the keys are zero padded, if necessary, to fill out 
04049                   ** a full block.
04050                   */
04051                   pText.len += context->blockSize - remainder;
04052                   pText.data = PORT_ZAlloc(pText.len);
04053                   if (pText.data)
04054                      memcpy(pText.data, attribute->attrib.pValue,
04055                                         attribute->attrib.ulValueLen);
04056                   else {
04057                      crv = CKR_HOST_MEMORY;
04058                      break;
04059                   }
04060               }
04061            }
04062 
04063            crv = NSC_Encrypt(hSession, (CK_BYTE_PTR)pText.data, 
04064                             pText.len, pWrappedKey, pulWrappedKeyLen);
04065            /* always force a finalize, both on errors and when
04066             * we are just getting the size */
04067            if (crv != CKR_OK || pWrappedKey == NULL) {
04068               CK_RV lcrv ;
04069               lcrv = sftk_GetContext(hSession,&context,
04070                                    SFTK_ENCRYPT,PR_FALSE,NULL);
04071               sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
04072               if (lcrv == CKR_OK && context) {
04073                   sftk_FreeContext(context);
04074               }
04075            }
04076 
04077            if (pText.data != (unsigned char *)attribute->attrib.pValue) 
04078               PORT_ZFree(pText.data, pText.len);
04079            sftk_FreeAttribute(attribute);
04080            break;
04081          }
04082 
04083        case CKO_PRIVATE_KEY:
04084            {
04085               SECItem *bpki = sftk_PackagePrivateKey(key, &crv);
04086               SFTKSessionContext *context = NULL;
04087 
04088               if(!bpki) {
04089                   break;
04090               }
04091 
04092               crv = sftk_CryptInit(hSession, pMechanism, hWrappingKey,
04093                                    CKA_WRAP, SFTK_ENCRYPT, PR_TRUE);
04094               if(crv != CKR_OK) {
04095                   SECITEM_ZfreeItem(bpki, PR_TRUE);
04096                   crv = CKR_KEY_TYPE_INCONSISTENT;
04097                   break;
04098               }
04099 
04100               crv = NSC_Encrypt(hSession, bpki->data, bpki->len,
04101                                    pWrappedKey, pulWrappedKeyLen);
04102               /* always force a finalize */
04103               if (crv != CKR_OK || pWrappedKey == NULL) {
04104                   CK_RV lcrv ;
04105                   lcrv = sftk_GetContext(hSession,&context,
04106                                       SFTK_ENCRYPT,PR_FALSE,NULL);
04107                   sftk_SetContextByType(session, SFTK_ENCRYPT, NULL);
04108                   if (lcrv == CKR_OK && context)  {
04109                      sftk_FreeContext(context);
04110                   }
04111               }
04112               SECITEM_ZfreeItem(bpki, PR_TRUE);
04113               break;
04114            }
04115 
04116        default:
04117            crv = CKR_KEY_TYPE_INCONSISTENT;
04118            break;
04119     }
04120     sftk_FreeObject(key);
04121 
04122     return sftk_mapWrap(crv);
04123 }
04124 
04125 /*
04126  * import a pprivate key info into the desired slot
04127  */
04128 static SECStatus
04129 sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki)
04130 {
04131     CK_BBOOL cktrue = CK_TRUE; 
04132     CK_KEY_TYPE keyType = CKK_RSA;
04133     SECStatus rv = SECFailure;
04134     const SEC_ASN1Template *keyTemplate, *paramTemplate;
04135     void *paramDest = NULL;
04136     PLArenaPool *arena;
04137     NSSLOWKEYPrivateKey *lpk = NULL;
04138     NSSLOWKEYPrivateKeyInfo *pki = NULL;
04139     CK_RV crv = CKR_KEY_TYPE_INCONSISTENT;
04140 
04141     arena = PORT_NewArena(2048);
04142     if(!arena) {
04143        return SECFailure;
04144     }
04145 
04146     pki = (NSSLOWKEYPrivateKeyInfo*)PORT_ArenaZAlloc(arena, 
04147                                    sizeof(NSSLOWKEYPrivateKeyInfo));
04148     if(!pki) {
04149        PORT_FreeArena(arena, PR_FALSE);
04150        return SECFailure;
04151     }
04152 
04153     if(SEC_ASN1DecodeItem(arena, pki, nsslowkey_PrivateKeyInfoTemplate, bpki) 
04154                             != SECSuccess) {
04155        PORT_FreeArena(arena, PR_TRUE);
04156        return SECFailure;
04157     }
04158 
04159     lpk = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(arena,
04160                                             sizeof(NSSLOWKEYPrivateKey));
04161     if(lpk == NULL) {
04162        goto loser;
04163     }
04164     lpk->arena = arena;
04165 
04166     switch(SECOID_GetAlgorithmTag(&pki->algorithm)) {
04167        case SEC_OID_PKCS1_RSA_ENCRYPTION:
04168            keyTemplate = nsslowkey_RSAPrivateKeyTemplate;
04169            paramTemplate = NULL;
04170            paramDest = NULL;
04171            lpk->keyType = NSSLOWKEYRSAKey;
04172            prepare_low_rsa_priv_key_for_asn1(lpk);
04173            break;
04174        case SEC_OID_ANSIX9_DSA_SIGNATURE:
04175            keyTemplate = nsslowkey_DSAPrivateKeyExportTemplate;
04176            paramTemplate = nsslowkey_PQGParamsTemplate;
04177            paramDest = &(lpk->u.dsa.params);
04178            lpk->keyType = NSSLOWKEYDSAKey;
04179            prepare_low_dsa_priv_key_export_for_asn1(lpk);
04180            prepare_low_pqg_params_for_asn1(&lpk->u.dsa.params);
04181            break;
04182        /* case NSSLOWKEYDHKey: */
04183 #ifdef NSS_ENABLE_ECC
04184         case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
04185            keyTemplate = nsslowkey_ECPrivateKeyTemplate;
04186            paramTemplate = NULL;
04187            paramDest = &(lpk->u.ec.ecParams.DEREncoding);
04188            lpk->keyType = NSSLOWKEYECKey;
04189            prepare_low_ec_priv_key_for_asn1(lpk);
04190            prepare_low_ecparams_for_asn1(&lpk->u.ec.ecParams);
04191            break;
04192 #endif /* NSS_ENABLE_ECC */
04193        default:
04194            keyTemplate = NULL;
04195            paramTemplate = NULL;
04196            paramDest = NULL;
04197            break;
04198     }
04199 
04200     if(!keyTemplate) {
04201        goto loser;
04202     }
04203 
04204     /* decode the private key and any algorithm parameters */
04205     rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey);
04206 
04207 #ifdef NSS_ENABLE_ECC
04208     if (lpk->keyType == NSSLOWKEYECKey) {
04209         /* convert length in bits to length in bytes */
04210        lpk->u.ec.publicValue.len >>= 3;
04211         rv = SECITEM_CopyItem(arena, 
04212                            &(lpk->u.ec.ecParams.DEREncoding),
04213                              &(pki->algorithm.parameters));
04214        if(rv != SECSuccess) {
04215            goto loser;
04216        }
04217     }
04218 #endif /* NSS_ENABLE_ECC */
04219 
04220     if(rv != SECSuccess) {
04221        goto loser;
04222     }
04223     if(paramDest && paramTemplate) {
04224        rv = SEC_QuickDERDecodeItem(arena, paramDest, paramTemplate, 
04225                              &(pki->algorithm.parameters));
04226        if(rv != SECSuccess) {
04227            goto loser;
04228        }
04229     }
04230 
04231     rv = SECFailure;
04232 
04233     switch (lpk->keyType) {
04234         case NSSLOWKEYRSAKey:
04235            keyType = CKK_RSA;
04236            if(sftk_hasAttribute(key, CKA_NETSCAPE_DB)) {
04237               sftk_DeleteAttributeType(key, CKA_NETSCAPE_DB);
04238            }
04239            crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
04240                                    sizeof(keyType));
04241            if(crv != CKR_OK) break;
04242            crv = sftk_AddAttributeType(key, CKA_UNWRAP, &cktrue, 
04243                                    sizeof(CK_BBOOL));
04244            if(crv != CKR_OK) break;
04245            crv = sftk_AddAttributeType(key, CKA_DECRYPT, &cktrue, 
04246                                    sizeof(CK_BBOOL));
04247            if(crv != CKR_OK) break;
04248            crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
04249                                    sizeof(CK_BBOOL));
04250            if(crv != CKR_OK) break;
04251            crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
04252                                 sizeof(CK_BBOOL));
04253            if(crv != CKR_OK) break;
04254            crv = sftk_AddAttributeType(key, CKA_MODULUS, 
04255                             sftk_item_expand(&lpk->u.rsa.modulus));
04256            if(crv != CKR_OK) break;
04257            crv = sftk_AddAttributeType(key, CKA_PUBLIC_EXPONENT, 
04258                             sftk_item_expand(&lpk->u.rsa.publicExponent));
04259            if(crv != CKR_OK) break;
04260            crv = sftk_AddAttributeType(key, CKA_PRIVATE_EXPONENT, 
04261                             sftk_item_expand(&lpk->u.rsa.privateExponent));
04262            if(crv != CKR_OK) break;
04263            crv = sftk_AddAttributeType(key, CKA_PRIME_1, 
04264                             sftk_item_expand(&lpk->u.rsa.prime1));
04265            if(crv != CKR_OK) break;
04266            crv = sftk_AddAttributeType(key, CKA_PRIME_2, 
04267                             sftk_item_expand(&lpk->u.rsa.prime2));
04268            if(crv != CKR_OK) break;
04269            crv = sftk_AddAttributeType(key, CKA_EXPONENT_1, 
04270                             sftk_item_expand(&lpk->u.rsa.exponent1));
04271            if(crv != CKR_OK) break;
04272            crv = sftk_AddAttributeType(key, CKA_EXPONENT_2, 
04273                             sftk_item_expand(&lpk->u.rsa.exponent2));
04274            if(crv != CKR_OK) break;
04275            crv = sftk_AddAttributeType(key, CKA_COEFFICIENT, 
04276                             sftk_item_expand(&lpk->u.rsa.coefficient));
04277            break;
04278         case NSSLOWKEYDSAKey:
04279            keyType = CKK_DSA;
04280            crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
04281                                           CKR_KEY_TYPE_INCONSISTENT;
04282            if(crv != CKR_OK) break;
04283            crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
04284                                           sizeof(keyType));
04285            if(crv != CKR_OK) break;
04286            crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
04287                                           sizeof(CK_BBOOL));
04288            if(crv != CKR_OK) break;
04289            crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
04290                                           sizeof(CK_BBOOL)); 
04291            if(crv != CKR_OK) break;
04292            crv = sftk_AddAttributeType(key, CKA_PRIME,    
04293                                 sftk_item_expand(&lpk->u.dsa.params.prime));
04294            if(crv != CKR_OK) break;
04295            crv = sftk_AddAttributeType(key, CKA_SUBPRIME,
04296                              sftk_item_expand(&lpk->u.dsa.params.subPrime));
04297            if(crv != CKR_OK) break;
04298            crv = sftk_AddAttributeType(key, CKA_BASE,  
04299                                 sftk_item_expand(&lpk->u.dsa.params.base));
04300            if(crv != CKR_OK) break;
04301            crv = sftk_AddAttributeType(key, CKA_VALUE, 
04302                      sftk_item_expand(&lpk->u.dsa.privateValue));
04303            if(crv != CKR_OK) break;
04304            break;
04305 #ifdef notdef
04306         case NSSLOWKEYDHKey:
04307            template = dhTemplate;
04308            templateCount = sizeof(dhTemplate)/sizeof(CK_ATTRIBUTE);
04309            keyType = CKK_DH;
04310            break;
04311 #endif
04312        /* what about fortezza??? */
04313 #ifdef NSS_ENABLE_ECC
04314         case NSSLOWKEYECKey:
04315            keyType = CKK_EC;
04316            crv = (sftk_hasAttribute(key, CKA_NETSCAPE_DB)) ? CKR_OK :
04317                                           CKR_KEY_TYPE_INCONSISTENT;
04318            if(crv != CKR_OK) break;
04319            crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType, 
04320                                           sizeof(keyType));
04321            if(crv != CKR_OK) break;
04322            crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue, 
04323                                           sizeof(CK_BBOOL));
04324            if(crv != CKR_OK) break;
04325            crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue, 
04326                                           sizeof(CK_BBOOL)); 
04327            if(crv != CKR_OK) break;
04328            crv = sftk_AddAttributeType(key, CKA_DERIVE, &cktrue, 
04329                                           sizeof(CK_BBOOL)); 
04330            if(crv != CKR_OK) break;
04331            crv = sftk_AddAttributeType(key, CKA_EC_PARAMS,
04332                              sftk_item_expand(&lpk->u.ec.ecParams.DEREncoding));
04333            if(crv != CKR_OK) break;
04334            crv = sftk_AddAttributeType(key, CKA_VALUE, 
04335                      sftk_item_expand(&lpk->u.ec.privateValue));
04336            if(crv != CKR_OK) break;
04337            /* XXX Do we need to decode the EC Params here ?? */
04338            break;
04339 #endif /* NSS_ENABLE_ECC */
04340        default:
04341            crv = CKR_KEY_TYPE_INCONSISTENT;
04342            break;
04343     }
04344 
04345 loser:
04346     if(lpk) {
04347        nsslowkey_DestroyPrivateKey(lpk);
04348     }
04349 
04350     if(crv != CKR_OK) {
04351        return SECFailure;
04352     }
04353 
04354     return SECSuccess;
04355 }
04356 
04357 
04358 /* NSC_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object. */
04359 CK_RV NSC_UnwrapKey(CK_SESSION_HANDLE hSession,
04360     CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,
04361     CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,
04362     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
04363                                            CK_OBJECT_HANDLE_PTR phKey)
04364 {
04365     SFTKObject *key = NULL;
04366     SFTKSession *session;
04367     CK_ULONG key_length = 0;
04368     unsigned char * buf = NULL;
04369     CK_RV crv = CKR_OK;
04370     int i;
04371     CK_ULONG bsize = ulWrappedKeyLen;
04372     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
04373     SECItem bpki;
04374     CK_OBJECT_CLASS target_type = CKO_SECRET_KEY;
04375 
04376     /*
04377      * now lets create an object to hang the attributes off of
04378      */
04379     key = sftk_NewObject(slot); /* fill in the handle later */
04380     if (key == NULL) {
04381        return CKR_HOST_MEMORY;
04382     }
04383 
04384     /*
04385      * load the template values into the object
04386      */
04387     for (i=0; i < (int) ulAttributeCount; i++) {
04388        if (pTemplate[i].type == CKA_VALUE_LEN) {
04389            key_length = *(CK_ULONG *)pTemplate[i].pValue;
04390            continue;
04391        }
04392         if (pTemplate[i].type == CKA_CLASS) {
04393            target_type = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
04394        }
04395        crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
04396        if (crv != CKR_OK) break;
04397     }
04398     if (crv != CKR_OK) {
04399        sftk_FreeObject(key);
04400        return crv;
04401     }
04402 
04403     crv = sftk_CryptInit(hSession,pMechanism,hUnwrappingKey,CKA_UNWRAP,
04404                                                  SFTK_DECRYPT, PR_FALSE);
04405     if (crv != CKR_OK) {
04406        sftk_FreeObject(key);
04407        return sftk_mapWrap(crv);
04408     }
04409 
04410     /* allocate the buffer to decrypt into 
04411      * this assumes the unwrapped key is never larger than the
04412      * wrapped key. For all the mechanisms we support this is true */
04413     buf = (unsigned char *)PORT_Alloc( ulWrappedKeyLen);
04414     bsize = ulWrappedKeyLen;
04415 
04416     crv = NSC_Decrypt(hSession, pWrappedKey, ulWrappedKeyLen, buf, &bsize);
04417     if (crv != CKR_OK) {
04418        sftk_FreeObject(key);
04419        PORT_Free(buf);
04420        return sftk_mapWrap(crv);
04421     }
04422 
04423     switch(target_type) {
04424        case CKO_SECRET_KEY:
04425            if (!sftk_hasAttribute(key,CKA_KEY_TYPE)) {
04426               crv = CKR_TEMPLATE_INCOMPLETE;
04427               break;
04428            }
04429 
04430            if (key_length == 0 || key_length > bsize) {
04431               key_length = bsize;
04432            }
04433            if (key_length > MAX_KEY_LEN) {
04434               crv = CKR_TEMPLATE_INCONSISTENT;
04435               break;
04436            }
04437     
04438            /* add the value */
04439            crv = sftk_AddAttributeType(key,CKA_VALUE,buf,key_length);
04440            break;
04441        case CKO_PRIVATE_KEY:
04442            bpki.data = (unsigned char *)buf;
04443            bpki.len = bsize;
04444            crv = CKR_OK;
04445            if(sftk_unwrapPrivateKey(key, &bpki) != SECSuccess) {
04446               crv = CKR_TEMPLATE_INCOMPLETE;
04447            }
04448            break;
04449        default:
04450            crv = CKR_TEMPLATE_INCONSISTENT;
04451            break;
04452     }
04453 
04454     PORT_ZFree(buf, bsize);
04455     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
04456 
04457     /* get the session */
04458     session = sftk_SessionFromHandle(hSession);
04459     if (session == NULL) {
04460        sftk_FreeObject(key);
04461         return CKR_SESSION_HANDLE_INVALID;
04462     }
04463 
04464     /*
04465      * handle the base object stuff
04466      */
04467     crv = sftk_handleObject(key,session);
04468     *phKey = key->handle;
04469     sftk_FreeSession(session);
04470     sftk_FreeObject(key);
04471 
04472     return crv;
04473 
04474 }
04475 
04476 /*
04477  * The SSL key gen mechanism create's lots of keys. This function handles the
04478  * details of each of these key creation.
04479  */
04480 static CK_RV
04481 sftk_buildSSLKey(CK_SESSION_HANDLE hSession, SFTKObject *baseKey, 
04482     PRBool isMacKey, unsigned char *keyBlock, unsigned int keySize,
04483                                            CK_OBJECT_HANDLE *keyHandle)
04484 {
04485     SFTKObject *key;
04486     SFTKSession *session;
04487     CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
04488     CK_BBOOL cktrue = CK_TRUE;
04489     CK_BBOOL ckfalse = CK_FALSE;
04490     CK_RV crv = CKR_HOST_MEMORY;
04491 
04492     /*
04493      * now lets create an object to hang the attributes off of
04494      */
04495     *keyHandle = CK_INVALID_HANDLE;
04496     key = sftk_NewObject(baseKey->slot); 
04497     if (key == NULL) return CKR_HOST_MEMORY;
04498     sftk_narrowToSessionObject(key)->wasDerived = PR_TRUE;
04499 
04500     crv = sftk_CopyObject(key,baseKey);
04501     if (crv != CKR_OK) goto loser;
04502     if (isMacKey) {
04503        crv = sftk_forceAttribute(key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
04504        if (crv != CKR_OK) goto loser;
04505        crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
04506        if (crv != CKR_OK) goto loser;
04507        crv = sftk_forceAttribute(key,CKA_ENCRYPT,&ckfalse,sizeof(CK_BBOOL));
04508        if (crv != CKR_OK) goto loser;
04509        crv = sftk_forceAttribute(key,CKA_DECRYPT,&ckfalse,sizeof(CK_BBOOL));
04510        if (crv != CKR_OK) goto loser;
04511        crv = sftk_forceAttribute(key,CKA_SIGN,&cktrue,sizeof(CK_BBOOL));
04512        if (crv != CKR_OK) goto loser;
04513        crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
04514        if (crv != CKR_OK) goto loser;
04515        crv = sftk_forceAttribute(key,CKA_WRAP,&ckfalse,sizeof(CK_BBOOL));
04516        if (crv != CKR_OK) goto loser;
04517        crv = sftk_forceAttribute(key,CKA_UNWRAP,&ckfalse,sizeof(CK_BBOOL));
04518        if (crv != CKR_OK) goto loser;
04519     }
04520     crv = sftk_forceAttribute(key,CKA_VALUE,keyBlock,keySize);
04521     if (crv != CKR_OK) goto loser;
04522 
04523     /* get the session */
04524     crv = CKR_HOST_MEMORY;
04525     session = sftk_SessionFromHandle(hSession);
04526     if (session == NULL) { goto loser; }
04527 
04528     crv = sftk_handleObject(key,session);
04529     sftk_FreeSession(session);
04530     *keyHandle = key->handle;
04531 loser:
04532     if (key) sftk_FreeObject(key);
04533     return crv;
04534 }
04535 
04536 /*
04537  * if there is an error, we need to free the keys we already created in SSL
04538  * This is the routine that will do it..
04539  */
04540 static void
04541 sftk_freeSSLKeys(CK_SESSION_HANDLE session,
04542                             CK_SSL3_KEY_MAT_OUT *returnedMaterial ) 
04543 {
04544        if (returnedMaterial->hClientMacSecret != CK_INVALID_HANDLE) {
04545           NSC_DestroyObject(session,returnedMaterial->hClientMacSecret);
04546        }
04547        if (returnedMaterial->hServerMacSecret != CK_INVALID_HANDLE) {
04548           NSC_DestroyObject(session, returnedMaterial->hServerMacSecret);
04549        }
04550        if (returnedMaterial->hClientKey != CK_INVALID_HANDLE) {
04551           NSC_DestroyObject(session, returnedMaterial->hClientKey);
04552        }
04553        if (returnedMaterial->hServerKey != CK_INVALID_HANDLE) {
04554           NSC_DestroyObject(session, returnedMaterial->hServerKey);
04555        }
04556 }
04557 
04558 /*
04559  * when deriving from sensitive and extractable keys, we need to preserve some
04560  * of the semantics in the derived key. This helper routine maintains these
04561  * semantics.
04562  */
04563 static CK_RV
04564 sftk_DeriveSensitiveCheck(SFTKObject *baseKey,SFTKObject *destKey) 
04565 {
04566     PRBool hasSensitive;
04567     PRBool sensitive = PR_FALSE;
04568     PRBool hasExtractable;
04569     PRBool extractable = PR_TRUE;
04570     CK_RV crv = CKR_OK;
04571     SFTKAttribute *att;
04572 
04573     hasSensitive = PR_FALSE;
04574     att = sftk_FindAttribute(destKey,CKA_SENSITIVE);
04575     if (att) {
04576         hasSensitive = PR_TRUE;
04577        sensitive = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
04578        sftk_FreeAttribute(att);
04579     }
04580 
04581     hasExtractable = PR_FALSE;
04582     att = sftk_FindAttribute(destKey,CKA_EXTRACTABLE);
04583     if (att) {
04584         hasExtractable = PR_TRUE;
04585        extractable = (PRBool) *(CK_BBOOL *)att->attrib.pValue;
04586        sftk_FreeAttribute(att);
04587     }
04588 
04589 
04590     /* don't make a key more accessible */
04591     if (sftk_isTrue(baseKey,CKA_SENSITIVE) && hasSensitive && 
04592                                           (sensitive == PR_FALSE)) {
04593        return CKR_KEY_FUNCTION_NOT_PERMITTED;
04594     }
04595     if (!sftk_isTrue(baseKey,CKA_EXTRACTABLE) && hasExtractable && 
04596                                           (extractable == PR_TRUE)) {
04597        return CKR_KEY_FUNCTION_NOT_PERMITTED;
04598     }
04599 
04600     /* inherit parent's sensitivity */
04601     if (!hasSensitive) {
04602         att = sftk_FindAttribute(baseKey,CKA_SENSITIVE);
04603        if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
04604        crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
04605        sftk_FreeAttribute(att);
04606        if (crv != CKR_OK) return crv;
04607     }
04608     if (!hasExtractable) {
04609         att = sftk_FindAttribute(baseKey,CKA_EXTRACTABLE);
04610        if (att == NULL) return CKR_KEY_TYPE_INCONSISTENT;
04611        crv = sftk_defaultAttribute(destKey,sftk_attr_expand(&att->attrib));
04612        sftk_FreeAttribute(att);
04613        if (crv != CKR_OK) return crv;
04614     }
04615 
04616     /* we should inherit the parent's always extractable/ never sensitive info,
04617      * but handleObject always forces this attributes, so we would need to do
04618      * something special. */
04619     return CKR_OK;
04620 }
04621 
04622 /*
04623  * make known fixed PKCS #11 key types to their sizes in bytes
04624  */    
04625 unsigned long
04626 sftk_MapKeySize(CK_KEY_TYPE keyType) 
04627 {
04628     switch (keyType) {
04629     case CKK_CDMF:
04630        return 8;
04631     case CKK_DES:
04632        return 8;
04633     case CKK_DES2:
04634        return 16;
04635     case CKK_DES3:
04636        return 24;
04637     /* IDEA and CAST need to be added */
04638     default:
04639        break;
04640     }
04641     return 0;
04642 }
04643 
04644 /*
04645  * SSL Key generation given pre master secret
04646  */
04647 #define NUM_MIXERS 9
04648 static const char * const mixers[NUM_MIXERS] = { 
04649     "A", 
04650     "BB", 
04651     "CCC", 
04652     "DDDD", 
04653     "EEEEE", 
04654     "FFFFFF", 
04655     "GGGGGGG",
04656     "HHHHHHHH",
04657     "IIIIIIIII" };
04658 #define SSL3_PMS_LENGTH 48
04659 #define SSL3_MASTER_SECRET_LENGTH 48
04660 
04661 
04662 /* NSC_DeriveKey derives a key from a base key, creating a new key object. */
04663 CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession,
04664         CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey,
04665         CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, 
04666                                           CK_OBJECT_HANDLE_PTR phKey)
04667 {
04668     SFTKSession *   session;
04669     SFTKSlot    *   slot    = sftk_SlotFromSessionHandle(hSession);
04670     SFTKObject  *   key;
04671     SFTKObject  *   sourceKey;
04672     SFTKAttribute * att;
04673     SFTKAttribute * att2;
04674     unsigned char * buf;
04675     SHA1Context *   sha;
04676     MD5Context *    md5;
04677     MD2Context *    md2;
04678     CK_ULONG        macSize;
04679     CK_ULONG        tmpKeySize;
04680     CK_ULONG        IVSize;
04681     CK_ULONG        keySize = 0;
04682     CK_RV           crv     = CKR_OK;
04683     CK_BBOOL        cktrue  = CK_TRUE;
04684     CK_KEY_TYPE     keyType = CKK_GENERIC_SECRET;
04685     CK_OBJECT_CLASS classType      = CKO_SECRET_KEY;
04686     CK_KEY_DERIVATION_STRING_DATA *stringPtr;
04687     PRBool          isTLS = PR_FALSE;
04688     PRBool          isDH = PR_FALSE;
04689     SECStatus       rv;
04690     int             i;
04691     unsigned int    outLen;
04692     unsigned char   sha_out[SHA1_LENGTH];
04693     unsigned char   key_block[NUM_MIXERS * MD5_LENGTH];
04694     unsigned char   key_block2[MD5_LENGTH];
04695     PRBool          isFIPS;        
04696 
04697     /*
04698      * now lets create an object to hang the attributes off of
04699      */
04700     if (phKey) *phKey = CK_INVALID_HANDLE;
04701 
04702     key = sftk_NewObject(slot); /* fill in the handle later */
04703     if (key == NULL) {
04704        return CKR_HOST_MEMORY;
04705     }
04706     isFIPS = (slot->slotID == FIPS_SLOT_ID);
04707 
04708     /*
04709      * load the template values into the object
04710      */
04711     for (i=0; i < (int) ulAttributeCount; i++) {
04712        crv = sftk_AddAttributeType(key,sftk_attr_expand(&pTemplate[i]));
04713        if (crv != CKR_OK) break;
04714 
04715        if (pTemplate[i].type == CKA_KEY_TYPE) {
04716            keyType = *(CK_KEY_TYPE *)pTemplate[i].pValue;
04717        }
04718        if (pTemplate[i].type == CKA_VALUE_LEN) {
04719            keySize = *(CK_ULONG *)pTemplate[i].pValue;
04720        }
04721     }
04722     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
04723 
04724     if (keySize == 0) {
04725        keySize = sftk_MapKeySize(keyType);
04726     }
04727 
04728     /* Derive can only create SECRET KEY's currently... */
04729     classType = CKO_SECRET_KEY;
04730     crv = sftk_forceAttribute (key,CKA_CLASS,&classType,sizeof(classType));
04731     if (crv != CKR_OK) {
04732        sftk_FreeObject(key);
04733        return crv;
04734     }
04735 
04736     /* look up the base key we're deriving with */ 
04737     session = sftk_SessionFromHandle(hSession);
04738     if (session == NULL) {
04739        sftk_FreeObject(key);
04740         return CKR_SESSION_HANDLE_INVALID;
04741     }
04742 
04743     sourceKey = sftk_ObjectFromHandle(hBaseKey,session);
04744     sftk_FreeSession(session);
04745     if (sourceKey == NULL) {
04746        sftk_FreeObject(key);
04747         return CKR_KEY_HANDLE_INVALID;
04748     }
04749 
04750     /* get the value of the base key */
04751     att = sftk_FindAttribute(sourceKey,CKA_VALUE);
04752     if (att == NULL) {
04753        sftk_FreeObject(key);
04754        sftk_FreeObject(sourceKey);
04755         return CKR_KEY_HANDLE_INVALID;
04756     }
04757 
04758     switch (pMechanism->mechanism) {
04759     /*
04760      * generate the master secret 
04761      */
04762     case CKM_TLS_MASTER_KEY_DERIVE:
04763     case CKM_TLS_MASTER_KEY_DERIVE_DH:
04764        isTLS = PR_TRUE;
04765        /* fall thru */
04766     case CKM_SSL3_MASTER_KEY_DERIVE:
04767     case CKM_SSL3_MASTER_KEY_DERIVE_DH:
04768       {
04769        CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master;
04770        SSL3RSAPreMasterSecret *          rsa_pms;
04771        unsigned char                     crsrdata[SSL3_RANDOM_LENGTH * 2];
04772 
04773         if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) ||
04774             (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH))
04775               isDH = PR_TRUE;
04776 
04777        /* first do the consistancy checks */
04778        if (!isDH && (att->attrib.ulValueLen != SSL3_PMS_LENGTH)) {
04779            crv = CKR_KEY_TYPE_INCONSISTENT;
04780            break;
04781        }
04782        att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
04783        if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
04784                                    CKK_GENERIC_SECRET)) {
04785            if (att2) sftk_FreeAttribute(att2);
04786            crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
04787            break;
04788        }
04789        sftk_FreeAttribute(att2);
04790        if (keyType != CKK_GENERIC_SECRET) {
04791            crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
04792            break;
04793        }
04794        if ((keySize != 0) && (keySize != SSL3_MASTER_SECRET_LENGTH)) {
04795            crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
04796            break;
04797        }
04798 
04799        /* finally do the key gen */
04800        ssl3_master = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)
04801                                    pMechanism->pParameter;
04802 
04803        PORT_Memcpy(crsrdata, 
04804                    ssl3_master->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
04805        PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
04806                    ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
04807 
04808        if (ssl3_master->pVersion) {
04809            SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
04810            rsa_pms = (SSL3RSAPreMasterSecret *) att->attrib.pValue;
04811            /* don't leak more key material then necessary for SSL to work */
04812            if ((sessKey == NULL) || sessKey->wasDerived) {
04813               ssl3_master->pVersion->major = 0xff;
04814               ssl3_master->pVersion->minor = 0xff;
04815            } else {
04816               ssl3_master->pVersion->major = rsa_pms->client_version[0];
04817               ssl3_master->pVersion->minor = rsa_pms->client_version[1];
04818            }
04819        }
04820        if (ssl3_master->RandomInfo.ulClientRandomLen != SSL3_RANDOM_LENGTH) {
04821           crv = CKR_MECHANISM_PARAM_INVALID;
04822           break;
04823        }
04824        if (ssl3_master->RandomInfo.ulServerRandomLen != SSL3_RANDOM_LENGTH) {
04825           crv = CKR_MECHANISM_PARAM_INVALID;
04826           break;
04827        }
04828 
04829         if (isTLS) {
04830            SECStatus status;
04831            SECItem crsr   = { siBuffer, NULL, 0 };
04832            SECItem master = { siBuffer, NULL, 0 };
04833            SECItem pms    = { siBuffer, NULL, 0 };
04834 
04835            crsr.data   = crsrdata;
04836            crsr.len    = sizeof crsrdata;
04837            master.data = key_block;
04838            master.len  = SSL3_MASTER_SECRET_LENGTH;
04839            pms.data    = (unsigned char*)att->attrib.pValue;
04840            pms.len     =                 att->attrib.ulValueLen;
04841 
04842            status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
04843            if (status != SECSuccess) {
04844               crv = CKR_FUNCTION_FAILED;
04845               break;
04846            }
04847        } else {
04848            /* now allocate the hash contexts */
04849            md5 = MD5_NewContext();
04850            if (md5 == NULL) { 
04851               crv = CKR_HOST_MEMORY;
04852               break;
04853            }
04854            sha = SHA1_NewContext();
04855            if (sha == NULL) { 
04856               PORT_Free(md5);
04857               crv = CKR_HOST_MEMORY;
04858               break;
04859            }
04860             for (i = 0; i < 3; i++) {
04861               SHA1_Begin(sha);
04862               SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
04863               SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
04864                        att->attrib.ulValueLen);
04865               SHA1_Update(sha, crsrdata, sizeof crsrdata);
04866               SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
04867               PORT_Assert(outLen == SHA1_LENGTH);
04868 
04869               MD5_Begin(md5);
04870               MD5_Update(md5, (const unsigned char*)att->attrib.pValue, 
04871                       att->attrib.ulValueLen);
04872               MD5_Update(md5, sha_out, outLen);
04873               MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
04874               PORT_Assert(outLen == MD5_LENGTH);
04875             }
04876            PORT_Free(md5);
04877            PORT_Free(sha);
04878        }
04879 
04880        /* store the results */
04881        crv = sftk_forceAttribute
04882                      (key,CKA_VALUE,key_block,SSL3_MASTER_SECRET_LENGTH);
04883        if (crv != CKR_OK) break;
04884        keyType = CKK_GENERIC_SECRET;
04885        crv = sftk_forceAttribute (key,CKA_KEY_TYPE,&keyType,sizeof(keyType));
04886        if (isTLS) {
04887            /* TLS's master secret is used to "sign" finished msgs with PRF. */
04888            /* XXX This seems like a hack.   But SFTK_Derive only accepts 
04889             * one "operation" argument. */
04890            crv = sftk_forceAttribute(key,CKA_SIGN,  &cktrue,sizeof(CK_BBOOL));
04891            if (crv != CKR_OK) break;
04892            crv = sftk_forceAttribute(key,CKA_VERIFY,&cktrue,sizeof(CK_BBOOL));
04893            if (crv != CKR_OK) break;
04894            /* While we're here, we might as well force this, too. */
04895            crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
04896            if (crv != CKR_OK) break;
04897        }
04898        break;
04899       }
04900 
04901     case CKM_TLS_KEY_AND_MAC_DERIVE:
04902        isTLS = PR_TRUE;
04903        /* fall thru */
04904     case CKM_SSL3_KEY_AND_MAC_DERIVE:
04905       {
04906        CK_SSL3_KEY_MAT_PARAMS *ssl3_keys;
04907        CK_SSL3_KEY_MAT_OUT *   ssl3_keys_out;
04908        CK_ULONG                effKeySize;
04909        unsigned int            block_needed;
04910        unsigned char           srcrdata[SSL3_RANDOM_LENGTH * 2];
04911        unsigned char           crsrdata[SSL3_RANDOM_LENGTH * 2];
04912 
04913        crv = sftk_DeriveSensitiveCheck(sourceKey,key);
04914        if (crv != CKR_OK) break;
04915 
04916        if (att->attrib.ulValueLen != SSL3_MASTER_SECRET_LENGTH) {
04917            crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
04918            break;
04919        }
04920        att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
04921        if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
04922                                    CKK_GENERIC_SECRET)) {
04923            if (att2) sftk_FreeAttribute(att2);
04924            crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
04925            break;
04926        }
04927        sftk_FreeAttribute(att2);
04928        md5 = MD5_NewContext();
04929        if (md5 == NULL) { 
04930            crv = CKR_HOST_MEMORY;
04931            break;
04932        }
04933        sha = SHA1_NewContext();
04934        if (sha == NULL) { 
04935            PORT_Free(md5);
04936            crv = CKR_HOST_MEMORY;
04937            break;
04938        }
04939        ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter;
04940 
04941        PORT_Memcpy(srcrdata, 
04942                    ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
04943        PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, 
04944                   ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
04945 
04946        PORT_Memcpy(crsrdata, 
04947                   ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH);
04948        PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, 
04949                   ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH);
04950 
04951        /*
04952         * clear out our returned keys so we can recover on failure
04953         */
04954        ssl3_keys_out = ssl3_keys->pReturnedKeyMaterial;
04955        ssl3_keys_out->hClientMacSecret = CK_INVALID_HANDLE;
04956        ssl3_keys_out->hServerMacSecret = CK_INVALID_HANDLE;
04957        ssl3_keys_out->hClientKey       = CK_INVALID_HANDLE;
04958        ssl3_keys_out->hServerKey       = CK_INVALID_HANDLE;
04959 
04960        /*
04961         * How much key material do we need?
04962         */
04963        macSize    = ssl3_keys->ulMacSizeInBits/8;
04964        effKeySize = ssl3_keys->ulKeySizeInBits/8;
04965        IVSize     = ssl3_keys->ulIVSizeInBits/8;
04966        if (keySize == 0) {
04967            effKeySize = keySize;
04968        }
04969        block_needed = 2 * (macSize + effKeySize + 
04970                            ((!ssl3_keys->bIsExport) * IVSize));
04971        PORT_Assert(block_needed <= sizeof key_block);
04972        if (block_needed > sizeof key_block)
04973            block_needed = sizeof key_block;
04974 
04975        /*
04976         * generate the key material: This looks amazingly similar to the
04977         * PMS code, and is clearly crying out for a function to provide it.
04978         */
04979        if (isTLS) {
04980            SECStatus     status;
04981            SECItem       srcr   = { siBuffer, NULL, 0 };
04982            SECItem       keyblk = { siBuffer, NULL, 0 };
04983            SECItem       master = { siBuffer, NULL, 0 }; 
04984 
04985            srcr.data   = srcrdata;
04986            srcr.len    = sizeof srcrdata;
04987            keyblk.data = key_block;
04988            keyblk.len  = block_needed;
04989            master.data = (unsigned char*)att->attrib.pValue;
04990            master.len  =                 att->attrib.ulValueLen;
04991 
04992            status = TLS_PRF(&master, "key expansion", &srcr, &keyblk,
04993                            isFIPS);
04994            if (status != SECSuccess) {
04995               goto key_and_mac_derive_fail;
04996            }
04997        } else {
04998            unsigned int block_bytes = 0;
04999            /* key_block = 
05000             *     MD5(master_secret + SHA('A' + master_secret + 
05001             *                      ServerHello.random + ClientHello.random)) +
05002             *     MD5(master_secret + SHA('BB' + master_secret + 
05003             *                      ServerHello.random + ClientHello.random)) +
05004             *     MD5(master_secret + SHA('CCC' + master_secret + 
05005             *                      ServerHello.random + ClientHello.random)) +
05006             *     [...];
05007             */
05008            for (i = 0; i < NUM_MIXERS && block_bytes < block_needed; i++) {
05009              SHA1_Begin(sha);
05010              SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i]));
05011              SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, 
05012                        att->attrib.ulValueLen);
05013              SHA1_Update(sha, srcrdata, sizeof srcrdata);
05014              SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH);
05015              PORT_Assert(outLen == SHA1_LENGTH);
05016              MD5_Begin(md5);
05017              MD5_Update(md5, (const unsigned char*)att->attrib.pValue,
05018                       att->attrib.ulValueLen);
05019              MD5_Update(md5, sha_out, outLen);
05020              MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH);
05021              PORT_Assert(outLen == MD5_LENGTH);
05022              block_bytes += outLen;
05023            }
05024        }
05025 
05026        /*
05027         * Put the key material where it goes.
05028         */
05029        i = 0;               /* now shows how much consumed */
05030 
05031        /* 
05032         * The key_block is partitioned as follows:
05033         * client_write_MAC_secret[CipherSpec.hash_size]
05034         */
05035        crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
05036                                     &ssl3_keys_out->hClientMacSecret);
05037        if (crv != CKR_OK)
05038            goto key_and_mac_derive_fail;
05039 
05040        i += macSize;
05041 
05042        /* 
05043         * server_write_MAC_secret[CipherSpec.hash_size]
05044         */
05045        crv = sftk_buildSSLKey(hSession,key,PR_TRUE,&key_block[i],macSize,
05046                                        &ssl3_keys_out->hServerMacSecret);
05047        if (crv != CKR_OK) {
05048            goto key_and_mac_derive_fail;
05049        }
05050        i += macSize;
05051 
05052        if (keySize) {
05053            if (!ssl3_keys->bIsExport) {
05054               /* 
05055               ** Generate Domestic write keys and IVs.
05056               ** client_write_key[CipherSpec.key_material]
05057               */
05058               crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
05059                                    keySize, &ssl3_keys_out->hClientKey);
05060               if (crv != CKR_OK) {
05061                   goto key_and_mac_derive_fail;
05062               }
05063               i += keySize;
05064 
05065               /* 
05066               ** server_write_key[CipherSpec.key_material]
05067               */
05068               crv = sftk_buildSSLKey(hSession,key,PR_FALSE,&key_block[i],
05069                                    keySize, &ssl3_keys_out->hServerKey);
05070               if (crv != CKR_OK) {
05071                   goto key_and_mac_derive_fail;
05072               }
05073               i += keySize;
05074 
05075               /* 
05076               ** client_write_IV[CipherSpec.IV_size]
05077               */
05078               if (IVSize > 0) {
05079                   PORT_Memcpy(ssl3_keys_out->pIVClient, 
05080                               &key_block[i], IVSize);
05081                   i += IVSize;
05082               }
05083 
05084               /* 
05085               ** server_write_IV[CipherSpec.IV_size]
05086               */
05087               if (IVSize > 0) {
05088                   PORT_Memcpy(ssl3_keys_out->pIVServer, 
05089                               &key_block[i], IVSize);
05090                   i += IVSize;
05091               }
05092               PORT_Assert(i <= sizeof key_block);
05093 
05094            } else if (!isTLS) {
05095 
05096               /*
05097               ** Generate SSL3 Export write keys and IVs.
05098               ** client_write_key[CipherSpec.key_material]
05099               ** final_client_write_key = MD5(client_write_key +
05100               **                   ClientHello.random + ServerHello.random);
05101               */
05102               MD5_Begin(md5);
05103               MD5_Update(md5, &key_block[i], effKeySize);
05104               MD5_Update(md5, crsrdata, sizeof crsrdata);
05105               MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
05106               i += effKeySize;
05107               crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
05108                                    keySize,&ssl3_keys_out->hClientKey);
05109               if (crv != CKR_OK) {
05110                   goto key_and_mac_derive_fail;
05111               }
05112 
05113               /*
05114               ** server_write_key[CipherSpec.key_material]
05115               ** final_server_write_key = MD5(server_write_key +
05116               **                    ServerHello.random + ClientHello.random);
05117               */
05118               MD5_Begin(md5);
05119               MD5_Update(md5, &key_block[i], effKeySize);
05120               MD5_Update(md5, srcrdata, sizeof srcrdata);
05121               MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
05122               i += effKeySize;
05123               crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2,
05124                                     keySize,&ssl3_keys_out->hServerKey);
05125               if (crv != CKR_OK) {
05126                   goto key_and_mac_derive_fail;
05127               }
05128 
05129               /*
05130               ** client_write_IV = 
05131               **     MD5(ClientHello.random + ServerHello.random);
05132               */
05133               MD5_Begin(md5);
05134               MD5_Update(md5, crsrdata, sizeof crsrdata);
05135               MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
05136               PORT_Memcpy(ssl3_keys_out->pIVClient, key_block2, IVSize);
05137 
05138               /*
05139               ** server_write_IV = 
05140               **     MD5(ServerHello.random + ClientHello.random);
05141               */
05142               MD5_Begin(md5);
05143               MD5_Update(md5, srcrdata, sizeof srcrdata);
05144               MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
05145               PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize);
05146 
05147            } else {
05148 
05149               /*
05150               ** Generate TLS Export write keys and IVs.
05151               */
05152               SECStatus     status;
05153               SECItem       secret = { siBuffer, NULL, 0 };
05154               SECItem       crsr   = { siBuffer, NULL, 0 };
05155               SECItem       keyblk = { siBuffer, NULL, 0 };
05156 
05157               /*
05158               ** client_write_key[CipherSpec.key_material]
05159               ** final_client_write_key = PRF(client_write_key, 
05160               **                              "client write key",
05161               **                              client_random + server_random);
05162               */
05163               secret.data = &key_block[i];
05164               secret.len  = effKeySize;
05165               i          += effKeySize;
05166               crsr.data   = crsrdata;
05167               crsr.len    = sizeof crsrdata;
05168               keyblk.data = key_block2;
05169               keyblk.len  = sizeof key_block2;
05170               status = TLS_PRF(&secret, "client write key", &crsr, &keyblk,
05171                               isFIPS);
05172               if (status != SECSuccess) {
05173                   goto key_and_mac_derive_fail;
05174               }
05175               crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
05176                                    keySize, &ssl3_keys_out->hClientKey);
05177               if (crv != CKR_OK) {
05178                   goto key_and_mac_derive_fail;
05179               }
05180 
05181               /*
05182               ** server_write_key[CipherSpec.key_material]
05183               ** final_server_write_key = PRF(server_write_key,
05184               **                              "server write key",
05185               **                              client_random + server_random);
05186               */
05187               secret.data = &key_block[i];
05188               secret.len  = effKeySize;
05189               i          += effKeySize;
05190               keyblk.data = key_block2;
05191               keyblk.len  = sizeof key_block2;
05192               status = TLS_PRF(&secret, "server write key", &crsr, &keyblk,
05193                               isFIPS);
05194               if (status != SECSuccess) {
05195                   goto key_and_mac_derive_fail;
05196               }
05197               crv = sftk_buildSSLKey(hSession, key, PR_FALSE, key_block2, 
05198                                    keySize, &ssl3_keys_out->hServerKey);
05199               if (crv != CKR_OK) {
05200                   goto key_and_mac_derive_fail;
05201               }
05202 
05203               /*
05204               ** iv_block = PRF("", "IV block", 
05205               **                    client_random + server_random);
05206               ** client_write_IV[SecurityParameters.IV_size]
05207               ** server_write_IV[SecurityParameters.IV_size]
05208               */
05209               if (IVSize) {
05210                   secret.data = NULL;
05211                   secret.len  = 0;
05212                   keyblk.data = &key_block[i];
05213                   keyblk.len  = 2 * IVSize;
05214                   status = TLS_PRF(&secret, "IV block", &crsr, &keyblk,
05215                                   isFIPS);
05216                   if (status != SECSuccess) {
05217                      goto key_and_mac_derive_fail;
05218                   }
05219                   PORT_Memcpy(ssl3_keys_out->pIVClient, keyblk.data, IVSize);
05220                   PORT_Memcpy(ssl3_keys_out->pIVServer, keyblk.data + IVSize,
05221                                 IVSize);
05222               }
05223            }
05224        }
05225 
05226        crv = CKR_OK;
05227 
05228        if (0) {
05229 key_and_mac_derive_fail:
05230            if (crv == CKR_OK)
05231               crv = CKR_FUNCTION_FAILED;
05232            sftk_freeSSLKeys(hSession, ssl3_keys_out);
05233        }
05234        MD5_DestroyContext(md5, PR_TRUE);
05235        SHA1_DestroyContext(sha, PR_TRUE);
05236        sftk_FreeObject(key);
05237        key = NULL;
05238        break;
05239       }
05240 
05241     case CKM_CONCATENATE_BASE_AND_KEY:
05242       {
05243        SFTKObject *newKey;
05244 
05245        crv = sftk_DeriveSensitiveCheck(sourceKey,key);
05246        if (crv != CKR_OK) break;
05247 
05248        session = sftk_SessionFromHandle(hSession);
05249        if (session == NULL) {
05250             crv = CKR_SESSION_HANDLE_INVALID;
05251            break;
05252        }
05253 
05254        newKey = sftk_ObjectFromHandle(*(CK_OBJECT_HANDLE *)
05255                                    pMechanism->pParameter,session);
05256        sftk_FreeSession(session);
05257        if ( newKey == NULL) {
05258             crv = CKR_KEY_HANDLE_INVALID;
05259            break;
05260        }
05261 
05262        if (sftk_isTrue(newKey,CKA_SENSITIVE)) {
05263            crv = sftk_forceAttribute(newKey,CKA_SENSITIVE,&cktrue,
05264                                                  sizeof(CK_BBOOL));
05265            if (crv != CKR_OK) {
05266               sftk_FreeObject(newKey);
05267               break;
05268            }
05269        }
05270 
05271        att2 = sftk_FindAttribute(newKey,CKA_VALUE);
05272        if (att2 == NULL) {
05273            sftk_FreeObject(newKey);
05274             crv = CKR_KEY_HANDLE_INVALID;
05275            break;
05276        }
05277        tmpKeySize = att->attrib.ulValueLen+att2->attrib.ulValueLen;
05278        if (keySize == 0) keySize = tmpKeySize;
05279        if (keySize > tmpKeySize) {
05280            sftk_FreeObject(newKey);
05281            sftk_FreeAttribute(att2);
05282            crv = CKR_TEMPLATE_INCONSISTENT;
05283            break;
05284        }
05285        buf = (unsigned char*)PORT_Alloc(tmpKeySize);
05286        if (buf == NULL) {
05287            sftk_FreeAttribute(att2);
05288            sftk_FreeObject(newKey);
05289            crv = CKR_HOST_MEMORY;  
05290            break;
05291        }
05292 
05293        PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
05294        PORT_Memcpy(buf+att->attrib.ulValueLen,
05295                             att2->attrib.pValue,att2->attrib.ulValueLen);
05296 
05297        crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
05298        PORT_ZFree(buf,tmpKeySize);
05299        sftk_FreeAttribute(att2);
05300        sftk_FreeObject(newKey);
05301        break;
05302       }
05303 
05304     case CKM_CONCATENATE_BASE_AND_DATA:
05305        crv = sftk_DeriveSensitiveCheck(sourceKey,key);
05306        if (crv != CKR_OK) break;
05307 
05308        stringPtr = (CK_KEY_DERIVATION_STRING_DATA *) pMechanism->pParameter;
05309        tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
05310        if (keySize == 0) keySize = tmpKeySize;
05311        if (keySize > tmpKeySize) {
05312            crv = CKR_TEMPLATE_INCONSISTENT;
05313            break;
05314        }
05315        buf = (unsigned char*)PORT_Alloc(tmpKeySize);
05316        if (buf == NULL) {
05317            crv = CKR_HOST_MEMORY;
05318            break;
05319        }
05320 
05321        PORT_Memcpy(buf,att->attrib.pValue,att->attrib.ulValueLen);
05322        PORT_Memcpy(buf+att->attrib.ulValueLen,stringPtr->pData,
05323                                                  stringPtr->ulLen);
05324 
05325        crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
05326        PORT_ZFree(buf,tmpKeySize);
05327        break;
05328     case CKM_CONCATENATE_DATA_AND_BASE:
05329        crv = sftk_DeriveSensitiveCheck(sourceKey,key);
05330        if (crv != CKR_OK) break;
05331 
05332        stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
05333        tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen;
05334        if (keySize == 0) keySize = tmpKeySize;
05335        if (keySize > tmpKeySize) {
05336            crv = CKR_TEMPLATE_INCONSISTENT;
05337            break;
05338        }
05339        buf = (unsigned char*)PORT_Alloc(tmpKeySize);
05340        if (buf == NULL) {
05341            crv = CKR_HOST_MEMORY;
05342            break;
05343        }
05344 
05345        PORT_Memcpy(buf,stringPtr->pData,stringPtr->ulLen);
05346        PORT_Memcpy(buf+stringPtr->ulLen,att->attrib.pValue,
05347                                                  att->attrib.ulValueLen);
05348 
05349        crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
05350        PORT_ZFree(buf,tmpKeySize);
05351        break;
05352     case CKM_XOR_BASE_AND_DATA:
05353        crv = sftk_DeriveSensitiveCheck(sourceKey,key);
05354        if (crv != CKR_OK) break;
05355 
05356        stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
05357        tmpKeySize = PR_MIN(att->attrib.ulValueLen,stringPtr->ulLen);
05358        if (keySize == 0) keySize = tmpKeySize;
05359        if (keySize > tmpKeySize) {
05360            crv = CKR_TEMPLATE_INCONSISTENT;
05361            break;
05362        }
05363        buf = (unsigned char*)PORT_Alloc(keySize);
05364        if (buf == NULL) {
05365            crv = CKR_HOST_MEMORY;
05366            break;
05367        }
05368 
05369        
05370        PORT_Memcpy(buf,att->attrib.pValue,keySize);
05371        for (i=0; i < (int)keySize; i++) {
05372            buf[i] ^= stringPtr->pData[i];
05373        }
05374 
05375        crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
05376        PORT_ZFree(buf,keySize);
05377        break;
05378 
05379     case CKM_EXTRACT_KEY_FROM_KEY:
05380       {
05381        /* the following assumes 8 bits per byte */
05382        CK_ULONG extract = *(CK_EXTRACT_PARAMS *)pMechanism->pParameter;
05383        CK_ULONG shift   = extract & 0x7;      /* extract mod 8 the fast way */
05384        CK_ULONG offset  = extract >> 3;       /* extract div 8 the fast way */
05385 
05386        crv = sftk_DeriveSensitiveCheck(sourceKey,key);
05387        if (crv != CKR_OK) break;
05388 
05389        if (keySize == 0)  {
05390            crv = CKR_TEMPLATE_INCOMPLETE;
05391            break;
05392        }
05393        /* make sure we have enough bits in the original key */
05394        if (att->attrib.ulValueLen < 
05395                      (offset + keySize + ((shift != 0)? 1 :0)) ) {
05396            crv = CKR_MECHANISM_PARAM_INVALID;
05397            break;
05398        }
05399        buf = (unsigned char*)PORT_Alloc(keySize);
05400        if (buf == NULL) {
05401            crv = CKR_HOST_MEMORY;
05402            break;
05403        }
05404 
05405        /* copy the bits we need into the new key */     
05406        for (i=0; i < (int)keySize; i++) {
05407            unsigned char *value =
05408                       ((unsigned char *)att->attrib.pValue)+offset+i;
05409            if (shift) {
05410                buf[i] = (value[0] << (shift)) | (value[1] >> (8 - shift));
05411            } else {
05412               buf[i] = value[0];
05413            }
05414        }
05415 
05416        crv = sftk_forceAttribute (key,CKA_VALUE,buf,keySize);
05417        PORT_ZFree(buf,keySize);
05418        break;
05419       }
05420     case CKM_MD2_KEY_DERIVATION:
05421        if (keySize == 0) keySize = MD2_LENGTH;
05422        if (keySize > MD2_LENGTH) {
05423            crv = CKR_TEMPLATE_INCONSISTENT;
05424            break;
05425        }
05426        /* now allocate the hash contexts */
05427        md2 = MD2_NewContext();
05428        if (md2 == NULL) { 
05429            crv = CKR_HOST_MEMORY;
05430            break;
05431        }
05432        MD2_Begin(md2);
05433        MD2_Update(md2,(const unsigned char*)att->attrib.pValue,
05434                  att->attrib.ulValueLen);
05435        MD2_End(md2,key_block,&outLen,MD2_LENGTH);
05436        MD2_DestroyContext(md2, PR_TRUE);
05437 
05438        crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
05439        break;
05440     case CKM_MD5_KEY_DERIVATION:
05441        if (keySize == 0) keySize = MD5_LENGTH;
05442        if (keySize > MD5_LENGTH) {
05443            crv = CKR_TEMPLATE_INCONSISTENT;
05444            break;
05445        }
05446        /* now allocate the hash contexts */
05447        md5 = MD5_NewContext();
05448        if (md5 == NULL) { 
05449            crv = CKR_HOST_MEMORY;
05450            break;
05451        }
05452        MD5_Begin(md5);
05453        MD5_Update(md5,(const unsigned char*)att->attrib.pValue,
05454                  att->attrib.ulValueLen);
05455        MD5_End(md5,key_block,&outLen,MD5_LENGTH);
05456        MD5_DestroyContext(md5, PR_TRUE);
05457 
05458        crv = sftk_forceAttribute (key,CKA_VALUE,key_block,keySize);
05459        break;
05460      case CKM_SHA1_KEY_DERIVATION:
05461        if (keySize == 0) keySize = SHA1_LENGTH;
05462        if (keySize > SHA1_LENGTH) {
05463            crv = CKR_TEMPLATE_INCONSISTENT;
05464            break;
05465        }
05466        /* now allocate the hash contexts */
05467        sha = SHA1_NewContext();
05468        if (sha == NULL) { 
05469            crv = CKR_HOST_MEMORY;
05470            break;
05471        }
05472        SHA1_Begin(sha);
05473        SHA1_Update(sha,(const unsigned char*)att->attrib.pValue,
05474                   att->attrib.ulValueLen);
05475        SHA1_End(sha,key_block,&outLen,SHA1_LENGTH);
05476        SHA1_DestroyContext(sha, PR_TRUE);
05477 
05478        crv = sftk_forceAttribute(key,CKA_VALUE,key_block,keySize);
05479        break;
05480 
05481     case CKM_DH_PKCS_DERIVE:
05482       {
05483        SECItem  derived,  dhPublic;
05484        SECItem  dhPrime,  dhValue;
05485        /* sourceKey - values for the local existing low key */
05486        /* get prime and value attributes */
05487        crv = sftk_Attribute2SecItem(NULL, &dhPrime, sourceKey, CKA_PRIME); 
05488        if (crv != SECSuccess) break;
05489        crv = sftk_Attribute2SecItem(NULL, &dhValue, sourceKey, CKA_VALUE); 
05490        if (crv != SECSuccess) {
05491            PORT_Free(dhPrime.data);
05492            break;
05493        }
05494 
05495        dhPublic.data = pMechanism->pParameter;
05496        dhPublic.len  = pMechanism->ulParameterLen;
05497 
05498        /* calculate private value - oct */
05499        rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize); 
05500 
05501        PORT_Free(dhPrime.data);
05502        PORT_Free(dhValue.data);
05503      
05504        if (rv == SECSuccess) {
05505            sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
05506            PORT_ZFree(derived.data, derived.len);
05507        } else
05508            crv = CKR_HOST_MEMORY;
05509            
05510        break;
05511       }
05512 
05513 #ifdef NSS_ENABLE_ECC
05514     case CKM_ECDH1_DERIVE:
05515     case CKM_ECDH1_COFACTOR_DERIVE:
05516       {
05517        SECItem  ecScalar, ecPoint;
05518        SECItem  tmp;
05519        PRBool   withCofactor = PR_FALSE;
05520        unsigned char secret_hash[20];
05521        unsigned char *secret;
05522        unsigned char *keyData = NULL;
05523        int secretlen;
05524        CK_ECDH1_DERIVE_PARAMS *mechParams;
05525        NSSLOWKEYPrivateKey *privKey;
05526 
05527        /* Check mechanism parameters */
05528        mechParams = (CK_ECDH1_DERIVE_PARAMS *) pMechanism->pParameter;
05529        if ((pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) ||
05530            ((mechParams->kdf == CKD_NULL) &&
05531               ((mechParams->ulSharedDataLen != 0) || 
05532                   (mechParams->pSharedData != NULL)))) {
05533            crv = CKR_MECHANISM_PARAM_INVALID;
05534            break;
05535        }
05536 
05537        privKey = sftk_GetPrivKey(sourceKey, CKK_EC, &crv);
05538        if (privKey == NULL) {
05539            break;
05540        }
05541 
05542        /* Now we are working with a non-NULL private key */
05543        SECITEM_CopyItem(NULL, &ecScalar, &privKey->u.ec.privateValue);
05544 
05545        ecPoint.data = mechParams->pPublicData;
05546        ecPoint.len  = mechParams->ulPublicDataLen;
05547 
05548        if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
05549            withCofactor = PR_TRUE;
05550        } else {
05551            /* When not using cofactor derivation, one should
05552             * validate the public key to avoid small subgroup
05553             * attacks.
05554             */
05555            if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint) 
05556               != SECSuccess) {
05557               crv = CKR_ARGUMENTS_BAD;
05558               PORT_Free(ecScalar.data);
05559               if (privKey != sourceKey->objectInfo)
05560                   nsslowkey_DestroyPrivateKey(privKey);
05561               break;
05562            }
05563        }
05564 
05565        rv = ECDH_Derive(&ecPoint, &privKey->u.ec.ecParams, &ecScalar,
05566                         withCofactor, &tmp); 
05567        PORT_Free(ecScalar.data);
05568        if (privKey != sourceKey->objectInfo)
05569           nsslowkey_DestroyPrivateKey(privKey);
05570 
05571        if (rv != SECSuccess) {
05572            crv = CKR_DEVICE_ERROR;
05573            break;
05574        }
05575 
05576        /*
05577         * tmp is the raw data created by ECDH_Derive,
05578         * secret and secretlen are the values we will eventually pass as our
05579         * generated key.
05580         */
05581        secret = tmp.data;
05582        secretlen = tmp.len;
05583 
05584        /*
05585         * apply the kdf function.
05586         */
05587        if (mechParams->kdf == CKD_SHA1_KDF) {
05588            /* Compute SHA1 hash */
05589            PORT_Memset(secret_hash, 0, 20);
05590            rv = SHA1_HashBuf(secret_hash, tmp.data, tmp.len);
05591            if (rv != SECSuccess) {
05592               PORT_ZFree(tmp.data, tmp.len);
05593               crv = CKR_HOST_MEMORY;
05594               break;
05595            } 
05596            secret = secret_hash;
05597            secretlen = 20;
05598        }
05599 
05600        /*
05601         * if keySize is supplied, then we are generating a key of a specific 
05602         * length. This is done by taking the least significant 'keySize' 
05603         * bytes from the unsigned value calculated by ECDH. Note: this may 
05604         * mean padding temp with extra leading zeros from what ECDH_Derive 
05605         * already returned (which itself may contain leading zeros).
05606         */
05607        if (keySize) {
05608            if (secretlen < keySize) {
05609                keyData = PORT_ZAlloc(keySize);
05610               if (!keyData) {
05611                   PORT_ZFree(tmp.data, tmp.len);
05612                   crv = CKR_HOST_MEMORY;
05613                   break;
05614               }
05615               PORT_Memcpy(&keyData[keySize-secretlen],secret,secretlen);
05616               secret = keyData;
05617            } else {
05618               secret += (secretlen - keySize);
05619            }
05620            secretlen = keySize;
05621        }
05622 
05623        sftk_forceAttribute(key, CKA_VALUE, secret, secretlen);
05624        PORT_ZFree(tmp.data, tmp.len);
05625        if (keyData) {
05626            PORT_ZFree(keyData, keySize);
05627        }
05628        PORT_Memset(secret_hash, 0, 20);
05629            
05630        break;
05631       }
05632 #endif /* NSS_ENABLE_ECC */
05633 
05634     default:
05635        crv = CKR_MECHANISM_INVALID;
05636     }
05637     sftk_FreeAttribute(att);
05638     sftk_FreeObject(sourceKey);
05639     if (crv != CKR_OK) { 
05640        if (key) sftk_FreeObject(key);
05641        return crv;
05642     }
05643 
05644     /* link the key object into the list */
05645     if (key) {
05646        SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key);
05647        PORT_Assert(sessKey);
05648        /* get the session */
05649        sessKey->wasDerived = PR_TRUE;
05650        session = sftk_SessionFromHandle(hSession);
05651        if (session == NULL) {
05652            sftk_FreeObject(key);
05653            return CKR_HOST_MEMORY;
05654        }
05655 
05656        crv = sftk_handleObject(key,session);
05657        sftk_FreeSession(session);
05658        *phKey = key->handle;
05659        sftk_FreeObject(key);
05660     }
05661     return crv;
05662 }
05663 
05664 
05665 /* NSC_GetFunctionStatus obtains an updated status of a function running 
05666  * in parallel with an application. */
05667 CK_RV NSC_GetFunctionStatus(CK_SESSION_HANDLE hSession)
05668 {
05669     return CKR_FUNCTION_NOT_PARALLEL;
05670 }
05671 
05672 /* NSC_CancelFunction cancels a function running in parallel */
05673 CK_RV NSC_CancelFunction(CK_SESSION_HANDLE hSession)
05674 {
05675     return CKR_FUNCTION_NOT_PARALLEL;
05676 }
05677 
05678 /* NSC_GetOperationState saves the state of the cryptographic 
05679  *operation in a session.
05680  * NOTE: This code only works for digest functions for now. eventually need
05681  * to add full flatten/resurect to our state stuff so that all types of state
05682  * can be saved */
05683 CK_RV NSC_GetOperationState(CK_SESSION_HANDLE hSession, 
05684        CK_BYTE_PTR  pOperationState, CK_ULONG_PTR pulOperationStateLen)
05685 {
05686     SFTKSessionContext *context;
05687     SFTKSession *session;
05688     CK_RV crv;
05689     CK_ULONG pOSLen = *pulOperationStateLen;
05690 
05691     /* make sure we're legal */
05692     crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, &session);
05693     if (crv != CKR_OK) return crv;
05694 
05695     *pulOperationStateLen = context->cipherInfoLen + sizeof(CK_MECHANISM_TYPE)
05696                             + sizeof(SFTKContextType);
05697     if (pOperationState == NULL) {
05698         sftk_FreeSession(session);
05699        return CKR_OK;
05700     } else {
05701        if (pOSLen < *pulOperationStateLen) {
05702            return CKR_BUFFER_TOO_SMALL;
05703        }
05704     }
05705     PORT_Memcpy(pOperationState,&context->type,sizeof(SFTKContextType));
05706     pOperationState += sizeof(SFTKContextType);
05707     PORT_Memcpy(pOperationState,&context->currentMech,
05708                                           sizeof(CK_MECHANISM_TYPE));
05709     pOperationState += sizeof(CK_MECHANISM_TYPE);
05710     PORT_Memcpy(pOperationState,context->cipherInfo,context->cipherInfoLen);
05711     sftk_FreeSession(session);
05712     return CKR_OK;
05713 }
05714 
05715 
05716 #define sftk_Decrement(stateSize,len) \
05717        stateSize = ((stateSize) > (CK_ULONG)(len)) ? \
05718                             ((stateSize) - (CK_ULONG)(len)) : 0;
05719 
05720 /* NSC_SetOperationState restores the state of the cryptographic 
05721  * operation in a session. This is coded like it can restore lots of
05722  * states, but it only works for truly flat cipher structures. */
05723 CK_RV NSC_SetOperationState(CK_SESSION_HANDLE hSession, 
05724        CK_BYTE_PTR  pOperationState, CK_ULONG  ulOperationStateLen,
05725         CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey)
05726 {
05727     SFTKSessionContext *context;
05728     SFTKSession *session;
05729     SFTKContextType type;
05730     CK_MECHANISM mech;
05731     CK_RV crv = CKR_OK;
05732 
05733     while (ulOperationStateLen != 0) {
05734        /* get what type of state we're dealing with... */
05735        PORT_Memcpy(&type,pOperationState, sizeof(SFTKContextType));
05736 
05737        /* fix up session contexts based on type */
05738        session = sftk_SessionFromHandle(hSession);
05739        if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
05740        context = sftk_ReturnContextByType(session, type);
05741        sftk_SetContextByType(session, type, NULL);
05742        if (context) { 
05743             sftk_FreeContext(context);
05744        }
05745        pOperationState += sizeof(SFTKContextType);
05746        sftk_Decrement(ulOperationStateLen,sizeof(SFTKContextType));
05747 
05748 
05749        /* get the mechanism structure */
05750        PORT_Memcpy(&mech.mechanism,pOperationState,sizeof(CK_MECHANISM_TYPE));
05751        pOperationState += sizeof(CK_MECHANISM_TYPE);
05752        sftk_Decrement(ulOperationStateLen, sizeof(CK_MECHANISM_TYPE));
05753        /* should be filled in... but not necessary for hash */
05754        mech.pParameter = NULL;
05755        mech.ulParameterLen = 0;
05756        switch (type) {
05757        case SFTK_HASH:
05758            crv = NSC_DigestInit(hSession,&mech);
05759            if (crv != CKR_OK) break;
05760            crv = sftk_GetContext(hSession, &context, SFTK_HASH, PR_TRUE, 
05761                                                         NULL);
05762            if (crv != CKR_OK) break;
05763            PORT_Memcpy(context->cipherInfo,pOperationState,
05764                                           context->cipherInfoLen);
05765            pOperationState += context->cipherInfoLen;
05766            sftk_Decrement(ulOperationStateLen,context->cipherInfoLen);
05767            break;
05768        default:
05769            /* do sign/encrypt/decrypt later */
05770            crv = CKR_SAVED_STATE_INVALID;
05771          }
05772          sftk_FreeSession(session);
05773         if (crv != CKR_OK) break;
05774     }
05775     return crv;
05776 }
05777 
05778 /* Dual-function cryptographic operations */
05779 
05780 /* NSC_DigestEncryptUpdate continues a multiple-part digesting and encryption 
05781  * operation. */
05782 CK_RV NSC_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
05783     CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
05784                                     CK_ULONG_PTR pulEncryptedPartLen)
05785 {
05786     CK_RV crv;
05787 
05788     crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart, 
05789                                                 pulEncryptedPartLen);
05790     if (crv != CKR_OK) return crv;
05791     crv = NSC_DigestUpdate(hSession,pPart,ulPartLen);
05792 
05793     return crv;
05794 }
05795 
05796 
05797 /* NSC_DecryptDigestUpdate continues a multiple-part decryption and 
05798  * digesting operation. */
05799 CK_RV NSC_DecryptDigestUpdate(CK_SESSION_HANDLE hSession,
05800     CK_BYTE_PTR  pEncryptedPart, CK_ULONG  ulEncryptedPartLen,
05801                             CK_BYTE_PTR  pPart, CK_ULONG_PTR pulPartLen)
05802 {
05803     CK_RV crv;
05804 
05805     crv = NSC_DecryptUpdate(hSession,pEncryptedPart, ulEncryptedPartLen, 
05806                                                  pPart, pulPartLen);
05807     if (crv != CKR_OK) return crv;
05808     crv = NSC_DigestUpdate(hSession,pPart,*pulPartLen);
05809 
05810     return crv;
05811 }
05812 
05813 
05814 /* NSC_SignEncryptUpdate continues a multiple-part signing and 
05815  * encryption operation. */
05816 CK_RV NSC_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR  pPart,
05817         CK_ULONG  ulPartLen, CK_BYTE_PTR  pEncryptedPart,
05818                                     CK_ULONG_PTR pulEncryptedPartLen)
05819 {
05820     CK_RV crv;
05821 
05822     crv = NSC_EncryptUpdate(hSession,pPart,ulPartLen, pEncryptedPart, 
05823                                                 pulEncryptedPartLen);
05824     if (crv != CKR_OK) return crv;
05825     crv = NSC_SignUpdate(hSession,pPart,ulPartLen);
05826 
05827     return crv;
05828 }
05829 
05830 
05831 /* NSC_DecryptVerifyUpdate continues a multiple-part decryption 
05832  * and verify operation. */
05833 CK_RV NSC_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, 
05834        CK_BYTE_PTR  pEncryptedData, CK_ULONG  ulEncryptedDataLen, 
05835                             CK_BYTE_PTR  pData, CK_ULONG_PTR pulDataLen)
05836 {
05837     CK_RV crv;
05838 
05839     crv = NSC_DecryptUpdate(hSession,pEncryptedData, ulEncryptedDataLen, 
05840                                                  pData, pulDataLen);
05841     if (crv != CKR_OK) return crv;
05842     crv = NSC_VerifyUpdate(hSession, pData, *pulDataLen);
05843 
05844     return crv;
05845 }
05846 
05847 /* NSC_DigestKey continues a multi-part message-digesting operation,
05848  * by digesting the value of a secret key as part of the data already digested.
05849  */
05850 CK_RV NSC_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) 
05851 {
05852     SFTKSession *session = NULL;
05853     SFTKObject *key = NULL;
05854     SFTKAttribute *att;
05855     CK_RV crv;
05856 
05857     session = sftk_SessionFromHandle(hSession);
05858     if (session == NULL) return CKR_SESSION_HANDLE_INVALID;
05859 
05860     key = sftk_ObjectFromHandle(hKey,session);
05861     sftk_FreeSession(session);
05862     if (key == NULL)  return CKR_KEY_HANDLE_INVALID;
05863 
05864     /* PUT ANY DIGEST KEY RESTRICTION CHECKS HERE */
05865 
05866     /* make sure it's a valid  key for this operation */
05867     if (key->objclass != CKO_SECRET_KEY) {
05868        sftk_FreeObject(key);
05869        return CKR_KEY_TYPE_INCONSISTENT;
05870     }
05871     /* get the key value */
05872     att = sftk_FindAttribute(key,CKA_VALUE);
05873     sftk_FreeObject(key);
05874     if (!att) {
05875         return CKR_KEY_HANDLE_INVALID;        
05876     }
05877     crv = NSC_DigestUpdate(hSession,(CK_BYTE_PTR)att->attrib.pValue,
05878                         att->attrib.ulValueLen);
05879     sftk_FreeAttribute(att);
05880     return crv;
05881 }