Back to index

lightning-sunbird  0.9+nobinonly
cfind.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  * Portions created by Red Hat, Inc, are Copyright (C) 2005
00021  *
00022  * Contributor(s):
00023  *   Bob Relyea (rrelyea@redhat.com)
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 #ifdef DEBUG
00039 static const char CVS_ID[] = "@(#) $RCSfile: cfind.c,v $ $Revision: 1.2 $ $Date: 2005/11/15 00:13:58 $";
00040 #endif /* DEBUG */
00041 
00042 #ifndef CKCAPI_H
00043 #include "ckcapi.h"
00044 #endif /* CKCAPI_H */
00045 
00046 /*
00047  * ckcapi/cfind.c
00048  *
00049  * This file implements the NSSCKMDFindObjects object for the
00050  * "capi" cryptoki module.
00051  */
00052 
00053 struct ckcapiFOStr {
00054   NSSArena *arena;
00055   CK_ULONG n;
00056   CK_ULONG i;
00057   ckcapiInternalObject **objs;
00058 };
00059 
00060 static void
00061 ckcapi_mdFindObjects_Final
00062 (
00063   NSSCKMDFindObjects *mdFindObjects,
00064   NSSCKFWFindObjects *fwFindObjects,
00065   NSSCKMDSession *mdSession,
00066   NSSCKFWSession *fwSession,
00067   NSSCKMDToken *mdToken,
00068   NSSCKFWToken *fwToken,
00069   NSSCKMDInstance *mdInstance,
00070   NSSCKFWInstance *fwInstance
00071 )
00072 {
00073   struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc;
00074   NSSArena *arena = fo->arena;
00075   PRUint32 i;
00076 
00077   /* walk down an free the unused 'objs' */
00078   for (i=fo->i; i < fo->n ; i++) {
00079     nss_ckcapi_DestroyInternalObject(fo->objs[i]);
00080   }
00081 
00082   nss_ZFreeIf(fo->objs);
00083   nss_ZFreeIf(fo);
00084   nss_ZFreeIf(mdFindObjects);
00085   if ((NSSArena *)NULL != arena) {
00086     NSSArena_Destroy(arena);
00087   }
00088 
00089   return;
00090 }
00091 
00092 static NSSCKMDObject *
00093 ckcapi_mdFindObjects_Next
00094 (
00095   NSSCKMDFindObjects *mdFindObjects,
00096   NSSCKFWFindObjects *fwFindObjects,
00097   NSSCKMDSession *mdSession,
00098   NSSCKFWSession *fwSession,
00099   NSSCKMDToken *mdToken,
00100   NSSCKFWToken *fwToken,
00101   NSSCKMDInstance *mdInstance,
00102   NSSCKFWInstance *fwInstance,
00103   NSSArena *arena,
00104   CK_RV *pError
00105 )
00106 {
00107   struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc;
00108   ckcapiInternalObject *io;
00109 
00110   if( fo->i == fo->n ) {
00111     *pError = CKR_OK;
00112     return (NSSCKMDObject *)NULL;
00113   }
00114 
00115   io = fo->objs[ fo->i ];
00116   fo->i++;
00117 
00118   return nss_ckcapi_CreateMDObject(arena, io, pError);
00119 }
00120 
00121 static CK_BBOOL
00122 ckcapi_attrmatch
00123 (
00124   CK_ATTRIBUTE_PTR a,
00125   ckcapiInternalObject *o
00126 )
00127 {
00128   PRBool prb;
00129   const NSSItem *b;
00130 
00131   b = nss_ckcapi_FetchAttribute(o, a->type);
00132   if (b == NULL) {
00133     return CK_FALSE;
00134   }
00135 
00136   if( a->ulValueLen != b->size ) {
00137     /* match a decoded serial number */
00138     if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) {
00139        int len;
00140        unsigned char *data;
00141 
00142        data = nss_ckcapi_DERUnwrap(b->data, b->size, &len, NULL);
00143        if ((len == a->ulValueLen) && 
00144               nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) {
00145            return CK_TRUE;
00146        }
00147     }
00148     return CK_FALSE;
00149   }
00150 
00151   prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL);
00152 
00153   if( PR_TRUE == prb ) {
00154     return CK_TRUE;
00155   } else {
00156     return CK_FALSE;
00157   }
00158 }
00159 
00160 
00161 static CK_BBOOL
00162 ckcapi_match
00163 (
00164   CK_ATTRIBUTE_PTR pTemplate,
00165   CK_ULONG ulAttributeCount,
00166   ckcapiInternalObject *o
00167 )
00168 {
00169   CK_ULONG i;
00170 
00171   for( i = 0; i < ulAttributeCount; i++ ) {
00172     if (CK_FALSE == ckcapi_attrmatch(&pTemplate[i], o)) {
00173       return CK_FALSE;
00174     }
00175   }
00176 
00177   /* Every attribute passed */
00178   return CK_TRUE;
00179 }
00180 
00181 #define CKAPI_ITEM_CHUNK  20
00182 
00183 #define PUT_Object(obj,err) \
00184   { \
00185     if (count >= size) { \
00186     *listp = *listp ? \
00187               nss_ZREALLOCARRAY(*listp, ckcapiInternalObject *, \
00188                              (size+CKAPI_ITEM_CHUNK) ) : \
00189               nss_ZNEWARRAY(NULL, ckcapiInternalObject *, \
00190                              (size+CKAPI_ITEM_CHUNK) ) ; \
00191       if ((ckcapiInternalObject **)NULL == *listp) { \
00192         err = CKR_HOST_MEMORY; \
00193         goto loser; \
00194       } \
00195       size += CKAPI_ITEM_CHUNK; \
00196     } \
00197     (*listp)[ count ] = (obj); \
00198     count++; \
00199   }
00200 
00201 
00202 /*
00203  * pass parameters back through the callback.
00204  */
00205 typedef struct BareCollectParamsStr {
00206   CK_OBJECT_CLASS objClass;
00207   CK_ATTRIBUTE_PTR pTemplate;
00208   CK_ULONG ulAttributeCount;
00209   ckcapiInternalObject ***listp;
00210   PRUint32 size;
00211   PRUint32 count;
00212 } BareCollectParams;
00213 
00214 /* collect_bare's callback. Called for each object that
00215  * supposedly has a PROVINDER_INFO property */
00216 static BOOL WINAPI
00217 doBareCollect
00218 (
00219   const CRYPT_HASH_BLOB *msKeyID,
00220   DWORD flags,
00221   void *reserved,
00222   void *args,
00223   DWORD cProp,
00224   DWORD *propID,
00225   void **propData,
00226   DWORD *propSize
00227 )
00228 {
00229   BareCollectParams *bcp = (BareCollectParams *) args;
00230   PRUint32 size = bcp->size;
00231   PRUint32 count = bcp->count;
00232   ckcapiInternalObject ***listp = bcp->listp;
00233   ckcapiInternalObject *io = NULL;
00234   DWORD i;
00235   CRYPT_KEY_PROV_INFO *keyProvInfo = NULL;
00236   void *idData;
00237   CK_RV error;
00238  
00239   /* make sure there is a Key Provider Info property */
00240   for (i=0; i < cProp; i++) {
00241     if (CERT_KEY_PROV_INFO_PROP_ID == propID[i]) {
00242        keyProvInfo = (CRYPT_KEY_PROV_INFO *)propData[i];
00243        break;
00244     }
00245   }
00246   if ((CRYPT_KEY_PROV_INFO *)NULL == keyProvInfo) {
00247     return 1;
00248   }
00249 
00250   /* copy the key ID */
00251   idData = nss_ZNEWARRAY(NULL, char, msKeyID->cbData);
00252   if ((void *)NULL == idData) {
00253      goto loser;
00254   }
00255   nsslibc_memcpy(idData, msKeyID->pbData, msKeyID->cbData);
00256 
00257   /* build a bare internal object */  
00258   io = nss_ZNEW(NULL, ckcapiInternalObject);
00259   if ((ckcapiInternalObject *)NULL == io) {
00260      goto loser;
00261   }
00262   io->type = ckcapiBareKey;
00263   io->objClass = bcp->objClass;
00264   io->u.key.provInfo = *keyProvInfo;
00265   io->u.key.provInfo.pwszContainerName = 
00266                      nss_ckcapi_WideDup(keyProvInfo->pwszContainerName);
00267   io->u.key.provInfo.pwszProvName = 
00268                      nss_ckcapi_WideDup(keyProvInfo->pwszProvName);
00269   io->u.key.provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName);
00270   io->u.key.containerName = 
00271                         nss_ckcapi_WideToUTF8(keyProvInfo->pwszContainerName);
00272   io->u.key.hProv = 0;
00273   io->idData = idData;
00274   io->id.data = idData;
00275   io->id.size = msKeyID->cbData;
00276   idData = NULL;
00277 
00278   /* see if it matches */ 
00279   if( CK_FALSE == ckcapi_match(bcp->pTemplate, bcp->ulAttributeCount, io) ) {
00280     goto loser;
00281   }
00282   PUT_Object(io, error);
00283   bcp->size = size;
00284   bcp->count = count;
00285   return 1;
00286 
00287 loser:
00288   if (io) {
00289     nss_ckcapi_DestroyInternalObject(io);
00290   }
00291   nss_ZFreeIf(idData);
00292   return 1;
00293 }
00294 
00295 /*
00296  * collect the bare keys running around
00297  */
00298 static PRUint32
00299 collect_bare(
00300   CK_OBJECT_CLASS objClass,
00301   CK_ATTRIBUTE_PTR pTemplate, 
00302   CK_ULONG ulAttributeCount, 
00303   ckcapiInternalObject ***listp,
00304   PRUint32 *sizep,
00305   PRUint32 count,
00306   CK_RV *pError
00307 )
00308 {
00309   BOOL rc;
00310   BareCollectParams bareCollectParams;
00311 
00312   bareCollectParams.objClass = objClass;
00313   bareCollectParams.pTemplate = pTemplate;
00314   bareCollectParams.ulAttributeCount = ulAttributeCount;
00315   bareCollectParams.listp = listp;
00316   bareCollectParams.size = *sizep;
00317   bareCollectParams.count = count;
00318 
00319   rc = CryptEnumKeyIdentifierProperties(NULL, CERT_KEY_PROV_INFO_PROP_ID, 0,
00320        NULL, NULL, &bareCollectParams, doBareCollect);
00321 
00322   *sizep = bareCollectParams.size;
00323   return bareCollectParams.count;
00324 }
00325 
00326 /* find all the certs that represent the appropriate object (cert, priv key, or
00327  *  pub key) in the cert store.
00328  */
00329 static PRUint32
00330 collect_class(
00331   CK_OBJECT_CLASS objClass,
00332   LPCSTR storeStr,
00333   PRBool hasID,
00334   CK_ATTRIBUTE_PTR pTemplate, 
00335   CK_ULONG ulAttributeCount, 
00336   ckcapiInternalObject ***listp,
00337   PRUint32 *sizep,
00338   PRUint32 count,
00339   CK_RV *pError
00340 )
00341 {
00342   PRUint32 size = *sizep;
00343   ckcapiInternalObject *next = NULL;
00344   HCERTSTORE hStore;
00345   PCCERT_CONTEXT certContext = NULL;
00346   PRBool  isKey = 
00347      (objClass == CKO_PUBLIC_KEY) | (objClass == CKO_PRIVATE_KEY);
00348 
00349   hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr);
00350   if (NULL == hStore) {
00351      return count; /* none found does not imply an error */
00352   }
00353 
00354   /* FUTURE: use CertFindCertificateInStore to filter better -- so we don't
00355    * have to enumerate all the certificates */
00356   while ((PCERT_CONTEXT) NULL != 
00357          (certContext= CertEnumCertificatesInStore(hStore, certContext))) {
00358     /* first filter out non user certs if we are looking for keys */
00359     if (isKey) {
00360       /* make sure there is a Key Provider Info property */
00361       CRYPT_KEY_PROV_INFO key_prov;
00362       DWORD size = sizeof(CRYPT_KEY_PROV_INFO);
00363       BOOL rv;
00364       rv =CertGetCertificateContextProperty(certContext,
00365         CERT_KEY_PROV_INFO_PROP_ID, &key_prov, &size);
00366       if (!rv) {
00367        int reason = GetLastError();
00368         /* we only care if it exists, we don't really need to fetch it yet */
00369        if (reason == CRYPT_E_NOT_FOUND) {
00370          continue;
00371        }
00372       }
00373     }
00374     
00375     if ((ckcapiInternalObject *)NULL == next) {
00376       next = nss_ZNEW(NULL, ckcapiInternalObject);
00377       if ((ckcapiInternalObject *)NULL == next) {
00378         *pError = CKR_HOST_MEMORY;
00379         goto loser;
00380       }
00381     }
00382     next->type = ckcapiCert;
00383     next->objClass = objClass;
00384     next->u.cert.certContext = certContext;
00385     next->u.cert.hasID = hasID;
00386     next->u.cert.certStore = storeStr;
00387     if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, next) ) {
00388       /* clear cached values that may be dependent on our old certContext */
00389       memset(&next->u.cert, 0, sizeof(next->u.cert));
00390       /* get a 'permanent' context */
00391       next->u.cert.certContext = CertDuplicateCertificateContext(certContext);
00392       next->objClass = objClass;
00393       next->u.cert.certContext = certContext;
00394       next->u.cert.hasID = hasID;
00395       next->u.cert.certStore = storeStr;
00396       PUT_Object(next, *pError);
00397       next = NULL; /* need to allocate a new one now */
00398     } else {
00399       /* don't cache the values we just loaded */
00400       memset(&next->u.cert, 0, sizeof(next->u.cert));
00401     }
00402   }
00403 loser:
00404   CertCloseStore(hStore, 0);
00405   nss_ZFreeIf(next);
00406   *sizep = size;
00407   return count;
00408 }
00409 
00410 NSS_IMPLEMENT PRUint32
00411 nss_ckcapi_collect_all_certs(
00412   CK_ATTRIBUTE_PTR pTemplate, 
00413   CK_ULONG ulAttributeCount, 
00414   ckcapiInternalObject ***listp,
00415   PRUint32 *sizep,
00416   PRUint32 count,
00417   CK_RV *pError
00418 )
00419 {
00420   count = collect_class(CKO_CERTIFICATE, "My", PR_TRUE, pTemplate, 
00421                      ulAttributeCount, listp, sizep, count, pError);
00422   count = collect_class(CKO_CERTIFICATE, "AddressBook", PR_FALSE, pTemplate, 
00423                         ulAttributeCount, listp, sizep, count, pError);
00424   count = collect_class(CKO_CERTIFICATE, "CA", PR_FALSE, pTemplate, 
00425                      ulAttributeCount, listp, sizep, count, pError);
00426   count = collect_class(CKO_CERTIFICATE, "Root", PR_FALSE, pTemplate, 
00427                      ulAttributeCount, listp, sizep, count, pError);
00428   count = collect_class(CKO_CERTIFICATE, "Trust", PR_FALSE, pTemplate, 
00429                      ulAttributeCount, listp, sizep, count, pError);
00430   count = collect_class(CKO_CERTIFICATE, "TrustedPeople", PR_FALSE, pTemplate, 
00431                         ulAttributeCount, listp, sizep, count, pError);
00432   count = collect_class(CKO_CERTIFICATE, "AuthRoot", PR_FALSE, pTemplate, 
00433                         ulAttributeCount, listp, sizep, count, pError);
00434   return count;
00435 }
00436 
00437 CK_OBJECT_CLASS
00438 ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate, 
00439                       CK_ULONG ulAttributeCount)
00440 {
00441   CK_ULONG i;
00442 
00443   for (i=0; i < ulAttributeCount; i++)
00444   {
00445     if (pTemplate[i].type == CKA_CLASS) {
00446       return *(CK_OBJECT_CLASS *) pTemplate[i].pValue;
00447     }
00448   }
00449   /* need to return a value that says 'fetch them all' */
00450   return CK_INVALID_HANDLE;
00451 }
00452 
00453 static PRUint32
00454 collect_objects(
00455   CK_ATTRIBUTE_PTR pTemplate, 
00456   CK_ULONG ulAttributeCount, 
00457   ckcapiInternalObject ***listp,
00458   CK_RV *pError
00459 )
00460 {
00461   PRUint32 i;
00462   PRUint32 count = 0;
00463   PRUint32 size = 0;
00464   CK_OBJECT_CLASS objClass;
00465 
00466   /*
00467    * first handle the static build in objects (if any)
00468    */
00469   for( i = 0; i < nss_ckcapi_nObjects; i++ ) {
00470     ckcapiInternalObject *o = (ckcapiInternalObject *)&nss_ckcapi_data[i];
00471 
00472     if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, o) ) {
00473       PUT_Object(o, *pError);
00474     }
00475   }
00476 
00477   /*
00478    * now handle the various object types
00479    */
00480   objClass = ckcapi_GetObjectClass(pTemplate, ulAttributeCount);
00481   *pError = CKR_OK;
00482   switch (objClass) {
00483   case CKO_CERTIFICATE:
00484     count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, 
00485                               &size, count, pError);
00486     break;
00487   case CKO_PUBLIC_KEY:
00488     count = collect_class(objClass, "My", PR_TRUE, pTemplate, 
00489                      ulAttributeCount, listp, &size, count, pError);
00490     count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
00491                      &size, count, pError);
00492     break;
00493   case CKO_PRIVATE_KEY:
00494     count = collect_class(objClass, "My", PR_TRUE, pTemplate, 
00495                      ulAttributeCount, listp, &size, count, pError);
00496     count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
00497                      &size, count, pError);
00498     break;
00499   /* all of them */
00500   case CK_INVALID_HANDLE:
00501     count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, 
00502                               &size, count, pError);
00503     count = collect_class(CKO_PUBLIC_KEY, "My", PR_TRUE, pTemplate, 
00504                      ulAttributeCount, listp, &size, count, pError);
00505     count = collect_bare(CKO_PUBLIC_KEY, pTemplate, ulAttributeCount, listp,
00506                      &size, count, pError);
00507     count = collect_class(CKO_PRIVATE_KEY, "My", PR_TRUE, pTemplate, 
00508                      ulAttributeCount, listp, &size, count, pError);
00509     count = collect_bare(CKO_PRIVATE_KEY, pTemplate, ulAttributeCount, listp,
00510                      &size, count, pError);
00511     break;
00512   default:
00513     goto done; /* no other object types we understand in this module */
00514   }
00515   if (CKR_OK != *pError) {
00516     goto loser;
00517   }
00518 
00519 
00520 done:
00521   return count;
00522 loser:
00523   nss_ZFreeIf(*listp);
00524   return 0;
00525 }
00526 
00527 
00528 
00529 NSS_IMPLEMENT NSSCKMDFindObjects *
00530 nss_ckcapi_FindObjectsInit
00531 (
00532   NSSCKFWSession *fwSession,
00533   CK_ATTRIBUTE_PTR pTemplate,
00534   CK_ULONG ulAttributeCount,
00535   CK_RV *pError
00536 )
00537 {
00538   /* This could be made more efficient.  I'm rather rushed. */
00539   NSSArena *arena;
00540   NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL;
00541   struct ckcapiFOStr *fo = (struct ckcapiFOStr *)NULL;
00542   ckcapiInternalObject **temp = (ckcapiInternalObject **)NULL;
00543 
00544   arena = NSSArena_Create();
00545   if( (NSSArena *)NULL == arena ) {
00546     goto loser;
00547   }
00548 
00549   rv = nss_ZNEW(arena, NSSCKMDFindObjects);
00550   if( (NSSCKMDFindObjects *)NULL == rv ) {
00551     *pError = CKR_HOST_MEMORY;
00552     goto loser;
00553   }
00554 
00555   fo = nss_ZNEW(arena, struct ckcapiFOStr);
00556   if( (struct ckcapiFOStr *)NULL == fo ) {
00557     *pError = CKR_HOST_MEMORY;
00558     goto loser;
00559   }
00560 
00561   fo->arena = arena;
00562   /* fo->n and fo->i are already zero */
00563 
00564   rv->etc = (void *)fo;
00565   rv->Final = ckcapi_mdFindObjects_Final;
00566   rv->Next = ckcapi_mdFindObjects_Next;
00567   rv->null = (void *)NULL;
00568 
00569   fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError);
00570   if (*pError != CKR_OK) {
00571     goto loser;
00572   }
00573 
00574   fo->objs = nss_ZNEWARRAY(arena, ckcapiInternalObject *, fo->n);
00575   if( (ckcapiInternalObject **)NULL == fo->objs ) {
00576     *pError = CKR_HOST_MEMORY;
00577     goto loser;
00578   }
00579 
00580   (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckcapiInternalObject *) * fo->n);
00581   nss_ZFreeIf(temp);
00582   temp = (ckcapiInternalObject **)NULL;
00583 
00584   return rv;
00585 
00586  loser:
00587   nss_ZFreeIf(temp);
00588   nss_ZFreeIf(fo);
00589   nss_ZFreeIf(rv);
00590   if ((NSSArena *)NULL != arena) {
00591      NSSArena_Destroy(arena);
00592   }
00593   return (NSSCKMDFindObjects *)NULL;
00594 }
00595