PageRenderTime 64ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/security/nss/lib/softoken/sftkdb.c

http://github.com/zpao/v8monkey
C | 2770 lines | 1950 code | 275 blank | 545 comment | 574 complexity | 2cfb7015beb67e3f5fbe9ba30de64a93 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause, GPL-2.0, JSON, Apache-2.0, 0BSD
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. *
  4. * The contents of this file are subject to the Mozilla Public License Version
  5. * 1.1 (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. * http://www.mozilla.org/MPL/
  8. *
  9. * Software distributed under the License is distributed on an "AS IS" basis,
  10. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing rights and limitations under the
  12. * License.
  13. *
  14. * The Original Code is the Netscape security libraries.
  15. *
  16. * The Initial Developer of the Original Code is
  17. * Netscape Communications Corporation.
  18. * Portions created by the Initial Developer are Copyright (C) 1994-2007
  19. * the Initial Developer. All Rights Reserved.
  20. *
  21. * Contributor(s):
  22. *
  23. * Alternatively, the contents of this file may be used under the terms of
  24. * either the GNU General Public License Version 2 or later (the "GPL"), or
  25. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26. * in which case the provisions of the GPL or the LGPL are applicable instead
  27. * of those above. If you wish to allow use of your version of this file only
  28. * under the terms of either the GPL or the LGPL, and not to allow others to
  29. * use your version of this file under the terms of the MPL, indicate your
  30. * decision by deleting the provisions above and replace them with the notice
  31. * and other provisions required by the GPL or the LGPL. If you do not delete
  32. * the provisions above, a recipient may use your version of this file under
  33. * the terms of any one of the MPL, the GPL or the LGPL.
  34. *
  35. * ***** END LICENSE BLOCK ***** */
  36. /*
  37. * The following code handles the storage of PKCS 11 modules used by the
  38. * NSS. For the rest of NSS, only one kind of database handle exists:
  39. *
  40. * SFTKDBHandle
  41. *
  42. * There is one SFTKDBHandle for the each key database and one for each cert
  43. * database. These databases are opened as associated pairs, one pair per
  44. * slot. SFTKDBHandles are reference counted objects.
  45. *
  46. * Each SFTKDBHandle points to a low level database handle (SDB). This handle
  47. * represents the underlying physical database. These objects are not
  48. * reference counted, an are 'owned' by their respective SFTKDBHandles.
  49. *
  50. *
  51. */
  52. #include "sftkdb.h"
  53. #include "sftkdbti.h"
  54. #include "pkcs11t.h"
  55. #include "pkcs11i.h"
  56. #include "sdb.h"
  57. #include "prprf.h"
  58. #include "secmodt.h"
  59. #include "pratom.h"
  60. #include "lgglue.h"
  61. #include "sftkpars.h"
  62. #include "secerr.h"
  63. #include "softoken.h"
  64. /*
  65. * We want all databases to have the same binary representation independent of
  66. * endianness or length of the host architecture. In general PKCS #11 attributes
  67. * are endian/length independent except those attributes that pass CK_ULONG.
  68. *
  69. * The following functions fixes up the CK_ULONG type attributes so that the data
  70. * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
  71. * byte order values (big endian).
  72. */
  73. #define BBP 8
  74. static PRBool
  75. sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type)
  76. {
  77. switch(type) {
  78. case CKA_CERTIFICATE_CATEGORY:
  79. case CKA_CERTIFICATE_TYPE:
  80. case CKA_CLASS:
  81. case CKA_JAVA_MIDP_SECURITY_DOMAIN:
  82. case CKA_KEY_GEN_MECHANISM:
  83. case CKA_KEY_TYPE:
  84. case CKA_MECHANISM_TYPE:
  85. case CKA_MODULUS_BITS:
  86. case CKA_PRIME_BITS:
  87. case CKA_SUBPRIME_BITS:
  88. case CKA_VALUE_BITS:
  89. case CKA_VALUE_LEN:
  90. case CKA_TRUST_DIGITAL_SIGNATURE:
  91. case CKA_TRUST_NON_REPUDIATION:
  92. case CKA_TRUST_KEY_ENCIPHERMENT:
  93. case CKA_TRUST_DATA_ENCIPHERMENT:
  94. case CKA_TRUST_KEY_AGREEMENT:
  95. case CKA_TRUST_KEY_CERT_SIGN:
  96. case CKA_TRUST_CRL_SIGN:
  97. case CKA_TRUST_SERVER_AUTH:
  98. case CKA_TRUST_CLIENT_AUTH:
  99. case CKA_TRUST_CODE_SIGNING:
  100. case CKA_TRUST_EMAIL_PROTECTION:
  101. case CKA_TRUST_IPSEC_END_SYSTEM:
  102. case CKA_TRUST_IPSEC_TUNNEL:
  103. case CKA_TRUST_IPSEC_USER:
  104. case CKA_TRUST_TIME_STAMPING:
  105. case CKA_TRUST_STEP_UP_APPROVED:
  106. return PR_TRUE;
  107. default:
  108. break;
  109. }
  110. return PR_FALSE;
  111. }
  112. /* are the attributes private? */
  113. static PRBool
  114. sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type)
  115. {
  116. switch(type) {
  117. case CKA_VALUE:
  118. case CKA_PRIVATE_EXPONENT:
  119. case CKA_PRIME_1:
  120. case CKA_PRIME_2:
  121. case CKA_EXPONENT_1:
  122. case CKA_EXPONENT_2:
  123. case CKA_COEFFICIENT:
  124. return PR_TRUE;
  125. default:
  126. break;
  127. }
  128. return PR_FALSE;
  129. }
  130. /* These attributes must be authenticated with an hmac. */
  131. static PRBool
  132. sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type)
  133. {
  134. switch(type) {
  135. case CKA_MODULUS:
  136. case CKA_PUBLIC_EXPONENT:
  137. case CKA_CERT_SHA1_HASH:
  138. case CKA_CERT_MD5_HASH:
  139. case CKA_TRUST_SERVER_AUTH:
  140. case CKA_TRUST_CLIENT_AUTH:
  141. case CKA_TRUST_EMAIL_PROTECTION:
  142. case CKA_TRUST_CODE_SIGNING:
  143. case CKA_TRUST_STEP_UP_APPROVED:
  144. case CKA_NSS_OVERRIDE_EXTENSIONS:
  145. return PR_TRUE;
  146. default:
  147. break;
  148. }
  149. return PR_FALSE;
  150. }
  151. /*
  152. * convert a native ULONG to a database ulong. Database ulong's
  153. * are all 4 byte big endian values.
  154. */
  155. void
  156. sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value)
  157. {
  158. int i;
  159. for (i=0; i < SDB_ULONG_SIZE; i++) {
  160. data[i] = (value >> (SDB_ULONG_SIZE-1-i)*BBP) & 0xff;
  161. }
  162. }
  163. /*
  164. * convert a database ulong back to a native ULONG. (reverse of the above
  165. * function.
  166. */
  167. static CK_ULONG
  168. sftk_SDBULong2ULong(unsigned char *data)
  169. {
  170. int i;
  171. CK_ULONG value = 0;
  172. for (i=0; i < SDB_ULONG_SIZE; i++) {
  173. value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE-1-i)*BBP);
  174. }
  175. return value;
  176. }
  177. /*
  178. * fix up the input templates. Our fixed up ints are stored in data and must
  179. * be freed by the caller. The new template must also be freed. If there are no
  180. * CK_ULONG attributes, the orignal template is passed in as is.
  181. */
  182. static CK_ATTRIBUTE *
  183. sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
  184. unsigned char **dataOut)
  185. {
  186. int i;
  187. int ulongCount = 0;
  188. unsigned char *data;
  189. CK_ATTRIBUTE *ntemplate;
  190. *dataOut = NULL;
  191. /* first count the number of CK_ULONG attributes */
  192. for (i=0; i < count; i++) {
  193. /* Don't 'fixup' NULL values */
  194. if (!template[i].pValue) {
  195. continue;
  196. }
  197. if (template[i].ulValueLen == sizeof (CK_ULONG)) {
  198. if ( sftkdb_isULONGAttribute(template[i].type)) {
  199. ulongCount++;
  200. }
  201. }
  202. }
  203. /* no attributes to fixup, just call on through */
  204. if (ulongCount == 0) {
  205. return (CK_ATTRIBUTE *)template;
  206. }
  207. /* allocate space for new ULONGS */
  208. data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE*ulongCount);
  209. if (!data) {
  210. return NULL;
  211. }
  212. /* allocate new template */
  213. ntemplate = PORT_NewArray(CK_ATTRIBUTE,count);
  214. if (!ntemplate) {
  215. PORT_Free(data);
  216. return NULL;
  217. }
  218. *dataOut = data;
  219. /* copy the old template, fixup the actual ulongs */
  220. for (i=0; i < count; i++) {
  221. ntemplate[i] = template[i];
  222. /* Don't 'fixup' NULL values */
  223. if (!template[i].pValue) {
  224. continue;
  225. }
  226. if (template[i].ulValueLen == sizeof (CK_ULONG)) {
  227. if ( sftkdb_isULONGAttribute(template[i].type) ) {
  228. CK_ULONG value = *(CK_ULONG *) template[i].pValue;
  229. sftk_ULong2SDBULong(data, value);
  230. ntemplate[i].pValue = data;
  231. ntemplate[i].ulValueLen = SDB_ULONG_SIZE;
  232. data += SDB_ULONG_SIZE;
  233. }
  234. }
  235. }
  236. return ntemplate;
  237. }
  238. static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x";
  239. /*
  240. * return a string describing the database type (key or cert)
  241. */
  242. const char *
  243. sftkdb_TypeString(SFTKDBHandle *handle)
  244. {
  245. return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert";
  246. }
  247. /*
  248. * Some attributes are signed with an Hmac and a pbe key generated from
  249. * the password. This signature is stored indexed by object handle and
  250. * attribute type in the meta data table in the key database.
  251. *
  252. * Signature entries are indexed by the string
  253. * sig_[cert/key]_{ObjectID}_{Attribute}
  254. *
  255. * This function fetches that pkcs5 signature. Caller supplies a SECItem
  256. * pre-allocated to the appropriate size if the SECItem is too small the
  257. * function will fail with CKR_BUFFER_TOO_SMALL.
  258. */
  259. static CK_RV
  260. sftkdb_getAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle,
  261. CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
  262. SECItem *signText)
  263. {
  264. SDB *db;
  265. char id[30];
  266. CK_RV crv;
  267. db = SFTK_GET_SDB(keyHandle);
  268. sprintf(id, SFTKDB_META_SIG_TEMPLATE,
  269. sftkdb_TypeString(handle),
  270. (unsigned int)objectID, (unsigned int)type);
  271. crv = (*db->sdb_GetMetaData)(db, id, signText, NULL);
  272. return crv;
  273. }
  274. /*
  275. * Some attributes are signed with an Hmac and a pbe key generated from
  276. * the password. This signature is stored indexed by object handle and
  277. * attribute type in the meta data table in the key database.
  278. *
  279. * Signature entries are indexed by the string
  280. * sig_[cert/key]_{ObjectID}_{Attribute}
  281. *
  282. * This function stores that pkcs5 signature.
  283. */
  284. CK_RV
  285. sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget,
  286. CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
  287. SECItem *signText)
  288. {
  289. char id[30];
  290. CK_RV crv;
  291. sprintf(id, SFTKDB_META_SIG_TEMPLATE,
  292. sftkdb_TypeString(handle),
  293. (unsigned int)objectID, (unsigned int)type);
  294. crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL);
  295. return crv;
  296. }
  297. /*
  298. * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated
  299. * separate data sections for the database ULONG values.
  300. */
  301. static CK_RV
  302. sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID,
  303. CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle)
  304. {
  305. int i;
  306. CK_RV crv = CKR_OK;
  307. SFTKDBHandle *keyHandle;
  308. PRBool checkSig = PR_TRUE;
  309. PRBool checkEnc = PR_TRUE;
  310. PORT_Assert(handle);
  311. /* find the key handle */
  312. keyHandle = handle;
  313. if (handle->type != SFTK_KEYDB_TYPE) {
  314. checkEnc = PR_FALSE;
  315. keyHandle = handle->peerDB;
  316. }
  317. if ((keyHandle == NULL) ||
  318. ((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) ||
  319. (keyHandle->passwordKey.data == NULL)) {
  320. checkSig = PR_FALSE;
  321. }
  322. for (i=0; i < count; i++) {
  323. CK_ULONG length = template[i].ulValueLen;
  324. template[i].ulValueLen = ntemplate[i].ulValueLen;
  325. /* fixup ulongs */
  326. if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) {
  327. if (sftkdb_isULONGAttribute(template[i].type)) {
  328. if (template[i].pValue) {
  329. CK_ULONG value;
  330. unsigned char *data;
  331. data = (unsigned char *)ntemplate[i].pValue;
  332. value = sftk_SDBULong2ULong(ntemplate[i].pValue);
  333. if (length < sizeof(CK_ULONG)) {
  334. template[i].ulValueLen = -1;
  335. crv = CKR_BUFFER_TOO_SMALL;
  336. continue;
  337. }
  338. PORT_Memcpy(template[i].pValue,&value,sizeof(CK_ULONG));
  339. }
  340. template[i].ulValueLen = sizeof(CK_ULONG);
  341. }
  342. }
  343. /* if no data was retrieved, no need to process encrypted or signed
  344. * attributes */
  345. if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) {
  346. continue;
  347. }
  348. /* fixup private attributes */
  349. if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) {
  350. /* we have a private attribute */
  351. /* This code depends on the fact that the cipherText is bigger
  352. * than the plain text */
  353. SECItem cipherText;
  354. SECItem *plainText;
  355. SECStatus rv;
  356. cipherText.data = ntemplate[i].pValue;
  357. cipherText.len = ntemplate[i].ulValueLen;
  358. PZ_Lock(handle->passwordLock);
  359. if (handle->passwordKey.data == NULL) {
  360. PZ_Unlock(handle->passwordLock);
  361. template[i].ulValueLen = -1;
  362. crv = CKR_USER_NOT_LOGGED_IN;
  363. continue;
  364. }
  365. rv = sftkdb_DecryptAttribute(&handle->passwordKey,
  366. &cipherText, &plainText);
  367. PZ_Unlock(handle->passwordLock);
  368. if (rv != SECSuccess) {
  369. PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
  370. template[i].ulValueLen = -1;
  371. crv = CKR_GENERAL_ERROR;
  372. continue;
  373. }
  374. PORT_Assert(template[i].ulValueLen >= plainText->len);
  375. if (template[i].ulValueLen < plainText->len) {
  376. SECITEM_FreeItem(plainText,PR_TRUE);
  377. PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
  378. template[i].ulValueLen = -1;
  379. crv = CKR_GENERAL_ERROR;
  380. continue;
  381. }
  382. /* copy the plain text back into the template */
  383. PORT_Memcpy(template[i].pValue, plainText->data, plainText->len);
  384. template[i].ulValueLen = plainText->len;
  385. SECITEM_FreeItem(plainText,PR_TRUE);
  386. }
  387. /* make sure signed attributes are valid */
  388. if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) {
  389. SECStatus rv;
  390. SECItem signText;
  391. SECItem plainText;
  392. unsigned char signData[SDB_MAX_META_DATA_LEN];
  393. signText.data = signData;
  394. signText.len = sizeof(signData);
  395. rv = sftkdb_getAttributeSignature(handle, keyHandle,
  396. objectID, ntemplate[i].type, &signText);
  397. if (rv != SECSuccess) {
  398. PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
  399. template[i].ulValueLen = -1;
  400. crv = CKR_DATA_INVALID; /* better error code? */
  401. continue;
  402. }
  403. plainText.data = ntemplate[i].pValue;
  404. plainText.len = ntemplate[i].ulValueLen;
  405. /*
  406. * we do a second check holding the lock just in case the user
  407. * loggout while we were trying to get the signature.
  408. */
  409. PZ_Lock(keyHandle->passwordLock);
  410. if (keyHandle->passwordKey.data == NULL) {
  411. /* if we are no longer logged in, no use checking the other
  412. * Signatures either. */
  413. checkSig = PR_FALSE;
  414. PZ_Unlock(keyHandle->passwordLock);
  415. continue;
  416. }
  417. rv = sftkdb_VerifyAttribute(&keyHandle->passwordKey,
  418. objectID, ntemplate[i].type,
  419. &plainText, &signText);
  420. PZ_Unlock(keyHandle->passwordLock);
  421. if (rv != SECSuccess) {
  422. PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
  423. template[i].ulValueLen = -1;
  424. crv = CKR_SIGNATURE_INVALID; /* better error code? */
  425. }
  426. /* This Attribute is fine */
  427. }
  428. }
  429. return crv;
  430. }
  431. /*
  432. * Some attributes are signed with an HMAC and a pbe key generated from
  433. * the password. This signature is stored indexed by object handle and
  434. *
  435. * Those attributes are:
  436. * 1) Trust object hashes and trust values.
  437. * 2) public key values.
  438. *
  439. * Certs themselves are considered properly authenticated by virtue of their
  440. * signature, or their matching hash with the trust object.
  441. *
  442. * These signature is only checked for objects coming from shared databases.
  443. * Older dbm style databases have such no signature checks. HMACs are also
  444. * only checked when the token is logged in, as it requires a pbe generated
  445. * from the password.
  446. *
  447. * Tokens which have no key database (and therefore no master password) do not
  448. * have any stored signature values. Signature values are stored in the key
  449. * database, since the signature data is tightly coupled to the key database
  450. * password.
  451. *
  452. * This function takes a template of attributes that were either created or
  453. * modified. These attributes are checked to see if the need to be signed.
  454. * If they do, then this function signs the attributes and writes them
  455. * to the meta data store.
  456. *
  457. * This function can fail if there are attributes that must be signed, but
  458. * the token is not logged in.
  459. *
  460. * The caller is expected to abort any transaction he was in in the
  461. * event of a failure of this function.
  462. */
  463. static CK_RV
  464. sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle,
  465. PRBool mayBeUpdateDB,
  466. CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
  467. CK_ULONG count)
  468. {
  469. int i;
  470. CK_RV crv;
  471. SFTKDBHandle *keyHandle = handle;
  472. SDB *keyTarget = NULL;
  473. PRBool usingPeerDB = PR_FALSE;
  474. PRBool inPeerDBTransaction = PR_FALSE;
  475. PORT_Assert(handle);
  476. if (handle->type != SFTK_KEYDB_TYPE) {
  477. keyHandle = handle->peerDB;
  478. usingPeerDB = PR_TRUE;
  479. }
  480. /* no key DB defined? then no need to sign anything */
  481. if (keyHandle == NULL) {
  482. crv = CKR_OK;
  483. goto loser;
  484. }
  485. /* When we are in a middle of an update, we have an update database set,
  486. * but we want to write to the real database. The bool mayBeUpdateDB is
  487. * set to TRUE if it's possible that we want to write an update database
  488. * rather than a primary */
  489. keyTarget = (mayBeUpdateDB && keyHandle->update) ?
  490. keyHandle->update : keyHandle->db;
  491. /* skip the the database does not support meta data */
  492. if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
  493. crv = CKR_OK;
  494. goto loser;
  495. }
  496. /* If we had to switch databases, we need to initialize a transaction. */
  497. if (usingPeerDB) {
  498. crv = (*keyTarget->sdb_Begin)(keyTarget);
  499. if (crv != CKR_OK) {
  500. goto loser;
  501. }
  502. inPeerDBTransaction = PR_TRUE;
  503. }
  504. for (i=0; i < count; i ++) {
  505. if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
  506. SECStatus rv;
  507. SECItem *signText;
  508. SECItem plainText;
  509. plainText.data = template[i].pValue;
  510. plainText.len = template[i].ulValueLen;
  511. PZ_Lock(keyHandle->passwordLock);
  512. if (keyHandle->passwordKey.data == NULL) {
  513. PZ_Unlock(keyHandle->passwordLock);
  514. crv = CKR_USER_NOT_LOGGED_IN;
  515. goto loser;
  516. }
  517. rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey,
  518. objectID, template[i].type,
  519. &plainText, &signText);
  520. PZ_Unlock(keyHandle->passwordLock);
  521. if (rv != SECSuccess) {
  522. crv = CKR_GENERAL_ERROR; /* better error code here? */
  523. goto loser;
  524. }
  525. rv = sftkdb_PutAttributeSignature(handle, keyTarget,
  526. objectID, template[i].type, signText);
  527. if (rv != SECSuccess) {
  528. crv = CKR_GENERAL_ERROR; /* better error code here? */
  529. goto loser;
  530. }
  531. }
  532. }
  533. crv = CKR_OK;
  534. /* If necessary, commit the transaction */
  535. if (inPeerDBTransaction) {
  536. crv = (*keyTarget->sdb_Commit)(keyTarget);
  537. if (crv != CKR_OK) {
  538. goto loser;
  539. }
  540. inPeerDBTransaction = PR_FALSE;
  541. }
  542. loser:
  543. if (inPeerDBTransaction) {
  544. /* The transaction must have failed. Abort. */
  545. (*keyTarget->sdb_Abort)(keyTarget);
  546. PORT_Assert(crv != CKR_OK);
  547. if (crv == CKR_OK) crv = CKR_GENERAL_ERROR;
  548. }
  549. return crv;
  550. }
  551. static CK_RV
  552. sftkdb_CreateObject(PRArenaPool *arena, SFTKDBHandle *handle,
  553. SDB *db, CK_OBJECT_HANDLE *objectID,
  554. CK_ATTRIBUTE *template, CK_ULONG count)
  555. {
  556. PRBool inTransaction = PR_FALSE;
  557. CK_RV crv;
  558. inTransaction = PR_TRUE;
  559. crv = (*db->sdb_CreateObject)(db, objectID, template, count);
  560. if (crv != CKR_OK) {
  561. goto loser;
  562. }
  563. crv = sftk_signTemplate(arena, handle, (db == handle->update),
  564. *objectID, template, count);
  565. loser:
  566. return crv;
  567. }
  568. CK_ATTRIBUTE *
  569. sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
  570. SFTKDBHandle *handle,CK_ULONG *pcount,
  571. CK_RV *crv)
  572. {
  573. int count;
  574. CK_ATTRIBUTE *template;
  575. int i, templateIndex;
  576. SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
  577. PRBool doEnc = PR_TRUE;
  578. *crv = CKR_OK;
  579. if (sessObject == NULL) {
  580. *crv = CKR_GENERAL_ERROR; /* internal programming error */
  581. return NULL;
  582. }
  583. PORT_Assert(handle);
  584. /* find the key handle */
  585. if (handle->type != SFTK_KEYDB_TYPE) {
  586. doEnc = PR_FALSE;
  587. }
  588. PZ_Lock(sessObject->attributeLock);
  589. count = 0;
  590. for (i=0; i < sessObject->hashSize; i++) {
  591. SFTKAttribute *attr;
  592. for (attr=sessObject->head[i]; attr; attr=attr->next) {
  593. count++;
  594. }
  595. }
  596. template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count);
  597. if (template == NULL) {
  598. PZ_Unlock(sessObject->attributeLock);
  599. *crv = CKR_HOST_MEMORY;
  600. return NULL;
  601. }
  602. templateIndex = 0;
  603. for (i=0; i < sessObject->hashSize; i++) {
  604. SFTKAttribute *attr;
  605. for (attr=sessObject->head[i]; attr; attr=attr->next) {
  606. CK_ATTRIBUTE *tp = &template[templateIndex++];
  607. /* copy the attribute */
  608. *tp = attr->attrib;
  609. /* fixup ULONG s */
  610. if ((tp->ulValueLen == sizeof (CK_ULONG)) &&
  611. (sftkdb_isULONGAttribute(tp->type)) ) {
  612. CK_ULONG value = *(CK_ULONG *) tp->pValue;
  613. unsigned char *data;
  614. tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE);
  615. data = (unsigned char *)tp->pValue;
  616. if (data == NULL) {
  617. *crv = CKR_HOST_MEMORY;
  618. break;
  619. }
  620. sftk_ULong2SDBULong(data, value);
  621. tp->ulValueLen = SDB_ULONG_SIZE;
  622. }
  623. /* encrypt private attributes */
  624. if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
  625. /* we have a private attribute */
  626. SECItem *cipherText;
  627. SECItem plainText;
  628. SECStatus rv;
  629. plainText.data = tp->pValue;
  630. plainText.len = tp->ulValueLen;
  631. PZ_Lock(handle->passwordLock);
  632. if (handle->passwordKey.data == NULL) {
  633. PZ_Unlock(handle->passwordLock);
  634. *crv = CKR_USER_NOT_LOGGED_IN;
  635. break;
  636. }
  637. rv = sftkdb_EncryptAttribute(arena, &handle->passwordKey,
  638. &plainText, &cipherText);
  639. PZ_Unlock(handle->passwordLock);
  640. if (rv == SECSuccess) {
  641. tp->pValue = cipherText->data;
  642. tp->ulValueLen = cipherText->len;
  643. } else {
  644. *crv = CKR_GENERAL_ERROR; /* better error code here? */
  645. break;
  646. }
  647. PORT_Memset(plainText.data, 0, plainText.len);
  648. }
  649. }
  650. }
  651. PORT_Assert(templateIndex <= count);
  652. PZ_Unlock(sessObject->attributeLock);
  653. if (*crv != CKR_OK) {
  654. return NULL;
  655. }
  656. if (pcount) {
  657. *pcount = count;
  658. }
  659. return template;
  660. }
  661. /*
  662. * return a pointer to the attribute in the give template.
  663. * The return value is not const, as the caller may modify
  664. * the given attribute value, but such modifications will
  665. * modify the actual value in the template.
  666. */
  667. static CK_ATTRIBUTE *
  668. sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute,
  669. CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  670. {
  671. CK_ULONG i;
  672. for (i=0; i < len; i++) {
  673. if (attribute == ptemplate[i].type) {
  674. return &ptemplate[i];
  675. }
  676. }
  677. return NULL;
  678. }
  679. static const CK_ATTRIBUTE *
  680. sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute,
  681. const CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  682. {
  683. CK_ULONG i;
  684. for (i=0; i < len; i++) {
  685. if (attribute == ptemplate[i].type) {
  686. return &ptemplate[i];
  687. }
  688. }
  689. return NULL;
  690. }
  691. /*
  692. * fetch a template which identifies 'unique' entries based on object type
  693. */
  694. static CK_RV
  695. sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData,
  696. CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount,
  697. CK_ATTRIBUTE *ptemplate, int len)
  698. {
  699. CK_ATTRIBUTE *attr;
  700. CK_ULONG count = 1;
  701. sftk_ULong2SDBULong(objTypeData, objectType);
  702. findTemplate[0].type = CKA_CLASS;
  703. findTemplate[0].pValue = objTypeData;
  704. findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
  705. switch (objectType) {
  706. case CKO_CERTIFICATE:
  707. case CKO_NSS_TRUST:
  708. attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len);
  709. if (attr == NULL) {
  710. return CKR_TEMPLATE_INCOMPLETE;
  711. }
  712. findTemplate[1] = *attr;
  713. attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER,
  714. ptemplate, len);
  715. if (attr == NULL) {
  716. return CKR_TEMPLATE_INCOMPLETE;
  717. }
  718. findTemplate[2] = *attr;
  719. count = 3;
  720. break;
  721. case CKO_PRIVATE_KEY:
  722. case CKO_PUBLIC_KEY:
  723. case CKO_SECRET_KEY:
  724. attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len);
  725. if (attr == NULL) {
  726. return CKR_TEMPLATE_INCOMPLETE;
  727. }
  728. if (attr->ulValueLen == 0) {
  729. /* key is too generic to determine that it's unique, usually
  730. * happens in the key gen case */
  731. return CKR_OBJECT_HANDLE_INVALID;
  732. }
  733. findTemplate[1] = *attr;
  734. count = 2;
  735. break;
  736. case CKO_NSS_CRL:
  737. attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
  738. if (attr == NULL) {
  739. return CKR_TEMPLATE_INCOMPLETE;
  740. }
  741. findTemplate[1] = *attr;
  742. count = 2;
  743. break;
  744. case CKO_NSS_SMIME:
  745. attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
  746. if (attr == NULL) {
  747. return CKR_TEMPLATE_INCOMPLETE;
  748. }
  749. findTemplate[1] = *attr;
  750. attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len);
  751. if (attr == NULL) {
  752. return CKR_TEMPLATE_INCOMPLETE;
  753. }
  754. findTemplate[2] = *attr;
  755. count = 3;
  756. break;
  757. default:
  758. attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len);
  759. if (attr == NULL) {
  760. return CKR_TEMPLATE_INCOMPLETE;
  761. }
  762. findTemplate[1] = *attr;
  763. count = 2;
  764. break;
  765. }
  766. *findCount = count;
  767. return CKR_OK;
  768. }
  769. /*
  770. * look to see if this object already exists and return its object ID if
  771. * it does.
  772. */
  773. static CK_RV
  774. sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType,
  775. CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  776. {
  777. CK_ATTRIBUTE findTemplate[3];
  778. CK_ULONG count = 1;
  779. CK_ULONG objCount = 0;
  780. SDBFind *find = NULL;
  781. unsigned char objTypeData[SDB_ULONG_SIZE];
  782. CK_RV crv;
  783. *id = CK_INVALID_HANDLE;
  784. if (objectType == CKO_NSS_CRL) {
  785. return CKR_OK;
  786. }
  787. crv = sftkdb_getFindTemplate(objectType, objTypeData,
  788. findTemplate, &count, ptemplate, len);
  789. if (crv == CKR_OBJECT_HANDLE_INVALID) {
  790. /* key is too generic to determine that it's unique, usually
  791. * happens in the key gen case, tell the caller to go ahead
  792. * and just create it */
  793. return CKR_OK;
  794. }
  795. if (crv != CKR_OK) {
  796. return crv;
  797. }
  798. /* use the raw find, so we get the correct database */
  799. crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find);
  800. if (crv != CKR_OK) {
  801. return crv;
  802. }
  803. (*db->sdb_FindObjects)(db, find, id, 1, &objCount);
  804. (*db->sdb_FindObjectsFinal)(db, find);
  805. if (objCount == 0) {
  806. *id = CK_INVALID_HANDLE;
  807. }
  808. return CKR_OK;
  809. }
  810. /*
  811. * check to see if this template conflicts with others in our current database.
  812. */
  813. static CK_RV
  814. sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType,
  815. const CK_ATTRIBUTE *ptemplate, CK_ULONG len,
  816. CK_OBJECT_HANDLE sourceID)
  817. {
  818. CK_ATTRIBUTE findTemplate[2];
  819. unsigned char objTypeData[SDB_ULONG_SIZE];
  820. /* we may need to allocate some temporaries. Keep track of what was
  821. * allocated so we can free it in the end */
  822. unsigned char *temp1 = NULL;
  823. unsigned char *temp2 = NULL;
  824. CK_ULONG objCount = 0;
  825. SDBFind *find = NULL;
  826. CK_OBJECT_HANDLE id;
  827. const CK_ATTRIBUTE *attr, *attr2;
  828. CK_RV crv;
  829. CK_ATTRIBUTE subject;
  830. /* Currently the only conflict is with nicknames pointing to the same
  831. * subject when creating or modifying a certificate. */
  832. /* If the object is not a cert, no problem. */
  833. if (objectType != CKO_CERTIFICATE) {
  834. return CKR_OK;
  835. }
  836. /* if not setting a nickname then there's still no problem */
  837. attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len);
  838. if ((attr == NULL) || (attr->ulValueLen == 0)) {
  839. return CKR_OK;
  840. }
  841. /* fetch the subject of the source. For creation and merge, this should
  842. * be found in the template */
  843. attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len);
  844. if (sourceID == CK_INVALID_HANDLE) {
  845. if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) {
  846. crv = CKR_TEMPLATE_INCOMPLETE;
  847. goto done;
  848. }
  849. } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) {
  850. /* sourceID is set if we are trying to modify an existing entry instead
  851. * of creating a new one. In this case the subject may not be (probably
  852. * isn't) in the template, we have to read it from the database */
  853. subject.type = CKA_SUBJECT;
  854. subject.pValue = NULL;
  855. subject.ulValueLen = 0;
  856. crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
  857. if (crv != CKR_OK) {
  858. goto done;
  859. }
  860. if ((CK_LONG)subject.ulValueLen < 0) {
  861. crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */
  862. goto done;
  863. }
  864. temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen);
  865. if (temp1 == NULL) {
  866. crv = CKR_HOST_MEMORY;
  867. goto done;
  868. }
  869. crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
  870. if (crv != CKR_OK) {
  871. goto done;
  872. }
  873. attr2 = &subject;
  874. }
  875. /* check for another cert in the database with the same nickname */
  876. sftk_ULong2SDBULong(objTypeData, objectType);
  877. findTemplate[0].type = CKA_CLASS;
  878. findTemplate[0].pValue = objTypeData;
  879. findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
  880. findTemplate[1] = *attr;
  881. crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find);
  882. if (crv != CKR_OK) {
  883. goto done;
  884. }
  885. (*db->sdb_FindObjects)(db, find, &id, 1, &objCount);
  886. (*db->sdb_FindObjectsFinal)(db, find);
  887. /* object count == 0 means no conflicting certs found,
  888. * go on with the operation */
  889. if (objCount == 0) {
  890. crv = CKR_OK;
  891. goto done;
  892. }
  893. /* There is a least one cert that shares the nickname, make sure it also
  894. * matches the subject. */
  895. findTemplate[0] = *attr2;
  896. /* we know how big the source subject was. Use that length to create the
  897. * space for the target. If it's not enough space, then it means the
  898. * source subject is too big, and therefore not a match. GetAttributeValue
  899. * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough
  900. * space (or enough space to be able to compare the result. */
  901. temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen);
  902. if (temp2 == NULL) {
  903. crv = CKR_HOST_MEMORY;
  904. goto done;
  905. }
  906. crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1);
  907. if (crv != CKR_OK) {
  908. if (crv == CKR_BUFFER_TOO_SMALL) {
  909. /* if our buffer is too small, then the Subjects clearly do
  910. * not match */
  911. crv = CKR_ATTRIBUTE_VALUE_INVALID;
  912. goto loser;
  913. }
  914. /* otherwise we couldn't get the value, just fail */
  915. goto done;
  916. }
  917. /* Ok, we have both subjects, make sure they are the same.
  918. * Compare the subjects */
  919. if ((findTemplate[0].ulValueLen != attr2->ulValueLen) ||
  920. (attr2->ulValueLen > 0 &&
  921. PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen)
  922. != 0)) {
  923. crv = CKR_ATTRIBUTE_VALUE_INVALID;
  924. goto loser;
  925. }
  926. crv = CKR_OK;
  927. done:
  928. /* If we've failed for some other reason than a conflict, make sure we
  929. * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID.
  930. * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should
  931. * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia).
  932. */
  933. if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
  934. crv = CKR_GENERAL_ERROR; /* clearly a programming error */
  935. }
  936. /* exit point if we found a conflict */
  937. loser:
  938. PORT_Free(temp1);
  939. PORT_Free(temp2);
  940. return crv;
  941. }
  942. /*
  943. * try to update the template to fix any errors. This is only done
  944. * during update.
  945. *
  946. * NOTE: we must update the template or return an error, or the update caller
  947. * will loop forever!
  948. *
  949. * Two copies of the source code for this algorithm exist in NSS.
  950. * Changes must be made in both copies.
  951. * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c.
  952. *
  953. */
  954. static CK_RV
  955. sftkdb_resolveConflicts(PRArenaPool *arena, CK_OBJECT_CLASS objectType,
  956. CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
  957. {
  958. CK_ATTRIBUTE *attr;
  959. char *nickname, *newNickname;
  960. int end, digit;
  961. /* sanity checks. We should never get here with these errors */
  962. if (objectType != CKO_CERTIFICATE) {
  963. return CKR_GENERAL_ERROR; /* shouldn't happen */
  964. }
  965. attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
  966. if ((attr == NULL) || (attr->ulValueLen == 0)) {
  967. return CKR_GENERAL_ERROR; /* shouldn't happen */
  968. }
  969. /* update the nickname */
  970. /* is there a number at the end of the nickname already?
  971. * if so just increment that number */
  972. nickname = (char *)attr->pValue;
  973. /* does nickname end with " #n*" ? */
  974. for (end = attr->ulValueLen - 1;
  975. end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0';
  976. end--) /* just scan */ ;
  977. if (attr->ulValueLen >= 3 &&
  978. end < (attr->ulValueLen - 1) /* at least one digit */ &&
  979. nickname[end] == '#' &&
  980. nickname[end - 1] == ' ') {
  981. /* Already has a suitable suffix string */
  982. } else {
  983. /* ... append " #2" to the name */
  984. static const char num2[] = " #2";
  985. newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2));
  986. if (!newNickname) {
  987. return CKR_HOST_MEMORY;
  988. }
  989. PORT_Memcpy(newNickname, nickname, attr->ulValueLen);
  990. PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2));
  991. attr->pValue = newNickname; /* modifies ptemplate */
  992. attr->ulValueLen += 3; /* 3 is strlen(num2) */
  993. return CKR_OK;
  994. }
  995. for (end = attr->ulValueLen - 1;
  996. end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0';
  997. end--) {
  998. if (digit < '9') {
  999. nickname[end]++;
  1000. return CKR_OK;
  1001. }
  1002. nickname[end] = '0';
  1003. }
  1004. /* we overflowed, insert a new '1' for a carry in front of the number */
  1005. newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1);
  1006. if (!newNickname) {
  1007. return CKR_HOST_MEMORY;
  1008. }
  1009. /* PORT_Memcpy should handle len of '0' */
  1010. PORT_Memcpy(newNickname, nickname, ++end);
  1011. newNickname[end] = '1';
  1012. PORT_Memset(&newNickname[end+1],'0',attr->ulValueLen - end);
  1013. attr->pValue = newNickname;
  1014. attr->ulValueLen++;
  1015. return CKR_OK;
  1016. }
  1017. /*
  1018. * set an attribute and sign it if necessary
  1019. */
  1020. static CK_RV
  1021. sftkdb_setAttributeValue(PRArenaPool *arena, SFTKDBHandle *handle,
  1022. SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
  1023. CK_ULONG count)
  1024. {
  1025. CK_RV crv;
  1026. crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count);
  1027. if (crv != CKR_OK) {
  1028. return crv;
  1029. }
  1030. crv = sftk_signTemplate(arena, handle, db == handle->update,
  1031. objectID, template, count);
  1032. return crv;
  1033. }
  1034. /*
  1035. * write a softoken object out to the database.
  1036. */
  1037. CK_RV
  1038. sftkdb_write(SFTKDBHandle *handle, SFTKObject *object,
  1039. CK_OBJECT_HANDLE *objectID)
  1040. {
  1041. CK_ATTRIBUTE *template;
  1042. PLArenaPool *arena;
  1043. CK_ULONG count;
  1044. CK_RV crv;
  1045. SDB *db;
  1046. PRBool inTransaction = PR_FALSE;
  1047. CK_OBJECT_HANDLE id;
  1048. *objectID = CK_INVALID_HANDLE;
  1049. if (handle == NULL) {
  1050. return CKR_TOKEN_WRITE_PROTECTED;
  1051. }
  1052. db = SFTK_GET_SDB(handle);
  1053. /*
  1054. * we have opened a new database, but we have not yet updated it. We are
  1055. * still running pointing to the old database (so the application can
  1056. * still read). We don't want to write to the old database at this point,
  1057. * however, since it leads to user confusion. So at this point we simply
  1058. * require a user login. Let NSS know this so it can prompt the user.
  1059. */
  1060. if (db == handle->update) {
  1061. return CKR_USER_NOT_LOGGED_IN;
  1062. }
  1063. arena = PORT_NewArena(256);
  1064. if (arena == NULL) {
  1065. return CKR_HOST_MEMORY;
  1066. }
  1067. template = sftk_ExtractTemplate(arena, object, handle, &count, &crv);
  1068. if (!template) {
  1069. goto loser;
  1070. }
  1071. crv = (*db->sdb_Begin)(db);
  1072. if (crv != CKR_OK) {
  1073. goto loser;
  1074. }
  1075. inTransaction = PR_TRUE;
  1076. /*
  1077. * We want to make the base database as free from object specific knowledge
  1078. * as possible. To maintain compatibility, keep some of the desirable
  1079. * object specific semantics of the old database.
  1080. *
  1081. * These were 2 fold:
  1082. * 1) there were certain conflicts (like trying to set the same nickname
  1083. * on two different subjects) that would return an error.
  1084. * 2) Importing the 'same' object would silently update that object.
  1085. *
  1086. * The following 2 functions mimic the desirable effects of these two
  1087. * semantics without pushing any object knowledge to the underlying database
  1088. * code.
  1089. */
  1090. /* make sure we don't have attributes that conflict with the existing DB */
  1091. crv = sftkdb_checkConflicts(db, object->objclass, template, count,
  1092. CK_INVALID_HANDLE);
  1093. if (crv != CKR_OK) {
  1094. goto loser;
  1095. }
  1096. /* Find any copies that match this particular object */
  1097. crv = sftkdb_lookupObject(db, object->objclass, &id, template, count);
  1098. if (crv != CKR_OK) {
  1099. goto loser;
  1100. }
  1101. if (id == CK_INVALID_HANDLE) {
  1102. crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
  1103. } else {
  1104. /* object already exists, modify it's attributes */
  1105. *objectID = id;
  1106. crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count);
  1107. }
  1108. if (crv != CKR_OK) {
  1109. goto loser;
  1110. }
  1111. crv = (*db->sdb_Commit)(db);
  1112. inTransaction = PR_FALSE;
  1113. loser:
  1114. if (inTransaction) {
  1115. (*db->sdb_Abort)(db);
  1116. /* It is trivial to show the following code cannot
  1117. * happen unless something is horribly wrong with our compilier or
  1118. * hardware */
  1119. PORT_Assert(crv != CKR_OK);
  1120. if (crv == CKR_OK) crv = CKR_GENERAL_ERROR;
  1121. }
  1122. if (arena) {
  1123. PORT_FreeArena(arena,PR_FALSE);
  1124. }
  1125. if (crv == CKR_OK) {
  1126. *objectID |= (handle->type | SFTK_TOKEN_TYPE);
  1127. }
  1128. return crv;
  1129. }
  1130. CK_RV
  1131. sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template,
  1132. CK_ULONG count, SDBFind **find)
  1133. {
  1134. unsigned char *data = NULL;
  1135. CK_ATTRIBUTE *ntemplate = NULL;
  1136. CK_RV crv;
  1137. SDB *db;
  1138. if (handle == NULL) {
  1139. return CKR_OK;
  1140. }
  1141. db = SFTK_GET_SDB(handle);
  1142. if (count != 0) {
  1143. ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
  1144. if (ntemplate == NULL) {
  1145. return CKR_HOST_MEMORY;
  1146. }
  1147. }
  1148. crv = (*db->sdb_FindObjectsInit)(db, ntemplate,
  1149. count, find);
  1150. if (data) {
  1151. PORT_Free(ntemplate);
  1152. PORT_Free(data);
  1153. }
  1154. return crv;
  1155. }
  1156. CK_RV
  1157. sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find,
  1158. CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count)
  1159. {
  1160. CK_RV crv;
  1161. SDB *db;
  1162. if (handle == NULL) {
  1163. *count = 0;
  1164. return CKR_OK;
  1165. }
  1166. db = SFTK_GET_SDB(handle);
  1167. crv = (*db->sdb_FindObjects)(db, find, ids,
  1168. arraySize, count);
  1169. if (crv == CKR_OK) {
  1170. int i;
  1171. for (i=0; i < *count; i++) {
  1172. ids[i] |= (handle->type | SFTK_TOKEN_TYPE);
  1173. }
  1174. }
  1175. return crv;
  1176. }
  1177. CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find)
  1178. {
  1179. SDB *db;
  1180. if (handle == NULL) {
  1181. return CKR_OK;
  1182. }
  1183. db = SFTK_GET_SDB(handle);
  1184. return (*db->sdb_FindObjectsFinal)(db, find);
  1185. }
  1186. CK_RV
  1187. sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
  1188. CK_ATTRIBUTE *template, CK_ULONG count)
  1189. {
  1190. CK_RV crv,crv2;
  1191. CK_ATTRIBUTE *ntemplate;
  1192. unsigned char *data = NULL;
  1193. SDB *db;
  1194. if (handle == NULL) {
  1195. return CKR_GENERAL_ERROR;
  1196. }
  1197. /* short circuit common attributes */
  1198. if (count == 1 &&
  1199. (template[0].type == CKA_TOKEN ||
  1200. template[0].type == CKA_PRIVATE ||
  1201. template[0].type == CKA_SENSITIVE)) {
  1202. CK_BBOOL boolVal = CK_TRUE;
  1203. if (template[0].pValue == NULL) {
  1204. template[0].ulValueLen = sizeof(CK_BBOOL);
  1205. return CKR_OK;
  1206. }
  1207. if (template[0].ulValueLen < sizeof(CK_BBOOL)) {
  1208. template[0].ulValueLen = -1;
  1209. return CKR_BUFFER_TOO_SMALL;
  1210. }
  1211. if ((template[0].type == CKA_PRIVATE) &&
  1212. (handle->type != SFTK_KEYDB_TYPE)) {
  1213. boolVal = CK_FALSE;
  1214. }
  1215. if ((template[0].type == CKA_SENSITIVE) &&
  1216. (handle->type != SFTK_KEYDB_TYPE)) {
  1217. boolVal = CK_FALSE;
  1218. }
  1219. *(CK_BBOOL *)template[0].pValue = boolVal;
  1220. template[0].ulValueLen = sizeof(CK_BBOOL);
  1221. return CKR_OK;
  1222. }
  1223. db = SFTK_GET_SDB(handle);
  1224. /* nothing to do */
  1225. if (count == 0) {
  1226. return CKR_OK;
  1227. }
  1228. ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
  1229. if (ntemplate == NULL) {
  1230. return CKR_HOST_MEMORY;
  1231. }
  1232. objectID &= SFTK_OBJ_ID_MASK;
  1233. crv = (*db->sdb_GetAttributeValue)(db, objectID,
  1234. ntemplate, count);
  1235. crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate,
  1236. count, handle);
  1237. if (crv == CKR_OK) crv = crv2;
  1238. if (data) {
  1239. PORT_Free(ntemplate);
  1240. PORT_Free(data);
  1241. }
  1242. return crv;
  1243. }
  1244. CK_RV
  1245. sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object,
  1246. const CK_ATTRIBUTE *template, CK_ULONG count)
  1247. {
  1248. CK_ATTRIBUTE *ntemplate;
  1249. unsigned char *data = NULL;
  1250. PLArenaPool *arena = NULL;
  1251. SDB *db;
  1252. CK_RV crv = CKR_OK;
  1253. CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK);
  1254. PRBool inTransaction = PR_FALSE;
  1255. if (handle == NULL) {
  1256. return CKR_TOKEN_WRITE_PROTECTED;
  1257. }
  1258. db = SFTK_GET_SDB(handle);
  1259. /* nothing to do */
  1260. if (count == 0) {
  1261. return CKR_OK;
  1262. }
  1263. /*
  1264. * we have opened a new database, but we have not yet updated it. We are
  1265. * still running pointing to the old database (so the application can
  1266. * still read). We don't want to write to the old database at this point,
  1267. * however, since it leads to user confusion. So at this point we simply
  1268. * require a user login. Let NSS know this so it can prompt the user.
  1269. */
  1270. if (db == handle->update) {
  1271. return CKR_USER_NOT_LOGGED_IN;
  1272. }
  1273. ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
  1274. if (ntemplate == NULL) {
  1275. return CKR_HOST_MEMORY;
  1276. }
  1277. /* make sure we don't have attributes that conflict with the existing DB */
  1278. crv = sftkdb_checkConflicts(db, object->objclass, template, count, objectID);
  1279. if (crv != CKR_OK) {
  1280. goto loser;
  1281. }
  1282. arena = PORT_NewArena(256);
  1283. if (arena == NULL) {
  1284. crv = CKR_HOST_MEMORY;
  1285. goto loser;
  1286. }
  1287. crv = (*db->sdb_Begin)(db);
  1288. if (crv != CKR_OK) {
  1289. goto loser;
  1290. }
  1291. inTransaction = PR_TRUE;
  1292. crv = sftkdb_setAttributeValue(arena, handle, db,
  1293. objectID, template, count);
  1294. if (crv != CKR_OK) {
  1295. goto loser;
  1296. }
  1297. crv = (*db->sdb_Commit)(db);
  1298. loser:
  1299. if (crv != CKR_OK && inTransaction) {
  1300. (*db->sdb_Abort)(db);
  1301. }
  1302. if (data) {
  1303. PORT_Free(ntemplate);
  1304. PORT_Free(data);
  1305. }
  1306. if (arena) {
  1307. PORT_FreeArena(arena, PR_FALSE);
  1308. }
  1309. return crv;
  1310. }
  1311. CK_RV
  1312. sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID)
  1313. {
  1314. CK_RV crv = CKR_OK;
  1315. SDB *db;
  1316. if (handle == NULL) {
  1317. return CKR_TOKEN_WRITE_PROTECTED;
  1318. }
  1319. db = SFTK_GET_SDB(handle);
  1320. objectID &= SFTK_OBJ_ID_MASK;
  1321. crv = (*db->sdb_Begin)(db);
  1322. if (crv != CKR_OK) {
  1323. goto loser;
  1324. }
  1325. crv = (*db->sdb_DestroyObject)(db, objectID);
  1326. if (crv != CKR_OK) {
  1327. goto loser;
  1328. }
  1329. crv = (*db->sdb_Commit)(db);
  1330. loser:
  1331. if (crv != CKR_OK) {
  1332. (*db->sdb_Abort)(db);
  1333. }
  1334. return crv;
  1335. }
  1336. CK_RV
  1337. sftkdb_CloseDB(SFTKDBHandle *handle)
  1338. {
  1339. #ifdef NO_FORK_CHECK
  1340. PRBool parentForkedAfterC_Initialize = PR_FALSE;
  1341. #endif
  1342. if (handle == NULL) {
  1343. return CKR_OK;
  1344. }
  1345. if (handle->update) {
  1346. if (handle->db->sdb_SetForkState) {
  1347. (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
  1348. }
  1349. (*handle->update->sdb_Close)(handle->update);
  1350. }
  1351. if (handle->db) {
  1352. if (handle->db->sdb_SetForkState) {
  1353. (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
  1354. }
  1355. (*handle->db->sdb_Close)(handle->db);
  1356. }
  1357. if (handle->passwordKey.data) {
  1358. PORT_ZFree(handle->passwordKey.data, handle->passwordKey.len);
  1359. }
  1360. if (handle->passwordLock) {
  1361. SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock));
  1362. }
  1363. if (handle->updatePasswordKey) {
  1364. SECITEM_FreeItem(handle->updatePasswordKey, PR_TRUE);
  1365. }
  1366. if (handle->updateID) {
  1367. PORT_Free(handle->updateID);
  1368. }
  1369. PORT_Free(handle);
  1370. return CKR_OK;
  1371. }
  1372. /*
  1373. * reset a database to it's uninitialized state.
  1374. */
  1375. static CK_RV
  1376. sftkdb_ResetDB(SFTKDBHandle *handle)
  1377. {
  1378. CK_RV crv = CKR_OK;
  1379. SDB *db;
  1380. if (handle == NULL) {
  1381. return CKR_TOKEN_WRITE_PROTECTED;
  1382. }
  1383. db = SFTK_GET_SDB(handle);
  1384. crv = (*db->sdb_Begin)(db);
  1385. if (crv != CKR_OK) {
  1386. goto loser;
  1387. }
  1388. crv = (*db->sdb_Reset)(db);
  1389. if (crv != CKR_OK) {
  1390. goto loser;
  1391. }
  1392. crv = (*db->sdb_Commit)(db);
  1393. loser:
  1394. if (crv != CKR_OK) {
  1395. (*db->sdb_Abort)(db);
  1396. }
  1397. return crv;
  1398. }
  1399. CK_RV
  1400. sftkdb_Begin(SFTKDBHandle *handle)
  1401. {
  1402. CK_RV crv = CKR_OK;
  1403. SDB *db;
  1404. if (handle == NULL) {
  1405. return CKR_OK;
  1406. }
  1407. db = SFTK_GET_SDB(handle);
  1408. if (db) {
  1409. crv = (*db->sdb_Begin)(db);
  1410. }
  1411. return crv;
  1412. }
  1413. CK_RV
  1414. sftkdb_Commit(SFTKDBHandle *handle)
  1415. {
  1416. CK_RV crv = CKR_OK;
  1417. SDB *db;
  1418. if (handle == NULL) {
  1419. return CKR_OK;
  1420. }
  1421. db = SFTK_GET_SDB(handle);
  1422. if (db) {
  1423. (*db->sdb_Commit)(db);
  1424. }
  1425. return crv;
  1426. }
  1427. CK_RV
  1428. sftkdb_Abort(SFTKDBHandle *handle)
  1429. {
  1430. CK_RV crv = CKR_OK;
  1431. SDB *db;
  1432. if (handle == NULL) {
  1433. return CKR_OK;
  1434. }
  1435. db = SFTK_GET_SDB(handle);
  1436. if (db) {
  1437. crv = (db->sdb_Abort)(db);
  1438. }
  1439. return crv;
  1440. }
  1441. /*
  1442. * functions to update the database from an old database
  1443. */
  1444. /*
  1445. * known attributes
  1446. */
  1447. static const CK_ATTRIBUTE_TYPE known_attributes[] = {
  1448. CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
  1449. CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
  1450. CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED,
  1451. CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL,
  1452. CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY,
  1453. CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE,
  1454. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER,
  1455. CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE,
  1456. CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
  1457. CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT,
  1458. CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS,
  1459. CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE,
  1460. CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
  1461. CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
  1462. CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
  1463. CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE,
  1464. CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT,
  1465. CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS,
  1466. CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
  1467. CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
  1468. CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
  1469. CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL,
  1470. CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
  1471. CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
  1472. CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED,
  1473. CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC,
  1474. CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
  1475. CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
  1476. CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
  1477. CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING,
  1478. CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM,
  1479. CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
  1480. CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
  1481. CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS
  1482. };
  1483. static int known_attributes_size= sizeof(known_attributes)/
  1484. sizeof(known_attributes[0]);
  1485. static CK_RV
  1486. sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id,
  1487. CK_ATTRIBUTE *ptemplate, CK_ULONG *max)
  1488. {
  1489. int i,j;
  1490. CK_RV crv;
  1491. if (*max < known_attributes_size) {
  1492. *max = known_attributes_size;
  1493. return CKR_BUFFER_TOO_SMALL;
  1494. }
  1495. for (i=0; i < known_attributes_size; i++) {
  1496. ptemplate[i].type = known_attributes[i];
  1497. ptemplate[i].pValue = NULL;
  1498. ptemplate[i].ulValueLen = 0;
  1499. }
  1500. crv = (*source->sdb_GetAttributeValue)(source, id,
  1501. ptemplate, known_attributes_size);
  1502. if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
  1503. return crv;
  1504. }
  1505. for (i=0, j=0; i < known_attributes_size; i++, j++) {
  1506. while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) {
  1507. i++;
  1508. }
  1509. if (i >= known_attributes_size) {
  1510. break;
  1511. }
  1512. /* cheap optimization */
  1513. if (i == j) {
  1514. continue;
  1515. }
  1516. ptemplate[j] = ptemplate[i];
  1517. }
  1518. *max = j;
  1519. return CKR_OK;
  1520. }
  1521. static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s";
  1522. /*
  1523. * check to see if we have already updated this database.
  1524. * a NULL updateID means we are trying to do an in place
  1525. * single database update. In that case we have already
  1526. * determined that an update was necessary.
  1527. */
  1528. static PRBool
  1529. sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID)
  1530. {
  1531. char *id;
  1532. CK_RV crv;
  1533. SECItem dummy = { 0, NULL, 0 };
  1534. unsigned char dummyData[SDB_MAX_META_DATA_LEN];
  1535. if (!updateID) {
  1536. return PR_FALSE;
  1537. }
  1538. id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
  1539. if (id == NULL) {
  1540. return PR_FALSE;
  1541. }
  1542. dummy.data = dummyData;
  1543. dummy.len = sizeof(dummyData);
  1544. crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL);
  1545. PR_smprintf_free(id);
  1546. return crv == CKR_OK ? PR_TRUE : PR_FALSE;
  1547. }
  1548. /*
  1549. * we just completed an update, store the update id
  1550. * so we don't need to do it again. If non was given,
  1551. * there is nothing to do.
  1552. */
  1553. static CK_RV
  1554. sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID)
  1555. {
  1556. char *id;
  1557. CK_RV crv;
  1558. SECItem dummy = { 0, NULL, 0 };
  1559. /* if no id was given, nothing to do */
  1560. if (updateID == NULL) {
  1561. return CKR_OK;
  1562. }
  1563. dummy.data = (unsigned char *)updateID;
  1564. dummy.len = PORT_Strlen(updateID);
  1565. id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
  1566. if (id == NULL) {
  1567. return PR_FALSE;
  1568. }
  1569. crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL);
  1570. PR_smprintf_free(id);
  1571. return crv;
  1572. }
  1573. /*
  1574. * get a ULong attribute from a template:
  1575. * NOTE: this is a raw templated stored in database order!
  1576. */
  1577. static CK_ULONG
  1578. sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type,
  1579. CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  1580. {
  1581. CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type,
  1582. ptemplate, len);
  1583. if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) {
  1584. return sftk_SDBULong2ULong(attr->pValue);
  1585. }
  1586. return (CK_ULONG)-1;
  1587. }
  1588. /*
  1589. * we need to find a unique CKA_ID.
  1590. * The basic idea is to just increment the lowest byte.
  1591. * This code also handles the following corner cases:
  1592. * 1) the single byte overflows. On overflow we increment the next byte up
  1593. * and so forth until we have overflowed the entire CKA_ID.
  1594. * 2) If we overflow the entire CKA_ID we expand it by one byte.
  1595. * 3) the CKA_ID is non-existant, we create a new one with one byte.
  1596. * This means no matter what CKA_ID is passed, the result of this function
  1597. * is always a new CKA_ID, and this function will never return the same
  1598. * CKA_ID the it has returned in the passed.
  1599. */
  1600. static CK_RV
  1601. sftkdb_incrementCKAID(PRArenaPool *arena, CK_ATTRIBUTE *ptemplate)
  1602. {
  1603. unsigned char *buf = ptemplate->pValue;
  1604. CK_ULONG len = ptemplate->ulValueLen;
  1605. if (buf == NULL || len == (CK_ULONG)-1) {
  1606. /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
  1607. len = 0;
  1608. } else {
  1609. CK_ULONG i;
  1610. /* walk from the back to front, incrementing
  1611. * the CKA_ID until we no longer have a carry,
  1612. * or have hit the front of the id. */
  1613. for (i=len; i != 0; i--) {
  1614. buf[i-1]++;
  1615. if (buf[i-1] != 0) {
  1616. /* no more carries, the increment is complete */
  1617. return CKR_OK;
  1618. }
  1619. }
  1620. /* we've now overflowed, fall through and expand the CKA_ID by
  1621. * one byte */
  1622. }
  1623. buf = PORT_ArenaAlloc(arena, len+1);
  1624. if (!buf) {
  1625. return CKR_HOST_MEMORY;
  1626. }
  1627. if (len > 0) {
  1628. PORT_Memcpy(buf, ptemplate->pValue, len);
  1629. }
  1630. buf[len] = 0;
  1631. ptemplate->pValue = buf;
  1632. ptemplate->ulValueLen = len+1;
  1633. return CKR_OK;
  1634. }
  1635. /*
  1636. * drop an attribute from a template.
  1637. */
  1638. void
  1639. sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate,
  1640. CK_ULONG *plen)
  1641. {
  1642. CK_ULONG count = *plen;
  1643. CK_ULONG i;
  1644. for (i=0; i < count; i++) {
  1645. if (attr->type == ptemplate[i].type) {
  1646. break;
  1647. }
  1648. }
  1649. if (i == count) {
  1650. /* attribute not found */
  1651. return;
  1652. }
  1653. /* copy the remaining attributes up */
  1654. for ( i++; i < count; i++) {
  1655. ptemplate[i-1] = ptemplate[i];
  1656. }
  1657. /* decrement the template size */
  1658. *plen = count -1;
  1659. }
  1660. /*
  1661. * create some defines for the following functions to document the meaning
  1662. * of true/false. (make's it easier to remember what means what.
  1663. */
  1664. typedef enum {
  1665. SFTKDB_DO_NOTHING = 0,
  1666. SFTKDB_ADD_OBJECT,
  1667. SFTKDB_MODIFY_OBJECT,
  1668. SFTKDB_DROP_ATTRIBUTE
  1669. } sftkdbUpdateStatus;
  1670. /*
  1671. * helper function to reconcile a single trust entry.
  1672. * Identify which trust entry we want to keep.
  1673. * If we don't need to do anything (the records are already equal).
  1674. * return SFTKDB_DO_NOTHING.
  1675. * If we want to use the source version,
  1676. * return SFTKDB_MODIFY_OBJECT
  1677. * If we want to use the target version,
  1678. * return SFTKDB_DROP_ATTRIBUTE
  1679. *
  1680. * In the end the caller will remove any attributes in the source
  1681. * template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a
  1682. * set attributes with that template on the target if we received
  1683. * any SFTKDB_MODIFY_OBJECT returns.
  1684. */
  1685. sftkdbUpdateStatus
  1686. sftkdb_reconcileTrustEntry(PRArenaPool *arena, CK_ATTRIBUTE *target,
  1687. CK_ATTRIBUTE *source)
  1688. {
  1689. CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type,
  1690. target, 1);
  1691. CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type,
  1692. source, 1);
  1693. /*
  1694. * try to pick the best solution between the source and the
  1695. * target. Update the source template if we want the target value
  1696. * to win out. Prefer cases where we don't actually update the
  1697. * trust entry.
  1698. */
  1699. /* they are the same, everything is already kosher */
  1700. if (targetTrust == sourceTrust) {
  1701. return SFTKDB_DO_NOTHING;
  1702. }
  1703. /* handle the case where the source Trust attribute may be a bit
  1704. * flakey */
  1705. if (sourceTrust == (CK_ULONG)-1) {
  1706. /*
  1707. * The source Trust is invalid. We know that the target Trust
  1708. * must be valid here, otherwise the above
  1709. * targetTrust == sourceTrust check would have succeeded.
  1710. */
  1711. return SFTKDB_DROP_ATTRIBUTE;
  1712. }
  1713. /* target is invalid, use the source's idea of the trust value */
  1714. if (targetTrust == (CK_ULONG)-1) {
  1715. /* overwriting the target in this case is OK */
  1716. return SFTKDB_MODIFY_OBJECT;
  1717. }
  1718. /* at this point we know that both attributes exist and have the
  1719. * appropriate length (SDB_ULONG_SIZE). We no longer need to check
  1720. * ulValueLen for either attribute.
  1721. */
  1722. if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) {
  1723. return SFTKDB_DROP_ATTRIBUTE;
  1724. }
  1725. /* target has no idea, use the source's idea of the trust value */
  1726. if (targetTrust == CKT_NSS_TRUST_UNKNOWN) {
  1727. /* overwriting the target in this case is OK */
  1728. return SFTKDB_MODIFY_OBJECT;
  1729. }
  1730. /* so both the target and the source have some idea of what this
  1731. * trust attribute should be, and neither agree exactly.
  1732. * At this point, we prefer 'hard' attributes over 'soft' ones.
  1733. * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and
  1734. * CKT_NSS_NOT_TRUTED. Soft ones are ones which don't change the
  1735. * actual trust of the cert (CKT_MUST_VERIFY_TRUST,
  1736. * CKT_NSS_VALID_DELEGATOR).
  1737. */
  1738. if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST)
  1739. || (sourceTrust == CKT_NSS_VALID_DELEGATOR)) {
  1740. return SFTKDB_DROP_ATTRIBUTE;
  1741. }
  1742. if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST)
  1743. || (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
  1744. /* again, overwriting the target in this case is OK */
  1745. return SFTKDB_MODIFY_OBJECT;
  1746. }
  1747. /* both have hard attributes, we have a conflict, let the target win. */
  1748. return SFTKDB_DROP_ATTRIBUTE;
  1749. }
  1750. const CK_ATTRIBUTE_TYPE sftkdb_trustList[] =
  1751. { CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH,
  1752. CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION,
  1753. CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER,
  1754. CKA_TRUST_TIME_STAMPING };
  1755. #define SFTK_TRUST_TEMPLATE_COUNT \
  1756. (sizeof(sftkdb_trustList)/sizeof(sftkdb_trustList[0]))
  1757. /*
  1758. * Run through the list of known trust types, and reconcile each trust
  1759. * entry one by one. Keep track of we really need to write out the source
  1760. * trust object (overwriting the existing one).
  1761. */
  1762. static sftkdbUpdateStatus
  1763. sftkdb_reconcileTrust(PRArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id,
  1764. CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
  1765. {
  1766. CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT];
  1767. unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT*SDB_ULONG_SIZE];
  1768. sftkdbUpdateStatus update = SFTKDB_DO_NOTHING;
  1769. CK_ULONG i;
  1770. CK_RV crv;
  1771. for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) {
  1772. trustTemplate[i].type = sftkdb_trustList[i];
  1773. trustTemplate[i].pValue = &trustData[i*SDB_ULONG_SIZE];
  1774. trustTemplate[i].ulValueLen = SDB_ULONG_SIZE;
  1775. }
  1776. crv = (*db->sdb_GetAttributeValue)(db, id,
  1777. trustTemplate, SFTK_TRUST_TEMPLATE_COUNT);
  1778. if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
  1779. /* target trust has some problems, update it */
  1780. update = SFTKDB_MODIFY_OBJECT;
  1781. goto done;
  1782. }
  1783. for (i=0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) {
  1784. CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(
  1785. trustTemplate[i].type, ptemplate, *plen);
  1786. sftkdbUpdateStatus status;
  1787. /* if target trust value doesn't exist, nothing to merge */
  1788. if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) {
  1789. /* if the source exists, then we want the source entry,
  1790. * go ahead and update */
  1791. if (attr && attr->ulValueLen != (CK_ULONG)-1) {
  1792. update = SFTKDB_MODIFY_OBJECT;
  1793. }
  1794. continue;
  1795. }
  1796. /*
  1797. * the source doesn't have the attribute, go to the next attribute
  1798. */
  1799. if (attr == NULL) {
  1800. continue;
  1801. }
  1802. status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr);
  1803. if (status == SFTKDB_MODIFY_OBJECT) {
  1804. update = SFTKDB_MODIFY_OBJECT;
  1805. } else if (status == SFTKDB_DROP_ATTRIBUTE) {
  1806. /* drop the source copy of the attribute, we are going with
  1807. * the target's version */
  1808. sftkdb_dropAttribute(attr, ptemplate, plen);
  1809. }
  1810. }
  1811. /* finally manage stepup */
  1812. if (update == SFTKDB_MODIFY_OBJECT) {
  1813. CK_BBOOL stepUpBool = CK_FALSE;
  1814. /* if we are going to write from the source, make sure we don't
  1815. * overwrite the stepup bit if it's on*/
  1816. trustTemplate[0].type = CKA_TRUST_STEP_UP_APPROVED;
  1817. trustTemplate[0].pValue = &stepUpBool;
  1818. trustTemplate[0].ulValueLen = sizeof(stepUpBool);
  1819. crv = (*db->sdb_GetAttributeValue)(db, id, trustTemplate, 1);
  1820. if ((crv == CKR_OK) && (stepUpBool == CK_TRUE)) {
  1821. sftkdb_dropAttribute(trustTemplate, ptemplate, plen);
  1822. }
  1823. } else {
  1824. /* we currently aren't going to update. If the source stepup bit is
  1825. * on however, do an update so the target gets it as well */
  1826. CK_ATTRIBUTE *attr;
  1827. attr = sftkdb_getAttributeFromTemplate(CKA_TRUST_STEP_UP_APPROVED,
  1828. ptemplate, *plen);
  1829. if (attr && (attr->ulValueLen == sizeof(CK_BBOOL)) &&
  1830. (*(CK_BBOOL *)(attr->pValue) == CK_TRUE)) {
  1831. update = SFTKDB_MODIFY_OBJECT;
  1832. }
  1833. }
  1834. done:
  1835. return update;
  1836. }
  1837. static sftkdbUpdateStatus
  1838. sftkdb_handleIDAndName(PRArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id,
  1839. CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
  1840. {
  1841. sftkdbUpdateStatus update = SFTKDB_DO_NOTHING;
  1842. CK_ATTRIBUTE *attr1, *attr2;
  1843. CK_ATTRIBUTE ttemplate[2] = {
  1844. {CKA_ID, NULL, 0},
  1845. {CKA_LABEL, NULL, 0}
  1846. };
  1847. CK_RV crv;
  1848. attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
  1849. attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen);
  1850. /* if the source has neither an id nor label, don't bother updating */
  1851. if ( (!attr1 || attr1->ulValueLen == 0) &&
  1852. (! attr2 || attr2->ulValueLen == 0) ) {
  1853. return SFTKDB_DO_NOTHING;
  1854. }
  1855. /* the source has either an id or a label, see what the target has */
  1856. crv = (*db->sdb_GetAttributeValue)(db, id, ttemplate, 2);
  1857. /* if the target has neither, update from the source */
  1858. if ( ((ttemplate[0].ulValueLen == 0) ||
  1859. (ttemplate[0].ulValueLen == (CK_ULONG)-1)) &&
  1860. ((ttemplate[1].ulValueLen == 0) ||
  1861. (ttemplate[1].ulValueLen == (CK_ULONG)-1)) ) {
  1862. return SFTKDB_MODIFY_OBJECT;
  1863. }
  1864. /* check the CKA_ID */
  1865. if ((ttemplate[0].ulValueLen != 0) &&
  1866. (ttemplate[0].ulValueLen != (CK_ULONG)-1)) {
  1867. /* we have a CKA_ID in the target, don't overwrite
  1868. * the target with an empty CKA_ID from the source*/
  1869. if (attr1 && attr1->ulValueLen == 0) {
  1870. sftkdb_dropAttribute(attr1, ptemplate, plen);
  1871. }
  1872. } else if (attr1 && attr1->ulValueLen != 0) {
  1873. /* source has a CKA_ID, but the target doesn't, update the target */
  1874. update = SFTKDB_MODIFY_OBJECT;
  1875. }
  1876. /* check the nickname */
  1877. if ((ttemplate[1].ulValueLen != 0) &&
  1878. (ttemplate[1].ulValueLen != (CK_ULONG)-1)) {
  1879. /* we have a nickname in the target, and we don't have to update
  1880. * the CKA_ID. We are done. NOTE: if we add addition attributes
  1881. * in this check, this shortcut can only go on the last of them. */
  1882. if (update == SFTKDB_DO_NOTHING) {
  1883. return update;
  1884. }
  1885. /* we have a nickname in the target, don't overwrite
  1886. * the target with an empty nickname from the source */
  1887. if (attr2 && attr2->ulValueLen == 0) {
  1888. sftkdb_dropAttribute(attr2, ptemplate, plen);
  1889. }
  1890. } else if (attr2 && attr2->ulValueLen != 0) {
  1891. /* source has a nickname, but the target doesn't, update the target */
  1892. update = SFTKDB_MODIFY_OBJECT;
  1893. }
  1894. return update;
  1895. }
  1896. /*
  1897. * This function updates the template before we write the object out.
  1898. *
  1899. * If we are going to skip updating this object, return PR_FALSE.
  1900. * If it should be updated we return PR_TRUE.
  1901. * To help readability, these have been defined
  1902. * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively.
  1903. */
  1904. static PRBool
  1905. sftkdb_updateObjectTemplate(PRArenaPool *arena, SDB *db,
  1906. CK_OBJECT_CLASS objectType,
  1907. CK_ATTRIBUTE *ptemplate, CK_ULONG *plen,
  1908. CK_OBJECT_HANDLE *targetID)
  1909. {
  1910. PRBool done; /* should we repeat the loop? */
  1911. CK_OBJECT_HANDLE id;
  1912. CK_RV crv = CKR_OK;
  1913. do {
  1914. crv = sftkdb_checkConflicts(db, objectType, ptemplate,
  1915. *plen, CK_INVALID_HANDLE);
  1916. if (crv != CKR_ATTRIBUTE_VALUE_INVALID) {
  1917. break;
  1918. }
  1919. crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen);
  1920. } while (crv == CKR_OK);
  1921. if (crv != CKR_OK) {
  1922. return SFTKDB_DO_NOTHING;
  1923. }
  1924. do {
  1925. done = PR_TRUE;
  1926. crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen);
  1927. if (crv != CKR_OK) {
  1928. return SFTKDB_DO_NOTHING;
  1929. }
  1930. /* This object already exists, merge it, don't update */
  1931. if (id != CK_INVALID_HANDLE) {
  1932. CK_ATTRIBUTE *attr = NULL;
  1933. /* special post processing for attributes */
  1934. switch (objectType) {
  1935. case CKO_CERTIFICATE:
  1936. case CKO_PUBLIC_KEY:
  1937. case CKO_PRIVATE_KEY:
  1938. /* update target's CKA_ID and labels if they don't already
  1939. * exist */
  1940. *targetID = id;
  1941. return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen);
  1942. case CKO_NSS_TRUST:
  1943. /* if we have conflicting trust object types,
  1944. * we need to reconcile them */
  1945. *targetID = id;
  1946. return sftkdb_reconcileTrust(arena, db, id, ptemplate, plen);
  1947. case CKO_SECRET_KEY:
  1948. /* secret keys in the old database are all sdr keys,
  1949. * unfortunately they all appear to have the same CKA_ID,
  1950. * even though they are truly different keys, so we always
  1951. * want to update these keys, but we need to
  1952. * give them a new CKA_ID */
  1953. /* NOTE: this changes ptemplate */
  1954. attr = sftkdb_getAttributeFromTemplate(CKA_ID,ptemplate,*plen);
  1955. crv = attr ? sftkdb_incrementCKAID(arena, attr)
  1956. : CKR_HOST_MEMORY;
  1957. /* in the extremely rare event that we needed memory and
  1958. * couldn't get it, just drop the key */
  1959. if (crv != CKR_OK) {
  1960. return SFTKDB_DO_NOTHING;
  1961. }
  1962. done = PR_FALSE; /* repeat this find loop */
  1963. break;
  1964. default:
  1965. /* for all other objects, if we found the equivalent object,
  1966. * don't update it */
  1967. return SFTKDB_DO_NOTHING;
  1968. }
  1969. }
  1970. } while (!done);
  1971. /* this object doesn't exist, update it */
  1972. return SFTKDB_ADD_OBJECT;
  1973. }
  1974. #define MAX_ATTRIBUTES 500
  1975. static CK_RV
  1976. sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id,
  1977. SECItem *key)
  1978. {
  1979. CK_ATTRIBUTE template[MAX_ATTRIBUTES];
  1980. CK_ATTRIBUTE *ptemplate;
  1981. CK_ULONG max_attributes = MAX_ATTRIBUTES;
  1982. CK_OBJECT_CLASS objectType;
  1983. SDB *source = handle->update;
  1984. SDB *target = handle->db;
  1985. int i;
  1986. CK_RV crv;
  1987. PLArenaPool *arena = NULL;
  1988. arena = PORT_NewArena(256);
  1989. if (arena == NULL) {
  1990. return CKR_HOST_MEMORY;
  1991. }
  1992. ptemplate = &template[0];
  1993. id &= SFTK_OBJ_ID_MASK;
  1994. crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes);
  1995. if (crv == CKR_BUFFER_TOO_SMALL) {
  1996. ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes);
  1997. if (ptemplate == NULL) {
  1998. crv = CKR_HOST_MEMORY;
  1999. } else {
  2000. crv = sftkdb_GetObjectTemplate(source, id,
  2001. ptemplate, &max_attributes);
  2002. }
  2003. }
  2004. if (crv != CKR_OK) {
  2005. goto loser;
  2006. }
  2007. for (i=0; i < max_attributes; i++) {
  2008. ptemplate[i].pValue = PORT_ArenaAlloc(arena,ptemplate[i].ulValueLen);
  2009. if (ptemplate[i].pValue == NULL) {
  2010. crv = CKR_HOST_MEMORY;
  2011. goto loser;
  2012. }
  2013. }
  2014. crv = (*source->sdb_GetAttributeValue)(source, id,
  2015. ptemplate, max_attributes);
  2016. if (crv != CKR_OK) {
  2017. goto loser;
  2018. }
  2019. objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate,
  2020. max_attributes);
  2021. /*
  2022. * Update Object updates the object template if necessary then returns
  2023. * whether or not we need to actually write the object out to our target
  2024. * database.
  2025. */
  2026. if (!handle->updateID) {
  2027. crv = sftkdb_CreateObject(arena, handle, target, &id,
  2028. ptemplate, max_attributes);
  2029. } else {
  2030. sftkdbUpdateStatus update_status;
  2031. update_status = sftkdb_updateObjectTemplate(arena, target,
  2032. objectType, ptemplate, &max_attributes, &id);
  2033. switch (update_status) {
  2034. case SFTKDB_ADD_OBJECT:
  2035. crv = sftkdb_CreateObject(arena, handle, target, &id,
  2036. ptemplate, max_attributes);
  2037. break;
  2038. case SFTKDB_MODIFY_OBJECT:
  2039. crv = sftkdb_setAttributeValue(arena, handle, target,
  2040. id, ptemplate, max_attributes);
  2041. break;
  2042. case SFTKDB_DO_NOTHING:
  2043. case SFTKDB_DROP_ATTRIBUTE:
  2044. break;
  2045. }
  2046. }
  2047. loser:
  2048. if (arena) {
  2049. PORT_FreeArena(arena,PR_TRUE);
  2050. }
  2051. return crv;
  2052. }
  2053. #define MAX_IDS 10
  2054. /*
  2055. * update a new database from an old one, now that we have the key
  2056. */
  2057. CK_RV
  2058. sftkdb_Update(SFTKDBHandle *handle, SECItem *key)
  2059. {
  2060. SDBFind *find = NULL;
  2061. CK_ULONG idCount = MAX_IDS;
  2062. CK_OBJECT_HANDLE ids[MAX_IDS];
  2063. SECItem *updatePasswordKey = NULL;
  2064. CK_RV crv, crv2;
  2065. PRBool inTransaction = PR_FALSE;
  2066. int i;
  2067. if (handle == NULL) {
  2068. return CKR_OK;
  2069. }
  2070. if (handle->update == NULL) {
  2071. return CKR_OK;
  2072. }
  2073. /*
  2074. * put the whole update under a transaction. This allows us to handle
  2075. * any possible race conditions between with the updateID check.
  2076. */
  2077. crv = (*handle->db->sdb_Begin)(handle->db);
  2078. if (crv != CKR_OK) {
  2079. goto loser;
  2080. }
  2081. inTransaction = PR_TRUE;
  2082. /* some one else has already updated this db */
  2083. if (sftkdb_hasUpdate(sftkdb_TypeString(handle),
  2084. handle->db, handle->updateID)) {
  2085. crv = CKR_OK;
  2086. goto done;
  2087. }
  2088. updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle);
  2089. if (updatePasswordKey) {
  2090. /* pass the source DB key to the legacy code,
  2091. * so it can decrypt things */
  2092. handle->oldKey = updatePasswordKey;
  2093. }
  2094. /* find all the objects */
  2095. crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find);
  2096. if (crv != CKR_OK) {
  2097. goto loser;
  2098. }
  2099. while ((crv == CKR_OK) && (idCount == MAX_IDS)) {
  2100. crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount);
  2101. for (i=0; (crv == CKR_OK) && (i < idCount); i++) {
  2102. crv = sftkdb_mergeObject(handle, ids[i], key);
  2103. }
  2104. }
  2105. crv2 = sftkdb_FindObjectsFinal(handle, find);
  2106. if (crv == CKR_OK) crv = crv2;
  2107. loser:
  2108. /* no longer need the old key value */
  2109. handle->oldKey = NULL;
  2110. /* update the password - even if we didn't update objects */
  2111. if (handle->type == SFTK_KEYDB_TYPE) {
  2112. SECItem item1, item2;
  2113. unsigned char data1[SDB_MAX_META_DATA_LEN];
  2114. unsigned char data2[SDB_MAX_META_DATA_LEN];
  2115. item1.data = data1;
  2116. item1.len = sizeof(data1);
  2117. item2.data = data2;
  2118. item2.len = sizeof(data2);
  2119. /* if the target db already has a password, skip this. */
  2120. crv = (*handle->db->sdb_GetMetaData)(handle->db, "password",
  2121. &item1, &item2);
  2122. if (crv == CKR_OK) {
  2123. goto done;
  2124. }
  2125. /* nope, update it from the source */
  2126. crv = (*handle->update->sdb_GetMetaData)(handle->update, "password",
  2127. &item1, &item2);
  2128. if (crv != CKR_OK) {
  2129. goto done;
  2130. }
  2131. crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1,
  2132. &item2);
  2133. if (crv != CKR_OK) {
  2134. goto done;
  2135. }
  2136. }
  2137. done:
  2138. /* finally mark this up to date db up to date */
  2139. /* some one else has already updated this db */
  2140. if (crv == CKR_OK) {
  2141. crv = sftkdb_putUpdate(sftkdb_TypeString(handle),
  2142. handle->db, handle->updateID);
  2143. }
  2144. if (inTransaction) {
  2145. if (crv == CKR_OK) {
  2146. crv = (*handle->db->sdb_Commit)(handle->db);
  2147. } else {
  2148. (*handle->db->sdb_Abort)(handle->db);
  2149. }
  2150. }
  2151. if (handle->update) {
  2152. (*handle->update->sdb_Close)(handle->update);
  2153. handle->update = NULL;
  2154. }
  2155. if (handle->updateID) {
  2156. PORT_Free(handle->updateID);
  2157. handle->updateID = NULL;
  2158. }
  2159. sftkdb_FreeUpdatePasswordKey(handle);
  2160. if (updatePasswordKey) {
  2161. SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE);
  2162. }
  2163. handle->updateDBIsInit = PR_FALSE;
  2164. return crv;
  2165. }
  2166. /******************************************************************
  2167. * DB handle managing functions.
  2168. *
  2169. * These functions are called by softoken to initialize, acquire,
  2170. * and release database handles.
  2171. */
  2172. const char *
  2173. sftkdb_GetUpdateID(SFTKDBHandle *handle)
  2174. {
  2175. return handle->updateID;
  2176. }
  2177. /* release a database handle */
  2178. void
  2179. sftk_freeDB(SFTKDBHandle *handle)
  2180. {
  2181. PRInt32 ref;
  2182. if (!handle) return;
  2183. ref = PR_ATOMIC_DECREMENT(&handle->ref);
  2184. if (ref == 0) {
  2185. sftkdb_CloseDB(handle);
  2186. }
  2187. return;
  2188. }
  2189. /*
  2190. * acquire a database handle for a certificate db
  2191. * (database for public objects)
  2192. */
  2193. SFTKDBHandle *
  2194. sftk_getCertDB(SFTKSlot *slot)
  2195. {
  2196. SFTKDBHandle *dbHandle;
  2197. PZ_Lock(slot->slotLock);
  2198. dbHandle = slot->certDB;
  2199. if (dbHandle) {
  2200. PR_ATOMIC_INCREMENT(&dbHandle->ref);
  2201. }
  2202. PZ_Unlock(slot->slotLock);
  2203. return dbHandle;
  2204. }
  2205. /*
  2206. * acquire a database handle for a key database
  2207. * (database for private objects)
  2208. */
  2209. SFTKDBHandle *
  2210. sftk_getKeyDB(SFTKSlot *slot)
  2211. {
  2212. SFTKDBHandle *dbHandle;
  2213. SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
  2214. dbHandle = slot->keyDB;
  2215. if (dbHandle) {
  2216. PR_ATOMIC_INCREMENT(&dbHandle->ref);
  2217. }
  2218. SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
  2219. return dbHandle;
  2220. }
  2221. /*
  2222. * acquire the database for a specific object. NOTE: objectID must point
  2223. * to a Token object!
  2224. */
  2225. SFTKDBHandle *
  2226. sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID)
  2227. {
  2228. SFTKDBHandle *dbHandle;
  2229. PZ_Lock(slot->slotLock);
  2230. dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB;
  2231. if (dbHandle) {
  2232. PR_ATOMIC_INCREMENT(&dbHandle->ref);
  2233. }
  2234. PZ_Unlock(slot->slotLock);
  2235. return dbHandle;
  2236. }
  2237. /*
  2238. * initialize a new database handle
  2239. */
  2240. static SFTKDBHandle *
  2241. sftk_NewDBHandle(SDB *sdb, int type)
  2242. {
  2243. SFTKDBHandle *handle = PORT_New(SFTKDBHandle);
  2244. handle->ref = 1;
  2245. handle->db = sdb;
  2246. handle->update = NULL;
  2247. handle->peerDB = NULL;
  2248. handle->newKey = NULL;
  2249. handle->oldKey = NULL;
  2250. handle->updatePasswordKey = NULL;
  2251. handle->updateID = NULL;
  2252. handle->type = type;
  2253. handle->passwordKey.data = NULL;
  2254. handle->passwordKey.len = 0;
  2255. handle->passwordLock = NULL;
  2256. if (type == SFTK_KEYDB_TYPE) {
  2257. handle->passwordLock = PZ_NewLock(nssILockAttribute);
  2258. }
  2259. sdb->app_private = handle;
  2260. return handle;
  2261. }
  2262. /*
  2263. * reset the key database to it's uninitialized state. This call
  2264. * will clear all the key entried.
  2265. */
  2266. SECStatus
  2267. sftkdb_ResetKeyDB(SFTKDBHandle *handle)
  2268. {
  2269. CK_RV crv;
  2270. /* only rest the key db */
  2271. if (handle->type != SFTK_KEYDB_TYPE) {
  2272. return SECFailure;
  2273. }
  2274. crv = sftkdb_ResetDB(handle);
  2275. if (crv != CKR_OK) {
  2276. /* set error */
  2277. return SECFailure;
  2278. }
  2279. return SECSuccess;
  2280. }
  2281. static PRBool
  2282. sftk_oldVersionExists(const char *dir, int version)
  2283. {
  2284. int i;
  2285. PRStatus exists = PR_FAILURE;
  2286. char *file = NULL;
  2287. for (i=version; i > 1 ; i--) {
  2288. file = PR_smprintf("%s%d.db",dir,i);
  2289. if (file == NULL) {
  2290. continue;
  2291. }
  2292. exists = PR_Access(file, PR_ACCESS_EXISTS);
  2293. PR_smprintf_free(file);
  2294. if (exists == PR_SUCCESS) {
  2295. return PR_TRUE;
  2296. }
  2297. }
  2298. return PR_FALSE;
  2299. }
  2300. static PRBool
  2301. sftk_hasLegacyDB(const char *confdir, const char *certPrefix,
  2302. const char *keyPrefix, int certVersion, int keyVersion)
  2303. {
  2304. char *dir;
  2305. PRBool exists;
  2306. if (certPrefix == NULL) {
  2307. certPrefix = "";
  2308. }
  2309. if (keyPrefix == NULL) {
  2310. keyPrefix = "";
  2311. }
  2312. dir= PR_smprintf("%s/%scert", confdir, certPrefix);
  2313. if (dir == NULL) {
  2314. return PR_FALSE;
  2315. }
  2316. exists = sftk_oldVersionExists(dir, certVersion);
  2317. PR_smprintf_free(dir);
  2318. if (exists) {
  2319. return PR_TRUE;
  2320. }
  2321. dir= PR_smprintf("%s/%skey", confdir, keyPrefix);
  2322. if (dir == NULL) {
  2323. return PR_FALSE;
  2324. }
  2325. exists = sftk_oldVersionExists(dir, keyVersion);
  2326. PR_smprintf_free(dir);
  2327. return exists;
  2328. }
  2329. /*
  2330. * initialize certificate and key database handles as a pair.
  2331. *
  2332. * This function figures out what type of database we are opening and
  2333. * calls the appropriate low level function to open the database.
  2334. * It also figures out whether or not to setup up automatic update.
  2335. */
  2336. CK_RV
  2337. sftk_DBInit(const char *configdir, const char *certPrefix,
  2338. const char *keyPrefix, const char *updatedir,
  2339. const char *updCertPrefix, const char *updKeyPrefix,
  2340. const char *updateID, PRBool readOnly, PRBool noCertDB,
  2341. PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS,
  2342. SFTKDBHandle **certDB, SFTKDBHandle **keyDB)
  2343. {
  2344. const char *confdir;
  2345. SDBType dbType;
  2346. char *appName = NULL;
  2347. SDB *keySDB, *certSDB;
  2348. CK_RV crv = CKR_OK;
  2349. int flags = SDB_RDONLY;
  2350. PRBool newInit = PR_FALSE;
  2351. PRBool needUpdate = PR_FALSE;
  2352. if (!readOnly) {
  2353. flags = SDB_CREATE;
  2354. }
  2355. *certDB = NULL;
  2356. *keyDB = NULL;
  2357. if (noKeyDB && noCertDB) {
  2358. return CKR_OK;
  2359. }
  2360. confdir = sftk_EvaluateConfigDir(configdir, &dbType, &appName);
  2361. /*
  2362. * now initialize the appropriate database
  2363. */
  2364. switch (dbType) {
  2365. case SDB_LEGACY:
  2366. crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
  2367. isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB);
  2368. break;
  2369. case SDB_MULTIACCESS:
  2370. crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags,
  2371. isFIPS, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB);
  2372. break;
  2373. case SDB_SQL:
  2374. case SDB_EXTERN: /* SHOULD open a loadable db */
  2375. crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags,
  2376. noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit);
  2377. /*
  2378. * if we failed to open the DB's read only, use the old ones if
  2379. * the exists.
  2380. */
  2381. if (crv != CKR_OK) {
  2382. if ((flags == SDB_RDONLY) &&
  2383. sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) {
  2384. /* we have legacy databases, if we failed to open the new format
  2385. * DB's read only, just use the legacy ones */
  2386. crv = sftkdbCall_open(confdir, certPrefix,
  2387. keyPrefix, 8, 3, flags, isFIPS,
  2388. noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
  2389. }
  2390. /* Handle the database merge case.
  2391. *
  2392. * For the merge case, we need help from the application. Only
  2393. * the application knows where the old database is, and what unique
  2394. * identifier it has associated with it.
  2395. *
  2396. * If the client supplies these values, we use them to determine
  2397. * if we need to update.
  2398. */
  2399. } else if (
  2400. /* both update params have been supplied */
  2401. updatedir && *updatedir && updateID && *updateID
  2402. /* old dbs exist? */
  2403. && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3)
  2404. /* and they have not yet been updated? */
  2405. && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID))
  2406. || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) {
  2407. /* we need to update */
  2408. confdir = updatedir;
  2409. certPrefix = updCertPrefix;
  2410. keyPrefix = updKeyPrefix;
  2411. needUpdate = PR_TRUE;
  2412. } else if (newInit) {
  2413. /* if the new format DB was also a newly created DB, and we
  2414. * succeeded, then need to update that new database with data
  2415. * from the existing legacy DB */
  2416. if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) {
  2417. needUpdate = PR_TRUE;
  2418. }
  2419. }
  2420. break;
  2421. default:
  2422. crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST
  2423. * return one of the types we already
  2424. * specified. */
  2425. }
  2426. if (crv != CKR_OK) {
  2427. goto done;
  2428. }
  2429. if (!noCertDB) {
  2430. *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE);
  2431. } else {
  2432. *certDB = NULL;
  2433. }
  2434. if (!noKeyDB) {
  2435. *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE);
  2436. } else {
  2437. *keyDB = NULL;
  2438. }
  2439. /* link them together */
  2440. if (*certDB) {
  2441. (*certDB)->peerDB = *keyDB;
  2442. }
  2443. if (*keyDB) {
  2444. (*keyDB)->peerDB = *certDB;
  2445. }
  2446. /*
  2447. * if we need to update, open the legacy database and
  2448. * mark the handle as needing update.
  2449. */
  2450. if (needUpdate) {
  2451. SDB *updateCert = NULL;
  2452. SDB *updateKey = NULL;
  2453. CK_RV crv2;
  2454. crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
  2455. isFIPS, noCertDB ? NULL : &updateCert,
  2456. noKeyDB ? NULL : &updateKey);
  2457. if (crv2 == CKR_OK) {
  2458. if (*certDB) {
  2459. (*certDB)->update = updateCert;
  2460. (*certDB)->updateID = updateID && *updateID
  2461. ? PORT_Strdup(updateID) : NULL;
  2462. updateCert->app_private = (*certDB);
  2463. }
  2464. if (*keyDB) {
  2465. PRBool tokenRemoved = PR_FALSE;
  2466. (*keyDB)->update = updateKey;
  2467. (*keyDB)->updateID = updateID && *updateID ?
  2468. PORT_Strdup(updateID) : NULL;
  2469. updateKey->app_private = (*keyDB);
  2470. (*keyDB)->updateDBIsInit = PR_TRUE;
  2471. (*keyDB)->updateDBIsInit =
  2472. (sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ?
  2473. PR_TRUE : PR_FALSE;
  2474. /* if the password on the key db is NULL, kick off our update
  2475. * chain of events */
  2476. sftkdb_CheckPassword((*keyDB), "", &tokenRemoved);
  2477. } else {
  2478. /* we don't have a key DB, update the certificate DB now */
  2479. sftkdb_Update(*certDB, NULL);
  2480. }
  2481. }
  2482. }
  2483. done:
  2484. if (appName) {
  2485. PORT_Free(appName);
  2486. }
  2487. return forceOpen ? CKR_OK : crv;
  2488. }
  2489. CK_RV
  2490. sftkdb_Shutdown(void)
  2491. {
  2492. s_shutdown();
  2493. sftkdbCall_Shutdown();
  2494. return CKR_OK;
  2495. }