Back to index

lightning-sunbird  0.9+nobinonly
pk11obj.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, and
00023  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 /*
00039  * This file manages object type indepentent functions.
00040  */
00041 #include "seccomon.h"
00042 #include "secmod.h"
00043 #include "secmodi.h"
00044 #include "secmodti.h"
00045 #include "pkcs11.h"
00046 #include "pkcs11t.h"
00047 #include "pk11func.h"
00048 #include "key.h" 
00049 #include "secitem.h"
00050 #include "secerr.h"
00051 #include "sslerr.h"
00052 
00053 #define PK11_SEARCH_CHUNKSIZE 10
00054 
00055 /*
00056  * Build a block big enough to hold the data
00057  */
00058 SECItem *
00059 PK11_BlockData(SECItem *data,unsigned long size) {
00060     SECItem *newData;
00061 
00062     newData = (SECItem *)PORT_Alloc(sizeof(SECItem));
00063     if (newData == NULL) return NULL;
00064 
00065     newData->len = (data->len + (size-1))/size;
00066     newData->len *= size;
00067 
00068     newData->data = (unsigned char *) PORT_ZAlloc(newData->len); 
00069     if (newData->data == NULL) {
00070        PORT_Free(newData);
00071        return NULL;
00072     }
00073     PORT_Memset(newData->data,newData->len-data->len,newData->len); 
00074     PORT_Memcpy(newData->data,data->data,data->len);
00075     return newData;
00076 }
00077 
00078 
00079 SECStatus
00080 PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) {
00081     CK_RV crv;
00082 
00083     PK11_EnterSlotMonitor(slot);
00084     crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session,object);
00085     PK11_ExitSlotMonitor(slot);
00086     if (crv != CKR_OK) {
00087        return SECFailure;
00088     }
00089     return SECSuccess;
00090 }
00091 
00092 SECStatus
00093 PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) {
00094     CK_RV crv;
00095     SECStatus rv = SECSuccess;
00096     CK_SESSION_HANDLE rwsession;
00097 
00098     
00099     rwsession = PK11_GetRWSession(slot);
00100     if (rwsession == CK_INVALID_SESSION) {
00101        PORT_SetError(SEC_ERROR_BAD_DATA);
00102        return SECFailure;
00103     }
00104 
00105     crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession,object);
00106     if (crv != CKR_OK) {
00107        rv = SECFailure;
00108        PORT_SetError(PK11_MapError(crv));
00109     }
00110     PK11_RestoreROSession(slot,rwsession);
00111     return rv;
00112 }
00113 
00114 /*
00115  * Read in a single attribute into a SECItem. Allocate space for it with 
00116  * PORT_Alloc unless an arena is supplied. In the latter case use the arena
00117  * to allocate the space.
00118  */
00119 SECStatus
00120 PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
00121         CK_ATTRIBUTE_TYPE type, PRArenaPool *arena, SECItem *result) {
00122     CK_ATTRIBUTE attr = { 0, NULL, 0 };
00123     CK_RV crv;
00124 
00125     attr.type = type;
00126 
00127     PK11_EnterSlotMonitor(slot);
00128     crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
00129     if (crv != CKR_OK) {
00130        PK11_ExitSlotMonitor(slot);
00131        PORT_SetError(PK11_MapError(crv));
00132        return SECFailure;
00133     }
00134     if (arena) {
00135        attr.pValue = PORT_ArenaAlloc(arena,attr.ulValueLen);
00136     } else {
00137        attr.pValue = PORT_Alloc(attr.ulValueLen);
00138     }
00139     if (attr.pValue == NULL) {
00140        PK11_ExitSlotMonitor(slot);
00141        return SECFailure;
00142     }
00143     crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
00144     PK11_ExitSlotMonitor(slot);
00145     if (crv != CKR_OK) {
00146        PORT_SetError(PK11_MapError(crv));
00147        if (!arena) PORT_Free(attr.pValue);
00148        return SECFailure;
00149     }
00150 
00151     result->data = (unsigned char*)attr.pValue;
00152     result->len = attr.ulValueLen;
00153 
00154     return SECSuccess;
00155 }
00156 
00157 /*
00158  * Read in a single attribute into As a Ulong. 
00159  */
00160 CK_ULONG
00161 PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
00162         CK_ATTRIBUTE_TYPE type) {
00163     CK_ATTRIBUTE attr;
00164     CK_ULONG value = CK_UNAVAILABLE_INFORMATION;
00165     CK_RV crv;
00166 
00167     PK11_SETATTRS(&attr,type,&value,sizeof(value));
00168 
00169     PK11_EnterSlotMonitor(slot);
00170     crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1);
00171     PK11_ExitSlotMonitor(slot);
00172     if (crv != CKR_OK) {
00173        PORT_SetError(PK11_MapError(crv));
00174     }
00175     return value;
00176 }
00177 
00178 /*
00179  * check to see if a bool has been set.
00180  */
00181 CK_BBOOL
00182 PK11_HasAttributeSet( PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
00183                                                   CK_ATTRIBUTE_TYPE type )
00184 {
00185     CK_BBOOL ckvalue = CK_FALSE;
00186     CK_ATTRIBUTE theTemplate;
00187     CK_RV crv;
00188 
00189     /* Prepare to retrieve the attribute. */
00190     PK11_SETATTRS( &theTemplate, type, &ckvalue, sizeof( CK_BBOOL ) );
00191 
00192     /* Retrieve attribute value. */
00193     PK11_EnterSlotMonitor(slot);
00194     crv = PK11_GETTAB( slot )->C_GetAttributeValue( slot->session, id,
00195                                                     &theTemplate, 1 );
00196     PK11_ExitSlotMonitor(slot);
00197     if( crv != CKR_OK ) {
00198         PORT_SetError( PK11_MapError( crv ) );
00199         return CK_FALSE;
00200     }
00201 
00202     return ckvalue;
00203 }
00204 
00205 /*
00206  * returns a full list of attributes. Allocate space for them. If an arena is
00207  * provided, allocate space out of the arena.
00208  */
00209 CK_RV
00210 PK11_GetAttributes(PRArenaPool *arena,PK11SlotInfo *slot,
00211                      CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count)
00212 {
00213     int i;
00214     /* make pedantic happy... note that it's only used arena != NULL */ 
00215     void *mark = NULL; 
00216     CK_RV crv;
00217     PORT_Assert(slot->session != CK_INVALID_SESSION);
00218     if (slot->session == CK_INVALID_SESSION)
00219        return CKR_SESSION_HANDLE_INVALID;
00220 
00221     /*
00222      * first get all the lengths of the parameters.
00223      */
00224     PK11_EnterSlotMonitor(slot);
00225     crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count);
00226     if (crv != CKR_OK) {
00227        PK11_ExitSlotMonitor(slot);
00228        return crv;
00229     }
00230 
00231     if (arena) {
00232        mark = PORT_ArenaMark(arena);
00233        if (mark == NULL) return CKR_HOST_MEMORY;
00234     }
00235 
00236     /*
00237      * now allocate space to store the results.
00238      */
00239     for (i=0; i < count; i++) {
00240        if (arena) {
00241            attr[i].pValue = PORT_ArenaAlloc(arena,attr[i].ulValueLen);
00242            if (attr[i].pValue == NULL) {
00243               /* arena failures, just release the mark */
00244               PORT_ArenaRelease(arena,mark);
00245               PK11_ExitSlotMonitor(slot);
00246               return CKR_HOST_MEMORY;
00247            }
00248        } else {
00249            attr[i].pValue = PORT_Alloc(attr[i].ulValueLen);
00250            if (attr[i].pValue == NULL) {
00251               /* Separate malloc failures, loop to release what we have 
00252                * so far */
00253               int j;
00254               for (j= 0; j < i; j++) { 
00255                   PORT_Free(attr[j].pValue);
00256                   /* don't give the caller pointers to freed memory */
00257                   attr[j].pValue = NULL; 
00258               }
00259               PK11_ExitSlotMonitor(slot);
00260               return CKR_HOST_MEMORY;
00261            }
00262        }
00263     }
00264 
00265     /*
00266      * finally get the results.
00267      */
00268     crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count);
00269     PK11_ExitSlotMonitor(slot);
00270     if (crv != CKR_OK) {
00271        if (arena) {
00272            PORT_ArenaRelease(arena,mark);
00273        } else {
00274            for (i= 0; i < count; i++) {
00275               PORT_Free(attr[i].pValue);
00276               /* don't give the caller pointers to freed memory */
00277               attr[i].pValue = NULL;
00278            }
00279        }
00280     } else if (arena && mark) {
00281        PORT_ArenaUnmark(arena,mark);
00282     }
00283     return crv;
00284 }
00285 
00286 PRBool
00287 PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle)
00288 {
00289     return (PRBool) PK11_HasAttributeSet(slot, handle, CKA_TOKEN);
00290 }
00291 
00292 char *
00293 PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) 
00294 {
00295     char *nickname = NULL;
00296     SECItem result;
00297     SECStatus rv;
00298 
00299     rv = PK11_ReadAttribute(slot,id,CKA_LABEL,NULL,&result);
00300     if (rv != SECSuccess) {
00301        return NULL;
00302     }
00303 
00304     nickname = PORT_ZAlloc(result.len+1);
00305     if (nickname == NULL) {
00306        PORT_Free(result.data);
00307        return NULL;
00308     }
00309     PORT_Memcpy(nickname, result.data, result.len);
00310     PORT_Free(result.data);
00311     return nickname;
00312 }
00313 
00314 SECStatus
00315 PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, 
00316                                           const char *nickname) 
00317 {
00318     int len = PORT_Strlen(nickname);
00319     CK_ATTRIBUTE setTemplate;
00320     CK_RV crv;
00321     CK_SESSION_HANDLE rwsession;
00322 
00323     if (len < 0) {
00324        return SECFailure;
00325     }
00326 
00327     PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *) nickname, len);
00328     rwsession = PK11_GetRWSession(slot);
00329     if (rwsession == CK_INVALID_SESSION) {
00330        PORT_SetError(SEC_ERROR_BAD_DATA);
00331        return SECFailure;
00332     }
00333     crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id,
00334                      &setTemplate, 1);
00335     PK11_RestoreROSession(slot, rwsession);
00336     if (crv != CKR_OK) {
00337        PORT_SetError(PK11_MapError(crv));
00338        return SECFailure;
00339     }
00340     return SECSuccess;
00341 }
00342 
00343 /*
00344  * strip leading zero's from key material
00345  */
00346 void
00347 pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) {
00348     char *ptr = (char *)attrib->pValue;
00349     unsigned long len = attrib->ulValueLen;
00350 
00351     while (len && (*ptr == 0)) {
00352        len--;
00353        ptr++;
00354     }
00355     attrib->pValue = ptr;
00356     attrib->ulValueLen = len;
00357 }
00358 
00359 /*
00360  * get a new session on a slot. If we run out of session, use the slot's
00361  * 'exclusive' session. In this case owner becomes false.
00362  */
00363 CK_SESSION_HANDLE
00364 pk11_GetNewSession(PK11SlotInfo *slot,PRBool *owner)
00365 {
00366     CK_SESSION_HANDLE session;
00367     *owner =  PR_TRUE;
00368     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
00369     if ( PK11_GETTAB(slot)->C_OpenSession(slot->slotID,CKF_SERIAL_SESSION, 
00370                      slot,pk11_notify,&session) != CKR_OK) {
00371        *owner = PR_FALSE;
00372        session = slot->session;
00373     }
00374     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
00375 
00376     return session;
00377 }
00378 
00379 void
00380 pk11_CloseSession(PK11SlotInfo *slot,CK_SESSION_HANDLE session,PRBool owner)
00381 {
00382     if (!owner) return;
00383     if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot);
00384     (void) PK11_GETTAB(slot)->C_CloseSession(session);
00385     if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot);
00386 }
00387 
00388 
00389 SECStatus
00390 PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
00391                             CK_ATTRIBUTE *theTemplate, int count, 
00392                             PRBool token, CK_OBJECT_HANDLE *objectID)
00393 {
00394        CK_SESSION_HANDLE rwsession;
00395        CK_RV crv;
00396        SECStatus rv = SECSuccess;
00397 
00398        rwsession = session;
00399        if (token) {
00400            rwsession =  PK11_GetRWSession(slot);
00401        } else if (rwsession == CK_INVALID_SESSION) {
00402            rwsession =  slot->session;
00403            if (rwsession != CK_INVALID_SESSION)
00404               PK11_EnterSlotMonitor(slot);
00405        }
00406        if (rwsession == CK_INVALID_SESSION) {
00407            PORT_SetError(SEC_ERROR_BAD_DATA);
00408            return SECFailure;
00409        }
00410        crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, theTemplate,
00411                                                  count,objectID);
00412        if(crv != CKR_OK) {
00413            PORT_SetError( PK11_MapError(crv) );
00414            rv = SECFailure;
00415        }
00416        if (token) {
00417            PK11_RestoreROSession(slot, rwsession);
00418        } else if (session == CK_INVALID_SESSION) {
00419            PK11_ExitSlotMonitor(slot);
00420         }
00421 
00422        return rv;
00423 }
00424 
00425 
00426 /* This function may add a maximum of 9 attributes. */
00427 unsigned int
00428 pk11_OpFlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue)
00429 {
00430 
00431     const static CK_ATTRIBUTE_TYPE attrTypes[12] = {
00432        CKA_ENCRYPT,      CKA_DECRYPT, 0 /* DIGEST */,     CKA_SIGN,
00433        CKA_SIGN_RECOVER, CKA_VERIFY,  CKA_VERIFY_RECOVER, 0 /* GEN */,
00434        0 /* GEN PAIR */, CKA_WRAP,    CKA_UNWRAP,         CKA_DERIVE 
00435     };
00436 
00437     const CK_ATTRIBUTE_TYPE *pType = attrTypes;
00438           CK_ATTRIBUTE      *attr  = attrs;
00439           CK_FLAGS          test   = CKF_ENCRYPT;
00440 
00441 
00442     PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS));
00443     flags &= CKF_KEY_OPERATION_FLAGS;
00444 
00445     for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) {
00446        if (test & flags) {
00447            flags ^= test;
00448            PR_ASSERT(*pType);
00449            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); 
00450            ++attr;
00451        }
00452     }
00453     return (attr - attrs);
00454 }
00455 
00456 /*
00457  * Check for conflicting flags, for example, if both PK11_ATTR_PRIVATE
00458  * and PK11_ATTR_PUBLIC are set.
00459  */
00460 PRBool
00461 pk11_BadAttrFlags(PK11AttrFlags attrFlags)
00462 {
00463     PK11AttrFlags trueFlags = attrFlags & 0x55555555;
00464     PK11AttrFlags falseFlags = (attrFlags >> 1) & 0x55555555;
00465     return ((trueFlags & falseFlags) != 0);
00466 }
00467 
00468 /*
00469  * This function may add a maximum of 5 attributes.
00470  * The caller must make sure the attribute flags don't have conflicts.
00471  */
00472 unsigned int
00473 pk11_AttrFlagsToAttributes(PK11AttrFlags attrFlags, CK_ATTRIBUTE *attrs,
00474                             CK_BBOOL *ckTrue, CK_BBOOL *ckFalse)
00475 {
00476     const static CK_ATTRIBUTE_TYPE attrTypes[5] = {
00477        CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_SENSITIVE,
00478        CKA_EXTRACTABLE
00479     };
00480 
00481     const CK_ATTRIBUTE_TYPE *pType = attrTypes;
00482           CK_ATTRIBUTE      *attr  = attrs;
00483           PK11AttrFlags      test  = PK11_ATTR_TOKEN;
00484 
00485     PR_ASSERT(!pk11_BadAttrFlags(attrFlags));
00486 
00487     /* we test two related bitflags in each iteration */
00488     for (; attrFlags && test <= PK11_ATTR_EXTRACTABLE; test <<= 2, ++pType) {
00489        if (test & attrFlags) {
00490            attrFlags ^= test;
00491            PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); 
00492            ++attr;
00493        } else if ((test << 1) & attrFlags) {
00494            attrFlags ^= (test << 1);
00495            PK11_SETATTRS(attr, *pType, ckFalse, sizeof *ckFalse); 
00496            ++attr;
00497        }
00498     }
00499     return (attr - attrs);
00500 }
00501 
00502 /*
00503  * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually
00504  * set up a signature to get the signaure length.
00505  */
00506 static int
00507 pk11_backupGetSignLength(SECKEYPrivateKey *key)
00508 {
00509     PK11SlotInfo *slot = key->pkcs11Slot;
00510     CK_MECHANISM mech = {0, NULL, 0 };
00511     PRBool owner = PR_TRUE;
00512     CK_SESSION_HANDLE session;
00513     CK_ULONG len;
00514     CK_RV crv;
00515     unsigned char h_data[20]  = { 0 };
00516     unsigned char buf[20]; /* obviously to small */
00517     CK_ULONG smallLen = sizeof(buf);
00518 
00519     mech.mechanism = PK11_MapSignKeyType(key->keyType);
00520 
00521     session = pk11_GetNewSession(slot,&owner);
00522     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
00523     crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID);
00524     if (crv != CKR_OK) {
00525        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00526        pk11_CloseSession(slot,session,owner);
00527        PORT_SetError( PK11_MapError(crv) );
00528        return -1;
00529     }
00530     len = 0;
00531     crv = PK11_GETTAB(slot)->C_Sign(session,h_data,sizeof(h_data),
00532                                    NULL, &len);
00533     /* now call C_Sign with too small a buffer to clear the session state */
00534     (void) PK11_GETTAB(slot)->
00535                      C_Sign(session,h_data,sizeof(h_data),buf,&smallLen);
00536        
00537     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00538     pk11_CloseSession(slot,session,owner);
00539     if (crv != CKR_OK) {
00540        PORT_SetError( PK11_MapError(crv) );
00541        return -1;
00542     }
00543     return len;
00544 }
00545 
00546 /*
00547  * get the length of a signature object based on the key
00548  */
00549 int
00550 PK11_SignatureLen(SECKEYPrivateKey *key)
00551 {
00552     int val;
00553     CK_ATTRIBUTE theTemplate = { CKA_EC_PARAMS, NULL, 0 };
00554     SECItem params = {siBuffer, NULL, 0};
00555     int length; 
00556 
00557     switch (key->keyType) {
00558     case rsaKey:
00559        val = PK11_GetPrivateModulusLen(key);
00560        if (val == -1) {
00561            return pk11_backupGetSignLength(key);
00562        }
00563        return (unsigned long) val;
00564        
00565     case fortezzaKey:
00566     case dsaKey:
00567        return 40;
00568     case ecKey:
00569        if (PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID,
00570                             &theTemplate, 1) == CKR_OK) {
00571            if (theTemplate.pValue != NULL) {
00572                params.len = theTemplate.ulValueLen;
00573               params.data = (unsigned char *) theTemplate.pValue;
00574                length = SECKEY_ECParamsToBasePointOrderLen(&params);
00575                PORT_Free(theTemplate.pValue);
00576               if (length == 0) {
00577                   return pk11_backupGetSignLength(key);
00578               }
00579               length = ((length + 7)/8) * 2;
00580               return length;
00581            }
00582        }
00583        break;
00584     default:
00585        break;
00586     }
00587     PORT_SetError( SEC_ERROR_INVALID_KEY );
00588     return 0;
00589 }
00590 
00591 /*
00592  * copy a key (or any other object) on a token
00593  */
00594 CK_OBJECT_HANDLE
00595 PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject)
00596 {
00597     CK_OBJECT_HANDLE destObject;
00598     CK_RV crv;
00599 
00600     PK11_EnterSlotMonitor(slot);
00601     crv = PK11_GETTAB(slot)->C_CopyObject(slot->session,srcObject,NULL,0,
00602                             &destObject);
00603     PK11_ExitSlotMonitor(slot);
00604     if (crv == CKR_OK) return destObject;
00605     PORT_SetError( PK11_MapError(crv) );
00606     return CK_INVALID_HANDLE;
00607 }
00608 
00609 PRBool
00610 pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs,
00611                                           CK_ATTRIBUTE_TYPE target)
00612 {
00613     for (; numAttrs > 0; ++attr, --numAttrs) {
00614        if (attr->type == target)
00615            return PR_TRUE;
00616     }
00617     return PR_FALSE;
00618 }
00619        
00620 /*
00621  * Recover the Signed data. We need this because our old verify can't
00622  * figure out which hash algorithm to use until we decryptted this.
00623  */
00624 SECStatus
00625 PK11_VerifyRecover(SECKEYPublicKey *key,
00626                             SECItem *sig, SECItem *dsig, void *wincx)
00627 {
00628     PK11SlotInfo *slot = key->pkcs11Slot;
00629     CK_OBJECT_HANDLE id = key->pkcs11ID;
00630     CK_MECHANISM mech = {0, NULL, 0 };
00631     PRBool owner = PR_TRUE;
00632     CK_SESSION_HANDLE session;
00633     CK_ULONG len;
00634     CK_RV crv;
00635 
00636     mech.mechanism = PK11_MapSignKeyType(key->keyType);
00637 
00638     if (slot == NULL) {
00639        slot = PK11_GetBestSlot(mech.mechanism,wincx);
00640        if (slot == NULL) {
00641               PORT_SetError( SEC_ERROR_NO_MODULE );
00642               return SECFailure;
00643        }
00644        id = PK11_ImportPublicKey(slot,key,PR_FALSE);
00645     } else {
00646        PK11_ReferenceSlot(slot);
00647     }
00648 
00649     if (id == CK_INVALID_HANDLE) {
00650        PK11_FreeSlot(slot);
00651        PORT_SetError( SEC_ERROR_BAD_KEY );
00652        return SECFailure;
00653     }
00654 
00655     session = pk11_GetNewSession(slot,&owner);
00656     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
00657     crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session,&mech,id);
00658     if (crv != CKR_OK) {
00659        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00660        pk11_CloseSession(slot,session,owner);
00661        PORT_SetError( PK11_MapError(crv) );
00662        PK11_FreeSlot(slot);
00663        return SECFailure;
00664     }
00665     len = dsig->len;
00666     crv = PK11_GETTAB(slot)->C_VerifyRecover(session,sig->data,
00667                                           sig->len, dsig->data, &len);
00668     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00669     pk11_CloseSession(slot,session,owner);
00670     dsig->len = len;
00671     if (crv != CKR_OK) {
00672        PORT_SetError( PK11_MapError(crv) );
00673        PK11_FreeSlot(slot);
00674        return SECFailure;
00675     }
00676     PK11_FreeSlot(slot);
00677     return SECSuccess;
00678 }
00679 
00680 /*
00681  * verify a signature from its hash.
00682  */
00683 SECStatus
00684 PK11_Verify(SECKEYPublicKey *key, SECItem *sig, SECItem *hash, void *wincx)
00685 {
00686     PK11SlotInfo *slot = key->pkcs11Slot;
00687     CK_OBJECT_HANDLE id = key->pkcs11ID;
00688     CK_MECHANISM mech = {0, NULL, 0 };
00689     PRBool owner = PR_TRUE;
00690     CK_SESSION_HANDLE session;
00691     CK_RV crv;
00692 
00693     mech.mechanism = PK11_MapSignKeyType(key->keyType);
00694 
00695     if (slot == NULL) {
00696        slot = PK11_GetBestSlot(mech.mechanism,wincx);
00697        
00698        if (slot == NULL) {
00699            PORT_SetError( SEC_ERROR_NO_MODULE );
00700            return SECFailure;
00701        }
00702        id = PK11_ImportPublicKey(slot,key,PR_FALSE);
00703             
00704     } else {
00705        PK11_ReferenceSlot(slot);
00706     }
00707 
00708     if (id == CK_INVALID_HANDLE) {
00709        PK11_FreeSlot(slot);
00710        PORT_SetError( SEC_ERROR_BAD_KEY );
00711        return SECFailure;
00712     }
00713 
00714     session = pk11_GetNewSession(slot,&owner);
00715     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
00716     crv = PK11_GETTAB(slot)->C_VerifyInit(session,&mech,id);
00717     if (crv != CKR_OK) {
00718        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00719        pk11_CloseSession(slot,session,owner);
00720        PK11_FreeSlot(slot);
00721        PORT_SetError( PK11_MapError(crv) );
00722        return SECFailure;
00723     }
00724     crv = PK11_GETTAB(slot)->C_Verify(session,hash->data,
00725                                    hash->len, sig->data, sig->len);
00726     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00727     pk11_CloseSession(slot,session,owner);
00728     PK11_FreeSlot(slot);
00729     if (crv != CKR_OK) {
00730        PORT_SetError( PK11_MapError(crv) );
00731        return SECFailure;
00732     }
00733     return SECSuccess;
00734 }
00735 
00736 /*
00737  * sign a hash. The algorithm is determined by the key.
00738  */
00739 SECStatus
00740 PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash)
00741 {
00742     PK11SlotInfo *slot = key->pkcs11Slot;
00743     CK_MECHANISM mech = {0, NULL, 0 };
00744     PRBool owner = PR_TRUE;
00745     CK_SESSION_HANDLE session;
00746     CK_ULONG len;
00747     CK_RV crv;
00748 
00749     mech.mechanism = PK11_MapSignKeyType(key->keyType);
00750 
00751     if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) {
00752        PK11_HandlePasswordCheck(slot, key->wincx);
00753     }
00754 
00755     session = pk11_GetNewSession(slot,&owner);
00756     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
00757     crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID);
00758     if (crv != CKR_OK) {
00759        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00760        pk11_CloseSession(slot,session,owner);
00761        PORT_SetError( PK11_MapError(crv) );
00762        return SECFailure;
00763     }
00764     len = sig->len;
00765     crv = PK11_GETTAB(slot)->C_Sign(session,hash->data,
00766                                    hash->len, sig->data, &len);
00767     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00768     pk11_CloseSession(slot,session,owner);
00769     sig->len = len;
00770     if (crv != CKR_OK) {
00771        PORT_SetError( PK11_MapError(crv) );
00772        return SECFailure;
00773     }
00774     return SECSuccess;
00775 }
00776 
00777 /*
00778  * Now SSL 2.0 uses raw RSA stuff. These next to functions *must* use
00779  * RSA keys, or they'll fail. We do the checks up front. If anyone comes
00780  * up with a meaning for rawdecrypt for any other public key operation,
00781  * then we need to move this check into some of PK11_PubDecrypt callers,
00782  * (namely SSL 2.0).
00783  */
00784 static SECStatus
00785 pk11_PrivDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, 
00786        unsigned *outLen, unsigned int maxLen, unsigned char *enc,
00787                                 unsigned encLen, CK_MECHANISM_PTR mech)
00788 {
00789     PK11SlotInfo *slot = key->pkcs11Slot;
00790     CK_ULONG out = maxLen;
00791     PRBool owner = PR_TRUE;
00792     CK_SESSION_HANDLE session;
00793     CK_RV crv;
00794 
00795     if (key->keyType != rsaKey) {
00796        PORT_SetError( SEC_ERROR_INVALID_KEY );
00797        return SECFailure;
00798     }
00799 
00800     /* Why do we do a PK11_handle check here? for simple
00801      * decryption? .. because the user may have asked for 'ask always'
00802      * and this is a private key operation. In practice, thought, it's mute
00803      * since only servers wind up using this function */
00804     if (SECKEY_HAS_ATTRIBUTE_SET(key,CKA_PRIVATE)) {
00805        PK11_HandlePasswordCheck(slot, key->wincx);
00806     }
00807     session = pk11_GetNewSession(slot,&owner);
00808     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
00809     crv = PK11_GETTAB(slot)->C_DecryptInit(session, mech, key->pkcs11ID);
00810     if (crv != CKR_OK) {
00811        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00812        pk11_CloseSession(slot,session,owner);
00813        PORT_SetError( PK11_MapError(crv) );
00814        return SECFailure;
00815     }
00816     crv = PK11_GETTAB(slot)->C_Decrypt(session,enc, encLen, data, &out);
00817     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00818     pk11_CloseSession(slot,session,owner);
00819     *outLen = out;
00820     if (crv != CKR_OK) {
00821        PORT_SetError( PK11_MapError(crv) );
00822        return SECFailure;
00823     }
00824     return SECSuccess;
00825 }
00826 
00827 SECStatus
00828 PK11_PubDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, 
00829        unsigned *outLen, unsigned int maxLen, unsigned char *enc,
00830                                 unsigned encLen)
00831 {
00832     CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 };
00833     return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
00834 }
00835 
00836 SECStatus
00837 PK11_PrivDecryptPKCS1(SECKEYPrivateKey *key, unsigned char *data, 
00838        unsigned *outLen, unsigned int maxLen, unsigned char *enc,
00839                                 unsigned encLen)
00840 {
00841     CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 };
00842     return pk11_PrivDecryptRaw(key, data, outLen, maxLen, enc, encLen, &mech);
00843 }
00844 
00845 static SECStatus
00846 pk11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc,
00847                   unsigned char *data, unsigned dataLen, 
00848                   CK_MECHANISM_PTR mech, void *wincx)
00849 {
00850     PK11SlotInfo *slot;
00851     CK_OBJECT_HANDLE id;
00852     CK_ULONG out;
00853     PRBool owner = PR_TRUE;
00854     CK_SESSION_HANDLE session;
00855     CK_RV crv;
00856 
00857     if (!key || key->keyType != rsaKey) {
00858        PORT_SetError( SEC_ERROR_BAD_KEY );
00859        return SECFailure;
00860     }
00861     out = SECKEY_PublicKeyStrength(key);
00862 
00863     slot = PK11_GetBestSlot(mech->mechanism, wincx);
00864     if (slot == NULL) {
00865        PORT_SetError( SEC_ERROR_NO_MODULE );
00866        return SECFailure;
00867     }
00868 
00869     id = PK11_ImportPublicKey(slot,key,PR_FALSE);
00870 
00871     if (id == CK_INVALID_HANDLE) {
00872        PK11_FreeSlot(slot);
00873        PORT_SetError( SEC_ERROR_BAD_KEY );
00874        return SECFailure;
00875     }
00876 
00877     session = pk11_GetNewSession(slot,&owner);
00878     if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot);
00879     crv = PK11_GETTAB(slot)->C_EncryptInit(session, mech, id);
00880     if (crv != CKR_OK) {
00881        if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00882        pk11_CloseSession(slot,session,owner);
00883        PK11_FreeSlot(slot);
00884        PORT_SetError( PK11_MapError(crv) );
00885        return SECFailure;
00886     }
00887     crv = PK11_GETTAB(slot)->C_Encrypt(session,data,dataLen,enc,&out);
00888     if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot);
00889     pk11_CloseSession(slot,session,owner);
00890     PK11_FreeSlot(slot);
00891     if (crv != CKR_OK) {
00892        PORT_SetError( PK11_MapError(crv) );
00893        return SECFailure;
00894     }
00895     return SECSuccess;
00896 }
00897 
00898 SECStatus
00899 PK11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc,
00900               unsigned char *data, unsigned dataLen, void *wincx)
00901 {
00902     CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 };
00903     return pk11_PubEncryptRaw(key, enc, data, dataLen, &mech, wincx);
00904 }
00905 
00906 SECStatus
00907 PK11_PubEncryptPKCS1(SECKEYPublicKey *key, unsigned char *enc,
00908               unsigned char *data, unsigned dataLen, void *wincx)
00909 {
00910     CK_MECHANISM mech = {CKM_RSA_PKCS, NULL, 0 };
00911     return pk11_PubEncryptRaw(key, enc, data, dataLen, &mech, wincx);
00912 }
00913 
00914 SECKEYPrivateKey *
00915 PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
00916                  CK_MECHANISM_TYPE wrapType, SECItem *param, 
00917                  SECItem *wrappedKey, SECItem *label, 
00918                  SECItem *idValue, PRBool perm, PRBool sensitive,
00919                  CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage,
00920                  int usageCount, void *wincx)
00921 {
00922     CK_BBOOL cktrue = CK_TRUE;
00923     CK_BBOOL ckfalse = CK_FALSE;
00924     CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
00925     CK_ATTRIBUTE keyTemplate[15] ;
00926     int templateCount = 0;
00927     CK_OBJECT_HANDLE privKeyID;
00928     CK_MECHANISM mechanism;
00929     CK_ATTRIBUTE *attrs = keyTemplate;
00930     SECItem *param_free = NULL, *ck_id;
00931     CK_RV crv;
00932     CK_SESSION_HANDLE rwsession;
00933     PK11SymKey *newKey = NULL;
00934     int i;
00935 
00936     if(!slot || !wrappedKey || !idValue) {
00937        /* SET AN ERROR!!! */
00938        return NULL;
00939     }
00940 
00941     ck_id = PK11_MakeIDFromPubKey(idValue);
00942     if(!ck_id) {
00943        return NULL;
00944     }
00945 
00946     PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse,
00947                                     sizeof(cktrue)); attrs++;
00948     PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++;
00949     PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++;
00950     PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse,
00951                                     sizeof(cktrue)); attrs++;
00952     PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse,
00953                                    sizeof(cktrue)); attrs++;
00954     PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); attrs++;
00955     PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++;
00956     for (i=0; i < usageCount; i++) {
00957        PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); attrs++;
00958     }
00959 
00960     if (PK11_IsInternal(slot)) {
00961        PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, idValue->data, 
00962                     idValue->len); attrs++;
00963     }
00964 
00965     templateCount = attrs - keyTemplate;
00966     PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)) );
00967 
00968     mechanism.mechanism = wrapType;
00969     if(!param) param = param_free= PK11_ParamFromIV(wrapType, NULL);
00970     if(param) {
00971        mechanism.pParameter = param->data;
00972        mechanism.ulParameterLen = param->len;
00973     } else {
00974        mechanism.pParameter = NULL;
00975        mechanism.ulParameterLen = 0;
00976     }
00977 
00978     if (wrappingKey->slot != slot) {
00979        newKey = pk11_CopyToSlot(slot,wrapType,CKA_WRAP,wrappingKey);
00980     } else {
00981        newKey = PK11_ReferenceSymKey(wrappingKey);
00982     }
00983 
00984     if (newKey) {
00985        if (perm) {
00986            /* Get RW Session will either lock the monitor if necessary, 
00987             *  or return a thread safe session handle, or fail. */ 
00988            rwsession = PK11_GetRWSession(slot);
00989        } else {
00990            rwsession = slot->session;
00991            if (rwsession != CK_INVALID_SESSION) 
00992               PK11_EnterSlotMonitor(slot);
00993        }
00994        if (rwsession == CK_INVALID_SESSION) {
00995            PK11_FreeSymKey(newKey);
00996            PORT_SetError(SEC_ERROR_BAD_DATA);
00997            return NULL;
00998        }
00999        crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, 
01000                                     newKey->objectID,
01001                                     wrappedKey->data, 
01002                                     wrappedKey->len, keyTemplate, 
01003                                     templateCount, &privKeyID);
01004 
01005        if (perm) {
01006            PK11_RestoreROSession(slot, rwsession);
01007        } else {
01008            PK11_ExitSlotMonitor(slot);
01009        }
01010        PK11_FreeSymKey(newKey);
01011     } else {
01012        crv = CKR_FUNCTION_NOT_SUPPORTED;
01013     }
01014 
01015     if(ck_id) {
01016        SECITEM_FreeItem(ck_id, PR_TRUE);
01017        ck_id = NULL;
01018     }
01019 
01020     if (crv != CKR_OK) {
01021        /* we couldn't unwrap the key, use the internal module to do the
01022         * unwrap, then load the new key into the token */
01023         PK11SlotInfo *int_slot = PK11_GetInternalSlot();
01024 
01025        if (int_slot && (slot != int_slot)) {
01026            SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot,
01027                      wrappingKey, wrapType, param, wrappedKey, label,
01028                      idValue, PR_FALSE, PR_FALSE, 
01029                      keyType, usage, usageCount, wincx);
01030            if (privKey) {
01031               SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot,privKey,
01032                                           NULL,perm,sensitive);
01033               SECKEY_DestroyPrivateKey(privKey);
01034               PK11_FreeSlot(int_slot);
01035               return newPrivKey;
01036            }
01037        }
01038        if (int_slot) PK11_FreeSlot(int_slot);
01039        PORT_SetError( PK11_MapError(crv) );
01040        return NULL;
01041     }
01042     return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx);
01043 }
01044 
01045 /*
01046  * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey
01047  * The strategy is to get both keys to reside in the same slot,
01048  * one that can perform the desired crypto mechanism and then
01049  * call C_WrapKey after all the setup has taken place.
01050  */
01051 SECStatus
01052 PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, 
01053                SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, 
01054                SECItem *param, SECItem *wrappedKey, void *wincx)
01055 {
01056     PK11SlotInfo     *privSlot   = privKey->pkcs11Slot; /* The slot where
01057                                                   * the private key
01058                                                   * we are going to
01059                                                   * wrap lives.
01060                                                   */
01061     PK11SymKey       *newSymKey  = NULL;
01062     SECKEYPrivateKey *newPrivKey = NULL;
01063     SECItem          *param_free = NULL;
01064     CK_ULONG          len        = wrappedKey->len;
01065     CK_MECHANISM      mech;
01066     CK_RV             crv;
01067 
01068     if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) {
01069         /* Figure out a slot that does the mechanism and try to import
01070         * the private key onto that slot.
01071         */
01072         PK11SlotInfo *int_slot = PK11_GetInternalSlot();
01073 
01074        privSlot = int_slot; /* The private key has a new home */
01075        newPrivKey = PK11_LoadPrivKey(privSlot,privKey,NULL,PR_FALSE,PR_FALSE);
01076        /* newPrivKey has allocated its own reference to the slot, so it's
01077         * safe until we destroy newPrivkey.
01078         */
01079        PK11_FreeSlot(int_slot);
01080        if (newPrivKey == NULL) {
01081            return SECFailure;
01082        }
01083        privKey = newPrivKey;
01084     }
01085 
01086     if (privSlot != wrappingKey->slot) {
01087         newSymKey = pk11_CopyToSlot (privSlot, wrapType, CKA_WRAP, 
01088                                  wrappingKey);
01089        wrappingKey = newSymKey;
01090     }
01091 
01092     if (wrappingKey == NULL) {
01093         if (newPrivKey) {
01094               SECKEY_DestroyPrivateKey(newPrivKey);
01095        }
01096        return SECFailure;
01097     }
01098     mech.mechanism = wrapType;
01099     if (!param) {
01100         param = param_free = PK11_ParamFromIV(wrapType, NULL);
01101     }
01102     if (param) {
01103         mech.pParameter     = param->data;
01104        mech.ulParameterLen = param->len;
01105     } else {
01106         mech.pParameter     = NULL;
01107        mech.ulParameterLen = 0;
01108     }
01109 
01110     PK11_EnterSlotMonitor(privSlot);
01111     crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech, 
01112                                       wrappingKey->objectID, 
01113                                       privKey->pkcs11ID,
01114                                       wrappedKey->data, &len);
01115     PK11_ExitSlotMonitor(privSlot);
01116 
01117     if (newSymKey) {
01118         PK11_FreeSymKey(newSymKey);
01119     }
01120     if (newPrivKey) {
01121         SECKEY_DestroyPrivateKey(newPrivKey);
01122     }
01123     if (param_free) {
01124        SECITEM_FreeItem(param_free,PR_TRUE);
01125     }
01126 
01127     if (crv != CKR_OK) {
01128         PORT_SetError( PK11_MapError(crv) );
01129        return SECFailure;
01130     }
01131 
01132     wrappedKey->len = len;
01133     return SECSuccess;
01134 }
01135 
01136 /*
01137  * return a linked, non-circular list of generic objects. 
01138  * If you are only interested
01139  * in one object, just use the first object in the list. To find the
01140  * rest of the list use PK11_GetNextGenericObject() to return the next object.
01141  *
01142  * You can walk the list with the following code:
01143  *    firstObj = PK11_FindGenericObjects(slot, objClass);
01144  *    for (thisObj=firstObj; thisObj; 
01145  *                          thisObj=PK11_GetNextGenericObject(thisObj)) {
01146  *     /* operate on thisObj */
01147 /*    }
01148  *
01149  * If you want a particular object from the list...
01150  *    firstObj = PK11_FindGenericObjects(slot, objClass);
01151  *    for (thisObj=firstObj; thisObj; 
01152  *                             thisObj=PK11_GetNextGenericObject(thisObj)) {
01153  *     if (isMyObj(thisObj)) {
01154  *         if ( thisObj == firstObj) {
01155  *              /* NOTE: firstObj could be NULL at this point */
01156 /*            firstObj = PK11_GetNextGenericObject(thsObj); 
01157  *         }
01158  *         PK11_UnlinkGenericObject(thisObj);
01159  *          myObj = thisObj;
01160  *          break;
01161  *    }
01162  *
01163  *   PK11_DestroyGenericObjects(firstObj);
01164  *
01165  *    /* use myObj */
01166 /*   PK11_DestroyGenericObject(myObj);
01167  */
01168 PK11GenericObject *
01169 PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass)
01170 {
01171     CK_ATTRIBUTE template[1];
01172     CK_ATTRIBUTE *attrs = template;
01173     CK_OBJECT_HANDLE *objectIDs = NULL;
01174     PK11GenericObject *lastObj = NULL, *obj;
01175     PK11GenericObject *firstObj = NULL;
01176     int i, count = 0;
01177 
01178 
01179     PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++;
01180 
01181     objectIDs = pk11_FindObjectsByTemplate(slot,template,1,&count);
01182     if (objectIDs == NULL) {
01183        return NULL;
01184     }
01185 
01186     /* where we connect our object once we've created it.. */
01187     for (i=0; i < count; i++) {
01188        obj = PORT_New(PK11GenericObject);
01189        if ( !obj ) {
01190            PK11_DestroyGenericObjects(firstObj);
01191            PORT_Free(objectIDs);
01192            return NULL;
01193        }
01194        /* initialize it */  
01195        obj->slot = PK11_ReferenceSlot(slot);
01196        obj->objectID = objectIDs[i];
01197        obj->next = NULL;
01198        obj->prev = NULL;
01199 
01200        /* link it in */
01201        if (firstObj == NULL) {
01202            firstObj = obj;
01203        } else {
01204            PK11_LinkGenericObject(lastObj, obj);
01205        }
01206        lastObj = obj;
01207     }
01208     PORT_Free(objectIDs);
01209     return firstObj;
01210 }
01211 
01212 /*
01213  * get the Next Object in the list.
01214  */
01215 PK11GenericObject *
01216 PK11_GetNextGenericObject(PK11GenericObject *object)
01217 {
01218     return object->next;
01219 }
01220 
01221 PK11GenericObject *
01222 PK11_GetPrevGenericObject(PK11GenericObject *object)
01223 {
01224     return object->prev;
01225 }
01226 
01227 /*
01228  * Link a single object into a new list.
01229  * if the object is already in another list, remove it first.
01230  */
01231 SECStatus
01232 PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object)
01233 {
01234     PK11_UnlinkGenericObject(object);
01235     object->prev = list;
01236     object->next = list->next;
01237     list->next = object;
01238     if (object->next != NULL) {
01239        object->next->prev = object;
01240     }
01241    return SECSuccess;
01242 }
01243 
01244 /*
01245  * remove an object from the list. If the object isn't already in
01246  * a list unlink becomes a noop.
01247  */
01248 SECStatus
01249 PK11_UnlinkGenericObject(PK11GenericObject *object)
01250 {
01251     if (object->prev != NULL) {
01252        object->prev->next = object->next;
01253     }
01254     if (object->next != NULL) {
01255        object->next->prev = object->prev;
01256     }
01257 
01258     object->next = NULL;
01259     object->prev = NULL;
01260     return SECSuccess;
01261 }
01262 
01263 /*
01264  * This function removes a single object from the list and destroys it.
01265  * For an already unlinked object there is no difference between
01266  * PK11_DestroyGenericObject and PK11_DestroyGenericObjects
01267  */
01268 SECStatus 
01269 PK11_DestroyGenericObject(PK11GenericObject *object)
01270 {
01271     if (object == NULL) {
01272        return SECSuccess;
01273     }
01274 
01275     PK11_UnlinkGenericObject(object);
01276     if (object->slot) {
01277        PK11_FreeSlot(object->slot);
01278     }
01279     PORT_Free(object);
01280     return SECSuccess;
01281 }
01282 
01283 /*
01284  * walk down a link list of generic objects destroying them.
01285  * This will destroy all objects in a list that the object is linked into.
01286  * (the list is traversed in both directions).
01287  */
01288 SECStatus 
01289 PK11_DestroyGenericObjects(PK11GenericObject *objects)
01290 {
01291     PK11GenericObject *nextObject;
01292     PK11GenericObject *prevObject = objects->prev;
01293  
01294     if (objects == NULL) {
01295        return SECSuccess;
01296     }
01297 
01298     nextObject = objects->next;
01299     prevObject = objects->prev;
01300 
01301     /* delete all the objects after it in the list */
01302     for (; objects;  objects = nextObject) {
01303        nextObject = objects->next;
01304        PK11_DestroyGenericObject(objects);
01305     }
01306     /* delete all the objects before it in the list */
01307     for (objects = prevObject; objects;  objects = nextObject) {
01308        prevObject = objects->prev;
01309        PK11_DestroyGenericObject(objects);
01310     }
01311     return SECSuccess;
01312 }
01313 
01314 
01315 SECStatus
01316 PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec, 
01317                             CK_ATTRIBUTE_TYPE attrType, SECItem *item)
01318 {
01319     PK11SlotInfo *slot = NULL;
01320     CK_OBJECT_HANDLE handle;
01321 
01322     switch (objType) {
01323     case PK11_TypeGeneric:
01324        slot = ((PK11GenericObject *)objSpec)->slot;
01325        handle = ((PK11GenericObject *)objSpec)->objectID;
01326        break;
01327     case PK11_TypePrivKey:
01328        slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot;
01329        handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID;
01330        break;
01331     case PK11_TypePubKey:
01332        slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot;
01333        handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID;
01334        break;
01335     case PK11_TypeSymKey:
01336        slot = ((PK11SymKey *)objSpec)->slot;
01337        handle = ((PK11SymKey *)objSpec)->objectID;
01338        break;
01339     case PK11_TypeCert: /* don't handle cert case for now */
01340     default:
01341        break;
01342     }
01343     if (slot == NULL) {
01344        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
01345        return SECFailure;
01346     }
01347 
01348     return PK11_ReadAttribute(slot, handle, attrType, NULL, item);
01349 }
01350 
01351 
01352 /*
01353  * return the object handle that matches the template
01354  */
01355 CK_OBJECT_HANDLE
01356 pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize)
01357 {
01358     CK_OBJECT_HANDLE object;
01359     CK_RV crv;
01360     CK_ULONG objectCount;
01361 
01362     /*
01363      * issue the find
01364      */
01365     PK11_EnterSlotMonitor(slot);
01366     crv=PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, theTemplate, tsize);
01367     if (crv != CKR_OK) {
01368         PK11_ExitSlotMonitor(slot);
01369        PORT_SetError( PK11_MapError(crv) );
01370        return CK_INVALID_HANDLE;
01371     }
01372 
01373     crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount);
01374     PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
01375     PK11_ExitSlotMonitor(slot);
01376     if ((crv != CKR_OK) || (objectCount < 1)) {
01377        /* shouldn't use SSL_ERROR... here */
01378        PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) :
01379                                             SSL_ERROR_NO_CERTIFICATE);
01380        return CK_INVALID_HANDLE;
01381     }
01382 
01383     /* blow up if the PKCS #11 module returns us and invalid object handle */
01384     PORT_Assert(object != CK_INVALID_HANDLE);
01385     return object;
01386 } 
01387 
01388 /*
01389  * return all the object handles that matches the template
01390  */
01391 CK_OBJECT_HANDLE *
01392 pk11_FindObjectsByTemplate(PK11SlotInfo *slot,
01393               CK_ATTRIBUTE *findTemplate,int findCount,int *object_count) {
01394     CK_OBJECT_HANDLE *objID = NULL;
01395     CK_ULONG returned_count = 0;
01396     CK_RV crv;
01397 
01398 
01399     PK11_EnterSlotMonitor(slot);
01400     crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, findTemplate, 
01401                                                         findCount);
01402     if (crv != CKR_OK) {
01403        PK11_ExitSlotMonitor(slot);
01404        PORT_SetError( PK11_MapError(crv) );
01405        *object_count = -1;
01406        return NULL;
01407     }
01408 
01409 
01410     /*
01411      * collect all the Matching Objects
01412      */
01413     do {
01414        CK_OBJECT_HANDLE *oldObjID = objID;
01415 
01416        if (objID == NULL) {
01417            objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)*
01418                             (*object_count+ PK11_SEARCH_CHUNKSIZE));
01419        } else {
01420            objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID,
01421               sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE));
01422        }
01423 
01424        if (objID == NULL) {
01425            if (oldObjID) PORT_Free(oldObjID);
01426            break;
01427        }
01428        crv = PK11_GETTAB(slot)->C_FindObjects(slot->session,
01429               &objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count);
01430        if (crv != CKR_OK) {
01431            PORT_SetError( PK11_MapError(crv) );
01432            PORT_Free(objID);
01433            objID = NULL;
01434            break;
01435        }
01436        *object_count += returned_count;
01437     } while (returned_count == PK11_SEARCH_CHUNKSIZE);
01438 
01439     PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
01440     PK11_ExitSlotMonitor(slot);
01441 
01442     if (objID && (*object_count == 0)) {
01443        PORT_Free(objID);
01444        return NULL;
01445     }
01446     if (objID == NULL) *object_count = -1;
01447     return objID;
01448 }
01449 /*
01450  * given a PKCS #11 object, match it's peer based on the KeyID. searchID
01451  * is typically a privateKey or a certificate while the peer is the opposite
01452  */
01453 CK_OBJECT_HANDLE
01454 PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID,
01455                                           CK_OBJECT_CLASS matchclass)
01456 {
01457     CK_ATTRIBUTE theTemplate[] = {
01458        { CKA_ID, NULL, 0 },
01459        { CKA_CLASS, NULL, 0 }
01460     };
01461     /* if you change the array, change the variable below as well */
01462     CK_ATTRIBUTE *keyclass = &theTemplate[1];
01463     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
01464     /* if you change the array, change the variable below as well */
01465     CK_OBJECT_HANDLE peerID;
01466     CK_OBJECT_HANDLE parent;
01467     PRArenaPool *arena;
01468     CK_RV crv;
01469 
01470     /* now we need to create space for the public key */
01471     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
01472     if (arena == NULL) return CK_INVALID_HANDLE;
01473 
01474     crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize);
01475     if (crv != CKR_OK) {
01476        PORT_FreeArena(arena,PR_FALSE);
01477        PORT_SetError( PK11_MapError(crv) );
01478        return CK_INVALID_HANDLE;
01479     }
01480 
01481     if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) {
01482        PORT_FreeArena(arena,PR_FALSE);
01483        PORT_SetError(SEC_ERROR_BAD_KEY);
01484        return CK_INVALID_HANDLE;
01485      }
01486        
01487        
01488 
01489     /*
01490      * issue the find
01491      */
01492     parent = *(CK_OBJECT_CLASS *)(keyclass->pValue);
01493     *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;
01494 
01495     peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
01496     PORT_FreeArena(arena,PR_FALSE);
01497 
01498     return peerID;
01499 }
01500 
01501 /*
01502  * count the number of objects that match the template.
01503  */
01504 int
01505 PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, 
01506                                                  int templateCount)
01507 {
01508     CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE];
01509     int object_count = 0;
01510     CK_ULONG returned_count = 0;
01511     CK_RV crv;
01512 
01513     PK11_EnterSlotMonitor(slot);
01514     crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session,
01515                                    findTemplate, templateCount);
01516     if (crv != CKR_OK) {
01517         PK11_ExitSlotMonitor(slot);
01518        PORT_SetError( PK11_MapError(crv) );
01519        return 0;
01520     }
01521 
01522     /*
01523      * collect all the Matching Objects
01524      */
01525     do {
01526        crv = PK11_GETTAB(slot)->C_FindObjects(slot->session,
01527                             objID,PK11_SEARCH_CHUNKSIZE,&returned_count);
01528        if (crv != CKR_OK) {
01529            PORT_SetError( PK11_MapError(crv) );
01530            break;
01531        }
01532        object_count += returned_count;
01533     } while (returned_count == PK11_SEARCH_CHUNKSIZE);
01534 
01535     PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);
01536     PK11_ExitSlotMonitor(slot);
01537     return object_count;
01538 }
01539 
01540 /*
01541  * Traverse all the objects in a given slot.
01542  */
01543 SECStatus
01544 PK11_TraverseSlot(PK11SlotInfo *slot, void *arg)
01545 {
01546     int i;
01547     CK_OBJECT_HANDLE *objID = NULL;
01548     int object_count = 0;
01549     pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg;
01550 
01551     objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate,
01552               slotcb->templateCount,&object_count);
01553 
01554     /*Actually this isn't a failure... there just were no objs to be found*/
01555     if (object_count == 0) {
01556        return SECSuccess;
01557     }
01558 
01559     if (objID == NULL) {
01560        return SECFailure;
01561     }
01562 
01563     for (i=0; i < object_count; i++) {
01564        (*slotcb->callback)(slot,objID[i],slotcb->callbackArg);
01565     }
01566     PORT_Free(objID);
01567     return SECSuccess;
01568 }
01569 
01570 /*
01571  * Traverse all the objects in all slots.
01572  */
01573 SECStatus
01574 pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), 
01575                             void *arg, PRBool forceLogin, void *wincx) {
01576     PK11SlotList *list;
01577     PK11SlotListElement *le;
01578     SECStatus rv;
01579 
01580     /* get them all! */
01581     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx);
01582     if (list == NULL) return SECFailure;
01583 
01584     /* look at each slot and authenticate as necessary */
01585     for (le = list->head ; le; le = le->next) {
01586        if (forceLogin) {
01587            rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx);
01588            if (rv != SECSuccess) {
01589               continue;
01590            }
01591        }
01592        if (callback) {
01593            (*callback)(le->slot,arg);
01594        }
01595     }
01596 
01597     PK11_FreeSlotList(list);
01598 
01599     return SECSuccess;
01600 }
01601 
01602 CK_OBJECT_HANDLE *
01603 PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr,
01604               CK_OBJECT_CLASS objclass, int *returnCount, void *wincx)
01605 {
01606     char *tokenName;
01607     char *delimit;
01608     PK11SlotInfo *slot;
01609     CK_OBJECT_HANDLE *objID;
01610     CK_ATTRIBUTE findTemplate[] = {
01611         { CKA_LABEL, NULL, 0},
01612         { CKA_CLASS, NULL, 0},
01613     };
01614     int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]);
01615     SECStatus rv;
01616     PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass));
01617 
01618     *slotptr = slot = NULL;
01619     *returnCount = 0;
01620     /* first find the slot associated with this nickname */
01621     if ((delimit = PORT_Strchr(nickname,':')) != NULL) {
01622        int len = delimit - nickname;
01623        tokenName = (char*)PORT_Alloc(len+1);
01624        PORT_Memcpy(tokenName,nickname,len);
01625        tokenName[len] = 0;
01626 
01627         slot = *slotptr = PK11_FindSlotByName(tokenName);
01628         PORT_Free(tokenName);
01629        /* if we couldn't find a slot, assume the nickname is an internal cert
01630         * with no proceding slot name */
01631        if (slot == NULL) {
01632               slot = *slotptr = PK11_GetInternalKeySlot();
01633        } else {
01634               nickname = delimit+1;
01635        }
01636     } else {
01637        *slotptr = slot = PK11_GetInternalKeySlot();
01638     }
01639     if (slot == NULL) {
01640         return CK_INVALID_HANDLE;
01641     }
01642 
01643     rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
01644     if (rv != SECSuccess) {
01645        PK11_FreeSlot(slot);
01646        *slotptr = NULL;
01647        return CK_INVALID_HANDLE;
01648     }
01649 
01650     findTemplate[0].pValue = nickname;
01651     findTemplate[0].ulValueLen = PORT_Strlen(nickname);
01652     objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount);
01653     if (objID == NULL) {
01654        /* PKCS #11 isn't clear on whether or not the NULL is
01655         * stored in the template.... try the find again with the
01656         * full null terminated string. */
01657        findTemplate[0].ulValueLen += 1;
01658         objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,
01659                                                         returnCount);
01660        if (objID == NULL) {
01661            /* Well that's the best we can do. It's just not here */
01662            /* what about faked nicknames? */
01663            PK11_FreeSlot(slot);
01664            *slotptr = NULL;
01665            *returnCount = 0;
01666        }
01667     }
01668 
01669     return objID;
01670 }
01671 
01672 SECItem *
01673 pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) 
01674 {
01675     CK_ATTRIBUTE theTemplate[] = {
01676        { CKA_ID, NULL, 0 },
01677     };
01678     int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
01679     CK_RV crv;
01680     SECItem *item;
01681 
01682     item = SECITEM_AllocItem(NULL, NULL, 0);
01683 
01684     if (item == NULL) {
01685        return NULL;
01686     }
01687 
01688     crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize);
01689     if (crv != CKR_OK) {
01690        SECITEM_FreeItem(item,PR_TRUE);
01691        PORT_SetError( PK11_MapError(crv) );
01692        return NULL;
01693     }
01694 
01695     item->data = (unsigned char*) theTemplate[0].pValue;
01696     item->len =theTemplate[0].ulValueLen;
01697 
01698     return item;
01699 }
01700