security/nss/lib/ckfw/capi/cfind.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/. */
     5 #ifndef CKCAPI_H
     6 #include "ckcapi.h"
     7 #endif /* CKCAPI_H */
     9 /*
    10  * ckcapi/cfind.c
    11  *
    12  * This file implements the NSSCKMDFindObjects object for the
    13  * "capi" cryptoki module.
    14  */
    16 struct ckcapiFOStr {
    17   NSSArena *arena;
    18   CK_ULONG n;
    19   CK_ULONG i;
    20   ckcapiInternalObject **objs;
    21 };
    23 static void
    24 ckcapi_mdFindObjects_Final
    25 (
    26   NSSCKMDFindObjects *mdFindObjects,
    27   NSSCKFWFindObjects *fwFindObjects,
    28   NSSCKMDSession *mdSession,
    29   NSSCKFWSession *fwSession,
    30   NSSCKMDToken *mdToken,
    31   NSSCKFWToken *fwToken,
    32   NSSCKMDInstance *mdInstance,
    33   NSSCKFWInstance *fwInstance
    34 )
    35 {
    36   struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc;
    37   NSSArena *arena = fo->arena;
    38   PRUint32 i;
    40   /* walk down an free the unused 'objs' */
    41   for (i=fo->i; i < fo->n ; i++) {
    42     nss_ckcapi_DestroyInternalObject(fo->objs[i]);
    43   }
    45   nss_ZFreeIf(fo->objs);
    46   nss_ZFreeIf(fo);
    47   nss_ZFreeIf(mdFindObjects);
    48   if ((NSSArena *)NULL != arena) {
    49     NSSArena_Destroy(arena);
    50   }
    52   return;
    53 }
    55 static NSSCKMDObject *
    56 ckcapi_mdFindObjects_Next
    57 (
    58   NSSCKMDFindObjects *mdFindObjects,
    59   NSSCKFWFindObjects *fwFindObjects,
    60   NSSCKMDSession *mdSession,
    61   NSSCKFWSession *fwSession,
    62   NSSCKMDToken *mdToken,
    63   NSSCKFWToken *fwToken,
    64   NSSCKMDInstance *mdInstance,
    65   NSSCKFWInstance *fwInstance,
    66   NSSArena *arena,
    67   CK_RV *pError
    68 )
    69 {
    70   struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc;
    71   ckcapiInternalObject *io;
    73   if( fo->i == fo->n ) {
    74     *pError = CKR_OK;
    75     return (NSSCKMDObject *)NULL;
    76   }
    78   io = fo->objs[ fo->i ];
    79   fo->i++;
    81   return nss_ckcapi_CreateMDObject(arena, io, pError);
    82 }
    84 static CK_BBOOL
    85 ckcapi_attrmatch
    86 (
    87   CK_ATTRIBUTE_PTR a,
    88   ckcapiInternalObject *o
    89 )
    90 {
    91   PRBool prb;
    92   const NSSItem *b;
    94   b = nss_ckcapi_FetchAttribute(o, a->type);
    95   if (b == NULL) {
    96     return CK_FALSE;
    97   }
    99   if( a->ulValueLen != b->size ) {
   100     /* match a decoded serial number */
   101     if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) {
   102 	unsigned int len;
   103 	unsigned char *data;
   105 	data = nss_ckcapi_DERUnwrap(b->data, b->size, &len, NULL);
   106 	if ((len == a->ulValueLen) && 
   107 		nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) {
   108 	    return CK_TRUE;
   109 	}
   110     }
   111     return CK_FALSE;
   112   }
   114   prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL);
   116   if( PR_TRUE == prb ) {
   117     return CK_TRUE;
   118   } else {
   119     return CK_FALSE;
   120   }
   121 }
   124 static CK_BBOOL
   125 ckcapi_match
   126 (
   127   CK_ATTRIBUTE_PTR pTemplate,
   128   CK_ULONG ulAttributeCount,
   129   ckcapiInternalObject *o
   130 )
   131 {
   132   CK_ULONG i;
   134   for( i = 0; i < ulAttributeCount; i++ ) {
   135     if (CK_FALSE == ckcapi_attrmatch(&pTemplate[i], o)) {
   136       return CK_FALSE;
   137     }
   138   }
   140   /* Every attribute passed */
   141   return CK_TRUE;
   142 }
   144 #define CKAPI_ITEM_CHUNK  20
   146 #define PUT_Object(obj,err) \
   147   { \
   148     if (count >= size) { \
   149     *listp = *listp ? \
   150 		nss_ZREALLOCARRAY(*listp, ckcapiInternalObject *, \
   151 		               (size+CKAPI_ITEM_CHUNK) ) : \
   152 		nss_ZNEWARRAY(NULL, ckcapiInternalObject *, \
   153 		               (size+CKAPI_ITEM_CHUNK) ) ; \
   154       if ((ckcapiInternalObject **)NULL == *listp) { \
   155         err = CKR_HOST_MEMORY; \
   156         goto loser; \
   157       } \
   158       size += CKAPI_ITEM_CHUNK; \
   159     } \
   160     (*listp)[ count ] = (obj); \
   161     count++; \
   162   }
   165 /*
   166  * pass parameters back through the callback.
   167  */
   168 typedef struct BareCollectParamsStr {
   169   CK_OBJECT_CLASS objClass;
   170   CK_ATTRIBUTE_PTR pTemplate;
   171   CK_ULONG ulAttributeCount;
   172   ckcapiInternalObject ***listp;
   173   PRUint32 size;
   174   PRUint32 count;
   175 } BareCollectParams;
   177 /* collect_bare's callback. Called for each object that
   178  * supposedly has a PROVINDER_INFO property */
   179 static BOOL WINAPI
   180 doBareCollect
   181 (
   182   const CRYPT_HASH_BLOB *msKeyID,
   183   DWORD flags,
   184   void *reserved,
   185   void *args,
   186   DWORD cProp,
   187   DWORD *propID,
   188   void **propData,
   189   DWORD *propSize
   190 )
   191 {
   192   BareCollectParams *bcp = (BareCollectParams *) args;
   193   PRUint32 size = bcp->size;
   194   PRUint32 count = bcp->count;
   195   ckcapiInternalObject ***listp = bcp->listp;
   196   ckcapiInternalObject *io = NULL;
   197   DWORD i;
   198   CRYPT_KEY_PROV_INFO *keyProvInfo = NULL;
   199   void *idData;
   200   CK_RV error;
   202   /* make sure there is a Key Provider Info property */
   203   for (i=0; i < cProp; i++) {
   204     if (CERT_KEY_PROV_INFO_PROP_ID == propID[i]) {
   205 	keyProvInfo = (CRYPT_KEY_PROV_INFO *)propData[i];
   206 	break;
   207     }
   208   }
   209   if ((CRYPT_KEY_PROV_INFO *)NULL == keyProvInfo) {
   210     return 1;
   211   }
   213   /* copy the key ID */
   214   idData = nss_ZNEWARRAY(NULL, char, msKeyID->cbData);
   215   if ((void *)NULL == idData) {
   216      goto loser;
   217   }
   218   nsslibc_memcpy(idData, msKeyID->pbData, msKeyID->cbData);
   220   /* build a bare internal object */  
   221   io = nss_ZNEW(NULL, ckcapiInternalObject);
   222   if ((ckcapiInternalObject *)NULL == io) {
   223      goto loser;
   224   }
   225   io->type = ckcapiBareKey;
   226   io->objClass = bcp->objClass;
   227   io->u.key.provInfo = *keyProvInfo;
   228   io->u.key.provInfo.pwszContainerName = 
   229 			nss_ckcapi_WideDup(keyProvInfo->pwszContainerName);
   230   io->u.key.provInfo.pwszProvName = 
   231 			nss_ckcapi_WideDup(keyProvInfo->pwszProvName);
   232   io->u.key.provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName);
   233   io->u.key.containerName = 
   234                         nss_ckcapi_WideToUTF8(keyProvInfo->pwszContainerName);
   235   io->u.key.hProv = 0;
   236   io->idData = idData;
   237   io->id.data = idData;
   238   io->id.size = msKeyID->cbData;
   239   idData = NULL;
   241   /* see if it matches */ 
   242   if( CK_FALSE == ckcapi_match(bcp->pTemplate, bcp->ulAttributeCount, io) ) {
   243     goto loser;
   244   }
   245   PUT_Object(io, error);
   246   bcp->size = size;
   247   bcp->count = count;
   248   return 1;
   250 loser:
   251   if (io) {
   252     nss_ckcapi_DestroyInternalObject(io);
   253   }
   254   nss_ZFreeIf(idData);
   255   return 1;
   256 }
   258 /*
   259  * collect the bare keys running around
   260  */
   261 static PRUint32
   262 collect_bare(
   263   CK_OBJECT_CLASS objClass,
   264   CK_ATTRIBUTE_PTR pTemplate, 
   265   CK_ULONG ulAttributeCount, 
   266   ckcapiInternalObject ***listp,
   267   PRUint32 *sizep,
   268   PRUint32 count,
   269   CK_RV *pError
   270 )
   271 {
   272   BOOL rc;
   273   BareCollectParams bareCollectParams;
   275   bareCollectParams.objClass = objClass;
   276   bareCollectParams.pTemplate = pTemplate;
   277   bareCollectParams.ulAttributeCount = ulAttributeCount;
   278   bareCollectParams.listp = listp;
   279   bareCollectParams.size = *sizep;
   280   bareCollectParams.count = count;
   282   rc = CryptEnumKeyIdentifierProperties(NULL, CERT_KEY_PROV_INFO_PROP_ID, 0,
   283        NULL, NULL, &bareCollectParams, doBareCollect);
   285   *sizep = bareCollectParams.size;
   286   return bareCollectParams.count;
   287 }
   289 /* find all the certs that represent the appropriate object (cert, priv key, or
   290  *  pub key) in the cert store.
   291  */
   292 static PRUint32
   293 collect_class(
   294   CK_OBJECT_CLASS objClass,
   295   LPCSTR storeStr,
   296   PRBool hasID,
   297   CK_ATTRIBUTE_PTR pTemplate, 
   298   CK_ULONG ulAttributeCount, 
   299   ckcapiInternalObject ***listp,
   300   PRUint32 *sizep,
   301   PRUint32 count,
   302   CK_RV *pError
   303 )
   304 {
   305   PRUint32 size = *sizep;
   306   ckcapiInternalObject *next = NULL;
   307   HCERTSTORE hStore;
   308   PCCERT_CONTEXT certContext = NULL;
   309   PRBool  isKey = 
   310      (objClass == CKO_PUBLIC_KEY) | (objClass == CKO_PRIVATE_KEY);
   312   hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr);
   313   if (NULL == hStore) {
   314      return count; /* none found does not imply an error */
   315   }
   317   /* FUTURE: use CertFindCertificateInStore to filter better -- so we don't
   318    * have to enumerate all the certificates */
   319   while ((PCERT_CONTEXT) NULL != 
   320          (certContext= CertEnumCertificatesInStore(hStore, certContext))) {
   321     /* first filter out non user certs if we are looking for keys */
   322     if (isKey) {
   323       /* make sure there is a Key Provider Info property */
   324       CRYPT_KEY_PROV_INFO *keyProvInfo;
   325       DWORD size = 0;
   326       BOOL rv;
   327       rv =CertGetCertificateContextProperty(certContext,
   328         CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
   329       if (!rv) {
   330 	int reason = GetLastError();
   331         /* we only care if it exists, we don't really need to fetch it yet */
   332 	if (reason == CRYPT_E_NOT_FOUND) {
   333 	  continue;
   334 	}
   335       }
   336       /* filter out the non-microsoft providers */
   337       keyProvInfo = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size);
   338       if (keyProvInfo) {
   339         rv =CertGetCertificateContextProperty(certContext,
   340           CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size);
   341         if (rv) {
   342 	  char *provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName);
   343           nss_ZFreeIf(keyProvInfo);
   345 	  if (provName && 
   346 		(strncmp(provName, "Microsoft", sizeof("Microsoft")-1) != 0)) {
   347 	    continue;
   348 	  }
   349 	} else {
   350 	  int reason = GetLastError();
   351           /* we only care if it exists, we don't really need to fetch it yet */
   352           nss_ZFreeIf(keyProvInfo);
   353 	  if (reason == CRYPT_E_NOT_FOUND) {
   354 	   continue;
   355 	  }
   357         }
   358       }
   359     }
   361     if ((ckcapiInternalObject *)NULL == next) {
   362       next = nss_ZNEW(NULL, ckcapiInternalObject);
   363       if ((ckcapiInternalObject *)NULL == next) {
   364         *pError = CKR_HOST_MEMORY;
   365         goto loser;
   366       }
   367     }
   368     next->type = ckcapiCert;
   369     next->objClass = objClass;
   370     next->u.cert.certContext = certContext;
   371     next->u.cert.hasID = hasID;
   372     next->u.cert.certStore = storeStr;
   373     if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, next) ) {
   374       /* clear cached values that may be dependent on our old certContext */
   375       memset(&next->u.cert, 0, sizeof(next->u.cert));
   376       /* get a 'permanent' context */
   377       next->u.cert.certContext = CertDuplicateCertificateContext(certContext);
   378       next->objClass = objClass;
   379       next->u.cert.certContext = certContext;
   380       next->u.cert.hasID = hasID;
   381       next->u.cert.certStore = storeStr;
   382       PUT_Object(next, *pError);
   383       next = NULL; /* need to allocate a new one now */
   384     } else {
   385       /* don't cache the values we just loaded */
   386       memset(&next->u.cert, 0, sizeof(next->u.cert));
   387     }
   388   }
   389 loser:
   390   CertCloseStore(hStore, 0);
   391   nss_ZFreeIf(next);
   392   *sizep = size;
   393   return count;
   394 }
   396 NSS_IMPLEMENT PRUint32
   397 nss_ckcapi_collect_all_certs(
   398   CK_ATTRIBUTE_PTR pTemplate, 
   399   CK_ULONG ulAttributeCount, 
   400   ckcapiInternalObject ***listp,
   401   PRUint32 *sizep,
   402   PRUint32 count,
   403   CK_RV *pError
   404 )
   405 {
   406   count = collect_class(CKO_CERTIFICATE, "My", PR_TRUE, pTemplate, 
   407 			ulAttributeCount, listp, sizep, count, pError);
   408   /*count = collect_class(CKO_CERTIFICATE, "AddressBook", PR_FALSE, pTemplate, 
   409                         ulAttributeCount, listp, sizep, count, pError); */
   410   count = collect_class(CKO_CERTIFICATE, "CA", PR_FALSE, pTemplate, 
   411 			ulAttributeCount, listp, sizep, count, pError);
   412   count = collect_class(CKO_CERTIFICATE, "Root", PR_FALSE, pTemplate, 
   413 			ulAttributeCount, listp, sizep, count, pError);
   414   count = collect_class(CKO_CERTIFICATE, "Trust", PR_FALSE, pTemplate, 
   415 			ulAttributeCount, listp, sizep, count, pError);
   416   count = collect_class(CKO_CERTIFICATE, "TrustedPeople", PR_FALSE, pTemplate, 
   417                         ulAttributeCount, listp, sizep, count, pError);
   418   count = collect_class(CKO_CERTIFICATE, "AuthRoot", PR_FALSE, pTemplate, 
   419                         ulAttributeCount, listp, sizep, count, pError);
   420   return count;
   421 }
   423 CK_OBJECT_CLASS
   424 ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate, 
   425                       CK_ULONG ulAttributeCount)
   426 {
   427   CK_ULONG i;
   429   for (i=0; i < ulAttributeCount; i++)
   430   {
   431     if (pTemplate[i].type == CKA_CLASS) {
   432       return *(CK_OBJECT_CLASS *) pTemplate[i].pValue;
   433     }
   434   }
   435   /* need to return a value that says 'fetch them all' */
   436   return CK_INVALID_HANDLE;
   437 }
   439 static PRUint32
   440 collect_objects(
   441   CK_ATTRIBUTE_PTR pTemplate, 
   442   CK_ULONG ulAttributeCount, 
   443   ckcapiInternalObject ***listp,
   444   CK_RV *pError
   445 )
   446 {
   447   PRUint32 i;
   448   PRUint32 count = 0;
   449   PRUint32 size = 0;
   450   CK_OBJECT_CLASS objClass;
   452   /*
   453    * first handle the static build in objects (if any)
   454    */
   455   for( i = 0; i < nss_ckcapi_nObjects; i++ ) {
   456     ckcapiInternalObject *o = (ckcapiInternalObject *)&nss_ckcapi_data[i];
   458     if( CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, o) ) {
   459       PUT_Object(o, *pError);
   460     }
   461   }
   463   /*
   464    * now handle the various object types
   465    */
   466   objClass = ckcapi_GetObjectClass(pTemplate, ulAttributeCount);
   467   *pError = CKR_OK;
   468   switch (objClass) {
   469   case CKO_CERTIFICATE:
   470     count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, 
   471                               &size, count, pError);
   472     break;
   473   case CKO_PUBLIC_KEY:
   474     count = collect_class(objClass, "My", PR_TRUE, pTemplate, 
   475 			ulAttributeCount, listp, &size, count, pError);
   476     count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
   477 			&size, count, pError);
   478     break;
   479   case CKO_PRIVATE_KEY:
   480     count = collect_class(objClass, "My", PR_TRUE, pTemplate, 
   481 			ulAttributeCount, listp, &size, count, pError);
   482     count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
   483 			&size, count, pError);
   484     break;
   485   /* all of them */
   486   case CK_INVALID_HANDLE:
   487     count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp, 
   488                               &size, count, pError);
   489     count = collect_class(CKO_PUBLIC_KEY, "My", PR_TRUE, pTemplate, 
   490 			ulAttributeCount, listp, &size, count, pError);
   491     count = collect_bare(CKO_PUBLIC_KEY, pTemplate, ulAttributeCount, listp,
   492 			&size, count, pError);
   493     count = collect_class(CKO_PRIVATE_KEY, "My", PR_TRUE, pTemplate, 
   494 			ulAttributeCount, listp, &size, count, pError);
   495     count = collect_bare(CKO_PRIVATE_KEY, pTemplate, ulAttributeCount, listp,
   496 			&size, count, pError);
   497     break;
   498   default:
   499     goto done; /* no other object types we understand in this module */
   500   }
   501   if (CKR_OK != *pError) {
   502     goto loser;
   503   }
   506 done:
   507   return count;
   508 loser:
   509   nss_ZFreeIf(*listp);
   510   return 0;
   511 }
   515 NSS_IMPLEMENT NSSCKMDFindObjects *
   516 nss_ckcapi_FindObjectsInit
   517 (
   518   NSSCKFWSession *fwSession,
   519   CK_ATTRIBUTE_PTR pTemplate,
   520   CK_ULONG ulAttributeCount,
   521   CK_RV *pError
   522 )
   523 {
   524   /* This could be made more efficient.  I'm rather rushed. */
   525   NSSArena *arena;
   526   NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL;
   527   struct ckcapiFOStr *fo = (struct ckcapiFOStr *)NULL;
   528   ckcapiInternalObject **temp = (ckcapiInternalObject **)NULL;
   530   arena = NSSArena_Create();
   531   if( (NSSArena *)NULL == arena ) {
   532     goto loser;
   533   }
   535   rv = nss_ZNEW(arena, NSSCKMDFindObjects);
   536   if( (NSSCKMDFindObjects *)NULL == rv ) {
   537     *pError = CKR_HOST_MEMORY;
   538     goto loser;
   539   }
   541   fo = nss_ZNEW(arena, struct ckcapiFOStr);
   542   if( (struct ckcapiFOStr *)NULL == fo ) {
   543     *pError = CKR_HOST_MEMORY;
   544     goto loser;
   545   }
   547   fo->arena = arena;
   548   /* fo->n and fo->i are already zero */
   550   rv->etc = (void *)fo;
   551   rv->Final = ckcapi_mdFindObjects_Final;
   552   rv->Next = ckcapi_mdFindObjects_Next;
   553   rv->null = (void *)NULL;
   555   fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError);
   556   if (*pError != CKR_OK) {
   557     goto loser;
   558   }
   560   fo->objs = nss_ZNEWARRAY(arena, ckcapiInternalObject *, fo->n);
   561   if( (ckcapiInternalObject **)NULL == fo->objs ) {
   562     *pError = CKR_HOST_MEMORY;
   563     goto loser;
   564   }
   566   (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckcapiInternalObject *) * fo->n);
   567   nss_ZFreeIf(temp);
   568   temp = (ckcapiInternalObject **)NULL;
   570   return rv;
   572  loser:
   573   nss_ZFreeIf(temp);
   574   nss_ZFreeIf(fo);
   575   nss_ZFreeIf(rv);
   576   if ((NSSArena *)NULL != arena) {
   577      NSSArena_Destroy(arena);
   578   }
   579   return (NSSCKMDFindObjects *)NULL;
   580 }

mercurial