PageRenderTime 64ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/mkato/mozilla-1.9.0-win64
C | 2713 lines | 1906 code | 270 blank | 537 comment | 561 complexity | ebd446c454642045d84a75cdd2765876 MD5 | raw file
Possible License(s): LGPL-3.0, MIT, BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  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. SFTKDBHandle *keyHandle = handle;
  471. SDB *keyTarget = NULL;
  472. PORT_Assert(handle);
  473. if (handle->type != SFTK_KEYDB_TYPE) {
  474. keyHandle = handle->peerDB;
  475. }
  476. /* no key DB defined? then no need to sign anything */
  477. if (keyHandle == NULL) {
  478. return CKR_OK;
  479. }
  480. /* When we are in a middle of an update, we have an update database set,
  481. * but we want to write to the real database. The bool mayBeUpdateDB is
  482. * set to TRUE if it's possible that we want to write an update database
  483. * rather than a primary */
  484. keyTarget = (mayBeUpdateDB && keyHandle->update) ?
  485. keyHandle->update : keyHandle->db;
  486. /* skip the the database does not support meta data */
  487. if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
  488. return CKR_OK;
  489. }
  490. for (i=0; i < count; i ++) {
  491. if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
  492. SECStatus rv;
  493. SECItem *signText;
  494. SECItem plainText;
  495. plainText.data = template[i].pValue;
  496. plainText.len = template[i].ulValueLen;
  497. PZ_Lock(keyHandle->passwordLock);
  498. if (keyHandle->passwordKey.data == NULL) {
  499. PZ_Unlock(keyHandle->passwordLock);
  500. return CKR_USER_NOT_LOGGED_IN;
  501. }
  502. rv = sftkdb_SignAttribute(arena, &keyHandle->passwordKey,
  503. objectID, template[i].type,
  504. &plainText, &signText);
  505. PZ_Unlock(keyHandle->passwordLock);
  506. if (rv != SECSuccess) {
  507. return CKR_GENERAL_ERROR; /* better error code here? */
  508. }
  509. rv = sftkdb_PutAttributeSignature(handle, keyTarget,
  510. objectID, template[i].type, signText);
  511. if (rv != SECSuccess) {
  512. return CKR_GENERAL_ERROR; /* better error code here? */
  513. }
  514. }
  515. }
  516. return CKR_OK;
  517. }
  518. static CK_RV
  519. sftkdb_CreateObject(PRArenaPool *arena, SFTKDBHandle *handle,
  520. SDB *db, CK_OBJECT_HANDLE *objectID,
  521. CK_ATTRIBUTE *template, CK_ULONG count)
  522. {
  523. PRBool inTransaction = PR_FALSE;
  524. CK_RV crv;
  525. inTransaction = PR_TRUE;
  526. crv = (*db->sdb_CreateObject)(db, objectID, template, count);
  527. if (crv != CKR_OK) {
  528. goto loser;
  529. }
  530. crv = sftk_signTemplate(arena, handle, (db == handle->update),
  531. *objectID, template, count);
  532. loser:
  533. return crv;
  534. }
  535. CK_ATTRIBUTE *
  536. sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
  537. SFTKDBHandle *handle,CK_ULONG *pcount,
  538. CK_RV *crv)
  539. {
  540. int count;
  541. CK_ATTRIBUTE *template;
  542. int i, templateIndex;
  543. SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
  544. PRBool doEnc = PR_TRUE;
  545. *crv = CKR_OK;
  546. if (sessObject == NULL) {
  547. *crv = CKR_GENERAL_ERROR; /* internal programming error */
  548. return NULL;
  549. }
  550. PORT_Assert(handle);
  551. /* find the key handle */
  552. if (handle->type != SFTK_KEYDB_TYPE) {
  553. doEnc = PR_FALSE;
  554. }
  555. PZ_Lock(sessObject->attributeLock);
  556. count = 0;
  557. for (i=0; i < sessObject->hashSize; i++) {
  558. SFTKAttribute *attr;
  559. for (attr=sessObject->head[i]; attr; attr=attr->next) {
  560. count++;
  561. }
  562. }
  563. template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count);
  564. if (template == NULL) {
  565. PZ_Unlock(sessObject->attributeLock);
  566. *crv = CKR_HOST_MEMORY;
  567. return NULL;
  568. }
  569. templateIndex = 0;
  570. for (i=0; i < sessObject->hashSize; i++) {
  571. SFTKAttribute *attr;
  572. for (attr=sessObject->head[i]; attr; attr=attr->next) {
  573. CK_ATTRIBUTE *tp = &template[templateIndex++];
  574. /* copy the attribute */
  575. *tp = attr->attrib;
  576. /* fixup ULONG s */
  577. if ((tp->ulValueLen == sizeof (CK_ULONG)) &&
  578. (sftkdb_isULONGAttribute(tp->type)) ) {
  579. CK_ULONG value = *(CK_ULONG *) tp->pValue;
  580. unsigned char *data;
  581. tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE);
  582. data = (unsigned char *)tp->pValue;
  583. if (data == NULL) {
  584. *crv = CKR_HOST_MEMORY;
  585. break;
  586. }
  587. sftk_ULong2SDBULong(data, value);
  588. tp->ulValueLen = SDB_ULONG_SIZE;
  589. }
  590. /* encrypt private attributes */
  591. if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
  592. /* we have a private attribute */
  593. SECItem *cipherText;
  594. SECItem plainText;
  595. SECStatus rv;
  596. plainText.data = tp->pValue;
  597. plainText.len = tp->ulValueLen;
  598. PZ_Lock(handle->passwordLock);
  599. if (handle->passwordKey.data == NULL) {
  600. PZ_Unlock(handle->passwordLock);
  601. *crv = CKR_USER_NOT_LOGGED_IN;
  602. break;
  603. }
  604. rv = sftkdb_EncryptAttribute(arena, &handle->passwordKey,
  605. &plainText, &cipherText);
  606. PZ_Unlock(handle->passwordLock);
  607. if (rv == SECSuccess) {
  608. tp->pValue = cipherText->data;
  609. tp->ulValueLen = cipherText->len;
  610. } else {
  611. *crv = CKR_GENERAL_ERROR; /* better error code here? */
  612. break;
  613. }
  614. PORT_Memset(plainText.data, 0, plainText.len);
  615. }
  616. }
  617. }
  618. PORT_Assert(templateIndex <= count);
  619. PZ_Unlock(sessObject->attributeLock);
  620. if (*crv != CKR_OK) {
  621. return NULL;
  622. }
  623. if (pcount) {
  624. *pcount = count;
  625. }
  626. return template;
  627. }
  628. /*
  629. * return a pointer to the attribute in the give template.
  630. * The return value is not const, as the caller may modify
  631. * the given attribute value, but such modifications will
  632. * modify the actual value in the template.
  633. */
  634. static CK_ATTRIBUTE *
  635. sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute,
  636. CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  637. {
  638. CK_ULONG i;
  639. for (i=0; i < len; i++) {
  640. if (attribute == ptemplate[i].type) {
  641. return &ptemplate[i];
  642. }
  643. }
  644. return NULL;
  645. }
  646. static const CK_ATTRIBUTE *
  647. sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute,
  648. const CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  649. {
  650. CK_ULONG i;
  651. for (i=0; i < len; i++) {
  652. if (attribute == ptemplate[i].type) {
  653. return &ptemplate[i];
  654. }
  655. }
  656. return NULL;
  657. }
  658. /*
  659. * fetch a template which identifies 'unique' entries based on object type
  660. */
  661. static CK_RV
  662. sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData,
  663. CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount,
  664. CK_ATTRIBUTE *ptemplate, int len)
  665. {
  666. CK_ATTRIBUTE *attr;
  667. CK_ULONG count = 1;
  668. sftk_ULong2SDBULong(objTypeData, objectType);
  669. findTemplate[0].type = CKA_CLASS;
  670. findTemplate[0].pValue = objTypeData;
  671. findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
  672. switch (objectType) {
  673. case CKO_CERTIFICATE:
  674. case CKO_NSS_TRUST:
  675. attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len);
  676. if (attr == NULL) {
  677. return CKR_TEMPLATE_INCOMPLETE;
  678. }
  679. findTemplate[1] = *attr;
  680. attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER,
  681. ptemplate, len);
  682. if (attr == NULL) {
  683. return CKR_TEMPLATE_INCOMPLETE;
  684. }
  685. findTemplate[2] = *attr;
  686. count = 3;
  687. break;
  688. case CKO_PRIVATE_KEY:
  689. case CKO_PUBLIC_KEY:
  690. case CKO_SECRET_KEY:
  691. attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len);
  692. if (attr == NULL) {
  693. return CKR_TEMPLATE_INCOMPLETE;
  694. }
  695. findTemplate[1] = *attr;
  696. count = 2;
  697. break;
  698. case CKO_NSS_CRL:
  699. attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
  700. if (attr == NULL) {
  701. return CKR_TEMPLATE_INCOMPLETE;
  702. }
  703. findTemplate[1] = *attr;
  704. count = 2;
  705. break;
  706. case CKO_NSS_SMIME:
  707. attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
  708. if (attr == NULL) {
  709. return CKR_TEMPLATE_INCOMPLETE;
  710. }
  711. findTemplate[1] = *attr;
  712. attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len);
  713. if (attr == NULL) {
  714. return CKR_TEMPLATE_INCOMPLETE;
  715. }
  716. findTemplate[2] = *attr;
  717. count = 3;
  718. break;
  719. default:
  720. attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len);
  721. if (attr == NULL) {
  722. return CKR_TEMPLATE_INCOMPLETE;
  723. }
  724. findTemplate[1] = *attr;
  725. count = 2;
  726. break;
  727. }
  728. *findCount = count;
  729. return CKR_OK;
  730. }
  731. /*
  732. * look to see if this object already exists and return it's object ID if
  733. * it does.
  734. */
  735. static CK_RV
  736. sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType,
  737. CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  738. {
  739. CK_ATTRIBUTE findTemplate[3];
  740. CK_ULONG count = 1;
  741. CK_ULONG objCount = 0;
  742. SDBFind *find = NULL;
  743. unsigned char objTypeData[SDB_ULONG_SIZE];
  744. CK_RV crv;
  745. *id = CK_INVALID_HANDLE;
  746. if (objectType == CKO_NSS_CRL) {
  747. return CKR_OK;
  748. }
  749. crv = sftkdb_getFindTemplate(objectType, objTypeData,
  750. findTemplate, &count, ptemplate, len);
  751. if (crv != CKR_OK) {
  752. return crv;
  753. }
  754. /* use the raw find, so we get the correct database */
  755. crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find);
  756. if (crv != CKR_OK) {
  757. return crv;
  758. }
  759. (*db->sdb_FindObjects)(db, find, id, 1, &objCount);
  760. (*db->sdb_FindObjectsFinal)(db, find);
  761. if (objCount == 0) {
  762. *id = CK_INVALID_HANDLE;
  763. }
  764. return CKR_OK;
  765. }
  766. /*
  767. * check to see if this template conflicts with others in our current database.
  768. */
  769. static CK_RV
  770. sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType,
  771. const CK_ATTRIBUTE *ptemplate, CK_ULONG len,
  772. CK_OBJECT_HANDLE sourceID)
  773. {
  774. CK_ATTRIBUTE findTemplate[2];
  775. unsigned char objTypeData[SDB_ULONG_SIZE];
  776. /* we may need to allocate some temporaries. Keep track of what was
  777. * allocated so we can free it in the end */
  778. unsigned char *temp1 = NULL;
  779. unsigned char *temp2 = NULL;
  780. CK_ULONG objCount = 0;
  781. SDBFind *find = NULL;
  782. CK_OBJECT_HANDLE id;
  783. const CK_ATTRIBUTE *attr, *attr2;
  784. CK_RV crv;
  785. CK_ATTRIBUTE subject;
  786. /* Currently the only conflict is with nicknames pointing to the same
  787. * subject when creating or modifying a certificate. */
  788. /* If the object is not a cert, no problem. */
  789. if (objectType != CKO_CERTIFICATE) {
  790. return CKR_OK;
  791. }
  792. /* if not setting a nickname then there's still no problem */
  793. attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len);
  794. if ((attr == NULL) || (attr->ulValueLen == 0)) {
  795. return CKR_OK;
  796. }
  797. /* fetch the subject of the source. For creation and merge, this should
  798. * be found in the template */
  799. attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len);
  800. if (sourceID == CK_INVALID_HANDLE) {
  801. if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) {
  802. crv = CKR_TEMPLATE_INCOMPLETE;
  803. goto done;
  804. }
  805. } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) {
  806. /* sourceID is set if we are trying to modify an existing entry instead
  807. * of creating a new one. In this case the subject may not be (probably
  808. * isn't) in the template, we have to read it from the database */
  809. subject.type = CKA_SUBJECT;
  810. subject.pValue = NULL;
  811. subject.ulValueLen = 0;
  812. crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
  813. if (crv != CKR_OK) {
  814. goto done;
  815. }
  816. if ((CK_LONG)subject.ulValueLen < 0) {
  817. crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */
  818. goto done;
  819. }
  820. temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen);
  821. if (temp1 == NULL) {
  822. crv = CKR_HOST_MEMORY;
  823. goto done;
  824. }
  825. crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
  826. if (crv != CKR_OK) {
  827. goto done;
  828. }
  829. attr2 = &subject;
  830. }
  831. /* check for another cert in the database with the same nickname */
  832. sftk_ULong2SDBULong(objTypeData, objectType);
  833. findTemplate[0].type = CKA_CLASS;
  834. findTemplate[0].pValue = objTypeData;
  835. findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
  836. findTemplate[1] = *attr;
  837. crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find);
  838. if (crv != CKR_OK) {
  839. goto done;
  840. }
  841. (*db->sdb_FindObjects)(db, find, &id, 1, &objCount);
  842. (*db->sdb_FindObjectsFinal)(db, find);
  843. /* object count == 0 means no conflicting certs found,
  844. * go on with the operation */
  845. if (objCount == 0) {
  846. crv = CKR_OK;
  847. goto done;
  848. }
  849. /* There is a least one cert that shares the nickname, make sure it also
  850. * matches the subject. */
  851. findTemplate[0] = *attr2;
  852. /* we know how big the source subject was. Use that length to create the
  853. * space for the target. If it's not enough space, then it means the
  854. * source subject is too big, and therefore not a match. GetAttributeValue
  855. * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough
  856. * space (or enough space to be able to compare the result. */
  857. temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen);
  858. if (temp2 == NULL) {
  859. crv = CKR_HOST_MEMORY;
  860. goto done;
  861. }
  862. crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1);
  863. if (crv != CKR_OK) {
  864. if (crv == CKR_BUFFER_TOO_SMALL) {
  865. /* if our buffer is too small, then the Subjects clearly do
  866. * not match */
  867. crv = CKR_ATTRIBUTE_VALUE_INVALID;
  868. goto loser;
  869. }
  870. /* otherwise we couldn't get the value, just fail */
  871. goto done;
  872. }
  873. /* Ok, we have both subjects, make sure they are the same.
  874. * Compare the subjects */
  875. if ((findTemplate[0].ulValueLen != attr2->ulValueLen) ||
  876. (attr2->ulValueLen > 0 &&
  877. PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen)
  878. != 0)) {
  879. crv = CKR_ATTRIBUTE_VALUE_INVALID;
  880. goto loser;
  881. }
  882. crv = CKR_OK;
  883. done:
  884. /* If we've failed for some other reason than a conflict, make sure we
  885. * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID.
  886. * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should
  887. * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia).
  888. */
  889. if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
  890. crv = CKR_GENERAL_ERROR; /* clearly a programming error */
  891. }
  892. /* exit point if we found a conflict */
  893. loser:
  894. PORT_Free(temp1);
  895. PORT_Free(temp2);
  896. return crv;
  897. }
  898. /*
  899. * try to update the template to fix any errors. This is only done
  900. * during update.
  901. *
  902. * NOTE: we must update the template or return an error, or the update caller
  903. * will loop forever!
  904. *
  905. * Two copies of the source code for this algorithm exist in NSS.
  906. * Changes must be made in both copies.
  907. * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c.
  908. *
  909. */
  910. static CK_RV
  911. sftkdb_resolveConflicts(PRArenaPool *arena, CK_OBJECT_CLASS objectType,
  912. CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
  913. {
  914. CK_ATTRIBUTE *attr;
  915. char *nickname, *newNickname;
  916. int end, digit;
  917. /* sanity checks. We should never get here with these errors */
  918. if (objectType != CKO_CERTIFICATE) {
  919. return CKR_GENERAL_ERROR; /* shouldn't happen */
  920. }
  921. attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
  922. if ((attr == NULL) || (attr->ulValueLen == 0)) {
  923. return CKR_GENERAL_ERROR; /* shouldn't happen */
  924. }
  925. /* update the nickname */
  926. /* is there a number at the end of the nickname already?
  927. * if so just increment that number */
  928. nickname = (char *)attr->pValue;
  929. /* does nickname end with " #n*" ? */
  930. for (end = attr->ulValueLen - 1;
  931. end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0';
  932. end--) /* just scan */ ;
  933. if (attr->ulValueLen >= 3 &&
  934. end < (attr->ulValueLen - 1) /* at least one digit */ &&
  935. nickname[end] == '#' &&
  936. nickname[end - 1] == ' ') {
  937. /* Already has a suitable suffix string */
  938. } else {
  939. /* ... append " #2" to the name */
  940. static const char num2[] = " #2";
  941. newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2));
  942. if (!newNickname) {
  943. return CKR_HOST_MEMORY;
  944. }
  945. PORT_Memcpy(newNickname, nickname, attr->ulValueLen);
  946. PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2));
  947. attr->pValue = newNickname; /* modifies ptemplate */
  948. attr->ulValueLen += 3; /* 3 is strlen(num2) */
  949. return CKR_OK;
  950. }
  951. for (end = attr->ulValueLen - 1;
  952. end >= 0 && (digit = nickname[end]) <= '9' && digit >= '0';
  953. end--) {
  954. if (digit < '9') {
  955. nickname[end]++;
  956. return CKR_OK;
  957. }
  958. nickname[end] = '0';
  959. }
  960. /* we overflowed, insert a new '1' for a carry in front of the number */
  961. newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1);
  962. if (!newNickname) {
  963. return CKR_HOST_MEMORY;
  964. }
  965. /* PORT_Memcpy should handle len of '0' */
  966. PORT_Memcpy(newNickname, nickname, ++end);
  967. newNickname[end] = '1';
  968. PORT_Memset(&newNickname[end+1],'0',attr->ulValueLen - end);
  969. attr->pValue = newNickname;
  970. attr->ulValueLen++;
  971. return CKR_OK;
  972. }
  973. /*
  974. * set an attribute and sign it if necessary
  975. */
  976. static CK_RV
  977. sftkdb_setAttributeValue(PRArenaPool *arena, SFTKDBHandle *handle,
  978. SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
  979. CK_ULONG count)
  980. {
  981. CK_RV crv;
  982. crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count);
  983. if (crv != CKR_OK) {
  984. return crv;
  985. }
  986. crv = sftk_signTemplate(arena, handle, db == handle->update,
  987. objectID, template, count);
  988. return crv;
  989. }
  990. /*
  991. * write a softoken object out to the database.
  992. */
  993. CK_RV
  994. sftkdb_write(SFTKDBHandle *handle, SFTKObject *object,
  995. CK_OBJECT_HANDLE *objectID)
  996. {
  997. CK_ATTRIBUTE *template;
  998. PLArenaPool *arena;
  999. CK_ULONG count;
  1000. CK_RV crv;
  1001. SDB *db;
  1002. PRBool inTransaction = PR_FALSE;
  1003. CK_OBJECT_HANDLE id;
  1004. *objectID = CK_INVALID_HANDLE;
  1005. if (handle == NULL) {
  1006. return CKR_TOKEN_WRITE_PROTECTED;
  1007. }
  1008. db = SFTK_GET_SDB(handle);
  1009. /*
  1010. * we have opened a new database, but we have not yet updated it. We are
  1011. * still running pointing to the old database (so the application can
  1012. * still read). We don't want to write to the old database at this point,
  1013. * however, since it leads to user confusion. So at this point we simply
  1014. * require a user login. Let NSS know this so it can prompt the user.
  1015. */
  1016. if (db == handle->update) {
  1017. return CKR_USER_NOT_LOGGED_IN;
  1018. }
  1019. arena = PORT_NewArena(256);
  1020. if (arena == NULL) {
  1021. return CKR_HOST_MEMORY;
  1022. }
  1023. template = sftk_ExtractTemplate(arena, object, handle, &count, &crv);
  1024. if (!template) {
  1025. goto loser;
  1026. }
  1027. crv = (*db->sdb_Begin)(db);
  1028. if (crv != CKR_OK) {
  1029. goto loser;
  1030. }
  1031. inTransaction = PR_TRUE;
  1032. /*
  1033. * We want to make the base database as free from object specific knowledge
  1034. * as possible. To maintain compatibility, keep some of the desirable
  1035. * object specific semantics of the old database.
  1036. *
  1037. * These were 2 fold:
  1038. * 1) there were certain conflicts (like trying to set the same nickname
  1039. * on two different subjects) that would return an error.
  1040. * 2) Importing the 'same' object would silently update that object.
  1041. *
  1042. * The following 2 functions mimic the desirable effects of these two
  1043. * semantics without pushing any object knowledge to the underlying database
  1044. * code.
  1045. */
  1046. /* make sure we don't have attributes that conflict with the existing DB */
  1047. crv = sftkdb_checkConflicts(db, object->objclass, template, count,
  1048. CK_INVALID_HANDLE);
  1049. if (crv != CKR_OK) {
  1050. goto loser;
  1051. }
  1052. /* Find any copies that match this particular object */
  1053. crv = sftkdb_lookupObject(db, object->objclass, &id, template, count);
  1054. if (crv != CKR_OK) {
  1055. goto loser;
  1056. }
  1057. if (id == CK_INVALID_HANDLE) {
  1058. crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
  1059. } else {
  1060. /* object already exists, modify it's attributes */
  1061. *objectID = id;
  1062. crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count);
  1063. }
  1064. if (crv != CKR_OK) {
  1065. goto loser;
  1066. }
  1067. crv = (*db->sdb_Commit)(db);
  1068. inTransaction = PR_FALSE;
  1069. loser:
  1070. if (inTransaction) {
  1071. (*db->sdb_Abort)(db);
  1072. /* It is trivial to show the following code cannot
  1073. * happen unless something is horribly wrong with our compilier or
  1074. * hardware */
  1075. PORT_Assert(crv != CKR_OK);
  1076. if (crv == CKR_OK) crv = CKR_GENERAL_ERROR;
  1077. }
  1078. if (arena) {
  1079. PORT_FreeArena(arena,PR_FALSE);
  1080. }
  1081. if (crv == CKR_OK) {
  1082. *objectID |= (handle->type | SFTK_TOKEN_TYPE);
  1083. }
  1084. return crv;
  1085. }
  1086. CK_RV
  1087. sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template,
  1088. CK_ULONG count, SDBFind **find)
  1089. {
  1090. unsigned char *data = NULL;
  1091. CK_ATTRIBUTE *ntemplate = NULL;
  1092. CK_RV crv;
  1093. SDB *db;
  1094. if (handle == NULL) {
  1095. return CKR_OK;
  1096. }
  1097. db = SFTK_GET_SDB(handle);
  1098. if (count != 0) {
  1099. ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
  1100. if (ntemplate == NULL) {
  1101. return CKR_HOST_MEMORY;
  1102. }
  1103. }
  1104. crv = (*db->sdb_FindObjectsInit)(db, ntemplate,
  1105. count, find);
  1106. if (data) {
  1107. PORT_Free(ntemplate);
  1108. PORT_Free(data);
  1109. }
  1110. return crv;
  1111. }
  1112. CK_RV
  1113. sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find,
  1114. CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count)
  1115. {
  1116. CK_RV crv;
  1117. SDB *db;
  1118. if (handle == NULL) {
  1119. *count = 0;
  1120. return CKR_OK;
  1121. }
  1122. db = SFTK_GET_SDB(handle);
  1123. crv = (*db->sdb_FindObjects)(db, find, ids,
  1124. arraySize, count);
  1125. if (crv == CKR_OK) {
  1126. int i;
  1127. for (i=0; i < *count; i++) {
  1128. ids[i] |= (handle->type | SFTK_TOKEN_TYPE);
  1129. }
  1130. }
  1131. return crv;
  1132. }
  1133. CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find)
  1134. {
  1135. SDB *db;
  1136. if (handle == NULL) {
  1137. return CKR_OK;
  1138. }
  1139. db = SFTK_GET_SDB(handle);
  1140. return (*db->sdb_FindObjectsFinal)(db, find);
  1141. }
  1142. CK_RV
  1143. sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
  1144. CK_ATTRIBUTE *template, CK_ULONG count)
  1145. {
  1146. CK_RV crv,crv2;
  1147. CK_ATTRIBUTE *ntemplate;
  1148. unsigned char *data = NULL;
  1149. SDB *db;
  1150. if (handle == NULL) {
  1151. return CKR_GENERAL_ERROR;
  1152. }
  1153. /* short circuit common attributes */
  1154. if (count == 1 &&
  1155. (template[0].type == CKA_TOKEN ||
  1156. template[0].type == CKA_PRIVATE ||
  1157. template[0].type == CKA_SENSITIVE)) {
  1158. CK_BBOOL boolVal = CK_TRUE;
  1159. if (template[0].pValue == NULL) {
  1160. template[0].ulValueLen = sizeof(CK_BBOOL);
  1161. return CKR_OK;
  1162. }
  1163. if (template[0].ulValueLen < sizeof(CK_BBOOL)) {
  1164. template[0].ulValueLen = -1;
  1165. return CKR_BUFFER_TOO_SMALL;
  1166. }
  1167. if ((template[0].type == CKA_PRIVATE) &&
  1168. (handle->type != SFTK_KEYDB_TYPE)) {
  1169. boolVal = CK_FALSE;
  1170. }
  1171. if ((template[0].type == CKA_SENSITIVE) &&
  1172. (handle->type != SFTK_KEYDB_TYPE)) {
  1173. boolVal = CK_FALSE;
  1174. }
  1175. *(CK_BBOOL *)template[0].pValue = boolVal;
  1176. template[0].ulValueLen = sizeof(CK_BBOOL);
  1177. return CKR_OK;
  1178. }
  1179. db = SFTK_GET_SDB(handle);
  1180. /* nothing to do */
  1181. if (count == 0) {
  1182. return CKR_OK;
  1183. }
  1184. ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
  1185. if (ntemplate == NULL) {
  1186. return CKR_HOST_MEMORY;
  1187. }
  1188. objectID &= SFTK_OBJ_ID_MASK;
  1189. crv = (*db->sdb_GetAttributeValue)(db, objectID,
  1190. ntemplate, count);
  1191. crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate,
  1192. count, handle);
  1193. if (crv == CKR_OK) crv = crv2;
  1194. if (data) {
  1195. PORT_Free(ntemplate);
  1196. PORT_Free(data);
  1197. }
  1198. return crv;
  1199. }
  1200. CK_RV
  1201. sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object,
  1202. const CK_ATTRIBUTE *template, CK_ULONG count)
  1203. {
  1204. CK_RV crv = CKR_OK;
  1205. CK_ATTRIBUTE *ntemplate;
  1206. unsigned char *data = NULL;
  1207. PLArenaPool *arena = NULL;
  1208. CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK);
  1209. SDB *db;
  1210. if (handle == NULL) {
  1211. return CKR_TOKEN_WRITE_PROTECTED;
  1212. }
  1213. db = SFTK_GET_SDB(handle);
  1214. /* nothing to do */
  1215. if (count == 0) {
  1216. return CKR_OK;
  1217. }
  1218. /*
  1219. * we have opened a new database, but we have not yet updated it. We are
  1220. * still running pointing to the old database (so the application can
  1221. * still read). We don't want to write to the old database at this point,
  1222. * however, since it leads to user confusion. So at this point we simply
  1223. * require a user login. Let NSS know this so it can prompt the user.
  1224. */
  1225. if (db == handle->update) {
  1226. return CKR_USER_NOT_LOGGED_IN;
  1227. }
  1228. ntemplate = sftkdb_fixupTemplateIn(template, count, &data);
  1229. if (ntemplate == NULL) {
  1230. return CKR_HOST_MEMORY;
  1231. }
  1232. /* make sure we don't have attributes that conflict with the existing DB */
  1233. crv = sftkdb_checkConflicts(db, object->objclass, template, count, objectID);
  1234. if (crv != CKR_OK) {
  1235. return crv;
  1236. }
  1237. arena = PORT_NewArena(256);
  1238. if (arena == NULL) {
  1239. return CKR_HOST_MEMORY;
  1240. }
  1241. crv = (*db->sdb_Begin)(db);
  1242. if (crv != CKR_OK) {
  1243. goto loser;
  1244. }
  1245. crv = sftkdb_setAttributeValue(arena, handle, db,
  1246. objectID, template, count);
  1247. if (crv != CKR_OK) {
  1248. goto loser;
  1249. }
  1250. crv = (*db->sdb_Commit)(db);
  1251. loser:
  1252. if (crv != CKR_OK) {
  1253. (*db->sdb_Abort)(db);
  1254. }
  1255. if (data) {
  1256. PORT_Free(ntemplate);
  1257. PORT_Free(data);
  1258. }
  1259. PORT_FreeArena(arena, PR_FALSE);
  1260. return crv;
  1261. }
  1262. CK_RV
  1263. sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID)
  1264. {
  1265. CK_RV crv = CKR_OK;
  1266. SDB *db;
  1267. if (handle == NULL) {
  1268. return CKR_TOKEN_WRITE_PROTECTED;
  1269. }
  1270. db = SFTK_GET_SDB(handle);
  1271. objectID &= SFTK_OBJ_ID_MASK;
  1272. crv = (*db->sdb_Begin)(db);
  1273. if (crv != CKR_OK) {
  1274. goto loser;
  1275. }
  1276. crv = (*db->sdb_DestroyObject)(db, objectID);
  1277. if (crv != CKR_OK) {
  1278. goto loser;
  1279. }
  1280. crv = (*db->sdb_Commit)(db);
  1281. loser:
  1282. if (crv != CKR_OK) {
  1283. (*db->sdb_Abort)(db);
  1284. }
  1285. return crv;
  1286. }
  1287. CK_RV
  1288. sftkdb_CloseDB(SFTKDBHandle *handle)
  1289. {
  1290. #ifdef NO_FORK_CHECK
  1291. PRBool parentForkedAfterC_Initialize = PR_FALSE;
  1292. #endif
  1293. if (handle == NULL) {
  1294. return CKR_OK;
  1295. }
  1296. if (handle->update) {
  1297. if (handle->db->sdb_SetForkState) {
  1298. (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
  1299. }
  1300. (*handle->update->sdb_Close)(handle->update);
  1301. }
  1302. if (handle->db) {
  1303. if (handle->db->sdb_SetForkState) {
  1304. (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
  1305. }
  1306. (*handle->db->sdb_Close)(handle->db);
  1307. }
  1308. if (handle->passwordLock) {
  1309. SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock));
  1310. }
  1311. if (handle->updatePasswordKey) {
  1312. SECITEM_FreeItem(handle->updatePasswordKey, PR_TRUE);
  1313. }
  1314. if (handle->updateID) {
  1315. PORT_Free(handle->updateID);
  1316. }
  1317. PORT_Free(handle);
  1318. return CKR_OK;
  1319. }
  1320. /*
  1321. * reset a database to it's uninitialized state.
  1322. */
  1323. static CK_RV
  1324. sftkdb_ResetDB(SFTKDBHandle *handle)
  1325. {
  1326. CK_RV crv = CKR_OK;
  1327. SDB *db;
  1328. if (handle == NULL) {
  1329. return CKR_TOKEN_WRITE_PROTECTED;
  1330. }
  1331. db = SFTK_GET_SDB(handle);
  1332. crv = (*db->sdb_Begin)(db);
  1333. if (crv != CKR_OK) {
  1334. goto loser;
  1335. }
  1336. crv = (*db->sdb_Reset)(db);
  1337. if (crv != CKR_OK) {
  1338. goto loser;
  1339. }
  1340. crv = (*db->sdb_Commit)(db);
  1341. loser:
  1342. if (crv != CKR_OK) {
  1343. (*db->sdb_Abort)(db);
  1344. }
  1345. return crv;
  1346. }
  1347. CK_RV
  1348. sftkdb_Begin(SFTKDBHandle *handle)
  1349. {
  1350. CK_RV crv = CKR_OK;
  1351. SDB *db;
  1352. if (handle == NULL) {
  1353. return CKR_OK;
  1354. }
  1355. db = SFTK_GET_SDB(handle);
  1356. if (db) {
  1357. crv = (*db->sdb_Begin)(db);
  1358. }
  1359. return crv;
  1360. }
  1361. CK_RV
  1362. sftkdb_Commit(SFTKDBHandle *handle)
  1363. {
  1364. CK_RV crv = CKR_OK;
  1365. SDB *db;
  1366. if (handle == NULL) {
  1367. return CKR_OK;
  1368. }
  1369. db = SFTK_GET_SDB(handle);
  1370. if (db) {
  1371. (*db->sdb_Commit)(db);
  1372. }
  1373. return crv;
  1374. }
  1375. CK_RV
  1376. sftkdb_Abort(SFTKDBHandle *handle)
  1377. {
  1378. CK_RV crv = CKR_OK;
  1379. SDB *db;
  1380. if (handle == NULL) {
  1381. return CKR_OK;
  1382. }
  1383. db = SFTK_GET_SDB(handle);
  1384. if (db) {
  1385. crv = (db->sdb_Abort)(db);
  1386. }
  1387. return crv;
  1388. }
  1389. /*
  1390. * functions to update the database from an old database
  1391. */
  1392. /*
  1393. * known attributes
  1394. */
  1395. static const CK_ATTRIBUTE_TYPE known_attributes[] = {
  1396. CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
  1397. CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
  1398. CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED,
  1399. CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL,
  1400. CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY,
  1401. CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE,
  1402. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER,
  1403. CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE,
  1404. CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
  1405. CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT,
  1406. CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS,
  1407. CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE,
  1408. CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
  1409. CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
  1410. CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
  1411. CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE,
  1412. CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT,
  1413. CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS,
  1414. CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
  1415. CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
  1416. CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
  1417. CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL,
  1418. CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
  1419. CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
  1420. CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED,
  1421. CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC,
  1422. CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
  1423. CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
  1424. CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
  1425. CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING,
  1426. CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM,
  1427. CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
  1428. CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
  1429. CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS
  1430. };
  1431. static int known_attributes_size= sizeof(known_attributes)/
  1432. sizeof(known_attributes[0]);
  1433. static CK_RV
  1434. sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id,
  1435. CK_ATTRIBUTE *ptemplate, CK_ULONG *max)
  1436. {
  1437. int i,j;
  1438. CK_RV crv;
  1439. if (*max < known_attributes_size) {
  1440. *max = known_attributes_size;
  1441. return CKR_BUFFER_TOO_SMALL;
  1442. }
  1443. for (i=0; i < known_attributes_size; i++) {
  1444. ptemplate[i].type = known_attributes[i];
  1445. ptemplate[i].pValue = NULL;
  1446. ptemplate[i].ulValueLen = 0;
  1447. }
  1448. crv = (*source->sdb_GetAttributeValue)(source, id,
  1449. ptemplate, known_attributes_size);
  1450. if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
  1451. return crv;
  1452. }
  1453. for (i=0, j=0; i < known_attributes_size; i++, j++) {
  1454. while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) {
  1455. i++;
  1456. }
  1457. if (i >= known_attributes_size) {
  1458. break;
  1459. }
  1460. /* cheap optimization */
  1461. if (i == j) {
  1462. continue;
  1463. }
  1464. ptemplate[j] = ptemplate[i];
  1465. }
  1466. *max = j;
  1467. return CKR_OK;
  1468. }
  1469. static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s";
  1470. /*
  1471. * check to see if we have already updated this database.
  1472. * a NULL updateID means we are trying to do an in place
  1473. * single database update. In that case we have already
  1474. * determined that an update was necessary.
  1475. */
  1476. static PRBool
  1477. sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID)
  1478. {
  1479. char *id;
  1480. CK_RV crv;
  1481. SECItem dummy = { 0, NULL, 0 };
  1482. unsigned char dummyData[SDB_MAX_META_DATA_LEN];
  1483. if (!updateID) {
  1484. return PR_FALSE;
  1485. }
  1486. id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
  1487. if (id == NULL) {
  1488. return PR_FALSE;
  1489. }
  1490. dummy.data = dummyData;
  1491. dummy.len = sizeof(dummyData);
  1492. crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL);
  1493. PR_smprintf_free(id);
  1494. return crv == CKR_OK ? PR_TRUE : PR_FALSE;
  1495. }
  1496. /*
  1497. * we just completed an update, store the update id
  1498. * so we don't need to do it again. If non was given,
  1499. * there is nothing to do.
  1500. */
  1501. static CK_RV
  1502. sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID)
  1503. {
  1504. char *id;
  1505. CK_RV crv;
  1506. SECItem dummy = { 0, NULL, 0 };
  1507. /* if no id was given, nothing to do */
  1508. if (updateID == NULL) {
  1509. return CKR_OK;
  1510. }
  1511. dummy.data = (unsigned char *)updateID;
  1512. dummy.len = PORT_Strlen(updateID);
  1513. id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
  1514. if (id == NULL) {
  1515. return PR_FALSE;
  1516. }
  1517. crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL);
  1518. PR_smprintf_free(id);
  1519. return crv;
  1520. }
  1521. /*
  1522. * get a ULong attribute from a template:
  1523. * NOTE: this is a raw templated stored in database order!
  1524. */
  1525. static CK_ULONG
  1526. sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type,
  1527. CK_ATTRIBUTE *ptemplate, CK_ULONG len)
  1528. {
  1529. CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type,
  1530. ptemplate, len);
  1531. if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) {
  1532. return sftk_SDBULong2ULong(attr->pValue);
  1533. }
  1534. return (CK_ULONG)-1;
  1535. }
  1536. /*
  1537. * we need to find a unique CKA_ID.
  1538. * The basic idea is to just increment the lowest byte.
  1539. * This code also handles the following corner cases:
  1540. * 1) the single byte overflows. On overflow we increment the next byte up
  1541. * and so forth until we have overflowed the entire CKA_ID.
  1542. * 2) If we overflow the entire CKA_ID we expand it by one byte.
  1543. * 3) the CKA_ID is non-existant, we create a new one with one byte.
  1544. * This means no matter what CKA_ID is passed, the result of this function
  1545. * is always a new CKA_ID, and this function will never return the same
  1546. * CKA_ID the it has returned in the passed.
  1547. */
  1548. static CK_RV
  1549. sftkdb_incrementCKAID(PRArenaPool *arena, CK_ATTRIBUTE *ptemplate)
  1550. {
  1551. unsigned char *buf = ptemplate->pValue;
  1552. CK_ULONG len = ptemplate->ulValueLen;
  1553. if (buf == NULL || len == (CK_ULONG)-1) {
  1554. /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
  1555. len = 0;
  1556. } else {
  1557. CK_ULONG i;
  1558. /* walk from the back to front, incrementing
  1559. * the CKA_ID until we no longer have a carry,
  1560. * or have hit the front of the id. */
  1561. for (i=len; i != 0; i--) {
  1562. buf[i-1]++;
  1563. if (buf[i-1] != 0) {
  1564. /* no more carries, the increment is complete */
  1565. return CKR_OK;
  1566. }
  1567. }
  1568. /* we've now overflowed, fall through and expand the CKA_ID by
  1569. * one byte */
  1570. }
  1571. buf = PORT_ArenaAlloc(arena, len+1);
  1572. if (!buf) {
  1573. return CKR_HOST_MEMORY;
  1574. }
  1575. if (len > 0) {
  1576. PORT_Memcpy(buf, ptemplate->pValue, len);
  1577. }
  1578. buf[len] = 0;
  1579. ptemplate->pValue = buf;
  1580. ptemplate->ulValueLen = len+1;
  1581. return CKR_OK;
  1582. }
  1583. /*
  1584. * drop an attribute from a template.
  1585. */
  1586. void
  1587. sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate,
  1588. CK_ULONG *plen)
  1589. {
  1590. CK_ULONG count = *plen;
  1591. CK_ULONG i;
  1592. for (i=0; i < count; i++) {
  1593. if (attr->type == ptemplate[i].type) {
  1594. break;
  1595. }
  1596. }
  1597. if (i == count) {
  1598. /* attribute not found */
  1599. return;
  1600. }
  1601. /* copy the remaining attributes up */
  1602. for ( i++; i < count; i++) {
  1603. ptemplate[i-1] = ptemplate[i];
  1604. }
  1605. /* decrement the template size */
  1606. *plen = count -1;
  1607. }
  1608. /*
  1609. * create some defines for the following functions to document the mea…

Large files files are truncated, but you can click here to view the full file