/security/nss/lib/softoken/legacydb/pcertdb.c

http://github.com/zpao/v8monkey · C · 5388 lines · 3939 code · 871 blank · 578 comment · 914 complexity · cb1cf42a254592733b815c8c285e0205 MD5 · raw file

Large files are truncated 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-2000
  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. * Permanent Certificate database handling code
  38. *
  39. * $Id: pcertdb.c,v 1.12 2010/07/20 01:26:04 wtc%google.com Exp $
  40. */
  41. #include "lowkeyti.h"
  42. #include "pcert.h"
  43. #include "mcom_db.h"
  44. #include "pcert.h"
  45. #include "secitem.h"
  46. #include "secder.h"
  47. #include "secerr.h"
  48. #include "lgdb.h"
  49. /* forward declaration */
  50. NSSLOWCERTCertificate *
  51. nsslowcert_FindCertByDERCertNoLocking(NSSLOWCERTCertDBHandle *handle, SECItem *derCert);
  52. static SECStatus
  53. nsslowcert_UpdateSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle,
  54. char *emailAddr, SECItem *derSubject, SECItem *emailProfile,
  55. SECItem *profileTime);
  56. static SECStatus
  57. nsslowcert_UpdatePermCert(NSSLOWCERTCertDBHandle *dbhandle,
  58. NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust);
  59. static SECStatus
  60. nsslowcert_UpdateCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl,
  61. SECItem *crlKey, char *url, PRBool isKRL);
  62. static NSSLOWCERTCertificate *certListHead = NULL;
  63. static NSSLOWCERTTrust *trustListHead = NULL;
  64. static certDBEntryCert *entryListHead = NULL;
  65. static int certListCount = 0;
  66. static int trustListCount = 0;
  67. static int entryListCount = 0;
  68. #define MAX_CERT_LIST_COUNT 10
  69. #define MAX_TRUST_LIST_COUNT 10
  70. #define MAX_ENTRY_LIST_COUNT 10
  71. /*
  72. * the following functions are wrappers for the db library that implement
  73. * a global lock to make the database thread safe.
  74. */
  75. static PZLock *dbLock = NULL;
  76. static PZLock *certRefCountLock = NULL;
  77. static PZLock *certTrustLock = NULL;
  78. static PZLock *freeListLock = NULL;
  79. void
  80. certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle)
  81. {
  82. if (dbLock == NULL) {
  83. dbLock = PZ_NewLock(nssILockCertDB);
  84. PORT_Assert(dbLock != NULL);
  85. }
  86. }
  87. SECStatus
  88. nsslowcert_InitLocks(void)
  89. {
  90. if (freeListLock == NULL) {
  91. freeListLock = PZ_NewLock(nssILockRefLock);
  92. if (freeListLock == NULL) {
  93. return SECFailure;
  94. }
  95. }
  96. if (certRefCountLock == NULL) {
  97. certRefCountLock = PZ_NewLock(nssILockRefLock);
  98. if (certRefCountLock == NULL) {
  99. return SECFailure;
  100. }
  101. }
  102. if (certTrustLock == NULL ) {
  103. certTrustLock = PZ_NewLock(nssILockCertDB);
  104. if (certTrustLock == NULL) {
  105. return SECFailure;
  106. }
  107. }
  108. return SECSuccess;
  109. }
  110. /*
  111. * Acquire the global lock on the cert database.
  112. * This lock is currently used for the following operations:
  113. * adding or deleting a cert to either the temp or perm databases
  114. * converting a temp to perm or perm to temp
  115. * changing (maybe just adding!?) the trust of a cert
  116. * chaning the DB status checking Configuration
  117. */
  118. static void
  119. nsslowcert_LockDB(NSSLOWCERTCertDBHandle *handle)
  120. {
  121. PZ_EnterMonitor(handle->dbMon);
  122. return;
  123. }
  124. /*
  125. * Free the global cert database lock.
  126. */
  127. static void
  128. nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle)
  129. {
  130. PRStatus prstat;
  131. prstat = PZ_ExitMonitor(handle->dbMon);
  132. PORT_Assert(prstat == PR_SUCCESS);
  133. return;
  134. }
  135. /*
  136. * Acquire the cert reference count lock
  137. * There is currently one global lock for all certs, but I'm putting a cert
  138. * arg here so that it will be easy to make it per-cert in the future if
  139. * that turns out to be necessary.
  140. */
  141. static void
  142. nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert)
  143. {
  144. PORT_Assert(certRefCountLock != NULL);
  145. PZ_Lock(certRefCountLock);
  146. return;
  147. }
  148. /*
  149. * Free the cert reference count lock
  150. */
  151. static void
  152. nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert)
  153. {
  154. PRStatus prstat;
  155. PORT_Assert(certRefCountLock != NULL);
  156. prstat = PZ_Unlock(certRefCountLock);
  157. PORT_Assert(prstat == PR_SUCCESS);
  158. return;
  159. }
  160. /*
  161. * Acquire the cert trust lock
  162. * There is currently one global lock for all certs, but I'm putting a cert
  163. * arg here so that it will be easy to make it per-cert in the future if
  164. * that turns out to be necessary.
  165. */
  166. static void
  167. nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert)
  168. {
  169. PORT_Assert(certTrustLock != NULL);
  170. PZ_Lock(certTrustLock);
  171. return;
  172. }
  173. /*
  174. * Free the cert trust lock
  175. */
  176. static void
  177. nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert)
  178. {
  179. PRStatus prstat;
  180. PORT_Assert(certTrustLock != NULL);
  181. prstat = PZ_Unlock(certTrustLock);
  182. PORT_Assert(prstat == PR_SUCCESS);
  183. return;
  184. }
  185. /*
  186. * Acquire the cert reference count lock
  187. * There is currently one global lock for all certs, but I'm putting a cert
  188. * arg here so that it will be easy to make it per-cert in the future if
  189. * that turns out to be necessary.
  190. */
  191. static void
  192. nsslowcert_LockFreeList(void)
  193. {
  194. PORT_Assert(freeListLock != NULL);
  195. SKIP_AFTER_FORK(PZ_Lock(freeListLock));
  196. return;
  197. }
  198. /*
  199. * Free the cert reference count lock
  200. */
  201. static void
  202. nsslowcert_UnlockFreeList(void)
  203. {
  204. PRStatus prstat = PR_SUCCESS;
  205. PORT_Assert(freeListLock != NULL);
  206. SKIP_AFTER_FORK(prstat = PZ_Unlock(freeListLock));
  207. PORT_Assert(prstat == PR_SUCCESS);
  208. return;
  209. }
  210. NSSLOWCERTCertificate *
  211. nsslowcert_DupCertificate(NSSLOWCERTCertificate *c)
  212. {
  213. if (c) {
  214. nsslowcert_LockCertRefCount(c);
  215. ++c->referenceCount;
  216. nsslowcert_UnlockCertRefCount(c);
  217. }
  218. return c;
  219. }
  220. static int
  221. certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
  222. {
  223. PRStatus prstat;
  224. int ret;
  225. PORT_Assert(dbLock != NULL);
  226. PZ_Lock(dbLock);
  227. ret = (* db->get)(db, key, data, flags);
  228. prstat = PZ_Unlock(dbLock);
  229. return(ret);
  230. }
  231. static int
  232. certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
  233. {
  234. PRStatus prstat;
  235. int ret = 0;
  236. PORT_Assert(dbLock != NULL);
  237. PZ_Lock(dbLock);
  238. ret = (* db->put)(db, key, data, flags);
  239. prstat = PZ_Unlock(dbLock);
  240. return(ret);
  241. }
  242. static int
  243. certdb_Sync(DB *db, unsigned int flags)
  244. {
  245. PRStatus prstat;
  246. int ret;
  247. PORT_Assert(dbLock != NULL);
  248. PZ_Lock(dbLock);
  249. ret = (* db->sync)(db, flags);
  250. prstat = PZ_Unlock(dbLock);
  251. return(ret);
  252. }
  253. #define DB_NOT_FOUND -30991 /* from DBM 3.2 */
  254. static int
  255. certdb_Del(DB *db, DBT *key, unsigned int flags)
  256. {
  257. PRStatus prstat;
  258. int ret;
  259. PORT_Assert(dbLock != NULL);
  260. PZ_Lock(dbLock);
  261. ret = (* db->del)(db, key, flags);
  262. prstat = PZ_Unlock(dbLock);
  263. /* don't fail if the record is already deleted */
  264. if (ret == DB_NOT_FOUND) {
  265. ret = 0;
  266. }
  267. return(ret);
  268. }
  269. static int
  270. certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
  271. {
  272. PRStatus prstat;
  273. int ret;
  274. PORT_Assert(dbLock != NULL);
  275. PZ_Lock(dbLock);
  276. ret = (* db->seq)(db, key, data, flags);
  277. prstat = PZ_Unlock(dbLock);
  278. return(ret);
  279. }
  280. static void
  281. certdb_Close(DB *db)
  282. {
  283. PRStatus prstat = PR_SUCCESS;
  284. PORT_Assert(dbLock != NULL);
  285. SKIP_AFTER_FORK(PZ_Lock(dbLock));
  286. (* db->close)(db);
  287. SKIP_AFTER_FORK(prstat = PZ_Unlock(dbLock));
  288. return;
  289. }
  290. void
  291. pkcs11_freeNickname(char *nickname, char *space)
  292. {
  293. if (nickname && nickname != space) {
  294. PORT_Free(nickname);
  295. }
  296. }
  297. char *
  298. pkcs11_copyNickname(char *nickname,char *space, int spaceLen)
  299. {
  300. int len;
  301. char *copy = NULL;
  302. len = PORT_Strlen(nickname)+1;
  303. if (len <= spaceLen) {
  304. copy = space;
  305. PORT_Memcpy(copy,nickname,len);
  306. } else {
  307. copy = PORT_Strdup(nickname);
  308. }
  309. return copy;
  310. }
  311. void
  312. pkcs11_freeStaticData (unsigned char *data, unsigned char *space)
  313. {
  314. if (data && data != space) {
  315. PORT_Free(data);
  316. }
  317. }
  318. unsigned char *
  319. pkcs11_allocStaticData(int len, unsigned char *space, int spaceLen)
  320. {
  321. unsigned char *data = NULL;
  322. if (len <= spaceLen) {
  323. data = space;
  324. } else {
  325. data = (unsigned char *) PORT_Alloc(len);
  326. }
  327. return data;
  328. }
  329. unsigned char *
  330. pkcs11_copyStaticData(unsigned char *data, int len,
  331. unsigned char *space, int spaceLen)
  332. {
  333. unsigned char *copy = pkcs11_allocStaticData(len, space, spaceLen);
  334. if (copy) {
  335. PORT_Memcpy(copy,data,len);
  336. }
  337. return copy;
  338. }
  339. /*
  340. * destroy a database entry
  341. */
  342. static void
  343. DestroyDBEntry(certDBEntry *entry)
  344. {
  345. PRArenaPool *arena = entry->common.arena;
  346. /* must be one of our certDBEntry from the free list */
  347. if (arena == NULL) {
  348. certDBEntryCert *certEntry;
  349. if ( entry->common.type != certDBEntryTypeCert) {
  350. return;
  351. }
  352. certEntry = (certDBEntryCert *)entry;
  353. pkcs11_freeStaticData(certEntry->derCert.data, certEntry->derCertSpace);
  354. pkcs11_freeNickname(certEntry->nickname, certEntry->nicknameSpace);
  355. nsslowcert_LockFreeList();
  356. if (entryListCount > MAX_ENTRY_LIST_COUNT) {
  357. PORT_Free(certEntry);
  358. } else {
  359. entryListCount++;
  360. PORT_Memset(certEntry, 0, sizeof( *certEntry));
  361. certEntry->next = entryListHead;
  362. entryListHead = certEntry;
  363. }
  364. nsslowcert_UnlockFreeList();
  365. return;
  366. }
  367. /* Zero out the entry struct, so that any further attempts to use it
  368. * will cause an exception (e.g. null pointer reference). */
  369. PORT_Memset(&entry->common, 0, sizeof entry->common);
  370. PORT_FreeArena(arena, PR_FALSE);
  371. return;
  372. }
  373. /* forward references */
  374. static void nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert);
  375. static SECStatus
  376. DeleteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey)
  377. {
  378. DBT key;
  379. int ret;
  380. /* init the database key */
  381. key.data = dbkey->data;
  382. key.size = dbkey->len;
  383. dbkey->data[0] = (unsigned char)type;
  384. /* delete entry from database */
  385. ret = certdb_Del(handle->permCertDB, &key, 0 );
  386. if ( ret != 0 ) {
  387. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  388. goto loser;
  389. }
  390. ret = certdb_Sync(handle->permCertDB, 0);
  391. if ( ret ) {
  392. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  393. goto loser;
  394. }
  395. return(SECSuccess);
  396. loser:
  397. return(SECFailure);
  398. }
  399. static SECStatus
  400. ReadDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
  401. SECItem *dbkey, SECItem *dbentry, PRArenaPool *arena)
  402. {
  403. DBT data, key;
  404. int ret;
  405. unsigned char *buf;
  406. /* init the database key */
  407. key.data = dbkey->data;
  408. key.size = dbkey->len;
  409. dbkey->data[0] = (unsigned char)entry->type;
  410. /* read entry from database */
  411. ret = certdb_Get(handle->permCertDB, &key, &data, 0 );
  412. if ( ret != 0 ) {
  413. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  414. goto loser;
  415. }
  416. /* validate the entry */
  417. if ( data.size < SEC_DB_ENTRY_HEADER_LEN ) {
  418. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  419. goto loser;
  420. }
  421. buf = (unsigned char *)data.data;
  422. /* version 7 has the same schema, we may be using a v7 db if we openned
  423. * the databases readonly. */
  424. if (!((buf[0] == (unsigned char)CERT_DB_FILE_VERSION)
  425. || (buf[0] == (unsigned char) CERT_DB_V7_FILE_VERSION))) {
  426. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  427. goto loser;
  428. }
  429. if ( buf[1] != (unsigned char)entry->type ) {
  430. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  431. goto loser;
  432. }
  433. /* copy out header information */
  434. entry->version = (unsigned int)buf[0];
  435. entry->type = (certDBEntryType)buf[1];
  436. entry->flags = (unsigned int)buf[2];
  437. /* format body of entry for return to caller */
  438. dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN;
  439. if ( dbentry->len ) {
  440. if (arena) {
  441. dbentry->data = (unsigned char *)
  442. PORT_ArenaAlloc(arena, dbentry->len);
  443. if ( dbentry->data == NULL ) {
  444. PORT_SetError(SEC_ERROR_NO_MEMORY);
  445. goto loser;
  446. }
  447. PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN],
  448. dbentry->len);
  449. } else {
  450. dbentry->data = &buf[SEC_DB_ENTRY_HEADER_LEN];
  451. }
  452. } else {
  453. dbentry->data = NULL;
  454. }
  455. return(SECSuccess);
  456. loser:
  457. return(SECFailure);
  458. }
  459. /**
  460. ** Implement low level database access
  461. **/
  462. static SECStatus
  463. WriteDBEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCommon *entry,
  464. SECItem *dbkey, SECItem *dbentry)
  465. {
  466. int ret;
  467. DBT data, key;
  468. unsigned char *buf;
  469. data.data = dbentry->data;
  470. data.size = dbentry->len;
  471. buf = (unsigned char*)data.data;
  472. buf[0] = (unsigned char)entry->version;
  473. buf[1] = (unsigned char)entry->type;
  474. buf[2] = (unsigned char)entry->flags;
  475. key.data = dbkey->data;
  476. key.size = dbkey->len;
  477. dbkey->data[0] = (unsigned char)entry->type;
  478. /* put the record into the database now */
  479. ret = certdb_Put(handle->permCertDB, &key, &data, 0);
  480. if ( ret != 0 ) {
  481. goto loser;
  482. }
  483. ret = certdb_Sync( handle->permCertDB, 0 );
  484. if ( ret ) {
  485. goto loser;
  486. }
  487. return(SECSuccess);
  488. loser:
  489. return(SECFailure);
  490. }
  491. /*
  492. * encode a database cert record
  493. */
  494. static SECStatus
  495. EncodeDBCertEntry(certDBEntryCert *entry, PRArenaPool *arena, SECItem *dbitem)
  496. {
  497. unsigned int nnlen;
  498. unsigned char *buf;
  499. char *nn;
  500. char zbuf = 0;
  501. if ( entry->nickname ) {
  502. nn = entry->nickname;
  503. } else {
  504. nn = &zbuf;
  505. }
  506. nnlen = PORT_Strlen(nn) + 1;
  507. /* allocate space for encoded database record, including space
  508. * for low level header
  509. */
  510. dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN +
  511. SEC_DB_ENTRY_HEADER_LEN;
  512. dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  513. if ( dbitem->data == NULL) {
  514. PORT_SetError(SEC_ERROR_NO_MEMORY);
  515. goto loser;
  516. }
  517. /* fill in database record */
  518. buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  519. buf[0] = (PRUint8)( entry->trust.sslFlags >> 8 );
  520. buf[1] = (PRUint8)( entry->trust.sslFlags );
  521. buf[2] = (PRUint8)( entry->trust.emailFlags >> 8 );
  522. buf[3] = (PRUint8)( entry->trust.emailFlags );
  523. buf[4] = (PRUint8)( entry->trust.objectSigningFlags >> 8 );
  524. buf[5] = (PRUint8)( entry->trust.objectSigningFlags );
  525. buf[6] = (PRUint8)( entry->derCert.len >> 8 );
  526. buf[7] = (PRUint8)( entry->derCert.len );
  527. buf[8] = (PRUint8)( nnlen >> 8 );
  528. buf[9] = (PRUint8)( nnlen );
  529. PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data,
  530. entry->derCert.len);
  531. PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len],
  532. nn, nnlen);
  533. return(SECSuccess);
  534. loser:
  535. return(SECFailure);
  536. }
  537. /*
  538. * encode a database key for a cert record
  539. */
  540. static SECStatus
  541. EncodeDBCertKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey)
  542. {
  543. unsigned int len = certKey->len + SEC_DB_KEY_HEADER_LEN;
  544. if (len > NSS_MAX_LEGACY_DB_KEY_SIZE)
  545. goto loser;
  546. if (arena) {
  547. dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
  548. } else {
  549. if (dbkey->len < len) {
  550. dbkey->data = (unsigned char *)PORT_Alloc(len);
  551. }
  552. }
  553. dbkey->len = len;
  554. if ( dbkey->data == NULL ) {
  555. goto loser;
  556. }
  557. PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
  558. certKey->data, certKey->len);
  559. dbkey->data[0] = certDBEntryTypeCert;
  560. return(SECSuccess);
  561. loser:
  562. return(SECFailure);
  563. }
  564. static SECStatus
  565. EncodeDBGenericKey(const SECItem *certKey, PRArenaPool *arena, SECItem *dbkey,
  566. certDBEntryType entryType)
  567. {
  568. /*
  569. * we only allow _one_ KRL key!
  570. */
  571. if (entryType == certDBEntryTypeKeyRevocation) {
  572. dbkey->len = SEC_DB_KEY_HEADER_LEN;
  573. dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  574. if ( dbkey->data == NULL ) {
  575. goto loser;
  576. }
  577. dbkey->data[0] = (unsigned char) entryType;
  578. return(SECSuccess);
  579. }
  580. dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
  581. if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
  582. goto loser;
  583. dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  584. if ( dbkey->data == NULL ) {
  585. goto loser;
  586. }
  587. PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
  588. certKey->data, certKey->len);
  589. dbkey->data[0] = (unsigned char) entryType;
  590. return(SECSuccess);
  591. loser:
  592. return(SECFailure);
  593. }
  594. static SECStatus
  595. DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry)
  596. {
  597. unsigned int nnlen;
  598. unsigned int headerlen;
  599. int lenoff;
  600. /* allow updates of old versions of the database */
  601. switch ( entry->common.version ) {
  602. case 5:
  603. headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
  604. lenoff = 3;
  605. break;
  606. case 6:
  607. /* should not get here */
  608. PORT_Assert(0);
  609. headerlen = DB_CERT_V6_ENTRY_HEADER_LEN;
  610. lenoff = 3;
  611. break;
  612. case 7:
  613. case 8:
  614. headerlen = DB_CERT_ENTRY_HEADER_LEN;
  615. lenoff = 6;
  616. break;
  617. default:
  618. /* better not get here */
  619. PORT_Assert(0);
  620. headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
  621. lenoff = 3;
  622. break;
  623. }
  624. /* is record long enough for header? */
  625. if ( dbentry->len < headerlen ) {
  626. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  627. goto loser;
  628. }
  629. /* is database entry correct length? */
  630. entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) |
  631. dbentry->data[lenoff+1] );
  632. nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] );
  633. lenoff = dbentry->len - ( entry->derCert.len + nnlen + headerlen );
  634. if ( lenoff ) {
  635. if ( lenoff < 0 || (lenoff & 0xffff) != 0 ) {
  636. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  637. goto loser;
  638. }
  639. /* The cert size exceeded 64KB. Reconstruct the correct length. */
  640. entry->derCert.len += lenoff;
  641. }
  642. /* copy the dercert */
  643. entry->derCert.data = pkcs11_copyStaticData(&dbentry->data[headerlen],
  644. entry->derCert.len,entry->derCertSpace,sizeof(entry->derCertSpace));
  645. if ( entry->derCert.data == NULL ) {
  646. PORT_SetError(SEC_ERROR_NO_MEMORY);
  647. goto loser;
  648. }
  649. /* copy the nickname */
  650. if ( nnlen > 1 ) {
  651. entry->nickname = (char *)pkcs11_copyStaticData(
  652. &dbentry->data[headerlen+entry->derCert.len], nnlen,
  653. (unsigned char *)entry->nicknameSpace,
  654. sizeof(entry->nicknameSpace));
  655. if ( entry->nickname == NULL ) {
  656. PORT_SetError(SEC_ERROR_NO_MEMORY);
  657. goto loser;
  658. }
  659. } else {
  660. entry->nickname = NULL;
  661. }
  662. if ( entry->common.version < 7 ) {
  663. /* allow updates of v5 db */
  664. entry->trust.sslFlags = dbentry->data[0];
  665. entry->trust.emailFlags = dbentry->data[1];
  666. entry->trust.objectSigningFlags = dbentry->data[2];
  667. } else {
  668. entry->trust.sslFlags = ( dbentry->data[0] << 8 ) | dbentry->data[1];
  669. entry->trust.emailFlags = ( dbentry->data[2] << 8 ) | dbentry->data[3];
  670. entry->trust.objectSigningFlags =
  671. ( dbentry->data[4] << 8 ) | dbentry->data[5];
  672. }
  673. return(SECSuccess);
  674. loser:
  675. return(SECFailure);
  676. }
  677. /*
  678. * Create a new certDBEntryCert from existing data
  679. */
  680. static certDBEntryCert *
  681. NewDBCertEntry(SECItem *derCert, char *nickname,
  682. NSSLOWCERTCertTrust *trust, int flags)
  683. {
  684. certDBEntryCert *entry;
  685. PRArenaPool *arena = NULL;
  686. int nnlen;
  687. arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
  688. if ( !arena ) {
  689. goto loser;
  690. }
  691. entry = PORT_ArenaZNew(arena, certDBEntryCert);
  692. if ( entry == NULL ) {
  693. goto loser;
  694. }
  695. /* fill in the dbCert */
  696. entry->common.arena = arena;
  697. entry->common.type = certDBEntryTypeCert;
  698. entry->common.version = CERT_DB_FILE_VERSION;
  699. entry->common.flags = flags;
  700. if ( trust ) {
  701. entry->trust = *trust;
  702. }
  703. entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len);
  704. if ( !entry->derCert.data ) {
  705. goto loser;
  706. }
  707. entry->derCert.len = derCert->len;
  708. PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len);
  709. nnlen = ( nickname ? strlen(nickname) + 1 : 0 );
  710. if ( nnlen ) {
  711. entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
  712. if ( !entry->nickname ) {
  713. goto loser;
  714. }
  715. PORT_Memcpy(entry->nickname, nickname, nnlen);
  716. } else {
  717. entry->nickname = 0;
  718. }
  719. return(entry);
  720. loser:
  721. /* allocation error, free arena and return */
  722. if ( arena ) {
  723. PORT_FreeArena(arena, PR_FALSE);
  724. }
  725. PORT_SetError(SEC_ERROR_NO_MEMORY);
  726. return(0);
  727. }
  728. /*
  729. * Decode a version 4 DBCert from the byte stream database format
  730. * and construct a current database entry struct
  731. */
  732. static certDBEntryCert *
  733. DecodeV4DBCertEntry(unsigned char *buf, int len)
  734. {
  735. certDBEntryCert *entry;
  736. int certlen;
  737. int nnlen;
  738. PRArenaPool *arena;
  739. /* make sure length is at least long enough for the header */
  740. if ( len < DBCERT_V4_HEADER_LEN ) {
  741. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  742. return(0);
  743. }
  744. /* get other lengths */
  745. certlen = buf[3] << 8 | buf[4];
  746. nnlen = buf[5] << 8 | buf[6];
  747. /* make sure DB entry is the right size */
  748. if ( ( certlen + nnlen + DBCERT_V4_HEADER_LEN ) != len ) {
  749. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  750. return(0);
  751. }
  752. /* allocate arena */
  753. arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
  754. if ( !arena ) {
  755. PORT_SetError(SEC_ERROR_NO_MEMORY);
  756. return(0);
  757. }
  758. /* allocate structure and members */
  759. entry = (certDBEntryCert *) PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
  760. if ( !entry ) {
  761. goto loser;
  762. }
  763. entry->common.arena = arena;
  764. entry->common.version = CERT_DB_FILE_VERSION;
  765. entry->common.type = certDBEntryTypeCert;
  766. entry->common.flags = 0;
  767. entry->trust.sslFlags = buf[0];
  768. entry->trust.emailFlags = buf[1];
  769. entry->trust.objectSigningFlags = buf[2];
  770. entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen);
  771. if ( !entry->derCert.data ) {
  772. goto loser;
  773. }
  774. entry->derCert.len = certlen;
  775. PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen);
  776. if ( nnlen ) {
  777. entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen);
  778. if ( !entry->nickname ) {
  779. goto loser;
  780. }
  781. PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen);
  782. if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) {
  783. entry->trust.sslFlags |= CERTDB_USER;
  784. }
  785. } else {
  786. entry->nickname = 0;
  787. }
  788. return(entry);
  789. loser:
  790. PORT_FreeArena(arena, PR_FALSE);
  791. PORT_SetError(SEC_ERROR_NO_MEMORY);
  792. return(0);
  793. }
  794. /*
  795. * Encode a Certificate database entry into byte stream suitable for
  796. * the database
  797. */
  798. static SECStatus
  799. WriteDBCertEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry)
  800. {
  801. SECItem dbitem, dbkey;
  802. PRArenaPool *tmparena = NULL;
  803. SECItem tmpitem;
  804. SECStatus rv;
  805. tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  806. if ( tmparena == NULL ) {
  807. goto loser;
  808. }
  809. rv = EncodeDBCertEntry(entry, tmparena, &dbitem);
  810. if ( rv != SECSuccess ) {
  811. goto loser;
  812. }
  813. /* get the database key and format it */
  814. rv = nsslowcert_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem);
  815. if ( rv == SECFailure ) {
  816. goto loser;
  817. }
  818. rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey);
  819. if ( rv == SECFailure ) {
  820. goto loser;
  821. }
  822. /* now write it to the database */
  823. rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  824. if ( rv != SECSuccess ) {
  825. goto loser;
  826. }
  827. PORT_FreeArena(tmparena, PR_FALSE);
  828. return(SECSuccess);
  829. loser:
  830. if ( tmparena ) {
  831. PORT_FreeArena(tmparena, PR_FALSE);
  832. }
  833. return(SECFailure);
  834. }
  835. /*
  836. * delete a certificate entry
  837. */
  838. static SECStatus
  839. DeleteDBCertEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
  840. {
  841. SECItem dbkey;
  842. SECStatus rv;
  843. dbkey.data= NULL;
  844. dbkey.len = 0;
  845. rv = EncodeDBCertKey(certKey, NULL, &dbkey);
  846. if ( rv != SECSuccess ) {
  847. goto loser;
  848. }
  849. rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
  850. if ( rv == SECFailure ) {
  851. goto loser;
  852. }
  853. PORT_Free(dbkey.data);
  854. return(SECSuccess);
  855. loser:
  856. if (dbkey.data) {
  857. PORT_Free(dbkey.data);
  858. }
  859. return(SECFailure);
  860. }
  861. static certDBEntryCert *
  862. CreateCertEntry(void)
  863. {
  864. certDBEntryCert *entry;
  865. nsslowcert_LockFreeList();
  866. entry = entryListHead;
  867. if (entry) {
  868. entryListCount--;
  869. entryListHead = entry->next;
  870. }
  871. PORT_Assert(entryListCount >= 0);
  872. nsslowcert_UnlockFreeList();
  873. if (entry) {
  874. return entry;
  875. }
  876. return PORT_ZNew(certDBEntryCert);
  877. }
  878. static void
  879. DestroyCertEntryFreeList(void)
  880. {
  881. certDBEntryCert *entry;
  882. nsslowcert_LockFreeList();
  883. while (NULL != (entry = entryListHead)) {
  884. entryListCount--;
  885. entryListHead = entry->next;
  886. PORT_Free(entry);
  887. }
  888. PORT_Assert(!entryListCount);
  889. entryListCount = 0;
  890. nsslowcert_UnlockFreeList();
  891. }
  892. /*
  893. * Read a certificate entry
  894. */
  895. static certDBEntryCert *
  896. ReadDBCertEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *certKey)
  897. {
  898. certDBEntryCert *entry;
  899. SECItem dbkey;
  900. SECItem dbentry;
  901. SECStatus rv;
  902. unsigned char buf[512];
  903. dbkey.data = buf;
  904. dbkey.len = sizeof(buf);
  905. entry = CreateCertEntry();
  906. if ( entry == NULL ) {
  907. PORT_SetError(SEC_ERROR_NO_MEMORY);
  908. goto loser;
  909. }
  910. entry->common.arena = NULL;
  911. entry->common.type = certDBEntryTypeCert;
  912. rv = EncodeDBCertKey(certKey, NULL, &dbkey);
  913. if ( rv != SECSuccess ) {
  914. goto loser;
  915. }
  916. rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
  917. if ( rv == SECFailure ) {
  918. goto loser;
  919. }
  920. rv = DecodeDBCertEntry(entry, &dbentry);
  921. if ( rv != SECSuccess ) {
  922. goto loser;
  923. }
  924. pkcs11_freeStaticData(dbkey.data,buf);
  925. dbkey.data = NULL;
  926. return(entry);
  927. loser:
  928. pkcs11_freeStaticData(dbkey.data,buf);
  929. dbkey.data = NULL;
  930. if ( entry ) {
  931. DestroyDBEntry((certDBEntry *)entry);
  932. }
  933. return(NULL);
  934. }
  935. /*
  936. * encode a database cert record
  937. */
  938. static SECStatus
  939. EncodeDBCrlEntry(certDBEntryRevocation *entry, PRArenaPool *arena, SECItem *dbitem)
  940. {
  941. unsigned int nnlen = 0;
  942. unsigned char *buf;
  943. if (entry->url) {
  944. nnlen = PORT_Strlen(entry->url) + 1;
  945. }
  946. /* allocate space for encoded database record, including space
  947. * for low level header
  948. */
  949. dbitem->len = entry->derCrl.len + nnlen
  950. + SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN;
  951. dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  952. if ( dbitem->data == NULL) {
  953. PORT_SetError(SEC_ERROR_NO_MEMORY);
  954. goto loser;
  955. }
  956. /* fill in database record */
  957. buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  958. buf[0] = (PRUint8)( entry->derCrl.len >> 8 );
  959. buf[1] = (PRUint8)( entry->derCrl.len );
  960. buf[2] = (PRUint8)( nnlen >> 8 );
  961. buf[3] = (PRUint8)( nnlen );
  962. PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data,
  963. entry->derCrl.len);
  964. if (nnlen != 0) {
  965. PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
  966. entry->url, nnlen);
  967. }
  968. return(SECSuccess);
  969. loser:
  970. return(SECFailure);
  971. }
  972. static SECStatus
  973. DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry)
  974. {
  975. unsigned int urlLen;
  976. int lenDiff;
  977. /* is record long enough for header? */
  978. if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) {
  979. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  980. goto loser;
  981. }
  982. /* is database entry correct length? */
  983. entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
  984. urlLen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
  985. lenDiff = dbentry->len -
  986. (entry->derCrl.len + urlLen + DB_CRL_ENTRY_HEADER_LEN);
  987. if (lenDiff) {
  988. if (lenDiff < 0 || (lenDiff & 0xffff) != 0) {
  989. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  990. goto loser;
  991. }
  992. /* CRL entry is greater than 64 K. Hack to make this continue to work */
  993. entry->derCrl.len += lenDiff;
  994. }
  995. /* copy the der CRL */
  996. entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  997. entry->derCrl.len);
  998. if ( entry->derCrl.data == NULL ) {
  999. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1000. goto loser;
  1001. }
  1002. PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN],
  1003. entry->derCrl.len);
  1004. /* copy the url */
  1005. entry->url = NULL;
  1006. if (urlLen != 0) {
  1007. entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, urlLen);
  1008. if ( entry->url == NULL ) {
  1009. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1010. goto loser;
  1011. }
  1012. PORT_Memcpy(entry->url,
  1013. &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
  1014. urlLen);
  1015. }
  1016. return(SECSuccess);
  1017. loser:
  1018. return(SECFailure);
  1019. }
  1020. /*
  1021. * Create a new certDBEntryRevocation from existing data
  1022. */
  1023. static certDBEntryRevocation *
  1024. NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags)
  1025. {
  1026. certDBEntryRevocation *entry;
  1027. PRArenaPool *arena = NULL;
  1028. int nnlen;
  1029. arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
  1030. if ( !arena ) {
  1031. goto loser;
  1032. }
  1033. entry = PORT_ArenaZNew(arena, certDBEntryRevocation);
  1034. if ( entry == NULL ) {
  1035. goto loser;
  1036. }
  1037. /* fill in the dbRevolcation */
  1038. entry->common.arena = arena;
  1039. entry->common.type = crlType;
  1040. entry->common.version = CERT_DB_FILE_VERSION;
  1041. entry->common.flags = flags;
  1042. entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len);
  1043. if ( !entry->derCrl.data ) {
  1044. goto loser;
  1045. }
  1046. if (url) {
  1047. nnlen = PORT_Strlen(url) + 1;
  1048. entry->url = (char *)PORT_ArenaAlloc(arena, nnlen);
  1049. if ( !entry->url ) {
  1050. goto loser;
  1051. }
  1052. PORT_Memcpy(entry->url, url, nnlen);
  1053. } else {
  1054. entry->url = NULL;
  1055. }
  1056. entry->derCrl.len = derCrl->len;
  1057. PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len);
  1058. return(entry);
  1059. loser:
  1060. /* allocation error, free arena and return */
  1061. if ( arena ) {
  1062. PORT_FreeArena(arena, PR_FALSE);
  1063. }
  1064. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1065. return(0);
  1066. }
  1067. static SECStatus
  1068. WriteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryRevocation *entry,
  1069. SECItem *crlKey )
  1070. {
  1071. SECItem dbkey;
  1072. PRArenaPool *tmparena = NULL;
  1073. SECItem encodedEntry;
  1074. SECStatus rv;
  1075. tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1076. if ( tmparena == NULL ) {
  1077. goto loser;
  1078. }
  1079. rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
  1080. if ( rv == SECFailure ) {
  1081. goto loser;
  1082. }
  1083. rv = EncodeDBGenericKey(crlKey, tmparena, &dbkey, entry->common.type);
  1084. if ( rv == SECFailure ) {
  1085. goto loser;
  1086. }
  1087. /* now write it to the database */
  1088. rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry);
  1089. if ( rv != SECSuccess ) {
  1090. goto loser;
  1091. }
  1092. PORT_FreeArena(tmparena, PR_FALSE);
  1093. return(SECSuccess);
  1094. loser:
  1095. if ( tmparena ) {
  1096. PORT_FreeArena(tmparena, PR_FALSE);
  1097. }
  1098. return(SECFailure);
  1099. }
  1100. /*
  1101. * delete a crl entry
  1102. */
  1103. static SECStatus
  1104. DeleteDBCrlEntry(NSSLOWCERTCertDBHandle *handle, const SECItem *crlKey,
  1105. certDBEntryType crlType)
  1106. {
  1107. SECItem dbkey;
  1108. PRArenaPool *arena = NULL;
  1109. SECStatus rv;
  1110. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1111. if ( arena == NULL ) {
  1112. goto loser;
  1113. }
  1114. rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType);
  1115. if ( rv != SECSuccess ) {
  1116. goto loser;
  1117. }
  1118. rv = DeleteDBEntry(handle, crlType, &dbkey);
  1119. if ( rv == SECFailure ) {
  1120. goto loser;
  1121. }
  1122. PORT_FreeArena(arena, PR_FALSE);
  1123. return(SECSuccess);
  1124. loser:
  1125. if ( arena ) {
  1126. PORT_FreeArena(arena, PR_FALSE);
  1127. }
  1128. return(SECFailure);
  1129. }
  1130. /*
  1131. * Read a certificate entry
  1132. */
  1133. static certDBEntryRevocation *
  1134. ReadDBCrlEntry(NSSLOWCERTCertDBHandle *handle, SECItem *certKey,
  1135. certDBEntryType crlType)
  1136. {
  1137. PRArenaPool *arena = NULL;
  1138. PRArenaPool *tmparena = NULL;
  1139. certDBEntryRevocation *entry;
  1140. SECItem dbkey;
  1141. SECItem dbentry;
  1142. SECStatus rv;
  1143. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1144. if ( arena == NULL ) {
  1145. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1146. goto loser;
  1147. }
  1148. tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1149. if ( tmparena == NULL ) {
  1150. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1151. goto loser;
  1152. }
  1153. entry = (certDBEntryRevocation *)
  1154. PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation));
  1155. if ( entry == NULL ) {
  1156. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1157. goto loser;
  1158. }
  1159. entry->common.arena = arena;
  1160. entry->common.type = crlType;
  1161. rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType);
  1162. if ( rv != SECSuccess ) {
  1163. goto loser;
  1164. }
  1165. rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, NULL);
  1166. if ( rv == SECFailure ) {
  1167. goto loser;
  1168. }
  1169. rv = DecodeDBCrlEntry(entry, &dbentry);
  1170. if ( rv != SECSuccess ) {
  1171. goto loser;
  1172. }
  1173. PORT_FreeArena(tmparena, PR_FALSE);
  1174. return(entry);
  1175. loser:
  1176. if ( tmparena ) {
  1177. PORT_FreeArena(tmparena, PR_FALSE);
  1178. }
  1179. if ( arena ) {
  1180. PORT_FreeArena(arena, PR_FALSE);
  1181. }
  1182. return(NULL);
  1183. }
  1184. void
  1185. nsslowcert_DestroyDBEntry(certDBEntry *entry)
  1186. {
  1187. DestroyDBEntry(entry);
  1188. return;
  1189. }
  1190. /*
  1191. * Encode a database nickname record
  1192. */
  1193. static SECStatus
  1194. EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena,
  1195. SECItem *dbitem)
  1196. {
  1197. unsigned char *buf;
  1198. /* allocate space for encoded database record, including space
  1199. * for low level header
  1200. */
  1201. dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN +
  1202. SEC_DB_ENTRY_HEADER_LEN;
  1203. dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  1204. if ( dbitem->data == NULL) {
  1205. goto loser;
  1206. }
  1207. /* fill in database record */
  1208. buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  1209. buf[0] = (PRUint8)( entry->subjectName.len >> 8 );
  1210. buf[1] = (PRUint8)( entry->subjectName.len );
  1211. PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data,
  1212. entry->subjectName.len);
  1213. return(SECSuccess);
  1214. loser:
  1215. return(SECFailure);
  1216. }
  1217. /*
  1218. * Encode a database key for a nickname record
  1219. */
  1220. static SECStatus
  1221. EncodeDBNicknameKey(char *nickname, PRArenaPool *arena,
  1222. SECItem *dbkey)
  1223. {
  1224. unsigned int nnlen;
  1225. nnlen = PORT_Strlen(nickname) + 1; /* includes null */
  1226. /* now get the database key and format it */
  1227. dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN;
  1228. if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
  1229. goto loser;
  1230. dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  1231. if ( dbkey->data == NULL ) {
  1232. goto loser;
  1233. }
  1234. PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen);
  1235. dbkey->data[0] = certDBEntryTypeNickname;
  1236. return(SECSuccess);
  1237. loser:
  1238. return(SECFailure);
  1239. }
  1240. static SECStatus
  1241. DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry,
  1242. char *nickname)
  1243. {
  1244. int lenDiff;
  1245. /* is record long enough for header? */
  1246. if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
  1247. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1248. goto loser;
  1249. }
  1250. /* is database entry correct length? */
  1251. entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
  1252. lenDiff = dbentry->len -
  1253. (entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN);
  1254. if (lenDiff) {
  1255. if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) {
  1256. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1257. goto loser;
  1258. }
  1259. /* The entry size exceeded 64KB. Reconstruct the correct length. */
  1260. entry->subjectName.len += lenDiff;
  1261. }
  1262. /* copy the certkey */
  1263. entry->subjectName.data =
  1264. (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1265. entry->subjectName.len);
  1266. if ( entry->subjectName.data == NULL ) {
  1267. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1268. goto loser;
  1269. }
  1270. PORT_Memcpy(entry->subjectName.data,
  1271. &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN],
  1272. entry->subjectName.len);
  1273. entry->subjectName.type = siBuffer;
  1274. entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena,
  1275. PORT_Strlen(nickname)+1);
  1276. if ( entry->nickname ) {
  1277. PORT_Strcpy(entry->nickname, nickname);
  1278. }
  1279. return(SECSuccess);
  1280. loser:
  1281. return(SECFailure);
  1282. }
  1283. /*
  1284. * create a new nickname entry
  1285. */
  1286. static certDBEntryNickname *
  1287. NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags)
  1288. {
  1289. PRArenaPool *arena = NULL;
  1290. certDBEntryNickname *entry;
  1291. int nnlen;
  1292. SECStatus rv;
  1293. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1294. if ( arena == NULL ) {
  1295. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1296. goto loser;
  1297. }
  1298. entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
  1299. sizeof(certDBEntryNickname));
  1300. if ( entry == NULL ) {
  1301. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1302. goto loser;
  1303. }
  1304. /* init common fields */
  1305. entry->common.arena = arena;
  1306. entry->common.type = certDBEntryTypeNickname;
  1307. entry->common.version = CERT_DB_FILE_VERSION;
  1308. entry->common.flags = flags;
  1309. /* copy the nickname */
  1310. nnlen = PORT_Strlen(nickname) + 1;
  1311. entry->nickname = (char*)PORT_ArenaAlloc(arena, nnlen);
  1312. if ( entry->nickname == NULL ) {
  1313. goto loser;
  1314. }
  1315. PORT_Memcpy(entry->nickname, nickname, nnlen);
  1316. rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
  1317. if ( rv != SECSuccess ) {
  1318. goto loser;
  1319. }
  1320. return(entry);
  1321. loser:
  1322. if ( arena ) {
  1323. PORT_FreeArena(arena, PR_FALSE);
  1324. }
  1325. return(NULL);
  1326. }
  1327. /*
  1328. * delete a nickname entry
  1329. */
  1330. static SECStatus
  1331. DeleteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
  1332. {
  1333. PRArenaPool *arena = NULL;
  1334. SECStatus rv;
  1335. SECItem dbkey;
  1336. if ( nickname == NULL ) {
  1337. return(SECSuccess);
  1338. }
  1339. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1340. if ( arena == NULL ) {
  1341. goto loser;
  1342. }
  1343. rv = EncodeDBNicknameKey(nickname, arena, &dbkey);
  1344. if ( rv != SECSuccess ) {
  1345. goto loser;
  1346. }
  1347. rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey);
  1348. if ( rv == SECFailure ) {
  1349. goto loser;
  1350. }
  1351. PORT_FreeArena(arena, PR_FALSE);
  1352. return(SECSuccess);
  1353. loser:
  1354. if ( arena ) {
  1355. PORT_FreeArena(arena, PR_FALSE);
  1356. }
  1357. return(SECFailure);
  1358. }
  1359. /*
  1360. * Read a nickname entry
  1361. */
  1362. static certDBEntryNickname *
  1363. ReadDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, char *nickname)
  1364. {
  1365. PRArenaPool *arena = NULL;
  1366. PRArenaPool *tmparena = NULL;
  1367. certDBEntryNickname *entry;
  1368. SECItem dbkey;
  1369. SECItem dbentry;
  1370. SECStatus rv;
  1371. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1372. if ( arena == NULL ) {
  1373. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1374. goto loser;
  1375. }
  1376. tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1377. if ( tmparena == NULL ) {
  1378. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1379. goto loser;
  1380. }
  1381. entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
  1382. sizeof(certDBEntryNickname));
  1383. if ( entry == NULL ) {
  1384. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1385. goto loser;
  1386. }
  1387. entry->common.arena = arena;
  1388. entry->common.type = certDBEntryTypeNickname;
  1389. rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey);
  1390. if ( rv != SECSuccess ) {
  1391. goto loser;
  1392. }
  1393. rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  1394. if ( rv == SECFailure ) {
  1395. goto loser;
  1396. }
  1397. /* is record long enough for header? */
  1398. if ( dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
  1399. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1400. goto loser;
  1401. }
  1402. rv = DecodeDBNicknameEntry(entry, &dbentry, nickname);
  1403. if ( rv != SECSuccess ) {
  1404. goto loser;
  1405. }
  1406. PORT_FreeArena(tmparena, PR_FALSE);
  1407. return(entry);
  1408. loser:
  1409. if ( tmparena ) {
  1410. PORT_FreeArena(tmparena, PR_FALSE);
  1411. }
  1412. if ( arena ) {
  1413. PORT_FreeArena(arena, PR_FALSE);
  1414. }
  1415. return(NULL);
  1416. }
  1417. /*
  1418. * Encode a nickname entry into byte stream suitable for
  1419. * the database
  1420. */
  1421. static SECStatus
  1422. WriteDBNicknameEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryNickname *entry)
  1423. {
  1424. SECItem dbitem, dbkey;
  1425. PRArenaPool *tmparena = NULL;
  1426. SECStatus rv;
  1427. tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1428. if ( tmparena == NULL ) {
  1429. goto loser;
  1430. }
  1431. rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem);
  1432. if ( rv != SECSuccess ) {
  1433. goto loser;
  1434. }
  1435. rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey);
  1436. if ( rv != SECSuccess ) {
  1437. goto loser;
  1438. }
  1439. /* now write it to the database */
  1440. rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  1441. if ( rv != SECSuccess ) {
  1442. goto loser;
  1443. }
  1444. PORT_FreeArena(tmparena, PR_FALSE);
  1445. return(SECSuccess);
  1446. loser:
  1447. if ( tmparena ) {
  1448. PORT_FreeArena(tmparena, PR_FALSE);
  1449. }
  1450. return(SECFailure);
  1451. }
  1452. static SECStatus
  1453. EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena,
  1454. SECItem *dbitem)
  1455. {
  1456. unsigned char *buf;
  1457. /* allocate space for encoded database record, including space
  1458. * for low level header
  1459. */
  1460. dbitem->len = entry->subjectName.len + entry->smimeOptions.len +
  1461. entry->optionsDate.len +
  1462. DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN;
  1463. dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  1464. if ( dbitem->data == NULL) {
  1465. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1466. goto loser;
  1467. }
  1468. /* fill in database record */
  1469. buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  1470. buf[0] = (PRUint8)( entry->subjectName.len >> 8 );
  1471. buf[1] = (PRUint8)( entry->subjectName.len );
  1472. buf[2] = (PRUint8)( entry->smimeOptions.len >> 8 );
  1473. buf[3] = (PRUint8)( entry->smimeOptions.len );
  1474. buf[4] = (PRUint8)( entry->optionsDate.len >> 8 );
  1475. buf[5] = (PRUint8)( entry->optionsDate.len );
  1476. /* if no smime options, then there should not be an options date either */
  1477. PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) &&
  1478. ( entry->optionsDate.len != 0 ) ) );
  1479. PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data,
  1480. entry->subjectName.len);
  1481. if ( entry->smimeOptions.len ) {
  1482. PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN+entry->subjectName.len],
  1483. entry->smimeOptions.data,
  1484. entry->smimeOptions.len);
  1485. PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len +
  1486. entry->smimeOptions.len],
  1487. entry->optionsDate.data,
  1488. entry->optionsDate.len);
  1489. }
  1490. return(SECSuccess);
  1491. loser:
  1492. return(SECFailure);
  1493. }
  1494. /*
  1495. * Encode a database key for a SMIME record
  1496. */
  1497. static SECStatus
  1498. EncodeDBSMimeKey(char *emailAddr, PRArenaPool *arena,
  1499. SECItem *dbkey)
  1500. {
  1501. unsigned int addrlen;
  1502. addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */
  1503. /* now get the database key and format it */
  1504. dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN;
  1505. if (dbkey->len > NSS_MAX_LEGACY_DB_KEY_SIZE)
  1506. goto loser;
  1507. dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  1508. if ( dbkey->data == NULL ) {
  1509. goto loser;
  1510. }
  1511. PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen);
  1512. dbkey->data[0] = certDBEntryTypeSMimeProfile;
  1513. return(SECSuccess);
  1514. loser:
  1515. return(SECFailure);
  1516. }
  1517. /*
  1518. * Decode a database SMIME record
  1519. */
  1520. static SECStatus
  1521. DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr)
  1522. {
  1523. int lenDiff;
  1524. /* is record long enough for header? */
  1525. if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) {
  1526. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1527. goto loser;
  1528. }
  1529. /* is database entry correct length? */
  1530. entry->subjectName.len = (( dbentry->data[0] << 8 ) | dbentry->data[1] );
  1531. entry->smimeOptions.len = (( dbentry->data[2] << 8 ) | dbentry->data[3] );
  1532. entry->optionsDate.len = (( dbentry->data[4] << 8 ) | dbentry->data[5] );
  1533. lenDiff = dbentry->len - (entry->subjectName.len +
  1534. entry->smimeOptions.len +
  1535. entry->optionsDate.len +
  1536. DB_SMIME_ENTRY_HEADER_LEN);
  1537. if (lenDiff) {
  1538. if (lenDiff < 0 || (lenDiff & 0xffff) != 0 ) {
  1539. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1540. goto loser;
  1541. }
  1542. /* The entry size exceeded 64KB. Reconstruct the correct length. */
  1543. entry->subjectName.len += lenDiff;
  1544. }
  1545. /* copy the subject name */
  1546. entry->subjectName.data =
  1547. (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1548. entry->subjectName.len);
  1549. if ( entry->subjectName.data == NULL ) {
  1550. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1551. goto loser;
  1552. }
  1553. PORT_Memcpy(entry->subjectName.data,
  1554. &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN],
  1555. entry->subjectName.len);
  1556. /* copy the smime options */
  1557. if ( entry->smimeOptions.len ) {
  1558. entry->smimeOptions.data =
  1559. (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1560. entry->smimeOptions.len);
  1561. if ( entry->smimeOptions.data == NULL ) {
  1562. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1563. goto loser;
  1564. }
  1565. PORT_Memcpy(entry->smimeOptions.data,
  1566. &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
  1567. entry->subjectName.len],
  1568. entry->smimeOptions.len);
  1569. }
  1570. if ( entry->optionsDate.len ) {
  1571. entry->optionsDate.data =
  1572. (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1573. entry->optionsDate.len);
  1574. if ( entry->optionsDate.data == NULL ) {
  1575. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1576. goto loser;
  1577. }
  1578. PORT_Memcpy(entry->optionsDate.data,
  1579. &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
  1580. entry->subjectName.len +
  1581. entry->smimeOptions.len],
  1582. entry->optionsDate.len);
  1583. }
  1584. /* both options and options date must either exist or not exist */
  1585. if ( ( ( entry->optionsDate.len == 0 ) ||
  1586. ( entry->smimeOptions.len == 0 ) ) &&
  1587. entry->smimeOptions.len != entry->optionsDate.len ) {
  1588. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1589. goto loser;
  1590. }
  1591. entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena,
  1592. PORT_Strlen(emailAddr)+1);
  1593. if ( entry->emailAddr ) {
  1594. PORT_Strcpy(entry->emailAddr, emailAddr);
  1595. }
  1596. return(SECSuccess);
  1597. loser:
  1598. return(SECFailure);
  1599. }
  1600. /*
  1601. * create a new SMIME entry
  1602. */
  1603. static certDBEntrySMime *
  1604. NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions,
  1605. SECItem *optionsDate, unsigned int flags)
  1606. {
  1607. PRArenaPool *arena = NULL;
  1608. certDBEntrySMime *entry;
  1609. int addrlen;
  1610. SECStatus rv;
  1611. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1612. if ( arena == NULL ) {
  1613. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1614. goto loser;
  1615. }
  1616. entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
  1617. sizeof(certDBEntrySMime));
  1618. if ( entry == NULL ) {
  1619. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1620. goto loser;
  1621. }
  1622. /* init common fields */
  1623. entry->common.arena = arena;
  1624. entry->common.type = certDBEntryTypeSMimeProfile;
  1625. entry->common.version = CERT_DB_FILE_VERSION;
  1626. entry->common.flags = flags;
  1627. /* copy the email addr */
  1628. addrlen = PORT_Strlen(emailAddr) + 1;
  1629. entry->emailAddr = (char*)PORT_ArenaAlloc(arena, addrlen);
  1630. if ( entry->emailAddr == NULL ) {
  1631. goto loser;
  1632. }
  1633. PORT_Memcpy(entry->emailAddr, emailAddr, addrlen);
  1634. /* copy the subject name */
  1635. rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
  1636. if ( rv != SECSuccess ) {
  1637. goto loser;
  1638. }
  1639. /* copy the smime options */
  1640. if ( smimeOptions ) {
  1641. rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions);
  1642. if ( rv != SECSuccess ) {
  1643. goto loser;
  1644. }
  1645. } else {
  1646. PORT_Assert(optionsDate == NULL);
  1647. entry->smimeOptions.data = NULL;
  1648. entry->smimeOptions.len = 0;
  1649. }
  1650. /* copy the options date */
  1651. if ( optionsDate ) {
  1652. rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate);
  1653. if ( rv != SECSuccess ) {
  1654. goto loser;
  1655. }
  1656. } else {
  1657. PORT_Assert(smimeOptions == NULL);
  1658. entry->optionsDate.data = NULL;
  1659. entry->optionsDate.len = 0;
  1660. }
  1661. return(entry);
  1662. loser:
  1663. if ( arena ) {
  1664. PORT_FreeArena(arena, PR_FALSE);
  1665. }
  1666. return(NULL);
  1667. }
  1668. /*
  1669. * delete a SMIME entry
  1670. */
  1671. static SECStatus
  1672. DeleteDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
  1673. {
  1674. PRArenaPool *arena = NULL;
  1675. SECStatus rv;
  1676. SECItem dbkey;
  1677. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1678. if ( arena == NULL ) {
  1679. goto loser;
  1680. }
  1681. rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey);
  1682. if ( rv != SECSuccess ) {
  1683. goto loser;
  1684. }
  1685. rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey);
  1686. if ( rv == SECFailure ) {
  1687. goto loser;
  1688. }
  1689. PORT_FreeArena(arena, PR_FALSE);
  1690. return(SECSuccess);
  1691. loser:
  1692. if ( arena ) {
  1693. PORT_FreeArena(arena, PR_FALSE);
  1694. }
  1695. return(SECFailure);
  1696. }
  1697. /*
  1698. * Read a SMIME entry
  1699. */
  1700. certDBEntrySMime *
  1701. nsslowcert_ReadDBSMimeEntry(NSSLOWCERTCertDBHandle *handle, char *emailAddr)
  1702. {
  1703. PRArenaPool *arena = NULL;
  1704. PRArenaPool *tmparena = NULL;
  1705. certDBEntrySMime *entry;
  1706. SECItem dbkey;
  1707. SECItem dbentry;
  1708. SECStatus rv;
  1709. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1710. if ( arena == NULL ) {
  1711. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1712. goto loser;
  1713. }
  1714. tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1715. if ( tmparena == NULL ) {
  1716. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1717. goto loser;
  1718. }
  1719. entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
  1720. sizeof(certDBEntrySMime));
  1721. if ( entry == NULL ) {
  1722. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1723. goto loser;
  1724. }
  1725. entry->common.arena = arena;
  1726. entry->common.type = certDBEntryTypeSMimeProfile;
  1727. rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey);
  1728. if (