security/nss/lib/pk11wrap/pk11skey.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 /*
     5  * This file implements the Symkey wrapper and the PKCS context
     6  * Interfaces.
     7  */
     9 #include "seccomon.h"
    10 #include "secmod.h"
    11 #include "nssilock.h"
    12 #include "secmodi.h"
    13 #include "secmodti.h"
    14 #include "pkcs11.h"
    15 #include "pk11func.h"
    16 #include "secitem.h"
    17 #include "secoid.h"
    18 #include "secerr.h"
    19 #include "hasht.h"
    21 static void
    22 pk11_EnterKeyMonitor(PK11SymKey *symKey) {
    23     if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe)) 
    24 	PK11_EnterSlotMonitor(symKey->slot);
    25 }
    27 static void
    28 pk11_ExitKeyMonitor(PK11SymKey *symKey) {
    29     if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe)) 
    30     	PK11_ExitSlotMonitor(symKey->slot);
    31 }
    33 /*
    34  * pk11_getKeyFromList returns a symKey that has a session (if needSession
    35  * was specified), or explicitly does not have a session (if needSession
    36  * was not specified).
    37  */
    38 static PK11SymKey *
    39 pk11_getKeyFromList(PK11SlotInfo *slot, PRBool needSession) {
    40     PK11SymKey *symKey = NULL;
    42     PZ_Lock(slot->freeListLock);
    43     /* own session list are symkeys with sessions that the symkey owns.
    44      * 'most' symkeys will own their own session. */
    45     if (needSession) {
    46 	if (slot->freeSymKeysWithSessionHead) {
    47     	    symKey = slot->freeSymKeysWithSessionHead;
    48 	    slot->freeSymKeysWithSessionHead = symKey->next;
    49 	    slot->keyCount--;
    50 	}
    51     }
    52     /* if we don't need a symkey with its own session, or we couldn't find
    53      * one on the owner list, get one from the non-owner free list. */
    54     if (!symKey) {
    55 	if (slot->freeSymKeysHead) {
    56     	    symKey = slot->freeSymKeysHead;
    57 	    slot->freeSymKeysHead = symKey->next;
    58 	    slot->keyCount--;
    59 	}
    60     }
    61     PZ_Unlock(slot->freeListLock);
    62     if (symKey) {
    63 	symKey->next = NULL;
    64 	if (!needSession) {
    65 	    return symKey;
    66 	}
    67 	/* if we are getting an owner key, make sure we have a valid session.
    68          * session could be invalid if the token has been removed or because
    69          * we got it from the non-owner free list */
    70 	if ((symKey->series != slot->series) || 
    71 			 (symKey->session == CK_INVALID_SESSION)) {
    72 	    symKey->session = pk11_GetNewSession(slot, &symKey->sessionOwner);
    73 	}
    74 	PORT_Assert(symKey->session != CK_INVALID_SESSION);
    75 	if (symKey->session != CK_INVALID_SESSION)
    76 	    return symKey;
    77 	PK11_FreeSymKey(symKey);
    78 	/* if we are here, we need a session, but couldn't get one, it's 
    79 	 * unlikely we pk11_GetNewSession will succeed if we call it a second
    80 	 * time. */
    81 	return NULL;
    82     }
    84     symKey = PORT_New(PK11SymKey);
    85     if (symKey == NULL) {
    86 	return NULL;
    87     }
    89     symKey->next = NULL;
    90     if (needSession) {
    91 	symKey->session = pk11_GetNewSession(slot,&symKey->sessionOwner);
    92 	PORT_Assert(symKey->session != CK_INVALID_SESSION);
    93         if (symKey->session == CK_INVALID_SESSION) {
    94 	    PK11_FreeSymKey(symKey);
    95 	    symKey = NULL;
    96 	}
    97     } else {
    98 	symKey->session = CK_INVALID_SESSION;
    99     }
   100     return symKey;
   101 }
   103 /* Caller MUST hold slot->freeListLock (or ref count == 0?) !! */
   104 void
   105 PK11_CleanKeyList(PK11SlotInfo *slot)
   106 {
   107     PK11SymKey *symKey = NULL;
   109     while (slot->freeSymKeysWithSessionHead) {
   110     	symKey = slot->freeSymKeysWithSessionHead;
   111 	slot->freeSymKeysWithSessionHead = symKey->next;
   112 	pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
   113 	PORT_Free(symKey);
   114     }
   115     while (slot->freeSymKeysHead) {
   116     	symKey = slot->freeSymKeysHead;
   117 	slot->freeSymKeysHead = symKey->next;
   118 	pk11_CloseSession(slot, symKey->session, symKey->sessionOwner);
   119 	PORT_Free(symKey);
   120     }
   121     return;
   122 }
   124 /*
   125  * create a symetric key:
   126  *      Slot is the slot to create the key in.
   127  *      type is the mechanism type 
   128  *      owner is does this symKey structure own it's object handle (rare
   129  *        that this is false).
   130  *      needSession means the returned symKey will return with a valid session
   131  *        allocated already.
   132  */
   133 static PK11SymKey *
   134 pk11_CreateSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, 
   135 		  PRBool owner, PRBool needSession, void *wincx)
   136 {
   138     PK11SymKey *symKey = pk11_getKeyFromList(slot, needSession);
   140     if (symKey == NULL) {
   141 	return NULL;
   142     }
   143     /* if needSession was specified, make sure we have a valid session.
   144      * callers which specify needSession as false should do their own
   145      * check of the session before returning the symKey */
   146     if (needSession && symKey->session == CK_INVALID_SESSION) {
   147     	PK11_FreeSymKey(symKey);
   148 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   149 	return NULL;
   150     }
   152     symKey->type = type;
   153     symKey->data.type = siBuffer;
   154     symKey->data.data = NULL;
   155     symKey->data.len = 0;
   156     symKey->owner = owner;
   157     symKey->objectID = CK_INVALID_HANDLE;
   158     symKey->slot = slot;
   159     symKey->series = slot->series;
   160     symKey->cx = wincx;
   161     symKey->size = 0;
   162     symKey->refCount = 1;
   163     symKey->origin = PK11_OriginNULL;
   164     symKey->parent = NULL;
   165     symKey->freeFunc = NULL;
   166     symKey->userData = NULL;
   167     PK11_ReferenceSlot(slot);
   168     return symKey;
   169 }
   171 /*
   172  * destroy a symetric key
   173  */
   174 void
   175 PK11_FreeSymKey(PK11SymKey *symKey)
   176 {
   177     PK11SlotInfo *slot;
   178     PRBool freeit = PR_TRUE;
   180     if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) {
   181 	PK11SymKey *parent = symKey->parent;
   183 	symKey->parent = NULL;
   184 	if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) {
   185 	    pk11_EnterKeyMonitor(symKey);
   186 	    (void) PK11_GETTAB(symKey->slot)->
   187 		C_DestroyObject(symKey->session, symKey->objectID);
   188 	    pk11_ExitKeyMonitor(symKey);
   189 	}
   190 	if (symKey->data.data) {
   191 	    PORT_Memset(symKey->data.data, 0, symKey->data.len);
   192 	    PORT_Free(symKey->data.data);
   193 	}
   194 	/* free any existing data */
   195 	if (symKey->userData && symKey->freeFunc) {
   196 	    (*symKey->freeFunc)(symKey->userData);
   197 	}
   198         slot = symKey->slot;
   199         PZ_Lock(slot->freeListLock);
   200 	if (slot->keyCount < slot->maxKeyCount) {
   201 	    /* 
   202              * freeSymkeysWithSessionHead contain a list of reusable
   203 	     *  SymKey structures with valid sessions.
   204 	     *    sessionOwner must be true.
   205              *    session must be valid.
   206              * freeSymKeysHead contain a list of SymKey structures without
   207              *  valid session.
   208              *    session must be CK_INVALID_SESSION.
   209 	     *    though sessionOwner is false, callers should not depend on
   210 	     *    this fact.
   211 	     */
   212 	    if (symKey->sessionOwner) {
   213 		PORT_Assert (symKey->session != CK_INVALID_SESSION);
   214 		symKey->next = slot->freeSymKeysWithSessionHead;
   215 		slot->freeSymKeysWithSessionHead = symKey;
   216 	    } else {
   217 		symKey->session = CK_INVALID_SESSION;
   218 		symKey->next = slot->freeSymKeysHead;
   219 		slot->freeSymKeysHead = symKey;
   220 	    }
   221 	    slot->keyCount++;
   222 	    symKey->slot = NULL;
   223 	    freeit = PR_FALSE;
   224         }
   225 	PZ_Unlock(slot->freeListLock);
   226         if (freeit) {
   227 	    pk11_CloseSession(symKey->slot, symKey->session,
   228 							symKey->sessionOwner);
   229 	    PORT_Free(symKey);
   230 	}
   231 	PK11_FreeSlot(slot);
   233 	if (parent) {
   234 	    PK11_FreeSymKey(parent);
   235 	}
   236     }
   237 }
   239 PK11SymKey *
   240 PK11_ReferenceSymKey(PK11SymKey *symKey)
   241 {
   242     PR_ATOMIC_INCREMENT(&symKey->refCount);
   243     return symKey;
   244 }
   246 /*
   247  * Accessors
   248  */
   249 CK_MECHANISM_TYPE
   250 PK11_GetMechanism(PK11SymKey *symKey)
   251 {
   252     return symKey->type;
   253 }
   255 /*
   256  * return the slot associated with a symetric key
   257  */
   258 PK11SlotInfo *
   259 PK11_GetSlotFromKey(PK11SymKey *symKey)
   260 {
   261     return PK11_ReferenceSlot(symKey->slot);
   262 }
   264 CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *symKey)
   265 {
   266     return PK11_GetKeyType(symKey->type,symKey->size);
   267 }
   269 PK11SymKey *
   270 PK11_GetNextSymKey(PK11SymKey *symKey)
   271 {
   272     return symKey ? symKey->next : NULL;
   273 }
   275 char *
   276 PK11_GetSymKeyNickname(PK11SymKey *symKey)
   277 {
   278     return PK11_GetObjectNickname(symKey->slot,symKey->objectID);
   279 }
   281 SECStatus
   282 PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname)
   283 {
   284     return PK11_SetObjectNickname(symKey->slot,symKey->objectID,nickname);
   285 }
   287 void *
   288 PK11_GetSymKeyUserData(PK11SymKey *symKey)
   289 {
   290     return symKey->userData;
   291 }
   293 void
   294 PK11_SetSymKeyUserData(PK11SymKey *symKey, void *userData, 
   295                                               PK11FreeDataFunc freeFunc)
   296 {
   297     /* free any existing data */
   298     if (symKey->userData && symKey->freeFunc) {
   299 	(*symKey->freeFunc)(symKey->userData);
   300     }
   301     symKey->userData = userData;
   302     symKey->freeFunc = freeFunc;
   303     return;
   304 }
   306 /*
   307  * turn key handle into an appropriate key object
   308  */
   309 PK11SymKey *
   310 PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, PK11Origin origin,
   311     CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, PRBool owner, void *wincx)
   312 {
   313     PK11SymKey *symKey;
   314     PRBool needSession = !(owner && parent);
   316     if (keyID == CK_INVALID_HANDLE) {
   317 	return NULL;
   318     }
   320     symKey = pk11_CreateSymKey(slot, type, owner, needSession, wincx);
   321     if (symKey == NULL) {
   322 	return NULL;
   323     }
   325     symKey->objectID = keyID;
   326     symKey->origin = origin;
   328     /* adopt the parent's session */
   329     /* This is only used by SSL. What we really want here is a session
   330      * structure with a ref count so  the session goes away only after all the
   331      * keys do. */
   332     if (!needSession) {
   333 	symKey->sessionOwner = PR_FALSE;
   334 	symKey->session = parent->session;
   335 	symKey->parent = PK11_ReferenceSymKey(parent);
   336         /* This is the only case where pk11_CreateSymKey does not explicitly
   337 	 * check symKey->session. We need to assert here to make sure.
   338 	 * the session isn't invalid. */
   339 	PORT_Assert(parent->session != CK_INVALID_SESSION);
   340 	if (parent->session == CK_INVALID_SESSION) {
   341 	    PK11_FreeSymKey(symKey);
   342 	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   343 	    return NULL;
   344 	}
   345     }
   347     return symKey;
   348 }
   350 /*
   351  * turn key handle into an appropriate key object
   352  */
   353 PK11SymKey *
   354 PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type,
   355 						    int series, void *wincx)
   356 {
   357     PK11SymKey *symKey = NULL;
   359     if (slot->series != series) return NULL;
   360     if (slot->refKeys[wrap] == CK_INVALID_HANDLE) return NULL;
   361     if (type == CKM_INVALID_MECHANISM) type = slot->wrapMechanism;
   363     symKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive,
   364 		 slot->wrapMechanism, slot->refKeys[wrap], PR_FALSE, wincx);
   365     return symKey;
   366 }
   368 /*
   369  * This function is not thread-safe because it sets wrapKey->sessionOwner
   370  * without using a lock or atomic routine.  It can only be called when
   371  * only one thread has a reference to wrapKey.
   372  */
   373 void
   374 PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey)
   375 {
   376     /* save the handle and mechanism for the wrapping key */
   377     /* mark the key and session as not owned by us to they don't get freed
   378      * when the key goes way... that lets us reuse the key later */
   379     slot->refKeys[wrap] = wrapKey->objectID;
   380     wrapKey->owner = PR_FALSE;
   381     wrapKey->sessionOwner = PR_FALSE;
   382     slot->wrapMechanism = wrapKey->type;
   383 }
   386 /*
   387  * figure out if a key is still valid or if it is stale.
   388  */
   389 PRBool
   390 PK11_VerifyKeyOK(PK11SymKey *key) {
   391     if (!PK11_IsPresent(key->slot)) {
   392 	return PR_FALSE;
   393     }
   394     return (PRBool)(key->series == key->slot->series);
   395 }
   397 static PK11SymKey *
   398 pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   399                   PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
   400 		  unsigned int templateCount, SECItem *key, void *wincx)
   401 {
   402     PK11SymKey *    symKey;
   403     SECStatus	    rv;
   405     symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
   406     if (symKey == NULL) {
   407 	return NULL;
   408     }
   410     symKey->size = key->len;
   412     PK11_SETATTRS(&keyTemplate[templateCount], CKA_VALUE, key->data, key->len);
   413     templateCount++;
   415     if (SECITEM_CopyItem(NULL,&symKey->data,key) != SECSuccess) {
   416 	PK11_FreeSymKey(symKey);
   417 	return NULL;
   418     }
   420     symKey->origin = origin;
   422     /* import the keys */
   423     rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
   424 		 	templateCount, isToken, &symKey->objectID);
   425     if ( rv != SECSuccess) {
   426 	PK11_FreeSymKey(symKey);
   427 	return NULL;
   428     }
   430     return symKey;
   431 }
   433 /*
   434  * turn key bits into an appropriate key object
   435  */
   436 PK11SymKey *
   437 PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   438      PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,void *wincx)
   439 {
   440     PK11SymKey *    symKey;
   441     unsigned int    templateCount = 0;
   442     CK_OBJECT_CLASS keyClass 	= CKO_SECRET_KEY;
   443     CK_KEY_TYPE     keyType 	= CKK_GENERIC_SECRET;
   444     CK_BBOOL        cktrue 	= CK_TRUE; /* sigh */
   445     CK_ATTRIBUTE    keyTemplate[5];
   446     CK_ATTRIBUTE *  attrs 	= keyTemplate;
   448     PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
   449     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
   450     PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
   451     templateCount = attrs - keyTemplate;
   452     PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
   454     keyType = PK11_GetKeyType(type,key->len);
   455     symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE, 
   456 				keyTemplate, templateCount, key, wincx);
   457     return symKey;
   458 }
   461 /*
   462  * turn key bits into an appropriate key object
   463  */
   464 PK11SymKey *
   465 PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   466      PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key,
   467      CK_FLAGS flags, PRBool isPerm, void *wincx)
   468 {
   469     PK11SymKey *    symKey;
   470     unsigned int    templateCount = 0;
   471     CK_OBJECT_CLASS keyClass 	= CKO_SECRET_KEY;
   472     CK_KEY_TYPE     keyType 	= CKK_GENERIC_SECRET;
   473     CK_BBOOL        cktrue 	= CK_TRUE; /* sigh */
   474     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
   475     CK_ATTRIBUTE *  attrs 	= keyTemplate;
   477     PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++;
   478     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++;
   479     if (isPerm) {
   480 	PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue) ); attrs++;
   481 	/* sigh some tokens think CKA_PRIVATE = false is a reasonable 
   482 	 * default for secret keys */
   483 	PK11_SETATTRS(attrs, CKA_PRIVATE, &cktrue, sizeof(cktrue) ); attrs++;
   484     }
   485     attrs += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
   486     if ((operation != CKA_FLAGS_ONLY) &&
   487     	 !pk11_FindAttrInTemplate(keyTemplate, attrs-keyTemplate, operation)) {
   488         PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue)); attrs++;
   489     }
   490     templateCount = attrs - keyTemplate;
   491     PR_ASSERT(templateCount+1 <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
   493     keyType = PK11_GetKeyType(type,key->len);
   494     symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
   495 				 keyTemplate, templateCount, key, wincx);
   496     if (symKey && isPerm) {
   497 	symKey->owner = PR_FALSE;
   498     }
   499     return symKey;
   500 }
   503 PK11SymKey *
   504 PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID,
   505 								void *wincx)
   506 {
   507     CK_ATTRIBUTE findTemp[4];
   508     CK_ATTRIBUTE *attrs;
   509     CK_BBOOL ckTrue = CK_TRUE;
   510     CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
   511     int tsize = 0;
   512     CK_OBJECT_HANDLE key_id;
   514     attrs = findTemp;
   515     PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
   516     PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
   517     if (keyID) {
   518         PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len); attrs++;
   519     }
   520     tsize = attrs - findTemp;
   521     PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
   523     key_id = pk11_FindObjectByTemplate(slot,findTemp,tsize);
   524     if (key_id == CK_INVALID_HANDLE) {
   525 	return NULL;
   526     }
   527     return PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, type, key_id,
   528 		 				PR_FALSE, wincx);
   529 }
   531 PK11SymKey *
   532 PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
   533 {
   534     CK_ATTRIBUTE findTemp[4];
   535     CK_ATTRIBUTE *attrs;
   536     CK_BBOOL ckTrue = CK_TRUE;
   537     CK_OBJECT_CLASS keyclass = CKO_SECRET_KEY;
   538     int tsize = 0;
   539     int objCount = 0;
   540     CK_OBJECT_HANDLE *key_ids;
   541     PK11SymKey *nextKey = NULL;
   542     PK11SymKey *topKey = NULL;
   543     int i,len;
   545     attrs = findTemp;
   546     PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++;
   547     PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++;
   548     if (nickname) {
   549 	len = PORT_Strlen(nickname);
   550 	PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++;
   551     }
   552     tsize = attrs - findTemp;
   553     PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE));
   555     key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount);
   556     if (key_ids == NULL) {
   557 	return NULL;
   558     }
   560     for (i=0; i < objCount ; i++) {
   561 	SECItem typeData;
   562 	CK_KEY_TYPE type = CKK_GENERIC_SECRET;
   563         SECStatus rv = PK11_ReadAttribute(slot, key_ids[i], 
   564 						CKA_KEY_TYPE, NULL, &typeData);
   565 	if (rv == SECSuccess) {
   566 	    if (typeData.len == sizeof(CK_KEY_TYPE)) {
   567 	    	type = *(CK_KEY_TYPE *)typeData.data;
   568 	    }
   569 	    PORT_Free(typeData.data);
   570 	}
   571 	nextKey = PK11_SymKeyFromHandle(slot, NULL, PK11_OriginDerive, 
   572 		PK11_GetKeyMechanism(type), key_ids[i], PR_FALSE, wincx);
   573 	if (nextKey) {
   574 	    nextKey->next = topKey;
   575 	    topKey = nextKey;
   576 	}
   577    }
   578    PORT_Free(key_ids);
   579    return topKey;
   580 }
   582 void *
   583 PK11_GetWindow(PK11SymKey *key)
   584 {
   585    return key->cx;
   586 }
   589 /*
   590  * extract a symetric key value. NOTE: if the key is sensitive, we will
   591  * not be able to do this operation. This function is used to move
   592  * keys from one token to another */
   593 SECStatus
   594 PK11_ExtractKeyValue(PK11SymKey *symKey)
   595 {
   596     SECStatus rv;
   598     if (symKey->data.data != NULL) {
   599 	if (symKey->size == 0) {
   600 	   symKey->size = symKey->data.len;
   601 	}
   602 	return SECSuccess;
   603     }
   605     if (symKey->slot == NULL) {
   606 	PORT_SetError( SEC_ERROR_INVALID_KEY );
   607 	return SECFailure;
   608     }
   610     rv = PK11_ReadAttribute(symKey->slot,symKey->objectID,CKA_VALUE,NULL,
   611 				&symKey->data);
   612     if (rv == SECSuccess) {
   613 	symKey->size = symKey->data.len;
   614     }
   615     return rv;
   616 }
   618 SECStatus
   619 PK11_DeleteTokenSymKey(PK11SymKey *symKey)
   620 {
   621     if (!PK11_IsPermObject(symKey->slot, symKey->objectID)) {
   622 	return SECFailure;
   623     }
   624     PK11_DestroyTokenObject(symKey->slot,symKey->objectID);
   625     symKey->objectID = CK_INVALID_HANDLE;
   626     return SECSuccess;
   627 }
   629 SECItem *
   630 PK11_GetKeyData(PK11SymKey *symKey)
   631 {
   632     return &symKey->data;
   633 }
   635 /* This symbol is exported for backward compatibility. */
   636 SECItem *
   637 __PK11_GetKeyData(PK11SymKey *symKey)
   638 {
   639     return PK11_GetKeyData(symKey);
   640 }
   643 /*
   644  * PKCS #11 key Types with predefined length
   645  */
   646 unsigned int
   647 pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType)
   648 {
   649     int length = 0;
   650     switch (keyType) {
   651       case CKK_DES: length = 8; break;
   652       case CKK_DES2: length = 16; break;
   653       case CKK_DES3: length = 24; break;
   654       case CKK_SKIPJACK: length = 10; break;
   655       case CKK_BATON: length = 20; break;
   656       case CKK_JUNIPER: length = 20; break;
   657       default: break;
   658     }
   659     return length;
   660 }
   662 /* return the keylength if possible.  '0' if not */
   663 unsigned int
   664 PK11_GetKeyLength(PK11SymKey *key)
   665 {
   666     CK_KEY_TYPE keyType;
   668     if (key->size != 0) return key->size;
   670     /* First try to figure out the key length from its type */
   671     keyType = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_KEY_TYPE);
   672     key->size = pk11_GetPredefinedKeyLength(keyType);
   673     if ((keyType == CKK_GENERIC_SECRET) &&
   674 	(key->type == CKM_SSL3_PRE_MASTER_KEY_GEN))  {
   675 	key->size=48;
   676     }
   678    if( key->size != 0 ) return key->size;
   680    if (key->data.data == NULL) {
   681 	PK11_ExtractKeyValue(key);
   682    }
   683    /* key is probably secret. Look up its length */
   684    /*  this is new PKCS #11 version 2.0 functionality. */
   685    if (key->size == 0) {
   686 	CK_ULONG keyLength;
   688 	keyLength = PK11_ReadULongAttribute(key->slot,key->objectID,CKA_VALUE_LEN);
   689 	if (keyLength != CK_UNAVAILABLE_INFORMATION) {
   690 	    key->size = (unsigned int)keyLength;
   691 	}
   692     }
   694    return key->size;
   695 }
   697 /* return the strength of a key. This is different from length in that
   698  * 1) it returns the size in bits, and 2) it returns only the secret portions
   699  * of the key minus any checksums or parity.
   700  */
   701 unsigned int
   702 PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid) 
   703 {
   704      int size=0;
   705      CK_MECHANISM_TYPE mechanism= CKM_INVALID_MECHANISM; /* RC2 only */
   706      SECItem *param = NULL; /* RC2 only */
   707      CK_RC2_CBC_PARAMS *rc2_params = NULL; /* RC2 ONLY */
   708      unsigned int effectiveBits = 0; /* RC2 ONLY */
   710      switch (PK11_GetKeyType(key->type,0)) {
   711      case CKK_CDMF:
   712 	return 40;
   713      case CKK_DES:
   714 	return 56;
   715      case CKK_DES3:
   716      case CKK_DES2:
   717 	size = PK11_GetKeyLength(key);
   718 	if (size == 16) {
   719 	   /* double des */
   720 	   return 112; /* 16*7 */
   721 	}
   722 	return 168;
   723     /*
   724      * RC2 has is different than other ciphers in that it allows the user
   725      * to deprecating keysize while still requiring all the bits for the 
   726      * original key. The info
   727      * on what the effective key strength is in the parameter for the key.
   728      * In S/MIME this parameter is stored in the DER encoded algid. In Our 
   729      * other uses of RC2, effectiveBits == keyBits, so this code functions
   730      * correctly without an algid.
   731      */
   732     case CKK_RC2:
   733 	/* if no algid was provided, fall through to default */
   734         if (!algid) {
   735 	    break; 
   736 	}
   737 	/* verify that the algid is for RC2 */
   738 	mechanism = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(algid));
   739 	if ((mechanism != CKM_RC2_CBC) && (mechanism != CKM_RC2_ECB)) {
   740 	    break;
   741 	}
   743 	/* now get effective bits from the algorithm ID. */
   744 	param = PK11_ParamFromAlgid(algid);
   745 	/* if we couldn't get memory just use key length */
   746 	if (param == NULL) {
   747 	    break;
   748 	}
   750 	rc2_params = (CK_RC2_CBC_PARAMS *) param->data;
   751 	/* paranoia... shouldn't happen */
   752 	PORT_Assert(param->data != NULL);
   753 	if (param->data == NULL) {
   754 	    SECITEM_FreeItem(param,PR_TRUE);
   755 	    break;
   756 	}
   757 	effectiveBits = (unsigned int)rc2_params->ulEffectiveBits;
   758 	SECITEM_FreeItem(param,PR_TRUE);
   759 	param = NULL; rc2_params=NULL; /* paranoia */
   761 	/* we have effective bits, is and allocated memory is free, now
   762 	 * we need to return the smaller of effective bits and keysize */
   763 	size = PK11_GetKeyLength(key);
   764 	if ((unsigned int)size*8 > effectiveBits) {
   765 	    return effectiveBits;
   766 	}
   768 	return size*8; /* the actual key is smaller, the strength can't be
   769 			* greater than the actual key size */
   771     default:
   772 	break;
   773     }
   774     return PK11_GetKeyLength(key) * 8;
   775 }
   777 /*
   778  * The next three utilities are to deal with the fact that a given operation
   779  * may be a multi-slot affair. This creates a new key object that is copied
   780  * into the new slot.
   781  */
   782 PK11SymKey *
   783 pk11_CopyToSlotPerm(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, 
   784 	 	CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, 
   785 		PRBool isPerm, PK11SymKey *symKey)
   786 {
   787     SECStatus rv;
   788     PK11SymKey *newKey = NULL;
   790     /* Extract the raw key data if possible */
   791     if (symKey->data.data == NULL) {
   792 	rv = PK11_ExtractKeyValue(symKey);
   793 	/* KEY is sensitive, we're try key exchanging it. */
   794 	if (rv != SECSuccess) {
   795 	    return pk11_KeyExchange(slot, type, operation, 
   796 						flags, isPerm, symKey);
   797 	}
   798     }
   800     newKey = PK11_ImportSymKeyWithFlags(slot,  type, symKey->origin,
   801 	operation, &symKey->data, flags, isPerm, symKey->cx);
   802     if (newKey == NULL) {
   803 	newKey = pk11_KeyExchange(slot, type, operation, flags, isPerm, symKey);
   804     }
   805     return newKey;
   806 }
   808 PK11SymKey *
   809 pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,
   810 	CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey)
   811 {
   812    return pk11_CopyToSlotPerm(slot, type, operation, 0, PR_FALSE, symKey);
   813 }
   815 /*
   816  * Make sure the slot we are in is the correct slot for the operation
   817  * by verifying that it supports all of the specified mechanism types.
   818  */
   819 PK11SymKey *
   820 pk11_ForceSlotMultiple(PK11SymKey *symKey, CK_MECHANISM_TYPE *type,
   821 			int mechCount, CK_ATTRIBUTE_TYPE operation)
   822 {
   823     PK11SlotInfo *slot = symKey->slot;
   824     PK11SymKey *newKey = NULL;
   825     PRBool needToCopy = PR_FALSE;
   826     int i;
   828     if (slot == NULL) {
   829 	needToCopy = PR_TRUE;
   830     } else {
   831 	i = 0;
   832 	while ((i < mechCount) && (needToCopy == PR_FALSE)) {
   833 	    if (!PK11_DoesMechanism(slot,type[i])) {
   834 		needToCopy = PR_TRUE;
   835 	    }
   836 	    i++;
   837 	}
   838     }
   840     if (needToCopy == PR_TRUE) {
   841 	slot = PK11_GetBestSlotMultiple(type,mechCount,symKey->cx);
   842 	if (slot == NULL) {
   843 	    PORT_SetError( SEC_ERROR_NO_MODULE );
   844 	    return NULL;
   845 	}
   846 	newKey = pk11_CopyToSlot(slot, type[0], operation, symKey);
   847 	PK11_FreeSlot(slot);
   848     }
   849     return newKey;
   850 }
   852 /*
   853  * Make sure the slot we are in is the correct slot for the operation
   854  */
   855 PK11SymKey *
   856 pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type,
   857 						CK_ATTRIBUTE_TYPE operation)
   858 {
   859     return pk11_ForceSlotMultiple(symKey, &type, 1, operation);
   860 }
   862 PK11SymKey *
   863 PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, 
   864 			CK_FLAGS flags, PRBool  perm, PK11SymKey *symKey)
   865 {
   866     if (symKey->slot == slot) {
   867 	if (perm) {
   868 	   return PK11_ConvertSessionSymKeyToTokenSymKey(symKey,symKey->cx);
   869 	} else {
   870 	   return PK11_ReferenceSymKey(symKey);
   871 	}
   872     }
   874     return pk11_CopyToSlotPerm(slot, symKey->type, 
   875 					operation, flags, perm, symKey);
   876 }
   878 /*
   879  * Use the token to generate a key. 
   880  * 
   881  * keySize must be 'zero' for fixed key length algorithms. A nonzero 
   882  *  keySize causes the CKA_VALUE_LEN attribute to be added to the template 
   883  *  for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN 
   884  *  attribute for keys with fixed length. The exception is DES2. If you
   885  *  select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
   886  *  parameter and use the key size to determine which underlying DES keygen
   887  *  function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
   888  *
   889  * keyType must be -1 for most algorithms. Some PBE algorthims cannot 
   890  *  determine the correct key type from the mechanism or the parameters,
   891  *  so key type must be specified. Other PKCS #11 mechanisms may do so in
   892  *  the future. Currently there is no need to export this publically.
   893  *  Keep it private until there is a need in case we need to expand the
   894  *  keygen parameters again...
   895  *
   896  * CK_FLAGS flags: key operation flags
   897  * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
   898  */
   899 PK11SymKey *
   900 pk11_TokenKeyGenWithFlagsAndKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   901     SECItem *param, CK_KEY_TYPE keyType, int keySize, SECItem *keyid, 
   902     CK_FLAGS opFlags, PK11AttrFlags attrFlags, void *wincx)
   903 {
   904     PK11SymKey *symKey;
   905     CK_ATTRIBUTE genTemplate[MAX_TEMPL_ATTRS];
   906     CK_ATTRIBUTE *attrs = genTemplate;
   907     int count = sizeof(genTemplate)/sizeof(genTemplate[0]);
   908     CK_MECHANISM_TYPE keyGenType;
   909     CK_BBOOL cktrue = CK_TRUE;
   910     CK_BBOOL ckfalse = CK_FALSE;
   911     CK_ULONG ck_key_size;       /* only used for variable-length keys */
   913     if (pk11_BadAttrFlags(attrFlags)) {
   914 	PORT_SetError( SEC_ERROR_INVALID_ARGS );
   915 	return NULL;
   916     }
   918     if ((keySize != 0) && (type != CKM_DES3_CBC) && 
   919 		(type !=CKM_DES3_CBC_PAD) && (type != CKM_DES3_ECB)) {
   920         ck_key_size = keySize; /* Convert to PK11 type */
   922         PK11_SETATTRS(attrs, CKA_VALUE_LEN, &ck_key_size, sizeof(ck_key_size)); 
   923 							attrs++;
   924     }
   926     if (keyType != -1) {
   927         PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(CK_KEY_TYPE)); 
   928 							attrs++;
   929     }
   931     /* Include key id value if provided */
   932     if (keyid) {
   933         PK11_SETATTRS(attrs, CKA_ID, keyid->data, keyid->len); attrs++;
   934     }
   936     attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
   937     attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
   939     count = attrs - genTemplate;
   940     PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE));
   942     keyGenType = PK11_GetKeyGenWithSize(type, keySize);
   943     if (keyGenType == CKM_FAKE_RANDOM) {
   944         PORT_SetError( SEC_ERROR_NO_MODULE );
   945         return NULL;
   946     }
   947     symKey = PK11_KeyGenWithTemplate(slot, type, keyGenType,
   948                                      param, genTemplate, count, wincx);
   949     if (symKey != NULL) {
   950         symKey->size = keySize;
   951     }
   952     return symKey;
   953 }
   955 /*
   956  * Use the token to generate a key.  - Public
   957  * 
   958  * keySize must be 'zero' for fixed key length algorithms. A nonzero 
   959  *  keySize causes the CKA_VALUE_LEN attribute to be added to the template 
   960  *  for the key. Most PKCS #11 modules fail if you specify the CKA_VALUE_LEN 
   961  *  attribute for keys with fixed length. The exception is DES2. If you
   962  *  select a CKM_DES3_CBC mechanism, this code will not add the CKA_VALUE_LEN
   963  *  parameter and use the key size to determine which underlying DES keygen
   964  *  function to use (CKM_DES2_KEY_GEN or CKM_DES3_KEY_GEN).
   965  *
   966  * CK_FLAGS flags: key operation flags
   967  * PK11AttrFlags attrFlags: PK11_ATTR_XXX key attribute flags
   968  */
   969 PK11SymKey *
   970 PK11_TokenKeyGenWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
   971     SECItem *param, int keySize, SECItem *keyid, CK_FLAGS opFlags,
   972     PK11AttrFlags attrFlags, void *wincx)
   973 {
   974     return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, -1, keySize, 
   975 	keyid, opFlags, attrFlags, wincx);
   976 }
   978 /*
   979  * Use the token to generate a key. keySize must be 'zero' for fixed key
   980  * length algorithms. A nonzero keySize causes the CKA_VALUE_LEN attribute
   981  * to be added to the template for the key. PKCS #11 modules fail if you
   982  * specify the CKA_VALUE_LEN attribute for keys with fixed length.
   983  * NOTE: this means to generate a DES2 key from this interface you must
   984  * specify CKM_DES2_KEY_GEN as the mechanism directly; specifying
   985  * CKM_DES3_CBC as the mechanism and 16 as keySize currently doesn't work.
   986  */
   987 PK11SymKey *
   988 PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
   989     int keySize, SECItem *keyid, PRBool isToken, void *wincx)
   990 {
   991     PK11SymKey *symKey;
   992     PRBool weird = PR_FALSE;   /* hack for fortezza */
   993     CK_FLAGS opFlags = CKF_SIGN;
   994     PK11AttrFlags attrFlags = 0;
   996     if ((keySize == -1) && (type == CKM_SKIPJACK_CBC64)) {
   997 	weird = PR_TRUE;
   998 	keySize = 0;
   999     }
  1001     opFlags |= weird ? CKF_DECRYPT : CKF_ENCRYPT;
  1003     if (isToken) {
  1004 	attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE);
  1007     symKey = pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, param, 
  1008 			-1, keySize, keyid, opFlags, attrFlags, wincx);
  1009     if (symKey && weird) {
  1010 	PK11_SetFortezzaHack(symKey);
  1013     return symKey;
  1016 PK11SymKey *
  1017 PK11_KeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param,
  1018 						int keySize, void *wincx)
  1020     return PK11_TokenKeyGen(slot, type, param, keySize, 0, PR_FALSE, wincx);
  1023 PK11SymKey *
  1024 PK11_KeyGenWithTemplate(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
  1025                         CK_MECHANISM_TYPE keyGenType,
  1026                         SECItem *param, CK_ATTRIBUTE * attrs,
  1027                         unsigned int attrsCount, void *wincx)
  1029     PK11SymKey *symKey;
  1030     CK_SESSION_HANDLE session;
  1031     CK_MECHANISM mechanism;
  1032     CK_RV crv;
  1033     PRBool isToken = CK_FALSE;
  1034     CK_ULONG keySize = 0;
  1035     unsigned i;
  1037     /* Extract the template's CKA_VALUE_LEN into keySize and CKA_TOKEN into
  1038        isToken. */
  1039     for (i = 0; i < attrsCount; ++i) {
  1040         switch (attrs[i].type) {
  1041             case CKA_VALUE_LEN:
  1042                 if (attrs[i].pValue == NULL ||
  1043                     attrs[i].ulValueLen != sizeof(CK_ULONG)) {
  1044                     PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
  1045                     return NULL;
  1047                 keySize = * (CK_ULONG *) attrs[i].pValue;
  1048                 break;
  1049             case CKA_TOKEN:
  1050                 if (attrs[i].pValue == NULL || 
  1051                     attrs[i].ulValueLen != sizeof(CK_BBOOL)) {
  1052                     PORT_SetError(PK11_MapError(CKR_TEMPLATE_INCONSISTENT));
  1053                     return NULL;
  1055                 isToken = (*(CK_BBOOL*)attrs[i].pValue) ? PR_TRUE : PR_FALSE;
  1056                 break;
  1060     /* find a slot to generate the key into */
  1061     /* Only do slot management if this is not a token key */
  1062     if (!isToken && (slot == NULL || !PK11_DoesMechanism(slot,type))) {
  1063         PK11SlotInfo *bestSlot = PK11_GetBestSlot(type,wincx);
  1064         if (bestSlot == NULL) {
  1065             PORT_SetError( SEC_ERROR_NO_MODULE );
  1066             return NULL;
  1068         symKey = pk11_CreateSymKey(bestSlot, type, !isToken, PR_TRUE, wincx);
  1069         PK11_FreeSlot(bestSlot);
  1070     } else {
  1071         symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
  1073     if (symKey == NULL) return NULL;
  1075     symKey->size = keySize;
  1076     symKey->origin = PK11_OriginGenerated;
  1078     /* Set the parameters for the key gen if provided */
  1079     mechanism.mechanism = keyGenType;
  1080     mechanism.pParameter = NULL;
  1081     mechanism.ulParameterLen = 0;
  1082     if (param) {
  1083         mechanism.pParameter = param->data;
  1084         mechanism.ulParameterLen = param->len;
  1087     /* Get session and perform locking */
  1088     if (isToken) {
  1089         PK11_Authenticate(symKey->slot,PR_TRUE,wincx);
  1090         /* Should always be original slot */
  1091         session = PK11_GetRWSession(symKey->slot);  
  1092         symKey->owner = PR_FALSE;
  1093     } else {
  1094         session = symKey->session;
  1095         if (session != CK_INVALID_SESSION) 
  1096             pk11_EnterKeyMonitor(symKey);
  1098     if (session == CK_INVALID_SESSION) {
  1099         PK11_FreeSymKey(symKey);
  1100         PORT_SetError(SEC_ERROR_BAD_DATA);
  1101         return NULL;
  1104     crv = PK11_GETTAB(symKey->slot)->C_GenerateKey(session,
  1105 			 &mechanism, attrs, attrsCount, &symKey->objectID);
  1107     /* Release lock and session */
  1108     if (isToken) {
  1109         PK11_RestoreROSession(symKey->slot, session);
  1110     } else {
  1111         pk11_ExitKeyMonitor(symKey);
  1114     if (crv != CKR_OK) {
  1115         PK11_FreeSymKey(symKey);
  1116         PORT_SetError( PK11_MapError(crv) );
  1117         return NULL;
  1120     return symKey;
  1124 /* --- */
  1125 PK11SymKey *
  1126 PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx)
  1128   return PK11_TokenKeyGen(slot, CKM_DES3_CBC, 0, 0, keyid, PR_TRUE, cx);
  1131 PK11SymKey*
  1132 PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
  1134     PK11SlotInfo* slot = symk->slot;
  1135     CK_ATTRIBUTE template[1];
  1136     CK_ATTRIBUTE *attrs = template;
  1137     CK_BBOOL cktrue = CK_TRUE;
  1138     CK_RV crv;
  1139     CK_OBJECT_HANDLE newKeyID;
  1140     CK_SESSION_HANDLE rwsession;
  1142     PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++;
  1144     PK11_Authenticate(slot, PR_TRUE, wincx);
  1145     rwsession = PK11_GetRWSession(slot);
  1146     if (rwsession == CK_INVALID_SESSION) {
  1147 	PORT_SetError(SEC_ERROR_BAD_DATA);
  1148 	return NULL;
  1150     crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID,
  1151         template, 1, &newKeyID);
  1152     PK11_RestoreROSession(slot, rwsession);
  1154     if (crv != CKR_OK) {
  1155         PORT_SetError( PK11_MapError(crv) );
  1156         return NULL;
  1159     return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin,
  1160         symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
  1163 /*
  1164  * This function does a straight public key wrap (which only RSA can do).
  1165  * Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
  1166  * Diffie-Hellman Ciphers. */
  1167 SECStatus
  1168 PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
  1169 				PK11SymKey *symKey, SECItem *wrappedKey)
  1171     PK11SlotInfo *slot;
  1172     CK_ULONG len =  wrappedKey->len;
  1173     PK11SymKey *newKey = NULL;
  1174     CK_OBJECT_HANDLE id;
  1175     CK_MECHANISM mechanism;
  1176     PRBool owner = PR_TRUE;
  1177     CK_SESSION_HANDLE session;
  1178     CK_RV crv;
  1180     if (symKey == NULL) {
  1181 	PORT_SetError( SEC_ERROR_INVALID_ARGS );
  1182 	return SECFailure;
  1185     /* if this slot doesn't support the mechanism, go to a slot that does */
  1186     newKey = pk11_ForceSlot(symKey,type,CKA_ENCRYPT);
  1187     if (newKey != NULL) {
  1188 	symKey = newKey;
  1191     if (symKey->slot == NULL) {
  1192 	PORT_SetError( SEC_ERROR_NO_MODULE );
  1193 	return SECFailure;
  1196     slot = symKey->slot;
  1197     mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
  1198     mechanism.pParameter = NULL;
  1199     mechanism.ulParameterLen = 0;
  1201     id = PK11_ImportPublicKey(slot,pubKey,PR_FALSE);
  1202     if (id == CK_INVALID_HANDLE) {
  1203 	if (newKey) {
  1204 	    PK11_FreeSymKey(newKey);
  1206 	return SECFailure;   /* Error code has been set. */
  1209     session = pk11_GetNewSession(slot,&owner);
  1210     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
  1211     crv = PK11_GETTAB(slot)->C_WrapKey(session,&mechanism,
  1212 		id,symKey->objectID,wrappedKey->data,&len);
  1213     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
  1214     pk11_CloseSession(slot,session,owner);
  1215     if (newKey) {
  1216 	PK11_FreeSymKey(newKey);
  1219     if (crv != CKR_OK) {
  1220 	PORT_SetError( PK11_MapError(crv) );
  1221 	return SECFailure;
  1223     wrappedKey->len = len;
  1224     return SECSuccess;
  1227 /*
  1228  * this little function uses the Encrypt function to wrap a key, just in
  1229  * case we have problems with the wrap implementation for a token.
  1230  */
  1231 static SECStatus
  1232 pk11_HandWrap(PK11SymKey *wrappingKey, SECItem *param, CK_MECHANISM_TYPE type,
  1233 			 SECItem *inKey, SECItem *outKey)
  1235     PK11SlotInfo *slot;
  1236     CK_ULONG len;
  1237     SECItem *data;
  1238     CK_MECHANISM mech;
  1239     PRBool owner = PR_TRUE;
  1240     CK_SESSION_HANDLE session;
  1241     CK_RV crv;
  1243     slot = wrappingKey->slot;
  1244     /* use NULL IV's for wrapping */
  1245     mech.mechanism = type;
  1246     if (param) {
  1247 	mech.pParameter = param->data;
  1248 	mech.ulParameterLen = param->len;
  1249     } else {
  1250 	mech.pParameter = NULL;
  1251 	mech.ulParameterLen = 0;
  1253     session = pk11_GetNewSession(slot,&owner);
  1254     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
  1255     crv = PK11_GETTAB(slot)->C_EncryptInit(session,&mech,
  1256 							wrappingKey->objectID);
  1257     if (crv != CKR_OK) {
  1258         if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
  1259         pk11_CloseSession(slot,session,owner);
  1260 	PORT_SetError( PK11_MapError(crv) );
  1261 	return SECFailure;
  1264     /* keys are almost always aligned, but if we get this far,
  1265      * we've gone above and beyond anyway... */
  1266     data = PK11_BlockData(inKey,PK11_GetBlockSize(type,param));
  1267     if (data == NULL) {
  1268         if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
  1269         pk11_CloseSession(slot,session,owner);
  1270 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1271 	return SECFailure;
  1273     len = outKey->len;
  1274     crv = PK11_GETTAB(slot)->C_Encrypt(session,data->data,data->len,
  1275 							   outKey->data, &len);
  1276     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
  1277     pk11_CloseSession(slot,session,owner);
  1278     SECITEM_FreeItem(data,PR_TRUE);
  1279     outKey->len = len;
  1280     if (crv != CKR_OK) {
  1281 	PORT_SetError( PK11_MapError(crv) );
  1282 	return SECFailure;
  1284     return SECSuccess;
  1287 /*
  1288  * This function does a symetric based wrap.
  1289  */
  1290 SECStatus
  1291 PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *param, 
  1292 	PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey)
  1294     PK11SlotInfo *slot;
  1295     CK_ULONG len = wrappedKey->len;
  1296     PK11SymKey *newKey = NULL;
  1297     SECItem *param_save = NULL;
  1298     CK_MECHANISM mechanism;
  1299     PRBool owner = PR_TRUE;
  1300     CK_SESSION_HANDLE session;
  1301     CK_RV crv;
  1302     SECStatus rv;
  1304     /* if this slot doesn't support the mechanism, go to a slot that does */
  1305     /* Force symKey and wrappingKey into the same slot */
  1306     if ((wrappingKey->slot == NULL) || (symKey->slot != wrappingKey->slot)) {
  1307 	/* first try copying the wrapping Key to the symKey slot */
  1308 	if (symKey->slot && PK11_DoesMechanism(symKey->slot,type)) {
  1309 	    newKey = pk11_CopyToSlot(symKey->slot,type,CKA_WRAP,wrappingKey);
  1311 	/* Nope, try it the other way */
  1312 	if (newKey == NULL) {
  1313 	    if (wrappingKey->slot) {
  1314 	        newKey = pk11_CopyToSlot(wrappingKey->slot,
  1315 					symKey->type, CKA_ENCRYPT, symKey);
  1317 	    /* just not playing... one last thing, can we get symKey's data?
  1318 	     * If it's possible, we it should already be in the 
  1319 	     * symKey->data.data pointer because pk11_CopyToSlot would have
  1320 	     * tried to put it there. */
  1321 	    if (newKey == NULL) {
  1322 		/* Can't get symKey's data: Game Over */
  1323 		if (symKey->data.data == NULL) {
  1324 		    PORT_SetError( SEC_ERROR_NO_MODULE );
  1325 		    return SECFailure;
  1327 		if (param == NULL) {
  1328 		    param_save = param = PK11_ParamFromIV(type,NULL);
  1330 		rv = pk11_HandWrap(wrappingKey, param, type,
  1331 						&symKey->data,wrappedKey);
  1332 		if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
  1333 		return rv;
  1335 	    /* we successfully moved the sym Key */
  1336 	    symKey = newKey;
  1337 	} else {
  1338 	    /* we successfully moved the wrapping Key */
  1339 	    wrappingKey = newKey;
  1343     /* at this point both keys are in the same token */
  1344     slot = wrappingKey->slot;
  1345     mechanism.mechanism = type;
  1346     /* use NULL IV's for wrapping */
  1347     if (param == NULL) {
  1348     	param_save = param = PK11_ParamFromIV(type,NULL);
  1350     if (param) {
  1351 	mechanism.pParameter = param->data;
  1352 	mechanism.ulParameterLen = param->len;
  1353     } else {
  1354 	mechanism.pParameter = NULL;
  1355 	mechanism.ulParameterLen = 0;
  1358     len = wrappedKey->len;
  1360     session = pk11_GetNewSession(slot,&owner);
  1361     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
  1362     crv = PK11_GETTAB(slot)->C_WrapKey(session, &mechanism,
  1363 		 wrappingKey->objectID, symKey->objectID, 
  1364 						wrappedKey->data, &len);
  1365     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
  1366     pk11_CloseSession(slot,session,owner);
  1367     rv = SECSuccess;
  1368     if (crv != CKR_OK) {
  1369 	/* can't wrap it? try hand wrapping it... */
  1370 	do {
  1371 	    if (symKey->data.data == NULL) {
  1372 		rv = PK11_ExtractKeyValue(symKey);
  1373 		if (rv != SECSuccess) break;
  1375 	    rv = pk11_HandWrap(wrappingKey, param, type, &symKey->data,
  1376 								 wrappedKey);
  1377 	} while (PR_FALSE);
  1378     } else {
  1379         wrappedKey->len = len;
  1381     if (newKey) PK11_FreeSymKey(newKey);
  1382     if (param_save) SECITEM_FreeItem(param_save,PR_TRUE);
  1383     return rv;
  1386 /*
  1387  * This Generates a new key based on a symetricKey
  1388  */
  1389 PK11SymKey *
  1390 PK11_Derive( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param, 
  1391              CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
  1392 	     int keySize)
  1394     return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
  1395 				   keySize, NULL, 0, PR_FALSE);
  1399 PK11SymKey *
  1400 PK11_DeriveWithFlags( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
  1401 	SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
  1402 	int keySize, CK_FLAGS flags)
  1404     CK_BBOOL        ckTrue	= CK_TRUE; 
  1405     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
  1406     unsigned int    templateCount;
  1408     templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
  1409     return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
  1410 		  keySize, keyTemplate, templateCount, PR_FALSE);
  1413 PK11SymKey *
  1414 PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
  1415 	SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
  1416 	int keySize, CK_FLAGS flags, PRBool isPerm)
  1418     CK_BBOOL        cktrue	= CK_TRUE; 
  1419     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
  1420     CK_ATTRIBUTE    *attrs;
  1421     unsigned int    templateCount = 0;
  1423     attrs = keyTemplate;
  1424     if (isPerm) {
  1425         PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
  1427     templateCount = attrs - keyTemplate;
  1428     templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
  1429     return PK11_DeriveWithTemplate(baseKey, derive, param, target, operation, 
  1430 				   keySize, keyTemplate, templateCount, isPerm);
  1433 PK11SymKey *
  1434 PK11_DeriveWithTemplate( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, 
  1435 	SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
  1436 	int keySize, CK_ATTRIBUTE *userAttr, unsigned int numAttrs,
  1437 							 PRBool isPerm)
  1439     PK11SlotInfo *  slot	= baseKey->slot;
  1440     PK11SymKey *    symKey;
  1441     PK11SymKey *    newBaseKey	= NULL;
  1442     CK_BBOOL        cktrue	= CK_TRUE; 
  1443     CK_OBJECT_CLASS keyClass	= CKO_SECRET_KEY;
  1444     CK_KEY_TYPE     keyType	= CKK_GENERIC_SECRET;
  1445     CK_ULONG        valueLen	= 0;
  1446     CK_MECHANISM    mechanism; 
  1447     CK_RV           crv;
  1448 #define MAX_ADD_ATTRS 4
  1449     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
  1450 #undef MAX_ADD_ATTRS
  1451     CK_ATTRIBUTE *  attrs	= keyTemplate;
  1452     CK_SESSION_HANDLE session;
  1453     unsigned int    templateCount;
  1455     if (numAttrs > MAX_TEMPL_ATTRS) {
  1456     	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1457 	return NULL;
  1460     /* first copy caller attributes in. */
  1461     for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
  1462     	*attrs++ = *userAttr++;
  1465     /* We only add the following attributes to the template if the caller
  1466     ** didn't already supply them.
  1467     */
  1468     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
  1469 	PK11_SETATTRS(attrs, CKA_CLASS,     &keyClass, sizeof keyClass); 
  1470 	attrs++;
  1472     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
  1473 	keyType = PK11_GetKeyType(target, keySize);
  1474 	PK11_SETATTRS(attrs, CKA_KEY_TYPE,  &keyType,  sizeof keyType ); 
  1475 	attrs++;
  1477     if (keySize > 0 &&
  1478     	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
  1479 	valueLen = (CK_ULONG)keySize;
  1480 	PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen); 
  1481 	attrs++;
  1483     if ((operation != CKA_FLAGS_ONLY) &&
  1484 	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
  1485 	PK11_SETATTRS(attrs, operation, &cktrue, sizeof cktrue); attrs++;
  1488     templateCount = attrs - keyTemplate;
  1489     PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
  1491     /* move the key to a slot that can do the function */
  1492     if (!PK11_DoesMechanism(slot,derive)) {
  1493 	/* get a new base key & slot */
  1494 	PK11SlotInfo *newSlot = PK11_GetBestSlot(derive, baseKey->cx);
  1496 	if (newSlot == NULL) return NULL;
  1498         newBaseKey = pk11_CopyToSlot (newSlot, derive, CKA_DERIVE, 
  1499 				     baseKey);
  1500 	PK11_FreeSlot(newSlot);
  1501 	if (newBaseKey == NULL) 
  1502 	    return NULL;	
  1503 	baseKey = newBaseKey;
  1504 	slot = baseKey->slot;
  1508     /* get our key Structure */
  1509     symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, baseKey->cx);
  1510     if (symKey == NULL) {
  1511 	return NULL;
  1514     symKey->size = keySize;
  1516     mechanism.mechanism = derive;
  1517     if (param) {
  1518 	mechanism.pParameter = param->data;
  1519 	mechanism.ulParameterLen = param->len;
  1520     } else {
  1521 	mechanism.pParameter = NULL;
  1522 	mechanism.ulParameterLen = 0;
  1524     symKey->origin=PK11_OriginDerive;
  1526     if (isPerm) {
  1527 	session =  PK11_GetRWSession(slot);
  1528     } else {
  1529         pk11_EnterKeyMonitor(symKey);
  1530 	session = symKey->session;
  1532     if (session == CK_INVALID_SESSION) {
  1533 	if (!isPerm)
  1534 	    pk11_ExitKeyMonitor(symKey);
  1535 	crv = CKR_SESSION_HANDLE_INVALID;
  1536     } else {
  1537 	crv = PK11_GETTAB(slot)->C_DeriveKey(session, &mechanism,
  1538 	     baseKey->objectID, keyTemplate, templateCount, &symKey->objectID);
  1539 	if (isPerm) {
  1540 	    PK11_RestoreROSession(slot, session);
  1541 	} else {
  1542 	    pk11_ExitKeyMonitor(symKey);
  1545     if (newBaseKey) 
  1546     	PK11_FreeSymKey(newBaseKey);
  1547     if (crv != CKR_OK) {
  1548 	PK11_FreeSymKey(symKey);
  1549 	return NULL;
  1551     return symKey;
  1554 /* Create a new key by concatenating base and data
  1555  */
  1556 static PK11SymKey *pk11_ConcatenateBaseAndData(PK11SymKey *base,
  1557 	CK_BYTE *data, CK_ULONG dataLen, CK_MECHANISM_TYPE target,
  1558 	CK_ATTRIBUTE_TYPE operation)
  1560     CK_KEY_DERIVATION_STRING_DATA mechParams;
  1561     SECItem param;
  1563     if (base == NULL) {
  1564 	PORT_SetError( SEC_ERROR_INVALID_ARGS );
  1565 	return NULL;
  1568     mechParams.pData = data;
  1569     mechParams.ulLen = dataLen;
  1570     param.data = (unsigned char *)&mechParams;
  1571     param.len = sizeof(CK_KEY_DERIVATION_STRING_DATA);
  1573     return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_DATA,
  1574 				&param, target, operation, 0);
  1577 /* Create a new key by concatenating base and key
  1578  */
  1579 static PK11SymKey *pk11_ConcatenateBaseAndKey(PK11SymKey *base,
  1580 			PK11SymKey *key, CK_MECHANISM_TYPE target,
  1581 			CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
  1583     SECItem param;
  1585     if ((base == NULL) || (key == NULL)) {
  1586 	PORT_SetError( SEC_ERROR_INVALID_ARGS );
  1587 	return NULL;
  1590     param.data = (unsigned char *)&(key->objectID);
  1591     param.len = sizeof(CK_OBJECT_HANDLE);
  1593     return PK11_Derive(base, CKM_CONCATENATE_BASE_AND_KEY,
  1594 				&param, target, operation, keySize);
  1597 /* Create a new key whose value is the hash of tobehashed.
  1598  * type is the mechanism for the derived key.
  1599  */
  1600 static PK11SymKey *pk11_HashKeyDerivation(PK11SymKey *toBeHashed,
  1601 	CK_MECHANISM_TYPE hashMechanism, CK_MECHANISM_TYPE target,
  1602 	CK_ATTRIBUTE_TYPE operation, CK_ULONG keySize)
  1604     return PK11_Derive(toBeHashed, hashMechanism, NULL, target, operation, keySize);
  1607 /* This function implements the ANSI X9.63 key derivation function
  1608  */
  1609 static PK11SymKey *pk11_ANSIX963Derive(PK11SymKey *sharedSecret,
  1610 		CK_EC_KDF_TYPE kdf, SECItem *sharedData,
  1611 		CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
  1612 		CK_ULONG keySize)
  1614     CK_KEY_TYPE keyType;
  1615     CK_MECHANISM_TYPE hashMechanism, mechanismArray[4];
  1616     CK_ULONG derivedKeySize, HashLen, counter, maxCounter, bufferLen;
  1617     CK_ULONG SharedInfoLen;
  1618     CK_BYTE *buffer = NULL;
  1619     PK11SymKey *toBeHashed, *hashOutput;
  1620     PK11SymKey *newSharedSecret = NULL;
  1621     PK11SymKey *oldIntermediateResult, *intermediateResult = NULL;
  1623     if (sharedSecret == NULL) {
  1624 	PORT_SetError( SEC_ERROR_INVALID_ARGS );
  1625 	return NULL;
  1628     switch (kdf) {
  1629     case CKD_SHA1_KDF:
  1630 	HashLen = SHA1_LENGTH;
  1631 	hashMechanism = CKM_SHA1_KEY_DERIVATION;
  1632 	break;
  1633     case CKD_SHA224_KDF:
  1634 	HashLen = SHA224_LENGTH;
  1635 	hashMechanism = CKM_SHA224_KEY_DERIVATION;
  1636 	break;
  1637     case CKD_SHA256_KDF:
  1638 	HashLen = SHA256_LENGTH;
  1639 	hashMechanism = CKM_SHA256_KEY_DERIVATION;
  1640 	break;
  1641     case CKD_SHA384_KDF:
  1642 	HashLen = SHA384_LENGTH;
  1643 	hashMechanism = CKM_SHA384_KEY_DERIVATION;
  1644 	break;
  1645     case CKD_SHA512_KDF:
  1646 	HashLen = SHA512_LENGTH;
  1647 	hashMechanism = CKM_SHA512_KEY_DERIVATION;
  1648 	break;
  1649     default:
  1650 	PORT_SetError( SEC_ERROR_INVALID_ARGS );
  1651 	return NULL;
  1654     derivedKeySize = keySize;
  1655     if (derivedKeySize == 0) {
  1656 	keyType = PK11_GetKeyType(target,keySize);
  1657 	derivedKeySize = pk11_GetPredefinedKeyLength(keyType);
  1658 	if (derivedKeySize == 0) {
  1659 	    derivedKeySize = HashLen;
  1663     /* Check that key_len isn't too long.  The maximum key length could be
  1664      * greatly increased if the code below did not limit the 4-byte counter
  1665      * to a maximum value of 255. */
  1666     if (derivedKeySize > 254 * HashLen) {
  1667 	PORT_SetError( SEC_ERROR_INVALID_ARGS );
  1668 	return NULL;
  1671     maxCounter = derivedKeySize / HashLen;
  1672     if (derivedKeySize > maxCounter * HashLen)
  1673 	maxCounter++;
  1675     if ((sharedData == NULL) || (sharedData->data == NULL))
  1676 	SharedInfoLen = 0;
  1677     else
  1678 	SharedInfoLen = sharedData->len;
  1680     bufferLen = SharedInfoLen + 4;
  1682     /* Populate buffer with Counter || sharedData
  1683      * where Counter is 0x00000001. */
  1684     buffer = (unsigned char *)PORT_Alloc(bufferLen);
  1685     if (buffer == NULL) {
  1686 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1687 	return NULL;
  1690     buffer[0] = 0;
  1691     buffer[1] = 0;
  1692     buffer[2] = 0;
  1693     buffer[3] = 1;
  1694     if (SharedInfoLen > 0) {
  1695 	PORT_Memcpy(&buffer[4], sharedData->data, SharedInfoLen);
  1698     /* Look for a slot that supports the mechanisms needed
  1699      * to implement the ANSI X9.63 KDF as well as the
  1700      * target mechanism.
  1701      */
  1702     mechanismArray[0] = CKM_CONCATENATE_BASE_AND_DATA;
  1703     mechanismArray[1] = hashMechanism;
  1704     mechanismArray[2] = CKM_CONCATENATE_BASE_AND_KEY;
  1705     mechanismArray[3] = target;
  1707     newSharedSecret = pk11_ForceSlotMultiple(sharedSecret,
  1708 					 mechanismArray, 4, operation);
  1709     if (newSharedSecret != NULL) {
  1710 	sharedSecret = newSharedSecret;
  1713     for(counter=1; counter <= maxCounter; counter++) {
  1714 	/* Concatenate shared_secret and buffer */
  1715 	toBeHashed = pk11_ConcatenateBaseAndData(sharedSecret, buffer,
  1716 					bufferLen, hashMechanism, operation);
  1717 	if (toBeHashed == NULL) {
  1718 	    goto loser;
  1721 	/* Hash value */
  1722 	if (maxCounter == 1) {
  1723 	    /* In this case the length of the key to be derived is
  1724 	     * less than or equal to the length of the hash output.
  1725 	     * So, the output of the hash operation will be the
  1726 	     * dervied key. */
  1727 	    hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
  1728 						target, operation, keySize);
  1729 	} else {
  1730 	    /* In this case, the output of the hash operation will be
  1731 	     * concatenated with other data to create the derived key. */
  1732 	    hashOutput = pk11_HashKeyDerivation(toBeHashed, hashMechanism,
  1733 				CKM_CONCATENATE_BASE_AND_KEY, operation, 0);
  1735 	PK11_FreeSymKey(toBeHashed);
  1736 	if (hashOutput == NULL) {
  1737 	    goto loser;
  1740 	/* Append result to intermediate result, if necessary */
  1741 	oldIntermediateResult = intermediateResult;
  1743 	if (oldIntermediateResult == NULL) {
  1744 	    intermediateResult = hashOutput;
  1745 	} else {
  1746 	    if (counter == maxCounter) {
  1747 		/* This is the final concatenation, and so the output
  1748 		 * will be the derived key. */
  1749 		intermediateResult =
  1750 		    pk11_ConcatenateBaseAndKey(oldIntermediateResult,
  1751 				hashOutput, target, operation, keySize);
  1752 	    } else {
  1753 		/* The output of this concatenation will be concatenated
  1754 		 * with other data to create the derived key. */
  1755 		intermediateResult =
  1756 		    pk11_ConcatenateBaseAndKey(oldIntermediateResult,
  1757 				hashOutput, CKM_CONCATENATE_BASE_AND_KEY,
  1758 				operation, 0);
  1761 	    PK11_FreeSymKey(hashOutput);
  1762 	    PK11_FreeSymKey(oldIntermediateResult);
  1763 	    if (intermediateResult == NULL) {
  1764 		goto loser;
  1768 	/* Increment counter (assumes maxCounter < 255) */
  1769 	buffer[3]++;
  1772     PORT_ZFree(buffer, bufferLen);
  1773     if (newSharedSecret != NULL)
  1774 	PK11_FreeSymKey(newSharedSecret);
  1775     return intermediateResult;
  1777 loser:
  1778     if (buffer != NULL)
  1779 	PORT_ZFree(buffer, bufferLen);
  1780     if (newSharedSecret != NULL)
  1781 	PK11_FreeSymKey(newSharedSecret);
  1782     if (intermediateResult != NULL)
  1783 	PK11_FreeSymKey(intermediateResult);
  1784     return NULL;
  1787 /*
  1788  * This Generates a wrapping key based on a privateKey, publicKey, and two
  1789  * random numbers. For Mail usage RandomB should be NULL. In the Sender's
  1790  * case RandomA is generate, outherwize it is passed.
  1791  */
  1792 static unsigned char *rb_email = NULL;
  1794 PK11SymKey *
  1795 PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 
  1796    PRBool isSender, SECItem *randomA, SECItem *randomB, 
  1797     CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
  1798 			CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx)
  1800     PK11SlotInfo *slot = privKey->pkcs11Slot;
  1801     CK_MECHANISM mechanism;
  1802     PK11SymKey *symKey;
  1803     CK_RV crv;
  1806     if (rb_email == NULL) {
  1807 	rb_email = PORT_ZAlloc(128);
  1808 	if (rb_email == NULL) {
  1809 	    return NULL;
  1811 	rb_email[127] = 1;
  1814     /* get our key Structure */
  1815     symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
  1816     if (symKey == NULL) {
  1817 	return NULL;
  1820     symKey->origin = PK11_OriginDerive;
  1822     switch (privKey->keyType) {
  1823     case rsaKey:
  1824     case nullKey:
  1825 	PORT_SetError(SEC_ERROR_BAD_KEY);
  1826 	break;
  1827     case dsaKey:
  1828     case keaKey:
  1829     case fortezzaKey:
  1831 	    CK_KEA_DERIVE_PARAMS param;
  1832 	    param.isSender = (CK_BBOOL) isSender;
  1833 	    param.ulRandomLen = randomA->len;
  1834 	    param.pRandomA = randomA->data;
  1835 	    param.pRandomB = rb_email;
  1836 	    if (randomB)
  1837 		 param.pRandomB = randomB->data;
  1838 	    if (pubKey->keyType == fortezzaKey) {
  1839 		param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
  1840 		param.pPublicData = pubKey->u.fortezza.KEAKey.data;
  1841 	    } else {
  1842 		/* assert type == keaKey */
  1843 		/* XXX change to match key key types */
  1844 		param.ulPublicDataLen = pubKey->u.fortezza.KEAKey.len;
  1845 		param.pPublicData = pubKey->u.fortezza.KEAKey.data;
  1848 	    mechanism.mechanism = derive;
  1849 	    mechanism.pParameter = &param;
  1850 	    mechanism.ulParameterLen = sizeof(param);
  1852 	    /* get a new symKey structure */
  1853 	    pk11_EnterKeyMonitor(symKey);
  1854 	    crv=PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
  1855 			privKey->pkcs11ID, NULL, 0, &symKey->objectID);
  1856 	    pk11_ExitKeyMonitor(symKey);
  1857 	    if (crv == CKR_OK) return symKey;
  1858 	    PORT_SetError( PK11_MapError(crv) );
  1860 	break;
  1861     case dhKey:
  1863 	    CK_BBOOL cktrue = CK_TRUE;
  1864 	    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
  1865 	    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
  1866 	    CK_ULONG key_size = 0;
  1867 	    CK_ATTRIBUTE keyTemplate[4];
  1868 	    int templateCount;
  1869 	    CK_ATTRIBUTE *attrs = keyTemplate;
  1871 	    if (pubKey->keyType != dhKey) {
  1872 		PORT_SetError(SEC_ERROR_BAD_KEY);
  1873 		break;
  1876 	    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
  1877 	    attrs++;
  1878 	    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
  1879 	    attrs++;
  1880 	    PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
  1881 	    PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); 
  1882 	    attrs++;
  1883 	    templateCount =  attrs - keyTemplate;
  1884 	    PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
  1886 	    keyType = PK11_GetKeyType(target,keySize);
  1887 	    key_size = keySize;
  1888 	    symKey->size = keySize;
  1889 	    if (key_size == 0) templateCount--;
  1891 	    mechanism.mechanism = derive;
  1893 	    /* we can undefine these when we define diffie-helman keys */
  1895 	    mechanism.pParameter = pubKey->u.dh.publicValue.data; 
  1896 	    mechanism.ulParameterLen = pubKey->u.dh.publicValue.len;
  1898 	    pk11_EnterKeyMonitor(symKey);
  1899 	    crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
  1900 	     privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
  1901 	    pk11_ExitKeyMonitor(symKey);
  1902 	    if (crv == CKR_OK) return symKey;
  1903 	    PORT_SetError( PK11_MapError(crv) );
  1905 	break;
  1906     case ecKey:
  1908 	    CK_BBOOL cktrue = CK_TRUE;
  1909 	    CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
  1910 	    CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
  1911 	    CK_ULONG key_size = 0;
  1912 	    CK_ATTRIBUTE keyTemplate[4];
  1913 	    int templateCount;
  1914 	    CK_ATTRIBUTE *attrs = keyTemplate;
  1915 	    CK_ECDH1_DERIVE_PARAMS *mechParams = NULL;
  1917 	    if (pubKey->keyType != ecKey) {
  1918 		PORT_SetError(SEC_ERROR_BAD_KEY);
  1919 		break;
  1922 	    PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
  1923 	    attrs++;
  1924 	    PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
  1925 	    attrs++;
  1926 	    PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
  1927 	    PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); 
  1928 	    attrs++;
  1929 	    templateCount =  attrs - keyTemplate;
  1930 	    PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
  1932 	    keyType = PK11_GetKeyType(target,keySize);
  1933 	    key_size = keySize;
  1934 	    if (key_size == 0) {
  1935 		if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
  1936 		    templateCount --;
  1937 		} else {
  1938 		    /* sigh, some tokens can't figure this out and require
  1939 		     * CKA_VALUE_LEN to be set */
  1940 		    key_size = SHA1_LENGTH;
  1943 	    symKey->size = key_size;
  1945 	    mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS); 
  1946 	    mechParams->kdf = CKD_SHA1_KDF;
  1947 	    mechParams->ulSharedDataLen = 0;
  1948 	    mechParams->pSharedData = NULL;
  1949 	    mechParams->ulPublicDataLen =  pubKey->u.ec.publicValue.len;
  1950 	    mechParams->pPublicData =  pubKey->u.ec.publicValue.data;
  1952 	    mechanism.mechanism = derive;
  1953 	    mechanism.pParameter = mechParams;
  1954 	    mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
  1956 	    pk11_EnterKeyMonitor(symKey);
  1957 	    crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, 
  1958 		&mechanism, privKey->pkcs11ID, keyTemplate, 
  1959 		templateCount, &symKey->objectID);
  1960 	    pk11_ExitKeyMonitor(symKey);
  1962 	    /* old PKCS #11 spec was ambiguous on what needed to be passed,
  1963 	     * try this again with and encoded public key */
  1964 	    if (crv != CKR_OK) {
  1965 		SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
  1966 			&pubKey->u.ec.publicValue,
  1967 			SEC_ASN1_GET(SEC_OctetStringTemplate));
  1968 		if (pubValue == NULL) {
  1969 	    	    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
  1970 		    break;
  1972 		mechParams->ulPublicDataLen =  pubValue->len;
  1973 		mechParams->pPublicData =  pubValue->data;
  1975 		pk11_EnterKeyMonitor(symKey);
  1976 		crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, 
  1977 		    &mechanism, privKey->pkcs11ID, keyTemplate, 
  1978 		    templateCount, &symKey->objectID);
  1979 		pk11_ExitKeyMonitor(symKey);
  1981 		SECITEM_FreeItem(pubValue,PR_TRUE);
  1984 	    PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
  1986 	    if (crv == CKR_OK) return symKey;
  1987 	    PORT_SetError( PK11_MapError(crv) );
  1991    PK11_FreeSymKey(symKey);
  1992    return NULL;
  1995 /* Returns the size of the public key, or 0 if there
  1996  * is an error. */
  1997 static CK_ULONG
  1998 pk11_ECPubKeySize(SECItem *publicValue)
  2000     if (publicValue->data[0] == 0x04) {
  2001 	/* key encoded in uncompressed form */
  2002 	return((publicValue->len - 1)/2);
  2003     } else if ( (publicValue->data[0] == 0x02) ||
  2004 		(publicValue->data[0] == 0x03)) {
  2005 	/* key encoded in compressed form */
  2006 	return(publicValue->len - 1);
  2008     /* key encoding not recognized */
  2009     return(0);
  2012 static PK11SymKey *
  2013 pk11_PubDeriveECKeyWithKDF(
  2014 		    SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
  2015 		    PRBool isSender, SECItem *randomA, SECItem *randomB,
  2016 		    CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
  2017 		    CK_ATTRIBUTE_TYPE operation, int keySize,
  2018 		    CK_ULONG kdf, SECItem *sharedData, void *wincx)
  2020     PK11SlotInfo           *slot            = privKey->pkcs11Slot;
  2021     PK11SymKey             *symKey;
  2022     PK11SymKey             *SharedSecret;
  2023     CK_MECHANISM            mechanism;
  2024     CK_RV                   crv;
  2025     CK_BBOOL                cktrue          = CK_TRUE;
  2026     CK_OBJECT_CLASS         keyClass        = CKO_SECRET_KEY;
  2027     CK_KEY_TYPE             keyType         = CKK_GENERIC_SECRET;
  2028     CK_ULONG                key_size        = 0;
  2029     CK_ATTRIBUTE            keyTemplate[4];
  2030     int                     templateCount;
  2031     CK_ATTRIBUTE           *attrs           = keyTemplate;
  2032     CK_ECDH1_DERIVE_PARAMS *mechParams      = NULL;
  2034     if (pubKey->keyType != ecKey) {
  2035 	PORT_SetError(SEC_ERROR_BAD_KEY);
  2036 	return NULL;
  2038     if ((kdf != CKD_NULL) && (kdf != CKD_SHA1_KDF) &&
  2039 	(kdf != CKD_SHA224_KDF) && (kdf != CKD_SHA256_KDF) &&
  2040 	(kdf != CKD_SHA384_KDF) && (kdf != CKD_SHA512_KDF)) {
  2041 	PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  2042 	return NULL;
  2045     /* get our key Structure */
  2046     symKey = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, wincx);
  2047     if (symKey == NULL) {
  2048 	return NULL;
  2051     symKey->origin = PK11_OriginDerive;
  2053     PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));     attrs++;
  2054     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));    attrs++;
  2055     PK11_SETATTRS(attrs, operation, &cktrue, 1);                      attrs++;
  2056     PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); attrs++;
  2057     templateCount =  attrs - keyTemplate;
  2058     PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
  2060     keyType = PK11_GetKeyType(target,keySize);
  2061     key_size = keySize;
  2062     if (key_size == 0) {
  2063 	if ((key_size = pk11_GetPredefinedKeyLength(keyType))) {
  2064 	    templateCount --;
  2065 	} else {
  2066 	    /* sigh, some tokens can't figure this out and require
  2067 	     * CKA_VALUE_LEN to be set */
  2068 	    switch (kdf) {
  2069 	    case CKD_NULL:
  2070 		key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
  2071 		if (key_size == 0) {
  2072 		    PK11_FreeSymKey(symKey);
  2073 		    return NULL;
  2075 		break;
  2076 	    case CKD_SHA1_KDF:
  2077 		key_size = SHA1_LENGTH;
  2078 		break;
  2079 	    case CKD_SHA224_KDF:
  2080 		key_size = SHA224_LENGTH;
  2081 		break;
  2082 	    case CKD_SHA256_KDF:
  2083 		key_size = SHA256_LENGTH;
  2084 		break;
  2085 	    case CKD_SHA384_KDF:
  2086 		key_size = SHA384_LENGTH;
  2087 		break;
  2088 	    case CKD_SHA512_KDF:
  2089 		key_size = SHA512_LENGTH;
  2090 		break;
  2091 	    default:
  2092 		PORT_Assert(!"Invalid CKD");
  2093 		PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  2094 		return NULL;
  2098     symKey->size = key_size;
  2100     mechParams = PORT_ZNew(CK_ECDH1_DERIVE_PARAMS);
  2101     if (!mechParams) {
  2102 	PK11_FreeSymKey(symKey);
  2103 	return NULL;
  2105     mechParams->kdf = kdf;
  2106     if (sharedData == NULL) {
  2107 	mechParams->ulSharedDataLen = 0;
  2108 	mechParams->pSharedData     = NULL;
  2109     } else {
  2110 	mechParams->ulSharedDataLen = sharedData->len;
  2111 	mechParams->pSharedData     = sharedData->data;
  2113     mechParams->ulPublicDataLen =  pubKey->u.ec.publicValue.len;
  2114     mechParams->pPublicData =  pubKey->u.ec.publicValue.data;
  2116     mechanism.mechanism      = derive;
  2117     mechanism.pParameter     = mechParams;
  2118     mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
  2120     pk11_EnterKeyMonitor(symKey);
  2121     crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism, 
  2122     	privKey->pkcs11ID, keyTemplate, templateCount, &symKey->objectID);
  2123     pk11_ExitKeyMonitor(symKey);
  2125     /* old PKCS #11 spec was ambiguous on what needed to be passed,
  2126      * try this again with an encoded public key */
  2127     if (crv != CKR_OK) {
  2128 	SECItem *pubValue = SEC_ASN1EncodeItem(NULL, NULL,
  2129 		&pubKey->u.ec.publicValue,
  2130 		SEC_ASN1_GET(SEC_OctetStringTemplate));
  2131 	if (pubValue == NULL) {
  2132 	    goto loser;
  2134 	mechParams->ulPublicDataLen =  pubValue->len;
  2135 	mechParams->pPublicData =  pubValue->data;
  2137 	pk11_EnterKeyMonitor(symKey);
  2138 	crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, 
  2139 	    &mechanism, privKey->pkcs11ID, keyTemplate, 
  2140 	    templateCount, &symKey->objectID);
  2141 	pk11_ExitKeyMonitor(symKey);
  2143 	if ((crv != CKR_OK) && (kdf != CKD_NULL)) {
  2144 	    /* Some PKCS #11 libraries cannot perform the key derivation
  2145 	     * function. So, try calling C_DeriveKey with CKD_NULL and then
  2146 	     * performing the KDF separately.
  2147 	     */
  2148 	    CK_ULONG derivedKeySize = key_size;
  2150 	    keyType = CKK_GENERIC_SECRET;
  2151 	    key_size = pk11_ECPubKeySize(&pubKey->u.ec.publicValue);
  2152 	    if (key_size == 0) {
  2153 		SECITEM_FreeItem(pubValue,PR_TRUE);
  2154 		goto loser;
  2156 	    SharedSecret = symKey;
  2157 	    SharedSecret->size = key_size;
  2159 	    mechParams->kdf             = CKD_NULL;
  2160 	    mechParams->ulSharedDataLen = 0;
  2161 	    mechParams->pSharedData     = NULL;
  2162 	    mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len;
  2163 	    mechParams->pPublicData     = pubKey->u.ec.publicValue.data;
  2165 	    pk11_EnterKeyMonitor(SharedSecret);
  2166 	    crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
  2167 			    &mechanism, privKey->pkcs11ID, keyTemplate,
  2168 			    templateCount, &SharedSecret->objectID);
  2169 	    pk11_ExitKeyMonitor(SharedSecret);
  2171 	    if (crv != CKR_OK) {
  2172 		/* old PKCS #11 spec was ambiguous on what needed to be passed,
  2173 		 * try this one final time with an encoded public key */
  2174 		mechParams->ulPublicDataLen =  pubValue->len;
  2175 		mechParams->pPublicData     =  pubValue->data;
  2177 		pk11_EnterKeyMonitor(SharedSecret);
  2178 		crv = PK11_GETTAB(slot)->C_DeriveKey(SharedSecret->session,
  2179 				&mechanism, privKey->pkcs11ID, keyTemplate,
  2180 				templateCount, &SharedSecret->objectID);
  2181 		pk11_ExitKeyMonitor(SharedSecret);
  2184 	    /* Perform KDF. */
  2185 	    if (crv == CKR_OK) {
  2186 		    symKey = pk11_ANSIX963Derive(SharedSecret, kdf,
  2187 					sharedData, target, operation,
  2188 					derivedKeySize);
  2189 		    PK11_FreeSymKey(SharedSecret);
  2190 		    if (symKey == NULL) {
  2191 			SECITEM_FreeItem(pubValue,PR_TRUE);
  2192 			PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
  2193 			return NULL;
  2197 	SECITEM_FreeItem(pubValue,PR_TRUE);
  2200 loser:
  2201     PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS));
  2203     if (crv != CKR_OK) {
  2204 	PK11_FreeSymKey(symKey);
  2205 	symKey = NULL;
  2206 	PORT_SetError( PK11_MapError(crv) );
  2208     return symKey;
  2211 PK11SymKey *
  2212 PK11_PubDeriveWithKDF(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, 
  2213 		      PRBool isSender, SECItem *randomA, SECItem *randomB, 
  2214 		      CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target,
  2215 		      CK_ATTRIBUTE_TYPE operation, int keySize,
  2216 		      CK_ULONG kdf, SECItem *sharedData, void *wincx)
  2219     switch (privKey->keyType) {
  2220     case rsaKey:
  2221     case nullKey:
  2222     case dsaKey:
  2223     case keaKey:
  2224     case fortezzaKey:
  2225     case dhKey:
  2226 	return PK11_PubDerive(privKey, pubKey, isSender, randomA, randomB,
  2227 		derive, target, operation, keySize, wincx);
  2228     case ecKey:
  2229 	return pk11_PubDeriveECKeyWithKDF( privKey, pubKey, isSender, 
  2230 		randomA, randomB, derive, target, operation, keySize, 
  2231 		kdf, sharedData, wincx);
  2232     default:
  2233         PORT_SetError(SEC_ERROR_BAD_KEY);
  2234         break;
  2237     return NULL;
  2240 /*
  2241  * this little function uses the Decrypt function to unwrap a key, just in
  2242  * case we are having problem with unwrap. NOTE: The key size may
  2243  * not be preserved properly for some algorithms!
  2244  */
  2245 static PK11SymKey *
  2246 pk11_HandUnwrap(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
  2247                 CK_MECHANISM *mech, SECItem *inKey, CK_MECHANISM_TYPE target, 
  2248 		CK_ATTRIBUTE *keyTemplate, unsigned int templateCount, 
  2249 		int key_size, void * wincx, CK_RV *crvp, PRBool isPerm)
  2251     CK_ULONG len;
  2252     SECItem outKey;
  2253     PK11SymKey *symKey;
  2254     CK_RV crv;
  2255     PRBool owner = PR_TRUE;
  2256     CK_SESSION_HANDLE session;
  2258     /* remove any VALUE_LEN parameters */
  2259     if (keyTemplate[templateCount-1].type == CKA_VALUE_LEN) {
  2260         templateCount--;
  2263     /* keys are almost always aligned, but if we get this far,
  2264      * we've gone above and beyond anyway... */
  2265     outKey.data = (unsigned char*)PORT_Alloc(inKey->len);
  2266     if (outKey.data == NULL) {
  2267 	PORT_SetError( SEC_ERROR_NO_MEMORY );
  2268 	if (crvp) *crvp = CKR_HOST_MEMORY;
  2269 	return NULL;
  2271     len = inKey->len;
  2273     /* use NULL IV's for wrapping */
  2274     session = pk11_GetNewSession(slot,&owner);
  2275     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
  2276     crv = PK11_GETTAB(slot)->C_DecryptInit(session,mech,wrappingKey);
  2277     if (crv != CKR_OK) {
  2278 	if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
  2279 	pk11_CloseSession(slot,session,owner);
  2280 	PORT_Free(outKey.data);
  2281 	PORT_SetError( PK11_MapError(crv) );
  2282 	if (crvp) *crvp =crv;
  2283 	return NULL;
  2285     crv = PK11_GETTAB(slot)->C_Decrypt(session,inKey->data,inKey->len,
  2286 							   outKey.data, &len);
  2287     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
  2288     pk11_CloseSession(slot,session,owner);
  2289     if (crv != CKR_OK) {
  2290 	PORT_Free(outKey.data);
  2291 	PORT_SetError( PK11_MapError(crv) );
  2292 	if (crvp) *crvp =crv;
  2293 	return NULL;
  2296     outKey.len = (key_size == 0) ? len : key_size;
  2297     outKey.type = siBuffer;
  2299     if (PK11_DoesMechanism(slot,target)) {
  2300 	symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap, 
  2301 	                                    isPerm, keyTemplate, 
  2302 					    templateCount, &outKey, wincx);
  2303     } else {
  2304 	slot = PK11_GetBestSlot(target,wincx);
  2305 	if (slot == NULL) {
  2306 	    PORT_SetError( SEC_ERROR_NO_MODULE );
  2307 	    PORT_Free(outKey.data);
  2308 	    if (crvp) *crvp = CKR_DEVICE_ERROR; 
  2309 	    return NULL;
  2311 	symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap, 
  2312 	                                    isPerm, keyTemplate,
  2313 					    templateCount, &outKey, wincx);
  2314 	PK11_FreeSlot(slot);
  2316     PORT_Free(outKey.data);
  2318     if (crvp) *crvp = symKey? CKR_OK : CKR_DEVICE_ERROR; 
  2319     return symKey;
  2322 /*
  2323  * The wrap/unwrap function is pretty much the same for private and
  2324  * public keys. It's just getting the Object ID and slot right. This is
  2325  * the combined unwrap function.
  2326  */
  2327 static PK11SymKey *
  2328 pk11_AnyUnwrapKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE wrappingKey,
  2329     CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey, 
  2330     CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize, 
  2331     void *wincx, CK_ATTRIBUTE *userAttr, unsigned int numAttrs, PRBool isPerm)
  2333     PK11SymKey *    symKey;
  2334     SECItem *       param_free	= NULL;
  2335     CK_BBOOL        cktrue	= CK_TRUE; 
  2336     CK_OBJECT_CLASS keyClass	= CKO_SECRET_KEY;
  2337     CK_KEY_TYPE     keyType	= CKK_GENERIC_SECRET;
  2338     CK_ULONG        valueLen	= 0;
  2339     CK_MECHANISM    mechanism;
  2340     CK_SESSION_HANDLE rwsession;
  2341     CK_RV           crv;
  2342     CK_MECHANISM_INFO mechanism_info;
  2343 #define MAX_ADD_ATTRS 4
  2344     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS + MAX_ADD_ATTRS];
  2345 #undef MAX_ADD_ATTRS
  2346     CK_ATTRIBUTE *  attrs	= keyTemplate;
  2347     unsigned int    templateCount;
  2349     if (numAttrs > MAX_TEMPL_ATTRS) {
  2350     	PORT_SetError(SEC_ERROR_INVALID_ARGS);
  2351 	return NULL;
  2354     /* first copy caller attributes in. */
  2355     for (templateCount = 0; templateCount < numAttrs; ++templateCount) {
  2356     	*attrs++ = *userAttr++;
  2359     /* We only add the following attributes to the template if the caller
  2360     ** didn't already supply them.
  2361     */
  2362     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_CLASS)) {
  2363 	PK11_SETATTRS(attrs, CKA_CLASS,     &keyClass, sizeof keyClass); 
  2364 	attrs++;
  2366     if (!pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_KEY_TYPE)) {
  2367 	keyType = PK11_GetKeyType(target, keySize);
  2368 	PK11_SETATTRS(attrs, CKA_KEY_TYPE,  &keyType,  sizeof keyType ); 
  2369 	attrs++;
  2371     if ((operation != CKA_FLAGS_ONLY) &&
  2372 	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, operation)) {
  2373 	PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++;
  2376     /*
  2377      * must be last in case we need to use this template to import the key
  2378      */
  2379     if (keySize > 0 &&
  2380     	  !pk11_FindAttrInTemplate(keyTemplate, numAttrs, CKA_VALUE_LEN)) {
  2381 	valueLen = (CK_ULONG)keySize;
  2382 	PK11_SETATTRS(attrs, CKA_VALUE_LEN, &valueLen, sizeof valueLen); 
  2383 	attrs++;
  2386     templateCount = attrs - keyTemplate;
  2387     PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE));
  2390     /* find out if we can do wrap directly. Because the RSA case if *very*
  2391      * common, cache the results for it. */
  2392     if ((wrapType == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
  2393 	mechanism_info.flags = slot->RSAInfoFlags;
  2394     } else {
  2395 	if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
  2396 	crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,wrapType,
  2397 				 &mechanism_info);
  2398     	if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
  2399     	if (crv != CKR_OK) {
  2400 	     mechanism_info.flags = 0;
  2402         if (wrapType == CKM_RSA_PKCS) {
  2403 	    slot->RSAInfoFlags = mechanism_info.flags;
  2404 	    slot->hasRSAInfo = PR_TRUE;
  2408     /* initialize the mechanism structure */
  2409     mechanism.mechanism = wrapType;
  2410     /* use NULL IV's for wrapping */
  2411     if (param == NULL) 
  2412 	param = param_free = PK11_ParamFromIV(wrapType,NULL);
  2413     if (param) {
  2414 	mechanism.pParameter = param->data;
  2415 	mechanism.ulParameterLen = param->len;
  2416     } else {
  2417 	mechanism.pParameter = NULL;
  2418 	mechanism.ulParameterLen = 0;
  2421     if ((mechanism_info.flags & CKF_DECRYPT)  
  2422 				&& !PK11_DoesMechanism(slot,target)) {
  2423 	symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey, 
  2424 	                         target, keyTemplate, templateCount, keySize, 
  2425 				 wincx, &crv, isPerm);
  2426 	if (symKey) {
  2427 	    if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
  2428 	    return symKey;
  2430 	/*
  2431 	 * if the RSA OP simply failed, don't try to unwrap again 
  2432 	 * with this module.
  2433 	 */
  2434 	if (crv == CKR_DEVICE_ERROR){
  2435 	    if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
  2436 	    return NULL;
  2438 	/* fall through, maybe they incorrectly set CKF_DECRYPT */
  2441     /* get our key Structure */
  2442     symKey = pk11_CreateSymKey(slot, target, !isPerm, PR_TRUE, wincx);
  2443     if (symKey == NULL) {
  2444 	if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
  2445 	return NULL;
  2448     symKey->size = keySize;
  2449     symKey->origin = PK11_OriginUnwrap;
  2451     if (isPerm) {
  2452 	rwsession = PK11_GetRWSession(slot);
  2453     } else {
  2454         pk11_EnterKeyMonitor(symKey);
  2455 	rwsession = symKey->session;
  2457     PORT_Assert(rwsession != CK_INVALID_SESSION);
  2458     if (rwsession == CK_INVALID_SESSION) 
  2459     	crv = CKR_SESSION_HANDLE_INVALID;
  2460     else
  2461 	crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession,&mechanism,wrappingKey,
  2462 		wrappedKey->data, wrappedKey->len, keyTemplate, templateCount, 
  2463 							  &symKey->objectID);
  2464     if (isPerm) {
  2465 	if (rwsession != CK_INVALID_SESSION)
  2466 	    PK11_RestoreROSession(slot, rwsession);
  2467     } else {
  2468         pk11_ExitKeyMonitor(symKey);
  2470     if (param_free) SECITEM_FreeItem(param_free,PR_TRUE);
  2471     if (crv != CKR_OK) {
  2472 	PK11_FreeSymKey(symKey);
  2473 	symKey = NULL;
  2474 	if (crv != CKR_DEVICE_ERROR) {
  2475 	    /* try hand Unwrapping */
  2476 	    symKey = pk11_HandUnwrap(slot, wrappingKey, &mechanism, wrappedKey, 
  2477 				     target, keyTemplate, templateCount,
  2478 				     keySize, wincx, NULL, isPerm);
  2482    return symKey;
  2485 /* use a symetric key to unwrap another symetric key */
  2486 PK11SymKey *
  2487 PK11_UnwrapSymKey( PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
  2488                    SECItem *param, SECItem *wrappedKey, 
  2489 		   CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
  2490 		   int keySize)
  2492     return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
  2493 		    wrapType, param, wrappedKey, target, operation, keySize, 
  2494 		    wrappingKey->cx, NULL, 0, PR_FALSE);
  2497 /* use a symetric key to unwrap another symetric key */
  2498 PK11SymKey *
  2499 PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType,
  2500                    SECItem *param, SECItem *wrappedKey, 
  2501 		   CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
  2502 		   int keySize, CK_FLAGS flags)
  2504     CK_BBOOL        ckTrue	= CK_TRUE; 
  2505     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
  2506     unsigned int    templateCount;
  2508     templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
  2509     return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
  2510 		    wrapType, param, wrappedKey, target, operation, keySize, 
  2511 		    wrappingKey->cx, keyTemplate, templateCount, PR_FALSE);
  2514 PK11SymKey *
  2515 PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, 
  2516 		   CK_MECHANISM_TYPE wrapType,
  2517                    SECItem *param, SECItem *wrappedKey, 
  2518 		   CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, 
  2519 		   int keySize, CK_FLAGS flags, PRBool isPerm)
  2521     CK_BBOOL        cktrue	= CK_TRUE; 
  2522     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
  2523     CK_ATTRIBUTE    *attrs;
  2524     unsigned int    templateCount;
  2526     attrs = keyTemplate;
  2527     if (isPerm) {
  2528         PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
  2530     templateCount = attrs-keyTemplate;
  2531     templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
  2533     return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
  2534 		    wrapType, param, wrappedKey, target, operation, keySize, 
  2535 		    wrappingKey->cx, keyTemplate, templateCount, isPerm);
  2539 /* unwrap a symetric key with a private key. */
  2540 PK11SymKey *
  2541 PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
  2542 	  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
  2544     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
  2545     PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
  2547     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
  2548 	PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
  2551     return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
  2552 	wrapType, NULL, wrappedKey, target, operation, keySize, 
  2553 	wrappingKey->wincx, NULL, 0, PR_FALSE);
  2556 /* unwrap a symetric key with a private key. */
  2557 PK11SymKey *
  2558 PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey, 
  2559 	  SECItem *wrappedKey, CK_MECHANISM_TYPE target, 
  2560 	  CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags)
  2562     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
  2563     CK_BBOOL        ckTrue	= CK_TRUE; 
  2564     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
  2565     unsigned int    templateCount;
  2566     PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
  2568     templateCount = pk11_OpFlagsToAttributes(flags, keyTemplate, &ckTrue);
  2570     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
  2571 	PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
  2574     return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
  2575 	wrapType, NULL, wrappedKey, target, operation, keySize, 
  2576 	wrappingKey->wincx, keyTemplate, templateCount, PR_FALSE);
  2579 PK11SymKey *
  2580 PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, 
  2581 	  SECItem *wrappedKey, CK_MECHANISM_TYPE target, 
  2582 	  CK_ATTRIBUTE_TYPE operation, int keySize,
  2583 	  CK_FLAGS flags, PRBool isPerm)
  2585     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
  2586     CK_BBOOL        cktrue	= CK_TRUE; 
  2587     CK_ATTRIBUTE    keyTemplate[MAX_TEMPL_ATTRS];
  2588     CK_ATTRIBUTE    *attrs;
  2589     unsigned int    templateCount;
  2590     PK11SlotInfo    *slot = wrappingKey->pkcs11Slot;
  2592     attrs = keyTemplate;
  2593     if (isPerm) {
  2594         PK11_SETATTRS(attrs, CKA_TOKEN,  &cktrue, sizeof(CK_BBOOL)); attrs++;
  2596     templateCount = attrs-keyTemplate;
  2598     templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
  2600     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey,CKA_PRIVATE)) {
  2601 	PK11_HandlePasswordCheck(slot,wrappingKey->wincx);
  2604     return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
  2605 	wrapType, NULL, wrappedKey, target, operation, keySize, 
  2606 	wrappingKey->wincx, keyTemplate, templateCount, isPerm);
  2609 PK11SymKey*
  2610 PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech)
  2612     CK_RV crv;
  2613     CK_ATTRIBUTE setTemplate;
  2614     CK_BBOOL ckTrue = CK_TRUE; 
  2615     PK11SlotInfo *slot = originalKey->slot;
  2617     /* first just try to set this key up for signing */
  2618     PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue));
  2619     pk11_EnterKeyMonitor(originalKey);
  2620     crv = PK11_GETTAB(slot)-> C_SetAttributeValue(originalKey->session, 
  2621 				originalKey->objectID, &setTemplate, 1);
  2622     pk11_ExitKeyMonitor(originalKey);
  2623     if (crv == CKR_OK) {
  2624 	return PK11_ReferenceSymKey(originalKey);
  2627     /* nope, doesn't like it, use the pk11 copy object command */
  2628     return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey);
  2631 void   
  2632 PK11_SetFortezzaHack(PK11SymKey *symKey) { 
  2633    symKey->origin = PK11_OriginFortezzaHack;
  2636 /*
  2637  * This is required to allow FORTEZZA_NULL and FORTEZZA_RC4
  2638  * working. This function simply gets a valid IV for the keys.
  2639  */
  2640 SECStatus
  2641 PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len)
  2643     CK_MECHANISM mech_info;
  2644     CK_ULONG count = 0;
  2645     CK_RV crv;
  2646     SECStatus rv = SECFailure;
  2648     mech_info.mechanism = CKM_SKIPJACK_CBC64;
  2649     mech_info.pParameter = iv;
  2650     mech_info.ulParameterLen = len;
  2652     /* generate the IV for fortezza */
  2653     PK11_EnterSlotMonitor(symKey->slot);
  2654     crv=PK11_GETTAB(symKey->slot)->C_EncryptInit(symKey->slot->session,
  2655 				&mech_info, symKey->objectID);
  2656     if (crv == CKR_OK) {
  2657 	PK11_GETTAB(symKey->slot)->C_EncryptFinal(symKey->slot->session, 
  2658 								NULL, &count);
  2659 	rv = SECSuccess;
  2661     PK11_ExitSlotMonitor(symKey->slot);
  2662     return rv;
  2665 CK_OBJECT_HANDLE
  2666 PK11_GetSymKeyHandle(PK11SymKey *symKey)
  2668     return symKey->objectID;

mercurial