Back to index

lightning-sunbird  0.9+nobinonly
pk11skey.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 Vipul Gupta <vipul.gupta@sun.com> and
00023  *   Douglas Stebila <douglas@stebila.ca>, 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 the Symkey wrapper and the PKCS context
00040  * Interfaces.
00041  */
00042 
00043 #include "seccomon.h"
00044 #include "secmod.h"
00045 #include "nssilock.h"
00046 #include "secmodi.h"
00047 #include "secmodti.h"
00048 #include "pkcs11.h"
00049 #include "pk11func.h"
00050 #include "secitem.h"
00051 #include "secoid.h"
00052 #include "secerr.h"
00053 
00054 /* forward static declarations. */
00055 static PK11SymKey *pk11_DeriveWithTemplate(PK11SymKey *baseKey, 
00056        CK_MECHANISM_TYPE derive, SECItem *param, CK_MECHANISM_TYPE target, 
00057        CK_ATTRIBUTE_TYPE operation, int keySize, CK_ATTRIBUTE *userAttr, 
00058        unsigned int numAttrs, PRBool isPerm);
00059 
00060 static void
00061 pk11_EnterKeyMonitor(PK11SymKey *symKey) {
00062     if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe)) 
00063        PK11_EnterSlotMonitor(symKey->slot);
00064 }
00065 
00066 static void
00067 pk11_ExitKeyMonitor(PK11SymKey *symKey) {
00068     if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe)) 
00069        PK11_ExitSlotMonitor(symKey->slot);
00070 }
00071 
00072 /*
00073  * pk11_getKeyFromList returns a symKey that has a session (if needSession
00074  * was specified), or explicitly does not have a session (if needSession
00075  * was not specified).
00076  */
00077 static PK11SymKey *
00078 pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession) {
00079     PK11SymKey *symKey = NULL;
00080 
00081     PZ_Lock(slot->freeListLock);
00082     /* own session list are symkeys with sessions that the symkey owns.
00083      * 'most' symkeys will own their own session. */
00084     if (needSession) {
00085        if (slot->freeSymKeysWithSessionHead) {
00086            symKey = slot->freeSymKeysWithSessionHead;
00087            slot->freeSymKeysWithSessionHead = symKey->next;
00088            slot->keyCount--;
00089        }
00090     }
00091     /* if we don't need a symkey with its own session, or we couldn't find
00092      * one on the owner list, get one from the non-owner free list. */
00093     if (!symKey) {
00094        if (slot->freeSymKeysHead) {
00095            symKey = slot->freeSymKeysHead;
00096            slot->freeSymKeysHead = symKey->next;
00097            slot->keyCount--;
00098        }
00099     }
00100     PZ_Unlock(slot->freeListLock);
00101     if (symKey) {
00102        symKey->next = NULL;
00103        if (!needSession) {
00104            return symKey;
00105        }
00106        /* if we are getting an owner key, make sure we have a valid session.
00107          * session could be invalid if the token has been removed or because
00108          * we got it from the non-owner free list */
00109        if ((symKey->series != slot->series) || 
00110                       (symKey->session == CK_INVALID_SESSION)) {
00111            symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
00112        }
00113        PORT_Assert(symKey->session != CK_INVALID_SESSION);
00114        if (symKey->session != CK_INVALID_SESSION)
00115            return symKey;
00116        PK11_FreeSymKey(symKey);
00117        /* if we are here, we need a session, but couldn't get one, it's 
00118         * unlikely we pk11_GetNewSession will succeed if we call it a second
00119         * time. */
00120        return NULL;
00121     }
00122 
00123     symKey = PORT_New(PK11SymKey);
00124     if (symKey == NULL) {
00125        return NULL;
00126     }
00127 
00128     symKey->next = NULL;
00129     if (needSession) {
00130        symKey->session = pk11_GetNewSession(slot,&symKey->sessionOwner);
00131        PORT_Assert(symKey->session != CK_INVALID_SESSION);
00132         if (symKey->session == CK_INVALID_SESSION) {
00133            PK11_FreeSymKey(symKey);
00134            symKey = NULL;
00135        }
00136     } else {
00137        symKey->session = CK_INVALID_SESSION;
00138     }
00139     return symKey;
00140 }
00141 
00142 /* Caller MUST hold slot->freeListLock (or ref count == 0?) !! */
00143 void
00144 PK11_CleanKeyList(PK11SlotInfo *slot)
00145 {
00146     PK11SymKey *symKey = NULL;
00147 
00148     while (slot->freeSymKeysWithSessionHead) {
00149        symKey = slot->freeSymKeysWithSessionHead;
00150        slot->freeSymKeysWithSessionHead = symKey->next;
00151        pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
00152        PORT_Free(symKey);
00153     }
00154     while (slot->freeSymKeysHead) {
00155        symKey = slot->freeSymKeysHead;
00156        slot->freeSymKeysHead = symKey->next;
00157        pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
00158        PORT_Free(symKey);
00159     }
00160     return;
00161 }
00162 
00163 /*
00164  * create a symetric key:
00165  *      Slot is the slot to create the key in.
00166  *      type is the mechanism type 
00167  *      owner is does this symKey structure own it's object handle (rare
00168  *        that this is false).
00169  *      needSession means the returned symKey will return with a valid session
00170  *        allocated already.
00171  */
00172 static PK11SymKey *
00173 pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 
00174                 PRBool owner, PRBool needSession, void *wincx)
00175 {
00176 
00177     PK11SymKey *symKey = pk11_getKeyFromList(slot, needSession);
00178 
00179     if (symKey == NULL) {
00180        return NULL;
00181     }
00182     /* if needSession was specified, make sure we have a valid session.
00183      * callers which specify needSession as false should do their own
00184      * check of the session before returning the symKey */
00185     if (needSession && symKey->session == CK_INVALID_SESSION) {
00186        PK11_FreeSymKey(symKey);
00187        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00188        return NULL;
00189     }
00190 
00191     symKey->type = type;
00192     symKey->data.type = siBuffer;
00193     symKey->data.data = NULL;
00194     symKey->data.len = 0;
00195     symKey->owner = owner;
00196     symKey->objectID = CK_INVALID_HANDLE;
00197     symKey->slot = slot;
00198     symKey->series = slot->series;
00199     symKey->cx = wincx;
00200     symKey->size = 0;
00201     symKey->refCount = 1;
00202     symKey->origin = PK11_OriginNULL;
00203     symKey->parent = NULL;
00204     symKey->freeFunc = NULL;
00205     symKey->userData = NULL;
00206     PK11_ReferenceSlot(slot);
00207     return symKey;
00208 }
00209 
00210 /*
00211  * destroy a symetric key
00212  */
00213 void
00214 PK11_FreeSymKey(PK11SymKey *symKey)
00215 {
00216     PK11SlotInfo *slot;
00217     PRBool freeit = PR_TRUE;
00218 
00219     if (PR_AtomicDecrement(&symKey->refCount) == 0) {
00220        PK11SymKey *parent = symKey->parent;
00221 
00222        symKey->parent = NULL;
00223        if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) {
00224            pk11_EnterKeyMonitor(symKey);
00225            (void) PK11_GETTAB(symKey->slot)->
00226               C_DestroyObject(symKey->session, symKey->objectID);
00227            pk11_ExitKeyMonitor(symKey);
00228        }
00229        if (symKey->data.data) {
00230            PORT_Memset(symKey->data.data, 0, symKey->data.len);
00231            PORT_Free(symKey->data.data);
00232        }
00233        /* free any existing data */
00234        if (symKey->userData && symKey->freeFunc) {
00235            (*symKey->freeFunc)(symKey->userData);
00236        }
00237         slot = symKey->slot;
00238         PZ_Lock(slot->freeListLock);
00239        if (slot->keyCount < slot->maxKeyCount) {
00240            /* 
00241              * freeSymkeysWithSessionHead contain a list of reusable
00242             *  SymKey structures with valid sessions.
00243             *    sessionOwner must be true.
00244              *    session must be valid.
00245              * freeSymKeysHead contain a list of SymKey structures without
00246              *  valid session.
00247              *    session must be CK_INVALID_SESSION.
00248             *    though sessionOwner is false, callers should not depend on
00249             *    this fact.
00250             */
00251            if (symKey->sessionOwner) {
00252               PORT_Assert (symKey->session != CK_INVALID_SESSION);
00253               symKey->next = slot->freeSymKeysWithSessionHead;
00254               slot->freeSymKeysWithSessionHead = symKey;
00255            } else {
00256               symKey->session = CK_INVALID_SESSION;
00257               symKey->next = slot->freeSymKeysHead;
00258               slot->freeSymKeysHead = symKey;
00259            }
00260            slot->keyCount++;
00261            symKey->slot = NULL;
00262            freeit = PR_FALSE;
00263         }
00264        PZ_Unlock(slot->freeListLock);
00265         if (freeit) {
00266            pk11_CloseSession(symKey->slot, symKey->session,
00267                                                  symKey->sessionOwner);
00268            PORT_Free(symKey);
00269        }
00270        PK11_FreeSlot(slot);
00271 
00272        if (parent) {
00273            PK11_FreeSymKey(parent);
00274        }
00275     }
00276 }
00277 
00278 PK11SymKey *
00279 PK11_ReferenceSymKey(PK11SymKey *symKey)
00280 {
00281     PR_AtomicIncrement(&symKey->refCount);
00282     return symKey;
00283 }
00284 
00285 /*
00286  * Accessors
00287  */
00288 CK_MECHANISM_TYPE
00289 PK11_GetMechanism(PK11SymKey *symKey)
00290 {
00291     return symKey->type;
00292 }
00293 
00294 /*
00295  * return the slot associated with a symetric key
00296  */
00297 PK11SlotInfo *
00298 PK11_GetSlotFromKey(PK11SymKey *symKey)
00299 {
00300     return PK11_ReferenceSlot(symKey->slot);
00301 }
00302 
00303 CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *symKey)
00304 {
00305     return PK11_GetKeyType(symKey->type,symKey->size);
00306 }
00307 
00308 PK11SymKey *
00309 PK11_GetNextSymKey(PK11SymKey *symKey)
00310 {
00311     return symKey ? symKey->next : NULL;
00312 }
00313 
00314 char *
00315 PK11_GetSymKeyNickname(PK11SymKey *symKey)
00316 {
00317     return PK11_GetObjectNickname(symKey->slot,symKey->objectID);
00318 }
00319 
00320 SECStatus
00321 PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname)
00322 {
00323     return PK11_SetObjectNickname(symKey->slot,symKey->objectID,nickname);
00324 }
00325 
00326 void *
00327 PK11_GetSymKeyUserData(PK11SymKey *symKey)
00328 {
00329     return symKey->userData;
00330 }
00331 
00332 void
00333 PK11_SetSymKeyUserData(PK11SymKey *symKey, void *userData, 
00334                                               PK11FreeDataFunc freeFunc)
00335 {
00336     /* free any existing data */
00337     if (symKey->userData && symKey->freeFunc) {
00338        (*symKey->freeFunc)(symKey->userData);
00339     }
00340     symKey->userData = userData;
00341     symKey->freeFunc = freeFunc;
00342     return;
00343 }
00344 
00345 /*
00346  * turn key handle into an appropriate key object
00347  */
00348 PK11SymKey *
00349 PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, PK11Origin origin,
00350     CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, PRBool owner, void *wincx)
00351 {
00352     PK11SymKey *symKey;
00353     PRBool needSession = !(owner && parent);
00354 
00355     if (keyID == CK_INVALID_HANDLE) {
00356        return NULL;
00357     }
00358 
00359     symKey = pk11_CreateSymKey(slot, type, owner, needSession, wincx);
00360     if (symKey == NULL) {
00361        return NULL;
00362     }
00363 
00364     symKey->objectID = keyID;
00365     symKey->origin = origin;
00366 
00367     /* adopt the parent's session */
00368     /* This is only used by SSL. What we really want here is a session
00369      * structure with a ref count so  the session goes away only after all the
00370      * keys do. */
00371     if (!needSession) {
00372        symKey->sessionOwner = PR_FALSE;
00373        symKey->session = parent->session;
00374        symKey->parent = PK11_ReferenceSymKey(parent);
00375         /* This is the only case where pk11_CreateSymKey does not explicitly
00376         * check symKey->session. We need to assert here to make sure.
00377         * the session isn't invalid. */
00378        PORT_Assert(parent->session != CK_INVALID_SESSION);
00379        if (parent->session == CK_INVALID_SESSION) {
00380            PK11_FreeSymKey(symKey);
00381            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
00382            return NULL;
00383        }
00384     }
00385 
00386     return symKey;
00387 }
00388 
00389 /*
00390  * turn key handle into an appropriate key object
00391  */
00392 PK11SymKey *
00393 PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type,
00394                                               int series, void *wincx)
00395 {
00396     PK11SymKey *symKey = NULL;
00397 
00398     if (slot->series != series) return NULL;
00399     if (slot->refKeys[wrap] == CK_INVALID_HANDLE) return NULL;
00400     if (type == CKM_INVALID_MECHANISM) type = slot->wrapMechanism;
00401 
00402     symKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
00403                slot->wrapMechanism, slot->refKeys[wrap], PR_FALSE, wincx);
00404     return symKey;
00405 }
00406 
00407 /*
00408  * This function is not thread-safe because it sets wrapKey->sessionOwner
00409  * without using a lock or atomic routine.  It can only be called when
00410  * only one thread has a reference to wrapKey.
00411  */
00412 void
00413 PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey)
00414 {
00415     /* save the handle and mechanism for the wrapping key */
00416     /* mark the key and session as not owned by us to they don't get freed
00417      * when the key goes way... that lets us reuse the key later */
00418     slot->refKeys[wrap] = wrapKey->objectID;
00419     wrapKey->owner = PR_FALSE;
00420     wrapKey->sessionOwner = PR_FALSE;
00421     slot->wrapMechanism = wrapKey->type;
00422 }
00423 
00424 
00425 /*
00426  * figure out if a key is still valid or if it is stale.
00427  */
00428 PRBool
00429 PK11_VerifyKeyOK(PK11SymKey *key) {
00430     if (!PK11_IsPresent(key->slot)) {
00431        return PR_FALSE;
00432     }
00433     return (PRBool)(key->series == key->slot->series);
00434 }
00435 
00436 static PK11SymKey *
00437 pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
00438                   PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
00439                 unsigned int templateCount, SECItem *key, void *wincx)
00440 {
00441     PK11SymKey *    symKey;
00442     SECStatus     rv;
00443 
00444     symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
00445     if (symKey == NULL) {
00446        return NULL;
00447     }
00448 
00449     symKey->size = key->len;
00450 
00451     PK11_SETATTRS(&keyTemplate[templateCount], CKA_VALUE, key->data, key->len);
00452     templateCount++;
00453 
00454     if (SECITEM_CopyItem(NULL,&symKey->data,key) != SECSuccess) {
00455        PK11_FreeSymKey(symKey);
00456        return NULL;
00457     }
00458 
00459     symKey->origin = origin;
00460 
00461     /* import the keys */
00462     rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
00463                      templateCount, isToken, &symKey->objectID);
00464     if ( rv != SECSuccess) {
00465        PK11_FreeSymKey(symKey);
00466        return NULL;
00467     }
00468 
00469     return symKey;
00470 }
00471 
00472 /*
00473  * turn key bits into an appropriate key object
00474  */
00475 PK11SymKey *
00476 PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
00477      PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,void *wincx)
00478 {
00479     PK11SymKey *    symKey;
00480     unsigned int    templateCount = 0;
00481     CK_OBJECT_CLASS keyClass       = CKO_SECRET_KEY;
00482     CK_KEY_TYPE     keyType        = CKK_GENERIC_SECRET;
00483     CK_BBOOL        cktrue  = CK_TRUE; /* sigh */
00484     CK_ATTRIBUTE    keyTemplate[5];
00485     CK_ATTRIBUTE *  attrs   = keyTemplate;
00486 
00487     PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
00488     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
00489     PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
00490     templateCount = attrs - keyTemplate;
00491     PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
00492 
00493     keyType = PK11_GetKeyType(type,key->len);
00494     symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE, 
00495                             keyTemplate, templateCount, key, wincx);
00496     return symKey;
00497 }
00498 
00499 
00500 /*
00501  * turn key bits into an appropriate key object
00502  */
00503 PK11SymKey *
00504 PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
00505      PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
00506      CK_FLAGS flags, PRBool isPerm, void *wincx)
00507 {
00508     PK11SymKey *    symKey;
00509     unsigned int    templateCount = 0;
00510     CK_OBJECT_CLASS keyClass       = CKO_SECRET_KEY;
00511     CK_KEY_TYPE     keyType        = CKK_GENERIC_SECRET;
00512     CK_BBOOL        cktrue  = CK_TRUE; /* sigh */
00513     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
00514     CK_ATTRIBUTE *  attrs   = keyTemplate;
00515 
00516     PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
00517     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
00518     if (isPerm) {
00519        PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue) ); attrs++;
00520        /* sigh some tokens think CKA_PRIVATE = false is a reasonable 
00521         * default for secret keys */
00522        PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue) ); attrs++;
00523     }
00524     attrs += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
00525     if ((operation != CKA_FLAGS_ONLY) &&
00526         !pk11_FindAttrInTemplate(keyTemplate, attrs-keyTemplate, operation)) {
00527         PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue)); attrs++;
00528     }
00529     templateCount = attrs - keyTemplate;
00530     PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
00531 
00532     keyType = PK11_GetKeyType(type,key->len);
00533     symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
00534                              keyTemplate, templateCount, key, wincx);
00535     if (symKey && isPerm) {
00536        symKey->owner = PR_FALSE;
00537     }
00538     return symKey;
00539 }
00540 
00541 
00542 PK11SymKey *
00543 PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID,
00544                                                         void *wincx)
00545 {
00546     CK_ATTRIBUTE findTemp[4];
00547     CK_ATTRIBUTE *attrs;
00548     CK_BBOOL ckTrue = CK_TRUE;
00549     CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
00550     int tsize = 0;
00551     CK_OBJECT_HANDLE key_id;
00552 
00553     attrs = findTemp;
00554     PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
00555     PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
00556     if (keyID) {
00557         PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len); attrs++;
00558     }
00559     tsize = attrs - findTemp;
00560     PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
00561 
00562     key_id = pk11_FindObjectByTemplate(slot,findTemp,tsize);
00563     if (key_id == CK_INVALID_HANDLE) {
00564        return NULL;
00565     }
00566     return PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, type, key_id,
00567                                           PR_FALSE, wincx);
00568 }
00569 
00570 PK11SymKey *
00571 PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
00572 {
00573     CK_ATTRIBUTE findTemp[4];
00574     CK_ATTRIBUTE *attrs;
00575     CK_BBOOL ckTrue = CK_TRUE;
00576     CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
00577     int tsize = 0;
00578     int objCount = 0;
00579     CK_OBJECT_HANDLE *key_ids;
00580     PK11SymKey *nextKey = NULL;
00581     PK11SymKey *topKey = NULL;
00582     int i,len;
00583 
00584     attrs = findTemp;
00585     PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
00586     PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
00587     if (nickname) {
00588        len = PORT_Strlen(nickname);
00589        PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
00590     }
00591     tsize = attrs - findTemp;
00592     PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
00593 
00594     key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
00595     if (key_ids == NULL) {
00596        return NULL;
00597     }
00598 
00599     for (i=0; i < objCount ; i++) {
00600        SECItem typeData;
00601        CK_KEY_TYPE type = CKK_GENERIC_SECRET;
00602         SECStatus rv = PK11_ReadAttribute(slot, key_ids[i], 
00603                                           CKA_KEY_TYPE, NULL, &typeData);
00604        if (rv == SECSuccess) {
00605            if (typeData.len == sizeof(CK_KEY_TYPE)) {
00606               type = *(CK_KEY_TYPE *)typeData.data;
00607            }
00608            PORT_Free(typeData.data);
00609        }
00610        nextKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, 
00611               PK11_GetKeyMechanism(type), key_ids[i], PR_FALSE, wincx);
00612        if (nextKey) {
00613            nextKey->next = topKey;
00614            topKey = nextKey;
00615        }
00616    }
00617    PORT_Free(key_ids);
00618    return topKey;
00619 }
00620 
00621 void *
00622 PK11_GetWindow(PK11SymKey *key)
00623 {
00624    return key->cx;
00625 }
00626     
00627 
00628 /*
00629  * extract a symetric key value. NOTE: if the key is sensitive, we will
00630  * not be able to do this operation. This function is used to move
00631  * keys from one token to another */
00632 SECStatus
00633 PK11_ExtractKeyValue(PK11SymKey *symKey)
00634 {
00635     SECStatus rv;
00636 
00637     if (symKey->data.data != NULL) {
00638        if (symKey->size == 0) {
00639           symKey->size = symKey->data.len;
00640        }
00641        return SECSuccess;
00642     }
00643 
00644     if (symKey->slot == NULL) {
00645        PORT_SetError( SEC_ERROR_INVALID_KEY );
00646        return SECFailure;
00647     }
00648 
00649     rv = PK11_ReadAttribute(symKey->slot,symKey->objectID,CKA_VALUE,NULL,
00650                             &symKey->data);
00651     if (rv == SECSuccess) {
00652        symKey->size = symKey->data.len;
00653     }
00654     return rv;
00655 }
00656 
00657 SECStatus
00658 PK11_DeleteTokenSymKey(PK11SymKey *symKey)
00659 {
00660     if (!PK11_IsPermObject(symKey->slot, symKey->objectID)) {
00661        return SECFailure;
00662     }
00663     PK11_DestroyTokenObject(symKey->slot,symKey->objectID);
00664     symKey->objectID = CK_INVALID_HANDLE;
00665     return SECSuccess;
00666 }
00667 
00668 SECItem *
00669 __PK11_GetKeyData(PK11SymKey *symKey)
00670 {
00671     return &symKey->data;
00672 }
00673 
00674 SECItem *
00675 PK11_GetKeyData(PK11SymKey *symKey)
00676 {
00677     return __PK11_GetKeyData(symKey);
00678 }
00679 
00680 /* return the keylength if possible.  '0' if not */
00681 unsigned int
00682 PK11_GetKeyLength(PK11SymKey *key)
00683 {
00684     CK_KEY_TYPE keyType;
00685 
00686     if (key->size != 0) return key->size;
00687 
00688     /* First try to figure out the key length from its type */
00689     keyType = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_KEY_TYPE);
00690     switch (keyType) {
00691       case CKK_DES: key->size = 8; break;
00692       case CKK_DES2: key->size = 16; break;
00693       case CKK_DES3: key->size = 24; break;
00694       case CKK_SKIPJACK: key->size = 10; break;
00695       case CKK_BATON: key->size = 20; break;
00696       case CKK_JUNIPER: key->size = 20; break;
00697       case CKK_GENERIC_SECRET:
00698        if (key->type == CKM_SSL3_PRE_MASTER_KEY_GEN)  {
00699            key->size=48;
00700        }
00701        break;
00702       default: break;
00703     }
00704    if( key->size != 0 ) return key->size;
00705 
00706    if (key->data.data == NULL) {
00707        PK11_ExtractKeyValue(key);
00708    }
00709    /* key is probably secret. Look up its length */
00710    /*  this is new PKCS #11 version 2.0 functionality. */
00711    if (key->size == 0) {
00712        CK_ULONG keyLength;
00713 
00714        keyLength = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_VALUE_LEN);
00715        if (keyLength != CK_UNAVAILABLE_INFORMATION) {
00716            key->size = (unsigned int)keyLength;
00717        }
00718     }
00719 
00720    return key->size;
00721 }
00722 
00723 /* return the strength of a key. This is different from length in that
00724  * 1) it returns the size in bits, and 2) it returns only the secret portions
00725  * of the key minus any checksums or parity.
00726  */
00727 unsigned int
00728 PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid) 
00729 {
00730      int size=0;
00731      CK_MECHANISM_TYPE mechanism= CKM_INVALID_MECHANISM; /* RC2 only */
00732      SECItem *param = NULL; /* RC2 only */
00733      CK_RC2_CBC_PARAMS *rc2_params = NULL; /* RC2 ONLY */
00734      unsigned int effectiveBits = 0; /* RC2 ONLY */
00735 
00736      switch (PK11_GetKeyType(key->type,0)) {
00737      case CKK_CDMF:
00738        return 40;
00739      case CKK_DES:
00740        return 56;
00741      case CKK_DES3:
00742      case CKK_DES2:
00743        size = PK11_GetKeyLength(key);
00744        if (size == 16) {
00745           /* double des */
00746           return 112; /* 16*7 */
00747        }
00748        return 168;
00749     /*
00750      * RC2 has is different than other ciphers in that it allows the user
00751      * to deprecating keysize while still requiring all the bits for the 
00752      * original key. The info
00753      * on what the effective key strength is in the parameter for the key.
00754      * In S/MIME this parameter is stored in the DER encoded algid. In Our 
00755      * other uses of RC2, effectiveBits == keyBits, so this code functions
00756      * correctly without an algid.
00757      */
00758     case CKK_RC2:
00759        /* if no algid was provided, fall through to default */
00760         if (!algid) {
00761            break; 
00762        }
00763        /* verify that the algid is for RC2 */
00764        mechanism = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(algid));
00765        if ((mechanism != CKM_RC2_CBC) && (mechanism != CKM_RC2_ECB)) {
00766            break;
00767        }
00768 
00769        /* now get effective bits from the algorithm ID. */
00770        param = PK11_ParamFromAlgid(algid);
00771        /* if we couldn't get memory just use key length */
00772        if (param == NULL) {
00773            break;
00774        }
00775 
00776        rc2_params = (CK_RC2_CBC_PARAMS *) param->data;
00777        /* paranoia... shouldn't happen */
00778        PORT_Assert(param->data != NULL);
00779        if (param->data == NULL) {
00780            SECITEM_FreeItem(param,PR_TRUE);
00781            break;
00782        }
00783        effectiveBits = (unsigned int)rc2_params->ulEffectiveBits;
00784        SECITEM_FreeItem(param,PR_TRUE);
00785        param = NULL; rc2_params=NULL; /* paranoia */
00786 
00787        /* we have effective bits, is and allocated memory is free, now
00788         * we need to return the smaller of effective bits and keysize */
00789        size = PK11_GetKeyLength(key);
00790        if ((unsigned int)size*8 > effectiveBits) {
00791            return effectiveBits;
00792        }
00793 
00794        return size*8; /* the actual key is smaller, the strength can't be
00795                      * greater than the actual key size */
00796        
00797     default:
00798        break;
00799     }
00800     return PK11_GetKeyLength(key) * 8;
00801 }
00802 
00803 /*
00804  * The next three utilities are to deal with the fact that a given operation
00805  * may be a multi-slot affair. This creates a new key object that is copied
00806  * into the new slot.
00807  */
00808 PK11SymKey *
00809 pk11_CopyToSlotPerm(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 
00810               CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, 
00811               PRBool isPerm, PK11SymKey *symKey)
00812 {
00813     SECStatus rv;
00814     PK11SymKey *newKey = NULL;
00815 
00816     /* Extract the raw key data if possible */
00817     if (symKey->data.data == NULL) {
00818        rv = PK11_ExtractKeyValue(symKey);
00819        /* KEY is sensitive, we're try key exchanging it. */
00820        if (rv != SECSuccess) {
00821            return pk11_KeyExchange(slot, type, operation, 
00822                                           flags, isPerm, symKey);
00823        }
00824     }
00825 
00826     newKey = PK11_ImportSymKeyWithFlags(slot,  type, symKey->origin,
00827        operation, &symKey->data, flags, isPerm, symKey->cx);
00828     if (newKey == NULL) {
00829        newKey = pk11_KeyExchange(slot, type, operation, flags, isPerm, symKey);
00830     }
00831     return newKey;
00832 }
00833 
00834 PK11SymKey *
00835 pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
00836        CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey)
00837 {
00838    return pk11_CopyToSlotPerm(slot, type, operation, 0, PR_FALSE, symKey);
00839 }
00840 
00841 /*
00842  * Make sure the slot we are in the correct slot for the operation
00843  */
00844 PK11SymKey *
00845 pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type,
00846                                           CK_ATTRIBUTE_TYPE operation)
00847 {
00848     PK11SlotInfo *slot = symKey->slot;
00849     PK11SymKey *newKey = NULL;
00850 
00851     if ((slot== NULL) || !PK11_DoesMechanism(slot,type)) {
00852        slot = PK11_GetBestSlot(type,symKey->cx);
00853        if (slot == NULL) {
00854            PORT_SetError( SEC_ERROR_NO_MODULE );
00855            return NULL;
00856        }
00857        newKey = pk11_CopyToSlot(slot, type, operation, symKey);
00858        PK11_FreeSlot(slot);
00859     }
00860     return newKey;
00861 }
00862 
00863 PK11SymKey *
00864 PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, 
00865                      CK_FLAGS flags, PRBool  perm, PK11SymKey *symKey)
00866 {
00867     if (symKey->slot == slot) {
00868        if (perm) {
00869           return PK11_ConvertSessionSymKeyToTokenSymKey(symKey,symKey->cx);
00870        } else {
00871           return PK11_ReferenceSymKey(symKey);
00872        }
00873     }
00874     
00875     return pk11_CopyToSlotPerm(slot, symKey->type, 
00876                                    operation, flags, perm, symKey);
00877 }
00878 
00879 
00880 /*
00881  * Use the token to generate a key. keySize must be 'zero' for fixed key
00882  * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute
00883  * to be added to the template for the key. PKCS #11 modules fail if you
00884  * specify the CKA_VALUE_LEN attribute for keys with fixed length.
00885  * NOTE: this means to generate a DES2 key from this interface you must
00886  * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying
00887  * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
00888  *
00889  * CK_FLAGS flags: key operation flags
00890  * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
00891  */
00892 PK11SymKey *
00893 PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
00894     SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags,
00895     PK11AttrFlags attrFlags, void *wincx)
00896 {
00897     PK11SymKey *symKey;
00898     CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS];
00899     CK_ATTRIBUTE *attrs = genTemplate;
00900     int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
00901     CK_SESSION_HANDLE session;
00902     CK_MECHANISM mechanism;
00903     CK_RV crv;
00904     CK_BBOOL cktrue = CK_TRUE;
00905     CK_BBOOL ckfalse = CK_FALSE;
00906     CK_ULONG ck_key_size;       /* only used for variable-length keys */
00907     PRBool isToken = ((attrFlags & PK11_ATTR_TOKEN) != 0);
00908 
00909     if (pk11_BadAttrFlags(attrFlags)) {
00910        PORT_SetError( SEC_ERROR_INVALID_ARGS );
00911        return NULL;
00912     }
00913 
00914     if (keySize != 0) {
00915         ck_key_size = keySize; /* Convert to PK11 type */
00916 
00917         PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size)); 
00918                                                  attrs++;
00919     }
00920 
00921     /* Include key id value if provided */
00922     if (keyid) {
00923         PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++;
00924     }
00925 
00926     attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
00927     attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
00928 
00929     count = attrs - genTemplate;
00930     PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE));
00931 
00932     /* Initialize the Key Gen Mechanism */
00933     mechanism.mechanism = PK11_GetKeyGenWithSize(type, keySize);
00934     if (mechanism.mechanism == CKM_FAKE_RANDOM) {
00935        PORT_SetError( SEC_ERROR_NO_MODULE );
00936        return NULL;
00937     }
00938 
00939     /* find a slot to generate the key into */
00940     /* Only do slot management if this is not a token key */
00941     if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot,type))) {
00942         PK11SlotInfo *bestSlot;
00943 
00944         bestSlot = PK11_GetBestSlot(type,wincx);
00945         if (bestSlot == NULL) {
00946            PORT_SetError( SEC_ERROR_NO_MODULE );
00947            return NULL;
00948        }
00949 
00950         symKey = pk11_CreateSymKey(bestSlot, type, !isToken, PR_TRUE, wincx);
00951 
00952         PK11_FreeSlot(bestSlot);
00953     } else {
00954        symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
00955     }
00956     if (symKey == NULL) return NULL;
00957 
00958     symKey->size = keySize;
00959     symKey->origin = PK11_OriginGenerated;
00960 
00961     /* Set the parameters for the key gen if provided */
00962     mechanism.pParameter = NULL;
00963     mechanism.ulParameterLen = 0;
00964     if (param) {
00965        mechanism.pParameter = param->data;
00966        mechanism.ulParameterLen = param->len;
00967     }
00968 
00969     /* Get session and perform locking */
00970     if (isToken) {
00971        PK11_Authenticate(symKey->slot,PR_TRUE,wincx);
00972        /* Should always be original slot */
00973         session = PK11_GetRWSession(symKey->slot);  
00974        symKey->owner = PR_FALSE;
00975     } else {
00976         session = symKey->session;
00977        if (session != CK_INVALID_SESSION) 
00978            pk11_EnterKeyMonitor(symKey);
00979     }
00980     if (session == CK_INVALID_SESSION) {
00981        PK11_FreeSymKey(symKey);
00982        PORT_SetError(SEC_ERROR_BAD_DATA);
00983        return NULL;
00984     }
00985 
00986     crv = PK11_GETTAB(symKey->slot)->C_GenerateKey(session,
00987                       &mechanism, genTemplate, count, &symKey->objectID);
00988 
00989     /* Release lock and session */
00990     if (isToken) {
00991         PK11_RestoreROSession(symKey->slot, session);
00992     } else {
00993         pk11_ExitKeyMonitor(symKey);
00994     }
00995 
00996     if (crv != CKR_OK) {
00997        PK11_FreeSymKey(symKey);
00998        PORT_SetError( PK11_MapError(crv) );
00999        return NULL;
01000     }
01001 
01002     return symKey;
01003 }
01004 
01005 /*
01006  * Use the token to generate a key. keySize must be 'zero' for fixed key
01007  * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute
01008  * to be added to the template for the key. PKCS #11 modules fail if you
01009  * specify the CKA_VALUE_LEN attribute for keys with fixed length.
01010  * NOTE: this means to generate a DES2 key from this interface you must
01011  * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying
01012  * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
01013  */
01014 PK11SymKey *
01015 PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
01016     int keySize, SECItem *keyid, PRBool isToken, void *wincx)
01017 {
01018     PK11SymKey *symKey;
01019     PRBool weird = PR_FALSE;   /* hack for fortezza */
01020     CK_FLAGS opFlags = CKF_SIGN;
01021     PK11AttrFlags attrFlags = 0;
01022 
01023     if ((keySize == -1) && (type == CKM_SKIPJACK_CBC64)) {
01024        weird = PR_TRUE;
01025        keySize = 0;
01026     }
01027 
01028     opFlags |= weird ? CKF_DECRYPT : CKF_ENCRYPT;
01029 
01030     if (isToken) {
01031        attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
01032     }
01033 
01034     symKey = PK11_TokenKeyGenWithFlags(slot, type, param, keySize, keyid,
01035                                           opFlags, attrFlags, wincx);
01036     if (symKey && weird) {
01037        PK11_SetFortezzaHack(symKey);
01038     }
01039 
01040     return symKey;
01041 }
01042 
01043 PK11SymKey *
01044 PK11_KeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
01045                                           int keySize, void *wincx)
01046 {
01047     return PK11_TokenKeyGen(slot, type, param, keySize, 0, PR_FALSE, wincx);
01048 }
01049 
01050 /* --- */
01051 PK11SymKey *
01052 PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx)
01053 {
01054   return PK11_TokenKeyGen(slot, CKM_DES3_CBC, 0, 0, keyid, PR_TRUE, cx);
01055 }
01056 
01057 PK11SymKey*
01058 PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
01059 {
01060     PK11SlotInfo* slot = symk->slot;
01061     CK_ATTRIBUTE template[1];
01062     CK_ATTRIBUTE *attrs = template;
01063     CK_BBOOL cktrue = CK_TRUE;
01064     CK_RV crv;
01065     CK_OBJECT_HANDLE newKeyID;
01066     CK_SESSION_HANDLE rwsession;
01067 
01068     PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++;
01069 
01070     PK11_Authenticate(slot, PR_TRUE, wincx);
01071     rwsession = PK11_GetRWSession(slot);
01072     if (rwsession == CK_INVALID_SESSION) {
01073        PORT_SetError(SEC_ERROR_BAD_DATA);
01074        return NULL;
01075     }
01076     crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID,
01077         template, 1, &newKeyID);
01078     PK11_RestoreROSession(slot, rwsession);
01079 
01080     if (crv != CKR_OK) {
01081         PORT_SetError( PK11_MapError(crv) );
01082         return NULL;
01083     }
01084 
01085     return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin,
01086         symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
01087 }
01088 
01089 /*
01090  * This function does a straight public key wrap (which only RSA can do).
01091  * Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
01092  * Diffie-Hellman Ciphers. */
01093 SECStatus
01094 PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
01095                             PK11SymKey *symKey, SECItem *wrappedKey)
01096 {
01097     PK11SlotInfo *slot;
01098     CK_ULONG len =  wrappedKey->len;
01099     PK11SymKey *newKey = NULL;
01100     CK_OBJECT_HANDLE id;
01101     CK_MECHANISM mechanism;
01102     PRBool owner = PR_TRUE;
01103     CK_SESSION_HANDLE session;
01104     CK_RV crv;
01105 
01106     /* if this slot doesn't support the mechanism, go to a slot that does */
01107     newKey = pk11_ForceSlot(symKey,type,CKA_ENCRYPT);
01108     if (newKey != NULL) {
01109        symKey = newKey;
01110     }
01111 
01112     if ((symKey == NULL) || (symKey->slot == NULL)) {
01113        PORT_SetError( SEC_ERROR_NO_MODULE );
01114        return SECFailure;
01115     }
01116 
01117     slot = symKey->slot;
01118     mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
01119     mechanism.pParameter = NULL;
01120     mechanism.ulParameterLen = 0;
01121 
01122     id = PK11_ImportPublicKey(slot,pubKey,PR_FALSE);
01123     if (id == CK_INVALID_HANDLE) {
01124        if (newKey) {
01125            PK11_FreeSymKey(newKey);
01126        }
01127        return SECFailure;   /* Error code has been set. */
01128     }
01129 
01130     session = pk11_GetNewSession(slot,&owner);
01131     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
01132     crv = PK11_GETTAB(slot)->C_WrapKey(session,&mechanism,
01133               id,symKey->objectID,wrappedKey->data,&len);
01134     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
01135     pk11_CloseSession(slot,session,owner);
01136     if (newKey) {
01137        PK11_FreeSymKey(newKey);
01138     }
01139 
01140     if (crv != CKR_OK) {
01141        PORT_SetError( PK11_MapError(crv) );
01142        return SECFailure;
01143     }
01144     wrappedKey->len = len;
01145     return SECSuccess;
01146 } 
01147 
01148 /*
01149  * this little function uses the Encrypt function to wrap a key, just in
01150  * case we have problems with the wrap implementation for a token.
01151  */
01152 static SECStatus
01153 pk11_HandWrap(PK11SymKey *wrappingKey, SECItem *param, CK_MECHANISM_TYPE type,
01154                       SECItem *inKey, SECItem *outKey)
01155 {
01156     PK11SlotInfo *slot;
01157     CK_ULONG len;
01158     SECItem *data;
01159     CK_MECHANISM mech;
01160     PRBool owner = PR_TRUE;
01161     CK_SESSION_HANDLE session;
01162     CK_RV crv;
01163 
01164     slot = wrappingKey->slot;
01165     /* use NULL IV's for wrapping */
01166     mech.mechanism = type;
01167     if (param) {
01168        mech.pParameter = param->data;
01169        mech.ulParameterLen = param->len;
01170     } else {
01171        mech.pParameter = NULL;
01172        mech.ulParameterLen = 0;
01173     }
01174     session = pk11_GetNewSession(slot,&owner);
01175     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
01176     crv = PK11_GETTAB(slot)->C_EncryptInit(session,&mech,
01177                                                  wrappingKey->objectID);
01178     if (crv != CKR_OK) {
01179         if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
01180         pk11_CloseSession(slot,session,owner);
01181        PORT_SetError( PK11_MapError(crv) );
01182        return SECFailure;
01183     }
01184 
01185     /* keys are almost always aligned, but if we get this far,
01186      * we've gone above and beyond anyway... */
01187     data = PK11_BlockData(inKey,PK11_GetBlockSize(type,param));
01188     if (data == NULL) {
01189         if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
01190         pk11_CloseSession(slot,session,owner);
01191        PORT_SetError(SEC_ERROR_NO_MEMORY);
01192        return SECFailure;
01193     }
01194     len = outKey->len;
01195     crv = PK11_GETTAB(slot)->C_Encrypt(session,data->data,data->len,
01196                                                     outKey->data, &len);
01197     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
01198     pk11_CloseSession(slot,session,owner);
01199     SECITEM_FreeItem(data,PR_TRUE);
01200     outKey->len = len;
01201     if (crv != CKR_OK) {
01202        PORT_SetError( PK11_MapError(crv) );
01203        return SECFailure;
01204     }
01205     return SECSuccess;
01206 }
01207 
01208 /*
01209  * This function does a symetric based wrap.
01210  */
01211 SECStatus
01212 PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *param, 
01213        PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey)
01214 {
01215     PK11SlotInfo *slot;
01216     CK_ULONG len = wrappedKey->len;
01217     PK11SymKey *newKey = NULL;
01218     SECItem *param_save = NULL;
01219     CK_MECHANISM mechanism;
01220     PRBool owner = PR_TRUE;
01221     CK_SESSION_HANDLE session;
01222     CK_RV crv;
01223     SECStatus rv;
01224 
01225     /* if this slot doesn't support the mechanism, go to a slot that does */
01226     /* Force symKey and wrappingKey into the same slot */
01227     if ((wrappingKey->slot == NULL) || (symKey->slot != wrappingKey->slot)) {
01228        /* first try copying the wrapping Key to the symKey slot */
01229        if (symKey->slot && PK11_DoesMechanism(symKey->slot,type)) {
01230            newKey = pk11_CopyToSlot(symKey->slot,type,CKA_WRAP,wrappingKey);
01231        }
01232        /* Nope, try it the other way */
01233        if (newKey == NULL) {
01234            if (wrappingKey->slot) {
01235                newKey = pk11_CopyToSlot(wrappingKey->slot,
01236                                    symKey->type, CKA_ENCRYPT, symKey);
01237            }
01238            /* just not playing... one last thing, can we get symKey's data?
01239             * If it's possible, we it should already be in the 
01240             * symKey->data.data pointer because pk11_CopyToSlot would have
01241             * tried to put it there. */
01242            if (newKey == NULL) {
01243               /* Can't get symKey's data: Game Over */
01244               if (symKey->data.data == NULL) {
01245                   PORT_SetError( SEC_ERROR_NO_MODULE );
01246                   return SECFailure;
01247               }
01248               if (param == NULL) {
01249                   param_save = param = PK11_ParamFromIV(type,NULL);
01250               }
01251               rv = pk11_HandWrap(wrappingKey, param, type,
01252                                           &symKey->data,wrappedKey);
01253               if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
01254               return rv;
01255            }
01256            /* we successfully moved the sym Key */
01257            symKey = newKey;
01258        } else {
01259            /* we successfully moved the wrapping Key */
01260            wrappingKey = newKey;
01261        }
01262     }
01263 
01264     /* at this point both keys are in the same token */
01265     slot = wrappingKey->slot;
01266     mechanism.mechanism = type;
01267     /* use NULL IV's for wrapping */
01268     if (param == NULL) {
01269        param_save = param = PK11_ParamFromIV(type,NULL);
01270     }
01271     if (param) {
01272        mechanism.pParameter = param->data;
01273        mechanism.ulParameterLen = param->len;
01274     } else {
01275        mechanism.pParameter = NULL;
01276        mechanism.ulParameterLen = 0;
01277     }
01278 
01279     len = wrappedKey->len;
01280 
01281     session = pk11_GetNewSession(slot,&owner);
01282     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
01283     crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
01284                wrappingKey->objectID, symKey->objectID, 
01285                                           wrappedKey->data, &len);
01286     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
01287     pk11_CloseSession(slot,session,owner);
01288     rv = SECSuccess;
01289     if (crv != CKR_OK) {
01290        /* can't wrap it? try hand wrapping it... */
01291        do {
01292            if (symKey->data.data == NULL) {
01293               rv = PK11_ExtractKeyValue(symKey);
01294               if (rv != SECSuccess) break;
01295            }
01296            rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data,
01297                                                          wrappedKey);
01298        } while (PR_FALSE);
01299     } else {
01300         wrappedKey->len = len;
01301     }
01302     if (newKey) PK11_FreeSymKey(newKey);
01303     if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
01304     return rv;
01305 } 
01306 
01307 /*
01308  * This Generates a new key based on a symetricKey
01309  */
01310 PK11SymKey *
01311 PK11_Derive( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param, 
01312              CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
01313             int keySize)
01314 {
01315     return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
01316                                keySize, NULL, 0, PR_FALSE);
01317 }
01318 
01319 
01320 PK11SymKey *
01321 PK11_DeriveWithFlags( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
01322        SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
01323        int keySize, CK_FLAGS flags)
01324 {
01325     CK_BBOOL        ckTrue  = CK_TRUE; 
01326     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
01327     unsigned int    templateCount;
01328 
01329     templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
01330     return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
01331                 keySize, keyTemplate, templateCount, PR_FALSE);
01332 }
01333 
01334 PK11SymKey *
01335 PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
01336        SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
01337        int keySize, CK_FLAGS flags, PRBool isPerm)
01338 {
01339     CK_BBOOL        cktrue  = CK_TRUE; 
01340     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
01341     CK_ATTRIBUTE    *attrs;
01342     unsigned int    templateCount = 0;
01343 
01344     attrs = keyTemplate;
01345     if (isPerm) {
01346         PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
01347     }
01348     templateCount = attrs - keyTemplate;
01349     templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
01350     return pk11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
01351                                keySize, keyTemplate, templateCount, isPerm);
01352 }
01353 
01354 static PK11SymKey *
01355 pk11_DeriveWithTemplate( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
01356        SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
01357        int keySize, CK_ATTRIBUTE *userAttr, unsigned int numAttrs,
01358                                                   PRBool isPerm)
01359 {
01360     PK11SlotInfo *  slot    = baseKey->slot;
01361     PK11SymKey *    symKey;
01362     PK11SymKey *    newBaseKey     = NULL;
01363     CK_BBOOL        cktrue  = CK_TRUE; 
01364     CK_OBJECT_CLASS keyClass       = CKO_SECRET_KEY;
01365     CK_KEY_TYPE     keyType = CKK_GENERIC_SECRET;
01366     CK_ULONG        valueLen       = 0;
01367     CK_MECHANISM    mechanism; 
01368     CK_RV           crv;
01369     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
01370     CK_ATTRIBUTE *  attrs   = keyTemplate;
01371     CK_SESSION_HANDLE session;
01372     unsigned int    templateCount;
01373 
01374     if (numAttrs > MAX_TEMPL_ATTRS) {
01375        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01376        return NULL;
01377     }
01378     /* first copy caller attributes in. */
01379     for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
01380        *attrs++ = *userAttr++;
01381     }
01382 
01383     /* We only add the following attributes to the template if the caller
01384     ** didn't already supply them.
01385     */
01386     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
01387        PK11_SETATTRS(attrs, CKA_CLASS,     &keyClass, sizeof keyClass); 
01388        attrs++;
01389     }
01390     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
01391        keyType = PK11_GetKeyType(target, keySize);
01392        PK11_SETATTRS(attrs, CKA_KEY_TYPE,  &keyType,  sizeof keyType ); 
01393        attrs++;
01394     }
01395     if (keySize > 0 &&
01396          !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
01397        valueLen = (CK_ULONG)keySize;
01398        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen); 
01399        attrs++;
01400     }
01401     if ((operation != CKA_FLAGS_ONLY) &&
01402          !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
01403        PK11_SETATTRS(attrs, operation, &cktrue, sizeof cktrue); attrs++;
01404     }
01405 
01406     templateCount = attrs - keyTemplate;
01407     PR_ASSERT(templateCount <= MAX_TEMPL_ATTRS);
01408 
01409     /* move the key to a slot that can do the function */
01410     if (!PK11_DoesMechanism(slot,derive)) {
01411        /* get a new base key & slot */
01412        PK11SlotInfo *newSlot = PK11_GetBestSlot(derive, baseKey->cx);
01413 
01414        if (newSlot == NULL) return NULL;
01415 
01416         newBaseKey = pk11_CopyToSlot (newSlot, derive, CKA_DERIVE, 
01417                                  baseKey);
01418        PK11_FreeSlot(newSlot);
01419        if (newBaseKey == NULL) 
01420            return NULL;     
01421        baseKey = newBaseKey;
01422        slot = baseKey->slot;
01423     }
01424 
01425 
01426     /* get our key Structure */
01427     symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, baseKey->cx);
01428     if (symKey == NULL) {
01429        return NULL;
01430     }
01431 
01432     symKey->size = keySize;
01433 
01434     mechanism.mechanism = derive;
01435     if (param) {
01436        mechanism.pParameter = param->data;
01437        mechanism.ulParameterLen = param->len;
01438     } else {
01439        mechanism.pParameter = NULL;
01440        mechanism.ulParameterLen = 0;
01441     }
01442     symKey->origin=PK11_OriginDerive;
01443 
01444     if (isPerm) {
01445        session =  PK11_GetRWSession(slot);
01446     } else {
01447         pk11_EnterKeyMonitor(symKey);
01448        session = symKey->session;
01449     }
01450     if (session == CK_INVALID_SESSION) {
01451        if (!isPerm)
01452            pk11_ExitKeyMonitor(symKey);
01453        crv = CKR_SESSION_HANDLE_INVALID;
01454     } else {
01455        crv = PK11_GETTAB(slot)->C_DeriveKey(session, &mechanism,
01456             baseKey->objectID, keyTemplate, templateCount, &symKey->objectID);
01457        if (isPerm) {
01458            PK11_RestoreROSession(slot, session);
01459        } else {
01460            pk11_ExitKeyMonitor(symKey);
01461        }
01462     }
01463     if (newBaseKey) 
01464        PK11_FreeSymKey(newBaseKey);
01465     if (crv != CKR_OK) {
01466        PK11_FreeSymKey(symKey);
01467        return NULL;
01468     }
01469     return symKey;
01470 }
01471 
01472 /*
01473  * This Generates a wrapping key based on a privateKey, publicKey, and two
01474  * random numbers. For Mail usage RandomB should be NULL. In the Sender's
01475  * case RandomA is generate, outherwize it is passed.
01476  */
01477 static unsigned char *rb_email = NULL;
01478 
01479 PK11SymKey *
01480 PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 
01481    PRBool isSender, SECItem *randomA, SECItem *randomB, 
01482     CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
01483                      CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx)
01484 {
01485     PK11SlotInfo *slot = privKey->pkcs11Slot;
01486     CK_MECHANISM mechanism;
01487     PK11SymKey *symKey;
01488     CK_RV crv;
01489 
01490 
01491     if (rb_email == NULL) {
01492        rb_email = PORT_ZAlloc(128);
01493        if (rb_email == NULL) {
01494            return NULL;
01495        }
01496        rb_email[127] = 1;
01497     }
01498 
01499     /* get our key Structure */
01500     symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
01501     if (symKey == NULL) {
01502        return NULL;
01503     }
01504 
01505     symKey->origin = PK11_OriginDerive;
01506 
01507     switch (privKey->keyType) {
01508     case rsaKey:
01509     case nullKey:
01510        PORT_SetError(SEC_ERROR_BAD_KEY);
01511        break;
01512     case dsaKey:
01513     case keaKey:
01514     case fortezzaKey:
01515        {
01516            CK_KEA_DERIVE_PARAMS param;
01517            param.isSender = (CK_BBOOL) isSender;
01518            param.ulRandomLen = randomA->len;
01519            param.pRandomA = randomA->data;
01520            param.pRandomB = rb_email;
01521            if (randomB)
01522                param.pRandomB = randomB->data;
01523            if (pubKey->keyType == fortezzaKey) {
01524               param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
01525               param.pPublicData = pubKey->u.fortezza.KEAKey.data;
01526            } else {
01527               /* assert type == keaKey */
01528               /* XXX change to match key key types */
01529               param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
01530               param.pPublicData = pubKey->u.fortezza.KEAKey.data;
01531            }
01532 
01533            mechanism.mechanism = derive;
01534            mechanism.pParameter = &param;
01535            mechanism.ulParameterLen = sizeof(param);
01536 
01537            /* get a new symKey structure */
01538            pk11_EnterKeyMonitor(symKey);
01539            crv=PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
01540                      privKey->pkcs11ID, NULL, 0, &symKey->objectID);
01541            pk11_ExitKeyMonitor(symKey);
01542            if (crv == CKR_OK) return symKey;
01543            PORT_SetError( PK11_MapError(crv) );
01544        }
01545        break;
01546     case dhKey:
01547        {
01548            CK_BBOOL cktrue = CK_TRUE;
01549            CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
01550            CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
01551            CK_ULONG key_size = 0;
01552            CK_ATTRIBUTE keyTemplate[4];
01553            int templateCount;
01554            CK_ATTRIBUTE *attrs = keyTemplate;
01555 
01556            if (pubKey->keyType != dhKey) {
01557               PORT_SetError(SEC_ERROR_BAD_KEY);
01558               break;
01559            }
01560 
01561            PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
01562            attrs++;
01563            PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
01564            attrs++;
01565            PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
01566            PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); 
01567            attrs++;
01568            templateCount =  attrs - keyTemplate;
01569            PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
01570 
01571            keyType = PK11_GetKeyType(target,keySize);
01572            key_size = keySize;
01573            symKey->size = keySize;
01574            if (key_size == 0) templateCount--;
01575 
01576            mechanism.mechanism = derive;
01577 
01578            /* we can undefine these when we define diffie-helman keys */
01579            mechanism.pParameter = pubKey->u.dh.publicValue.data; 
01580            mechanism.ulParameterLen = pubKey->u.dh.publicValue.len;
01581               
01582            pk11_EnterKeyMonitor(symKey);
01583            crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
01584             privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
01585            pk11_ExitKeyMonitor(symKey);
01586            if (crv == CKR_OK) return symKey;
01587            PORT_SetError( PK11_MapError(crv) );
01588        }
01589        break;
01590     case ecKey:
01591         {
01592            CK_BBOOL cktrue = CK_TRUE;
01593            CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
01594            CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
01595            CK_ULONG key_size = 0;
01596            CK_ATTRIBUTE keyTemplate[4];
01597            int templateCount;
01598            CK_ATTRIBUTE *attrs = keyTemplate;
01599            CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
01600 
01601            if (pubKey->keyType != ecKey) {
01602               PORT_SetError(SEC_ERROR_BAD_KEY);
01603               break;
01604            }
01605 
01606            PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
01607            attrs++;
01608            PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
01609            attrs++;
01610            PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
01611            PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); 
01612            attrs++;
01613            templateCount =  attrs - keyTemplate;
01614            PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
01615 
01616            keyType = PK11_GetKeyType(target,keySize);
01617            key_size = keySize;
01618            symKey->size = keySize;
01619            if (key_size == 0) templateCount--;
01620 
01621            mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS); 
01622            mechParams->kdf = CKD_SHA1_KDF;
01623            mechParams->ulSharedDataLen = 0;
01624            mechParams->pSharedData = NULL;
01625            mechParams->ulPublicDataLen =  pubKey->u.ec.publicValue.len;
01626            mechParams->pPublicData =  pubKey->u.ec.publicValue.data;
01627 
01628            mechanism.mechanism = derive;
01629            mechanism.pParameter = mechParams;
01630            mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
01631 
01632            pk11_EnterKeyMonitor(symKey);
01633            crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, 
01634               &mechanism, privKey->pkcs11ID, keyTemplate, 
01635               templateCount, &symKey->objectID);
01636            pk11_ExitKeyMonitor(symKey);
01637 
01638            PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
01639 
01640            if (crv == CKR_OK) return symKey;
01641            PORT_SetError( PK11_MapError(crv) );
01642        }
01643    }
01644 
01645    PK11_FreeSymKey(symKey);
01646    return NULL;
01647 }
01648 
01649 static PK11SymKey *
01650 pk11_PubDeriveECKeyWithKDF(
01651                   SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
01652                   PRBool isSender, SECItem *randomA, SECItem *randomB,
01653                   CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
01654                   CK_ATTRIBUTE_TYPE operation, int keySize,
01655                   CK_ULONG kdf, SECItem *sharedData, void *wincx)
01656 {
01657     PK11SlotInfo           *slot            = privKey->pkcs11Slot;
01658     PK11SymKey             *symKey;
01659     CK_MECHANISM            mechanism;
01660     CK_RV                   crv;
01661     CK_BBOOL                cktrue          = CK_TRUE;
01662     CK_OBJECT_CLASS         keyClass        = CKO_SECRET_KEY;
01663     CK_KEY_TYPE             keyType         = CKK_GENERIC_SECRET;
01664     CK_ULONG                key_size        = 0;
01665     CK_ATTRIBUTE            keyTemplate[4];
01666     int                     templateCount;
01667     CK_ATTRIBUTE           *attrs           = keyTemplate;
01668     CK_ECDH1_DERIVE_PARAMS *mechParams      = NULL;
01669 
01670     if (pubKey->keyType != ecKey) {
01671        PORT_SetError(SEC_ERROR_BAD_KEY);
01672        return NULL;
01673     }
01674     if ((kdf < CKD_NULL) || (kdf > CKD_SHA1_KDF)) {
01675        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
01676        return NULL;
01677     }
01678 
01679     /* get our key Structure */
01680     symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
01681     if (symKey == NULL) {
01682        return NULL;
01683     }
01684 
01685     symKey->origin = PK11_OriginDerive;
01686 
01687     PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));     attrs++;
01688     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));    attrs++;
01689     PK11_SETATTRS(attrs, operation, &cktrue, 1);                      attrs++;
01690     PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); attrs++;
01691     templateCount =  attrs - keyTemplate;
01692     PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
01693 
01694     keyType = PK11_GetKeyType(target,keySize);
01695     key_size = keySize;
01696     symKey->size = keySize;
01697     if (key_size == 0) 
01698        templateCount--;
01699 
01700     mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
01701     if (!mechParams) {
01702        PK11_FreeSymKey(symKey);
01703        return NULL;
01704     }
01705     mechParams->kdf = kdf;
01706     if (sharedData == NULL) {
01707        mechParams->ulSharedDataLen = 0;
01708        mechParams->pSharedData     = NULL;
01709     } else {
01710        mechParams->ulSharedDataLen = sharedData->len;
01711        mechParams->pSharedData     = sharedData->data;
01712     }
01713     mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
01714     mechParams->pPublicData     = pubKey->u.ec.publicValue.data;
01715 
01716     mechanism.mechanism      = derive;
01717     mechanism.pParameter     = mechParams;
01718     mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
01719 
01720     pk11_EnterKeyMonitor(symKey);
01721     crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism, 
01722        privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
01723     pk11_ExitKeyMonitor(symKey);
01724 
01725     PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
01726 
01727     if (crv != CKR_OK) {
01728        PK11_FreeSymKey(symKey);
01729        symKey = NULL;
01730        PORT_SetError( PK11_MapError(crv) );
01731     }
01732     return symKey;
01733 }
01734 
01735 PK11SymKey *
01736 PK11_PubDeriveWithKDF(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 
01737                     PRBool isSender, SECItem *randomA, SECItem *randomB, 
01738                     CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
01739                     CK_ATTRIBUTE_TYPE operation, int keySize,
01740                     CK_ULONG kdf, SECItem *sharedData, void *wincx)
01741 {
01742 
01743     switch (privKey->keyType) {
01744     case rsaKey:
01745     case nullKey:
01746     case dsaKey:
01747     case keaKey:
01748     case fortezzaKey:
01749     case dhKey:
01750        return PK11_PubDerive(privKey, pubKey, isSender, randomA, randomB,
01751               derive, target, operation, keySize, wincx);
01752     case ecKey:
01753        return pk11_PubDeriveECKeyWithKDF( privKey, pubKey, isSender, 
01754               randomA, randomB, derive, target, operation, keySize, 
01755               kdf, sharedData, wincx);
01756     default: break;
01757     }
01758 
01759     return NULL;
01760 }
01761 
01762 /*
01763  * this little function uses the Decrypt function to unwrap a key, just in
01764  * case we are having problem with unwrap. NOTE: The key size may
01765  * not be preserved properly for some algorithms!
01766  */
01767 static PK11SymKey *
01768 pk11_HandUnwrap(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
01769                 CK_MECHANISM *mech, SECItem *inKey, CK_MECHANISM_TYPE target, 
01770               CK_ATTRIBUTE *keyTemplate, unsigned int templateCount, 
01771               int key_size, void * wincx, CK_RV *crvp, PRBool isPerm)
01772 {
01773     CK_ULONG len;
01774     SECItem outKey;
01775     PK11SymKey *symKey;
01776     CK_RV crv;
01777     PRBool owner = PR_TRUE;
01778     CK_SESSION_HANDLE session;
01779 
01780     /* remove any VALUE_LEN parameters */
01781     if (keyTemplate[templateCount-1].type == CKA_VALUE_LEN) {
01782         templateCount--;
01783     }
01784 
01785     /* keys are almost always aligned, but if we get this far,
01786      * we've gone above and beyond anyway... */
01787     outKey.data = (unsigned char*)PORT_Alloc(inKey->len);
01788     if (outKey.data == NULL) {
01789        PORT_SetError( SEC_ERROR_NO_MEMORY );
01790        if (crvp) *crvp = CKR_HOST_MEMORY;
01791        return NULL;
01792     }
01793     len = inKey->len;
01794 
01795     /* use NULL IV's for wrapping */
01796     session = pk11_GetNewSession(slot,&owner);
01797     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
01798     crv = PK11_GETTAB(slot)->C_DecryptInit(session,mech,wrappingKey);
01799     if (crv != CKR_OK) {
01800        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
01801        pk11_CloseSession(slot,session,owner);
01802        PORT_Free(outKey.data);
01803        PORT_SetError( PK11_MapError(crv) );
01804        if (crvp) *crvp =crv;
01805        return NULL;
01806     }
01807     crv = PK11_GETTAB(slot)->C_Decrypt(session,inKey->data,inKey->len,
01808                                                     outKey.data, &len);
01809     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
01810     pk11_CloseSession(slot,session,owner);
01811     if (crv != CKR_OK) {
01812        PORT_Free(outKey.data);
01813        PORT_SetError( PK11_MapError(crv) );
01814        if (crvp) *crvp =crv;
01815        return NULL;
01816     }
01817 
01818     outKey.len = (key_size == 0) ? len : key_size;
01819     outKey.type = siBuffer;
01820 
01821     if (PK11_DoesMechanism(slot,target)) {
01822        symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap, 
01823                                            isPerm, keyTemplate, 
01824                                        templateCount, &outKey, wincx);
01825     } else {
01826        slot = PK11_GetBestSlot(target,wincx);
01827        if (slot == NULL) {
01828            PORT_SetError( SEC_ERROR_NO_MODULE );
01829            PORT_Free(outKey.data);
01830            if (crvp) *crvp = CKR_DEVICE_ERROR; 
01831            return NULL;
01832        }
01833        symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap, 
01834                                            isPerm, keyTemplate,
01835                                        templateCount, &outKey, wincx);
01836        PK11_FreeSlot(slot);
01837     }
01838     PORT_Free(outKey.data);
01839 
01840     if (crvp) *crvp = symKey? CKR_OK : CKR_DEVICE_ERROR; 
01841     return symKey;
01842 }
01843 
01844 /*
01845  * The wrap/unwrap function is pretty much the same for private and
01846  * public keys. It's just getting the Object ID and slot right. This is
01847  * the combined unwrap function.
01848  */
01849 static PK11SymKey *
01850 pk11_AnyUnwrapKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
01851     CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey, 
01852     CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize, 
01853     void *wincx, CK_ATTRIBUTE *userAttr, unsigned int numAttrs, PRBool isPerm)
01854 {
01855     PK11SymKey *    symKey;
01856     SECItem *       param_free     = NULL;
01857     CK_BBOOL        cktrue  = CK_TRUE; 
01858     CK_OBJECT_CLASS keyClass       = CKO_SECRET_KEY;
01859     CK_KEY_TYPE     keyType = CKK_GENERIC_SECRET;
01860     CK_ULONG        valueLen       = 0;
01861     CK_MECHANISM    mechanism;
01862     CK_SESSION_HANDLE rwsession;
01863     CK_RV           crv;
01864     CK_MECHANISM_INFO mechanism_info;
01865     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
01866     CK_ATTRIBUTE *  attrs   = keyTemplate;
01867     unsigned int    templateCount;
01868 
01869     if (numAttrs > MAX_TEMPL_ATTRS) {
01870        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01871        return NULL;
01872     }
01873     /* first copy caller attributes in. */
01874     for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
01875        *attrs++ = *userAttr++;
01876     }
01877 
01878     /* We only add the following attributes to the template if the caller
01879     ** didn't already supply them.
01880     */
01881     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
01882        PK11_SETATTRS(attrs, CKA_CLASS,     &keyClass, sizeof keyClass); 
01883        attrs++;
01884     }
01885     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
01886        keyType = PK11_GetKeyType(target, keySize);
01887        PK11_SETATTRS(attrs, CKA_KEY_TYPE,  &keyType,  sizeof keyType ); 
01888        attrs++;
01889     }
01890     if ((operation != CKA_FLAGS_ONLY) &&
01891          !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
01892        PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
01893     }
01894 
01895     /*
01896      * must be last in case we need to use this template to import the key
01897      */
01898     if (keySize > 0 &&
01899          !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
01900        valueLen = (CK_ULONG)keySize;
01901        PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen); 
01902        attrs++;
01903     }
01904 
01905     templateCount = attrs - keyTemplate;
01906     PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
01907 
01908 
01909     /* find out if we can do wrap directly. Because the RSA case if *very*
01910      * common, cache the results for it. */
01911     if ((wrapType == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
01912        mechanism_info.flags = slot->RSAInfoFlags;
01913     } else {
01914        if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
01915        crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,wrapType,
01916                              &mechanism_info);
01917        if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
01918        if (crv != CKR_OK) {
01919             mechanism_info.flags = 0;
01920        }
01921         if (wrapType == CKM_RSA_PKCS) {
01922            slot->RSAInfoFlags = mechanism_info.flags;
01923            slot->hasRSAInfo = PR_TRUE;
01924        }
01925     }
01926 
01927     /* initialize the mechanism structure */
01928     mechanism.mechanism = wrapType;
01929     /* use NULL IV's for wrapping */
01930     if (param == NULL) 
01931        param = param_free = PK11_ParamFromIV(wrapType,NULL);
01932     if (param) {
01933        mechanism.pParameter = param->data;
01934        mechanism.ulParameterLen = param->len;
01935     } else {
01936        mechanism.pParameter = NULL;
01937        mechanism.ulParameterLen = 0;
01938     }
01939 
01940     if ((mechanism_info.flags & CKF_DECRYPT)  
01941                             && !PK11_DoesMechanism(slot,target)) {
01942        symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey, 
01943                                 target, keyTemplate, templateCount, keySize, 
01944                              wincx, &crv, isPerm);
01945        if (symKey) {
01946            if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
01947            return symKey;
01948        }
01949        /*
01950         * if the RSA OP simply failed, don't try to unwrap again 
01951         * with this module.
01952         */
01953        if (crv == CKR_DEVICE_ERROR){
01954            if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
01955            return NULL;
01956        }
01957        /* fall through, maybe they incorrectly set CKF_DECRYPT */
01958     }
01959 
01960     /* get our key Structure */
01961     symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, wincx);
01962     if (symKey == NULL) {
01963        if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
01964        return NULL;
01965     }
01966 
01967     symKey->size = keySize;
01968     symKey->origin = PK11_OriginUnwrap;
01969 
01970     if (isPerm) {
01971        rwsession = PK11_GetRWSession(slot);
01972     } else {
01973         pk11_EnterKeyMonitor(symKey);
01974        rwsession = symKey->session;
01975     }
01976     PORT_Assert(rwsession != CK_INVALID_SESSION);
01977     if (rwsession == CK_INVALID_SESSION) 
01978        crv = CKR_SESSION_HANDLE_INVALID;
01979     else
01980        crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession,&mechanism,wrappingKey,
01981               wrappedKey->data, wrappedKey->len, keyTemplate, templateCount, 
01982                                                    &symKey->objectID);
01983     if (isPerm) {
01984        if (rwsession != CK_INVALID_SESSION)
01985            PK11_RestoreROSession(slot, rwsession);
01986     } else {
01987         pk11_ExitKeyMonitor(symKey);
01988     }
01989     if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
01990     if (crv != CKR_OK) {
01991        PK11_FreeSymKey(symKey);
01992        symKey = NULL;
01993        if (crv != CKR_DEVICE_ERROR) {
01994            /* try hand Unwrapping */
01995            symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey, 
01996                                  target, keyTemplate, templateCount,
01997                                  keySize, wincx, NULL, isPerm);
01998        }
01999    }
02000 
02001    return symKey;
02002 }
02003 
02004 /* use a symetric key to unwrap another symetric key */
02005 PK11SymKey *
02006 PK11_UnwrapSymKey( PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
02007                    SECItem *param, SECItem *wrappedKey, 
02008                  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
02009                  int keySize)
02010 {
02011     return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
02012                   wrapType, param, wrappedKey, target, operation, keySize, 
02013                   wrappingKey->cx, NULL, 0, PR_FALSE);
02014 }
02015 
02016 /* use a symetric key to unwrap another symetric key */
02017 PK11SymKey *
02018 PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
02019                    SECItem *param, SECItem *wrappedKey, 
02020                  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
02021                  int keySize, CK_FLAGS flags)
02022 {
02023     CK_BBOOL        ckTrue  = CK_TRUE; 
02024     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
02025     unsigned int    templateCount;
02026 
02027     templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
02028     return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
02029                   wrapType, param, wrappedKey, target, operation, keySize, 
02030                   wrappingKey->cx, keyTemplate, templateCount, PR_FALSE);
02031 }
02032 
02033 PK11SymKey *
02034 PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, 
02035                  CK_MECHANISM_TYPE wrapType,
02036                    SECItem *param, SECItem *wrappedKey, 
02037                  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
02038                  int keySize, CK_FLAGS flags, PRBool isPerm)
02039 {
02040     CK_BBOOL        cktrue  = CK_TRUE; 
02041     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
02042     CK_ATTRIBUTE    *attrs;
02043     unsigned int    templateCount;
02044 
02045     attrs = keyTemplate;
02046     if (isPerm) {
02047         PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
02048     }
02049     templateCount = attrs-keyTemplate;
02050     templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
02051 
02052     return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
02053                   wrapType, param, wrappedKey, target, operation, keySize, 
02054                   wrappingKey->cx, keyTemplate, templateCount, isPerm);
02055 }
02056 
02057 
02058 /* unwrap a symetric key with a private key. */
02059 PK11SymKey *
02060 PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
02061          CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
02062 {
02063     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
02064     PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
02065 
02066     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
02067        PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
02068     }
02069     
02070     return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
02071        wrapType, NULL, wrappedKey, target, operation, keySize, 
02072        wrappingKey->wincx, NULL, 0, PR_FALSE);
02073 }
02074 
02075 /* unwrap a symetric key with a private key. */
02076 PK11SymKey *
02077 PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey, 
02078          SECItem *wrappedKey, CK_MECHANISM_TYPE target, 
02079          CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags)
02080 {
02081     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
02082     CK_BBOOL        ckTrue  = CK_TRUE; 
02083     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
02084     unsigned int    templateCount;
02085     PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
02086 
02087     templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
02088 
02089     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
02090        PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
02091     }
02092     
02093     return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
02094        wrapType, NULL, wrappedKey, target, operation, keySize, 
02095        wrappingKey->wincx, keyTemplate, templateCount, PR_FALSE);
02096 }
02097 
02098 PK11SymKey *
02099 PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, 
02100          SECItem *wrappedKey, CK_MECHANISM_TYPE target, 
02101          CK_ATTRIBUTE_TYPE operation, int keySize,
02102          CK_FLAGS flags, PRBool isPerm)
02103 {
02104     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
02105     CK_BBOOL        cktrue  = CK_TRUE; 
02106     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
02107     CK_ATTRIBUTE    *attrs;
02108     unsigned int    templateCount;
02109     PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
02110 
02111     attrs = keyTemplate;
02112     if (isPerm) {
02113         PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
02114     }
02115     templateCount = attrs-keyTemplate;
02116 
02117     templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
02118 
02119     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
02120        PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
02121     }
02122     
02123     return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
02124        wrapType, NULL, wrappedKey, target, operation, keySize, 
02125        wrappingKey->wincx, keyTemplate, templateCount, isPerm);
02126 }
02127 
02128 PK11SymKey*
02129 PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech)
02130 {
02131     CK_RV crv;
02132     CK_ATTRIBUTE setTemplate;
02133     CK_BBOOL ckTrue = CK_TRUE; 
02134     PK11SlotInfo *slot = originalKey->slot;
02135 
02136     /* first just try to set this key up for signing */
02137     PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue));
02138     pk11_EnterKeyMonitor(originalKey);
02139     crv = PK11_GETTAB(slot)-> C_SetAttributeValue(originalKey->session, 
02140                             originalKey->objectID, &setTemplate, 1);
02141     pk11_ExitKeyMonitor(originalKey);
02142     if (crv == CKR_OK) {
02143        return PK11_ReferenceSymKey(originalKey);
02144     }
02145 
02146     /* nope, doesn't like it, use the pk11 copy object command */
02147     return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey);
02148 }
02149     
02150 void   
02151 PK11_SetFortezzaHack(PK11SymKey *symKey) { 
02152    symKey->origin = PK11_OriginFortezzaHack;
02153 }
02154 
02155 /*
02156  * This is required to allow FORTEZZA_NULL and FORTEZZA_RC4
02157  * working. This function simply gets a valid IV for the keys.
02158  */
02159 SECStatus
02160 PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len)
02161 {
02162     CK_MECHANISM mech_info;
02163     CK_ULONG count = 0;
02164     CK_RV crv;
02165     SECStatus rv = SECFailure;
02166 
02167     mech_info.mechanism = CKM_SKIPJACK_CBC64;
02168     mech_info.pParameter = iv;
02169     mech_info.ulParameterLen = len;
02170 
02171     /* generate the IV for fortezza */
02172     PK11_EnterSlotMonitor(symKey->slot);
02173     crv=PK11_GETTAB(symKey->slot)->C_EncryptInit(symKey->slot->session,
02174                             &mech_info, symKey->objectID);
02175     if (crv == CKR_OK) {
02176        PK11_GETTAB(symKey->slot)->C_EncryptFinal(symKey->slot->session, 
02177                                                         NULL, &count);
02178        rv = SECSuccess;
02179     }
02180     PK11_ExitSlotMonitor(symKey->slot);
02181     return rv;
02182 }