cfind.c 18 KB

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