pcertdb.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:171k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /*
  34.  * Permanent Certificate database handling code 
  35.  *
  36.  * $Id: pcertdb.c,v 1.4 2000/10/02 23:23:50 wtc%netscape.com Exp $
  37.  */
  38. #include "prtime.h"
  39. #include "cert.h"
  40. #include "mcom_db.h"
  41. #include "certdb.h"
  42. #include "secitem.h"
  43. #include "secder.h"
  44. /* Call to PK11_FreeSlot below */
  45. #include "secasn1.h"
  46. #include "secerr.h"
  47. #include "prlock.h"
  48. #include "prmon.h"
  49. #include "nsslocks.h"
  50. #include "base64.h"
  51. #include "sechash.h"
  52. #include "plhash.h"
  53. #include "cdbhdl.h"
  54. /*
  55.  * the following functions are wrappers for the db library that implement
  56.  * a global lock to make the database thread safe.
  57.  */
  58. static PRLock *dbLock = NULL;
  59. void
  60. certdb_InitDBLock(void)
  61. {
  62.     if (dbLock == NULL) {
  63. nss_InitLock(&dbLock);
  64. PORT_Assert(dbLock != NULL);
  65.     }
  66.     return;
  67. }
  68. static int
  69. certdb_Get(DB *db, DBT *key, DBT *data, unsigned int flags)
  70. {
  71.     PRStatus prstat;
  72.     int ret;
  73.     
  74.     PORT_Assert(dbLock != NULL);
  75.     PR_Lock(dbLock);
  76.     
  77.     ret = (* db->get)(db, key, data, flags);
  78.     prstat = PR_Unlock(dbLock);
  79.     return(ret);
  80. }
  81. static int
  82. certdb_Put(DB *db, DBT *key, DBT *data, unsigned int flags)
  83. {
  84.     PRStatus prstat;
  85.     int ret;
  86.     PORT_Assert(dbLock != NULL);
  87.     PR_Lock(dbLock);
  88.     ret = (* db->put)(db, key, data, flags);
  89.     
  90.     prstat = PR_Unlock(dbLock);
  91.     return(ret);
  92. }
  93. static int
  94. certdb_Sync(DB *db, unsigned int flags)
  95. {
  96.     PRStatus prstat;
  97.     int ret;
  98.     PORT_Assert(dbLock != NULL);
  99.     PR_Lock(dbLock);
  100.     ret = (* db->sync)(db, flags);
  101.     
  102.     prstat = PR_Unlock(dbLock);
  103.     return(ret);
  104. }
  105. static int
  106. certdb_Del(DB *db, DBT *key, unsigned int flags)
  107. {
  108.     PRStatus prstat;
  109.     int ret;
  110.     PORT_Assert(dbLock != NULL);
  111.     PR_Lock(dbLock);
  112.     ret = (* db->del)(db, key, flags);
  113.     
  114.     prstat = PR_Unlock(dbLock);
  115.     return(ret);
  116. }
  117. static int
  118. certdb_Seq(DB *db, DBT *key, DBT *data, unsigned int flags)
  119. {
  120.     PRStatus prstat;
  121.     int ret;
  122.     
  123.     PORT_Assert(dbLock != NULL);
  124.     PR_Lock(dbLock);
  125.     
  126.     ret = (* db->seq)(db, key, data, flags);
  127.     prstat = PR_Unlock(dbLock);
  128.     return(ret);
  129. }
  130. static void
  131. certdb_Close(DB *db)
  132. {
  133.     PRStatus prstat;
  134.     PORT_Assert(dbLock != NULL);
  135.     PR_Lock(dbLock);
  136.     (* db->close)(db);
  137.     
  138.     prstat = PR_Unlock(dbLock);
  139.     return;
  140. }
  141. /* forward references */
  142. static void CERT_DestroyCertificateNoLocking(CERTCertificate *cert);
  143. static SECStatus AddCertToSPKDigestTable(CERTCertDBHandle *handle,
  144.  CERTCertificate *cert);
  145. static SECStatus RemoveCertFromSPKDigestTable(CERTCertDBHandle *handle,
  146.       CERTCertificate *cert);
  147. static SECStatus
  148. DeleteDBEntry(CERTCertDBHandle *handle, certDBEntryType type, SECItem *dbkey)
  149. {
  150.     DBT key;
  151.     int ret;
  152.     /* init the database key */
  153.     key.data = dbkey->data;
  154.     key.size = dbkey->len;
  155.     
  156.     dbkey->data[0] = (unsigned char)type;
  157.     /* delete entry from database */
  158.     ret = certdb_Del(handle->permCertDB, &key, 0 );
  159.     if ( ret != 0 ) {
  160. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  161. goto loser;
  162.     }
  163.     ret = certdb_Sync(handle->permCertDB, 0);
  164.     if ( ret ) {
  165. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  166. goto loser;
  167.     }
  168.     return(SECSuccess);
  169.     
  170. loser:
  171.     return(SECFailure);
  172. }
  173. static SECStatus
  174. ReadDBEntry(CERTCertDBHandle *handle, certDBEntryCommon *entry,
  175.     SECItem *dbkey, SECItem *dbentry, PRArenaPool *arena)
  176. {
  177.     DBT data, key;
  178.     int ret;
  179.     unsigned char *buf;
  180.     
  181.     /* init the database key */
  182.     key.data = dbkey->data;
  183.     key.size = dbkey->len;
  184.     
  185.     dbkey->data[0] = (unsigned char)entry->type;
  186.     /* read entry from database */
  187.     ret = certdb_Get(handle->permCertDB, &key, &data, 0 );
  188.     if ( ret != 0 ) {
  189. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  190. goto loser;
  191.     }
  192.     
  193.     /* validate the entry */
  194.     if ( data.size < SEC_DB_ENTRY_HEADER_LEN ) {
  195. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  196. goto loser;
  197.     }
  198.     buf = (unsigned char *)data.data;
  199.     if ( buf[0] != (unsigned char)CERT_DB_FILE_VERSION ) {
  200. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  201. goto loser;
  202.     }
  203.     if ( buf[1] != (unsigned char)entry->type ) {
  204. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  205. goto loser;
  206.     }
  207.     /* copy out header information */
  208.     entry->version = (unsigned int)buf[0];
  209.     entry->type = (certDBEntryType)buf[1];
  210.     entry->flags = (unsigned int)buf[2];
  211.     
  212.     /* format body of entry for return to caller */
  213.     dbentry->len = data.size - SEC_DB_ENTRY_HEADER_LEN;
  214.     if ( dbentry->len ) {
  215. dbentry->data = (unsigned char *)PORT_ArenaAlloc(arena, dbentry->len);
  216. if ( dbentry->data == NULL ) {
  217.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  218.     goto loser;
  219. }
  220.     
  221. PORT_Memcpy(dbentry->data, &buf[SEC_DB_ENTRY_HEADER_LEN],
  222.   dbentry->len);
  223.     } else {
  224. dbentry->data = NULL;
  225.     }
  226.     
  227.     return(SECSuccess);
  228. loser:
  229.     return(SECFailure);
  230. }
  231. /**
  232.  ** Implement low level database access
  233.  **/
  234. static SECStatus
  235. WriteDBEntry(CERTCertDBHandle *handle, certDBEntryCommon *entry,
  236.      SECItem *dbkey, SECItem *dbentry)
  237. {
  238.     int ret;
  239.     DBT data, key;
  240.     unsigned char *buf;
  241.     
  242.     data.data = dbentry->data;
  243.     data.size = dbentry->len;
  244.     
  245.     buf = (unsigned char*)data.data;
  246.     
  247.     buf[0] = (unsigned char)entry->version;
  248.     buf[1] = (unsigned char)entry->type;
  249.     buf[2] = (unsigned char)entry->flags;
  250.     
  251.     key.data = dbkey->data;
  252.     key.size = dbkey->len;
  253.     
  254.     dbkey->data[0] = (unsigned char)entry->type;
  255.     /* put the record into the database now */
  256.     ret = certdb_Put(handle->permCertDB, &key, &data, 0);
  257.     if ( ret != 0 ) {
  258. goto loser;
  259.     }
  260.     ret = certdb_Sync( handle->permCertDB, 0 );
  261.     
  262.     if ( ret ) {
  263. goto loser;
  264.     }
  265.     return(SECSuccess);
  266. loser:
  267.     return(SECFailure);
  268. }
  269. /*
  270.  * encode a database cert record
  271.  */
  272. static SECStatus
  273. EncodeDBCertEntry(certDBEntryCert *entry, PRArenaPool *arena, SECItem *dbitem)
  274. {
  275.     unsigned int nnlen;
  276.     unsigned char *buf;
  277.     char *nn;
  278.     char zbuf = 0;
  279.     
  280.     if ( entry->nickname ) {
  281. nn = entry->nickname;
  282.     } else {
  283. nn = &zbuf;
  284.     }
  285.     nnlen = PORT_Strlen(nn) + 1;
  286.     
  287.     /* allocate space for encoded database record, including space
  288.      * for low level header
  289.      */
  290.     dbitem->len = entry->derCert.len + nnlen + DB_CERT_ENTRY_HEADER_LEN +
  291. SEC_DB_ENTRY_HEADER_LEN;
  292.     
  293.     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  294.     if ( dbitem->data == NULL) {
  295. PORT_SetError(SEC_ERROR_NO_MEMORY);
  296. goto loser;
  297.     }
  298.     
  299.     /* fill in database record */
  300.     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  301.     
  302.     buf[0] = ( entry->trust.sslFlags >> 8 ) & 0xff;
  303.     buf[1] = entry->trust.sslFlags & 0xff;
  304.     buf[2] = ( entry->trust.emailFlags >> 8 ) & 0xff;
  305.     buf[3] = entry->trust.emailFlags & 0xff;
  306.     buf[4] = ( entry->trust.objectSigningFlags >> 8 ) & 0xff;
  307.     buf[5] = entry->trust.objectSigningFlags & 0xff;
  308.     buf[6] = ( entry->derCert.len >> 8 ) & 0xff;
  309.     buf[7] = entry->derCert.len & 0xff;
  310.     buf[8] = ( nnlen >> 8 ) & 0xff;
  311.     buf[9] = nnlen & 0xff;
  312.     
  313.     PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN], entry->derCert.data,
  314.       entry->derCert.len);
  315.     PORT_Memcpy(&buf[DB_CERT_ENTRY_HEADER_LEN + entry->derCert.len],
  316.       nn, nnlen);
  317.     return(SECSuccess);
  318. loser:
  319.     return(SECFailure);
  320. }
  321. /*
  322.  * encode a database key for a cert record
  323.  */
  324. static SECStatus
  325. EncodeDBCertKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey)
  326. {
  327.     dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
  328.     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  329.     if ( dbkey->data == NULL ) {
  330. goto loser;
  331.     }
  332.     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
  333.       certKey->data, certKey->len);
  334.     dbkey->data[0] = certDBEntryTypeCert;
  335.     return(SECSuccess);
  336. loser:
  337.     return(SECFailure);
  338. }
  339. static SECStatus
  340. EncodeDBGenericKey(SECItem *certKey, PRArenaPool *arena, SECItem *dbkey, 
  341. certDBEntryType entryType)
  342. {
  343.     /*
  344.      * we only allow _one_ KRL key!
  345.      */
  346.     if (entryType == certDBEntryTypeKeyRevocation) {
  347. dbkey->len = SEC_DB_KEY_HEADER_LEN;
  348.   dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  349. if ( dbkey->data == NULL ) {
  350.     goto loser;
  351. }
  352.         dbkey->data[0] = (unsigned char) entryType;
  353.         return(SECSuccess);
  354.     }
  355.     
  356.     dbkey->len = certKey->len + SEC_DB_KEY_HEADER_LEN;
  357.     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  358.     if ( dbkey->data == NULL ) {
  359. goto loser;
  360.     }
  361.     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN],
  362.       certKey->data, certKey->len);
  363.     dbkey->data[0] = (unsigned char) entryType;
  364.     return(SECSuccess);
  365. loser:
  366.     return(SECFailure);
  367. }
  368. static SECStatus
  369. DecodeDBCertEntry(certDBEntryCert *entry, SECItem *dbentry)
  370. {
  371.     unsigned int nnlen;
  372.     int headerlen;
  373.     int lenoff;
  374.     /* allow updates of old versions of the database */
  375.     switch ( entry->common.version ) {
  376.       case 5:
  377. headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
  378. lenoff = 3;
  379. break;
  380.       case 6:
  381. /* should not get here */
  382. PORT_Assert(0);
  383. headerlen = DB_CERT_V6_ENTRY_HEADER_LEN;
  384. lenoff = 3;
  385. break;
  386.       case 7:
  387. headerlen = DB_CERT_ENTRY_HEADER_LEN;
  388. lenoff = 6;
  389. break;
  390.       default:
  391. /* better not get here */
  392. PORT_Assert(0);
  393. headerlen = DB_CERT_V5_ENTRY_HEADER_LEN;
  394. lenoff = 3;
  395. break;
  396.     }
  397.     
  398.     /* is record long enough for header? */
  399.     if ( dbentry->len < headerlen ) {
  400. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  401. goto loser;
  402.     }
  403.     
  404.     /* is database entry correct length? */
  405.     entry->derCert.len = ( ( dbentry->data[lenoff] << 8 ) |
  406.   dbentry->data[lenoff+1] );
  407.     nnlen = ( ( dbentry->data[lenoff+2] << 8 ) | dbentry->data[lenoff+3] );
  408.     if ( ( entry->derCert.len + nnlen + headerlen )
  409. != dbentry->len) {
  410. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  411. goto loser;
  412.     }
  413.     
  414.     /* copy the dercert */
  415.     entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  416.    entry->derCert.len);
  417.     if ( entry->derCert.data == NULL ) {
  418. PORT_SetError(SEC_ERROR_NO_MEMORY);
  419. goto loser;
  420.     }
  421.     PORT_Memcpy(entry->derCert.data, &dbentry->data[headerlen],
  422.       entry->derCert.len);
  423.     /* copy the nickname */
  424.     if ( nnlen > 1 ) {
  425. entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena, nnlen);
  426. if ( entry->nickname == NULL ) {
  427.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  428.     goto loser;
  429. }
  430. PORT_Memcpy(entry->nickname,
  431.     &dbentry->data[headerlen +
  432.    entry->derCert.len],
  433.     nnlen);
  434.     } else {
  435. entry->nickname = NULL;
  436.     }
  437.     
  438.     if ( entry->common.version < 7 ) {
  439. /* allow updates of v5 db */
  440. entry->trust.sslFlags = dbentry->data[0];
  441. entry->trust.emailFlags = dbentry->data[1];
  442. entry->trust.objectSigningFlags = dbentry->data[2];
  443.     } else {
  444. entry->trust.sslFlags = ( dbentry->data[0] << 8 ) | dbentry->data[1];
  445. entry->trust.emailFlags = ( dbentry->data[2] << 8 ) | dbentry->data[3];
  446. entry->trust.objectSigningFlags =
  447.     ( dbentry->data[4] << 8 ) | dbentry->data[5];
  448.     }
  449.     
  450.     return(SECSuccess);
  451. loser:
  452.     return(SECFailure);
  453. }
  454. /*
  455.  * Create a new certDBEntryCert from existing data
  456.  */
  457. static certDBEntryCert *
  458. NewDBCertEntry(SECItem *derCert, char *nickname,
  459.        CERTCertTrust *trust, int flags)
  460. {
  461.     certDBEntryCert *entry;
  462.     PRArenaPool *arena = NULL;
  463.     int nnlen;
  464.     
  465.     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
  466.     if ( !arena ) {
  467. goto loser;
  468.     }
  469.     entry = (certDBEntryCert *)PORT_ArenaZAlloc(arena, sizeof(certDBEntryCert));
  470.     if ( entry == NULL ) {
  471. goto loser;
  472.     }
  473.     
  474.     /* fill in the dbCert */
  475.     entry->common.arena = arena;
  476.     entry->common.type = certDBEntryTypeCert;
  477.     entry->common.version = CERT_DB_FILE_VERSION;
  478.     entry->common.flags = flags;
  479.     
  480.     if ( trust ) {
  481. entry->trust = *trust;
  482.     }
  483.     entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, derCert->len);
  484.     if ( !entry->derCert.data ) {
  485. goto loser;
  486.     }
  487.     entry->derCert.len = derCert->len;
  488.     PORT_Memcpy(entry->derCert.data, derCert->data, derCert->len);
  489.     
  490.     nnlen = ( nickname ? strlen(nickname) + 1 : 0 );
  491.     
  492.     if ( nnlen ) {
  493. entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
  494. if ( !entry->nickname ) {
  495.     goto loser;
  496. }
  497. PORT_Memcpy(entry->nickname, nickname, nnlen);
  498.     } else {
  499. entry->nickname = 0;
  500.     }
  501.     return(entry);
  502. loser:
  503.     
  504.     /* allocation error, free arena and return */
  505.     if ( arena ) {
  506. PORT_FreeArena(arena, PR_FALSE);
  507.     }
  508.     
  509.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  510.     return(0);
  511. }
  512. /*
  513.  * Decode a version 4 DBCert from the byte stream database format
  514.  * and construct a current database entry struct
  515.  */
  516. static certDBEntryCert *
  517. DecodeV4DBCertEntry(unsigned char *buf, int len)
  518. {
  519.     certDBEntryCert *entry;
  520.     int certlen;
  521.     int nnlen;
  522.     PRArenaPool *arena;
  523.     
  524.     /* make sure length is at least long enough for the header */
  525.     if ( len < DBCERT_V4_HEADER_LEN ) {
  526. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  527. return(0);
  528.     }
  529.     /* get other lengths */
  530.     certlen = buf[3] << 8 | buf[4];
  531.     nnlen = buf[5] << 8 | buf[6];
  532.     
  533.     /* make sure DB entry is the right size */
  534.     if ( ( certlen + nnlen + DBCERT_V4_HEADER_LEN ) != len ) {
  535. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  536. return(0);
  537.     }
  538.     /* allocate arena */
  539.     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
  540.     if ( !arena ) {
  541. PORT_SetError(SEC_ERROR_NO_MEMORY);
  542. return(0);
  543.     }
  544.     /* allocate structure and members */
  545.     entry = (certDBEntryCert *)  PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
  546.     if ( !entry ) {
  547. goto loser;
  548.     }
  549.     entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen);
  550.     if ( !entry->derCert.data ) {
  551. goto loser;
  552.     }
  553.     entry->derCert.len = certlen;
  554.     
  555.     if ( nnlen ) {
  556. entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen);
  557. if ( !entry->nickname ) {
  558.     goto loser;
  559. }
  560.     } else {
  561. entry->nickname = 0;
  562.     }
  563.     entry->common.arena = arena;
  564.     entry->common.version = CERT_DB_FILE_VERSION;
  565.     entry->common.type = certDBEntryTypeCert;
  566.     entry->common.flags = 0;
  567.     entry->trust.sslFlags = buf[0];
  568.     entry->trust.emailFlags = buf[1];
  569.     entry->trust.objectSigningFlags = buf[2];
  570.     PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen);
  571.     PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen);
  572.     return(entry);
  573.     
  574. loser:
  575.     PORT_FreeArena(arena, PR_FALSE);
  576.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  577.     return(0);
  578. }
  579. /*
  580.  * Encode a Certificate database entry into byte stream suitable for
  581.  * the database
  582.  */
  583. static SECStatus
  584. WriteDBCertEntry(CERTCertDBHandle *handle, certDBEntryCert *entry)
  585. {
  586.     SECItem dbitem, dbkey;
  587.     PRArenaPool *tmparena = NULL;
  588.     SECItem tmpitem;
  589.     SECStatus rv;
  590.     
  591.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  592.     if ( tmparena == NULL ) {
  593. goto loser;
  594.     }
  595.     
  596.     rv = EncodeDBCertEntry(entry, tmparena, &dbitem);
  597.     if ( rv != SECSuccess ) {
  598. goto loser;
  599.     }
  600.     /* get the database key and format it */
  601.     rv = CERT_KeyFromDERCert(tmparena, &entry->derCert, &tmpitem);
  602.     if ( rv == SECFailure ) {
  603. goto loser;
  604.     }
  605.     rv = EncodeDBCertKey(&tmpitem, tmparena, &dbkey);
  606.     if ( rv == SECFailure ) {
  607. goto loser;
  608.     }
  609.     
  610.     /* now write it to the database */
  611.     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  612.     if ( rv != SECSuccess ) {
  613. goto loser;
  614.     }
  615.     
  616.     PORT_FreeArena(tmparena, PR_FALSE);
  617.     return(SECSuccess);
  618. loser:
  619.     if ( tmparena ) {
  620. PORT_FreeArena(tmparena, PR_FALSE);
  621.     }
  622.     return(SECFailure);
  623. }
  624. /*
  625.  * delete a certificate entry
  626.  */
  627. static SECStatus
  628. DeleteDBCertEntry(CERTCertDBHandle *handle, SECItem *certKey)
  629. {
  630.     SECItem dbkey;
  631.     PRArenaPool *arena = NULL;
  632.     SECStatus rv;
  633.     
  634.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  635.     if ( arena == NULL ) {
  636. goto loser;
  637.     }
  638.     rv = EncodeDBCertKey(certKey, arena, &dbkey);
  639.     if ( rv != SECSuccess ) {
  640. goto loser;
  641.     }
  642.     
  643.     rv = DeleteDBEntry(handle, certDBEntryTypeCert, &dbkey);
  644.     if ( rv == SECFailure ) {
  645. goto loser;
  646.     }
  647.     PORT_FreeArena(arena, PR_FALSE);
  648.     return(SECSuccess);
  649. loser:
  650.     if ( arena ) {
  651. PORT_FreeArena(arena, PR_FALSE);
  652.     }
  653.     
  654.     return(SECFailure);
  655. }
  656. /*
  657.  * Read a certificate entry
  658.  */
  659. static certDBEntryCert *
  660. ReadDBCertEntry(CERTCertDBHandle *handle, SECItem *certKey)
  661. {
  662.     PRArenaPool *arena = NULL;
  663.     PRArenaPool *tmparena = NULL;
  664.     certDBEntryCert *entry;
  665.     SECItem dbkey;
  666.     SECItem dbentry;
  667.     SECStatus rv;
  668.     
  669.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  670.     if ( arena == NULL ) {
  671. PORT_SetError(SEC_ERROR_NO_MEMORY);
  672. goto loser;
  673.     }
  674.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  675.     if ( tmparena == NULL ) {
  676. PORT_SetError(SEC_ERROR_NO_MEMORY);
  677. goto loser;
  678.     }
  679.     
  680.     entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
  681.     if ( entry == NULL ) {
  682. PORT_SetError(SEC_ERROR_NO_MEMORY);
  683. goto loser;
  684.     }
  685.     entry->common.arena = arena;
  686.     entry->common.type = certDBEntryTypeCert;
  687.     rv = EncodeDBCertKey(certKey, tmparena, &dbkey);
  688.     if ( rv != SECSuccess ) {
  689. goto loser;
  690.     }
  691.     
  692.     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  693.     if ( rv == SECFailure ) {
  694. goto loser;
  695.     }
  696.     rv = DecodeDBCertEntry(entry, &dbentry);
  697.     if ( rv != SECSuccess ) {
  698. goto loser;
  699.     }
  700.     
  701.     PORT_FreeArena(tmparena, PR_FALSE);
  702.     return(entry);
  703.     
  704. loser:
  705.     if ( tmparena ) {
  706. PORT_FreeArena(tmparena, PR_FALSE);
  707.     }
  708.     if ( arena ) {
  709. PORT_FreeArena(arena, PR_FALSE);
  710.     }
  711.     
  712.     return(NULL);
  713. }
  714. /*
  715.  * encode a database cert record
  716.  */
  717. static SECStatus
  718. EncodeDBCrlEntry(certDBEntryRevocation *entry, PRArenaPool *arena, SECItem *dbitem)
  719. {
  720.     unsigned int nnlen = 0;
  721.     unsigned char *buf;
  722.   
  723.     if (entry->url) {  
  724. nnlen = PORT_Strlen(entry->url) + 1;
  725.     }
  726.     
  727.     /* allocate space for encoded database record, including space
  728.      * for low level header
  729.      */
  730.     dbitem->len = entry->derCrl.len + nnlen 
  731. + SEC_DB_ENTRY_HEADER_LEN + DB_CRL_ENTRY_HEADER_LEN;
  732.     
  733.     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  734.     if ( dbitem->data == NULL) {
  735. PORT_SetError(SEC_ERROR_NO_MEMORY);
  736. goto loser;
  737.     }
  738.     
  739.     /* fill in database record */
  740.     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  741.     
  742.     buf[0] = ( entry->derCrl.len >> 8 ) & 0xff;
  743.     buf[1] = entry->derCrl.len & 0xff;
  744.     buf[2] = ( nnlen >> 8 ) & 0xff;
  745.     buf[3] = nnlen & 0xff;
  746.     
  747.     PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN], entry->derCrl.data,
  748.       entry->derCrl.len);
  749.     if (nnlen != 0) {
  750. PORT_Memcpy(&buf[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
  751.       entry->url, nnlen);
  752.     }
  753.     return(SECSuccess);
  754. loser:
  755.     return(SECFailure);
  756. }
  757. static SECStatus
  758. DecodeDBCrlEntry(certDBEntryRevocation *entry, SECItem *dbentry)
  759. {
  760.     unsigned int nnlen;
  761.     
  762.     /* is record long enough for header? */
  763.     if ( dbentry->len < DB_CRL_ENTRY_HEADER_LEN ) {
  764. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  765. goto loser;
  766.     }
  767.     
  768.     /* is database entry correct length? */
  769.     entry->derCrl.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
  770.     nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
  771.     if ( ( entry->derCrl.len + nnlen + DB_CRL_ENTRY_HEADER_LEN )
  772. != dbentry->len) {
  773. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  774. goto loser;
  775.     }
  776.     
  777.     /* copy the dercert */
  778.     entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  779.  entry->derCrl.len);
  780.     if ( entry->derCrl.data == NULL ) {
  781. PORT_SetError(SEC_ERROR_NO_MEMORY);
  782. goto loser;
  783.     }
  784.     PORT_Memcpy(entry->derCrl.data, &dbentry->data[DB_CRL_ENTRY_HEADER_LEN],
  785.       entry->derCrl.len);
  786.     /* copy the url */
  787.     entry->url = NULL;
  788.     if (nnlen != 0) {
  789. entry->url = (char *)PORT_ArenaAlloc(entry->common.arena, nnlen);
  790. if ( entry->url == NULL ) {
  791.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  792.     goto loser;
  793. }
  794. PORT_Memcpy(entry->url,
  795.       &dbentry->data[DB_CRL_ENTRY_HEADER_LEN + entry->derCrl.len],
  796.       nnlen);
  797.     }
  798.     
  799.     return(SECSuccess);
  800. loser:
  801.     return(SECFailure);
  802. }
  803. /*
  804.  * Create a new certDBEntryRevocation from existing data
  805.  */
  806. static certDBEntryRevocation *
  807. NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags)
  808. {
  809.     certDBEntryRevocation *entry;
  810.     PRArenaPool *arena = NULL;
  811.     int nnlen;
  812.     
  813.     arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE );
  814.     if ( !arena ) {
  815. goto loser;
  816.     }
  817.     entry = (certDBEntryRevocation*)
  818. PORT_ArenaZAlloc(arena, sizeof(certDBEntryRevocation));
  819.     if ( entry == NULL ) {
  820. goto loser;
  821.     }
  822.     
  823.     /* fill in the dbRevolcation */
  824.     entry->common.arena = arena;
  825.     entry->common.type = crlType;
  826.     entry->common.version = CERT_DB_FILE_VERSION;
  827.     entry->common.flags = flags;
  828.     
  829.     entry->derCrl.data = (unsigned char *)PORT_ArenaAlloc(arena, derCrl->len);
  830.     if ( !entry->derCrl.data ) {
  831. goto loser;
  832.     }
  833.     if (url) {
  834. nnlen = PORT_Strlen(url) + 1;
  835. entry->url  = (char *)PORT_ArenaAlloc(arena, nnlen);
  836. if ( !entry->url ) {
  837.     goto loser;
  838. }
  839. PORT_Memcpy(entry->url, url, nnlen);
  840.     } else {
  841. entry->url = NULL;
  842.     }
  843.     entry->derCrl.len = derCrl->len;
  844.     PORT_Memcpy(entry->derCrl.data, derCrl->data, derCrl->len);
  845.     return(entry);
  846. loser:
  847.     
  848.     /* allocation error, free arena and return */
  849.     if ( arena ) {
  850. PORT_FreeArena(arena, PR_FALSE);
  851.     }
  852.     
  853.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  854.     return(0);
  855. }
  856. static SECStatus
  857. WriteDBCrlEntry(CERTCertDBHandle *handle, certDBEntryRevocation *entry )
  858. {
  859.     SECItem dbkey;
  860.     PRArenaPool *tmparena = NULL;
  861.     SECItem tmpitem,encodedEntry;
  862.     SECStatus rv;
  863.     
  864.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  865.     if ( tmparena == NULL ) {
  866. goto loser;
  867.     }
  868.     /* get the database key and format it */
  869.     rv = CERT_KeyFromDERCrl(tmparena, &entry->derCrl, &tmpitem);
  870.     if ( rv == SECFailure ) {
  871. goto loser;
  872.     }
  873.     rv = EncodeDBCrlEntry(entry, tmparena, &encodedEntry);
  874.     if ( rv == SECFailure ) {
  875. goto loser;
  876.     }
  877.     rv = EncodeDBGenericKey(&tmpitem, tmparena, &dbkey, entry->common.type);
  878.     if ( rv == SECFailure ) {
  879. goto loser;
  880.     }
  881.     
  882.     /* now write it to the database */
  883.     rv = WriteDBEntry(handle, &entry->common, &dbkey, &encodedEntry);
  884.     if ( rv != SECSuccess ) {
  885. goto loser;
  886.     }
  887.     
  888.     PORT_FreeArena(tmparena, PR_FALSE);
  889.     return(SECSuccess);
  890. loser:
  891.     if ( tmparena ) {
  892. PORT_FreeArena(tmparena, PR_FALSE);
  893.     }
  894.     return(SECFailure);
  895. }
  896. /*
  897.  * delete a crl entry
  898.  */
  899. static SECStatus
  900. DeleteDBCrlEntry(CERTCertDBHandle *handle, SECItem *crlKey, 
  901. certDBEntryType crlType)
  902. {
  903.     SECItem dbkey;
  904.     PRArenaPool *arena = NULL;
  905.     SECStatus rv;
  906.     
  907.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  908.     if ( arena == NULL ) {
  909. goto loser;
  910.     }
  911.     rv = EncodeDBGenericKey(crlKey, arena, &dbkey, crlType);
  912.     if ( rv != SECSuccess ) {
  913. goto loser;
  914.     }
  915.     
  916.     rv = DeleteDBEntry(handle, crlType, &dbkey);
  917.     if ( rv == SECFailure ) {
  918. goto loser;
  919.     }
  920.     PORT_FreeArena(arena, PR_FALSE);
  921.     return(SECSuccess);
  922. loser:
  923.     if ( arena ) {
  924. PORT_FreeArena(arena, PR_FALSE);
  925.     }
  926.     
  927.     return(SECFailure);
  928. }
  929. /*
  930.  * Read a certificate entry
  931.  */
  932. static certDBEntryRevocation *
  933. ReadDBCrlEntry(CERTCertDBHandle *handle, SECItem *certKey,
  934. certDBEntryType crlType)
  935. {
  936.     PRArenaPool *arena = NULL;
  937.     PRArenaPool *tmparena = NULL;
  938.     certDBEntryRevocation *entry;
  939.     SECItem dbkey;
  940.     SECItem dbentry;
  941.     SECStatus rv;
  942.     
  943.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  944.     if ( arena == NULL ) {
  945. PORT_SetError(SEC_ERROR_NO_MEMORY);
  946. goto loser;
  947.     }
  948.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  949.     if ( tmparena == NULL ) {
  950. PORT_SetError(SEC_ERROR_NO_MEMORY);
  951. goto loser;
  952.     }
  953.     
  954.     entry = (certDBEntryRevocation *)
  955. PORT_ArenaAlloc(arena, sizeof(certDBEntryRevocation));
  956.     if ( entry == NULL ) {
  957. PORT_SetError(SEC_ERROR_NO_MEMORY);
  958. goto loser;
  959.     }
  960.     entry->common.arena = arena;
  961.     entry->common.type = crlType;
  962.     rv = EncodeDBGenericKey(certKey, tmparena, &dbkey, crlType);
  963.     if ( rv != SECSuccess ) {
  964. goto loser;
  965.     }
  966.     
  967.     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  968.     if ( rv == SECFailure ) {
  969. goto loser;
  970.     }
  971.     rv = DecodeDBCrlEntry(entry, &dbentry);
  972.     if ( rv != SECSuccess ) {
  973. goto loser;
  974.     }
  975.     
  976.     PORT_FreeArena(tmparena, PR_FALSE);
  977.     return(entry);
  978.     
  979. loser:
  980.     if ( tmparena ) {
  981. PORT_FreeArena(tmparena, PR_FALSE);
  982.     }
  983.     if ( arena ) {
  984. PORT_FreeArena(arena, PR_FALSE);
  985.     }
  986.     
  987.     return(NULL);
  988. }
  989. /*
  990.  * destroy a database entry
  991.  */
  992. static void
  993. DestroyDBEntry(certDBEntry *entry)
  994. {
  995.     PRArenaPool *arena = entry->common.arena;
  996.     /* Zero out the entry struct, so that any further attempts to use it
  997.      * will cause an exception (e.g. null pointer reference). */
  998.     PORT_Memset(&entry->common, 0, sizeof entry->common);
  999.     PORT_FreeArena(arena, PR_FALSE);
  1000.     return;
  1001. }
  1002. /*
  1003.  * Encode a database nickname record
  1004.  */
  1005. static SECStatus
  1006. EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena,
  1007.       SECItem *dbitem)
  1008. {
  1009.     unsigned char *buf;
  1010.     
  1011.     /* allocate space for encoded database record, including space
  1012.      * for low level header
  1013.      */
  1014.     dbitem->len = entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN +
  1015. SEC_DB_ENTRY_HEADER_LEN;
  1016.     
  1017.     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  1018.     if ( dbitem->data == NULL) {
  1019. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1020. goto loser;
  1021.     }
  1022.     
  1023.     /* fill in database record */
  1024.     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  1025.     
  1026.     buf[0] = ( entry->subjectName.len >> 8 ) & 0xff;
  1027.     buf[1] = entry->subjectName.len & 0xff;
  1028.     
  1029.     PORT_Memcpy(&buf[DB_NICKNAME_ENTRY_HEADER_LEN], entry->subjectName.data,
  1030.       entry->subjectName.len);
  1031.     return(SECSuccess);
  1032. loser:
  1033.     return(SECFailure);
  1034. }
  1035. /*
  1036.  * Encode a database key for a nickname record
  1037.  */
  1038. static SECStatus
  1039. EncodeDBNicknameKey(char *nickname, PRArenaPool *arena,
  1040.     SECItem *dbkey)
  1041. {
  1042.     unsigned int nnlen;
  1043.     
  1044.     nnlen = PORT_Strlen(nickname) + 1; /* includes null */
  1045.     /* now get the database key and format it */
  1046.     dbkey->len = nnlen + SEC_DB_KEY_HEADER_LEN;
  1047.     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  1048.     if ( dbkey->data == NULL ) {
  1049. goto loser;
  1050.     }
  1051.     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], nickname, nnlen);
  1052.     dbkey->data[0] = certDBEntryTypeNickname;
  1053.     return(SECSuccess);
  1054. loser:
  1055.     return(SECFailure);
  1056. }
  1057. static SECStatus
  1058. DecodeDBNicknameEntry(certDBEntryNickname *entry, SECItem *dbentry)
  1059. {
  1060.     /* is record long enough for header? */
  1061.     if ( dbentry->len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
  1062. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1063. goto loser;
  1064.     }
  1065.     
  1066.     /* is database entry correct length? */
  1067.     entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
  1068.     if (( entry->subjectName.len + DB_NICKNAME_ENTRY_HEADER_LEN ) !=
  1069. dbentry->len ){
  1070. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1071. goto loser;
  1072.     }
  1073.     
  1074.     /* copy the certkey */
  1075.     entry->subjectName.data =
  1076. (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1077.  entry->subjectName.len);
  1078.     if ( entry->subjectName.data == NULL ) {
  1079. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1080. goto loser;
  1081.     }
  1082.     PORT_Memcpy(entry->subjectName.data,
  1083.       &dbentry->data[DB_NICKNAME_ENTRY_HEADER_LEN],
  1084.       entry->subjectName.len);
  1085.     
  1086.     return(SECSuccess);
  1087. loser:
  1088.     return(SECFailure);
  1089. }
  1090. /*
  1091.  * create a new nickname entry
  1092.  */
  1093. static certDBEntryNickname *
  1094. NewDBNicknameEntry(char *nickname, SECItem *subjectName, unsigned int flags)
  1095. {
  1096.     PRArenaPool *arena = NULL;
  1097.     certDBEntryNickname *entry;
  1098.     int nnlen;
  1099.     SECStatus rv;
  1100.     
  1101.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1102.     if ( arena == NULL ) {
  1103. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1104. goto loser;
  1105.     }
  1106.     entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
  1107.  sizeof(certDBEntryNickname));
  1108.     if ( entry == NULL ) {
  1109. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1110. goto loser;
  1111.     }
  1112.     /* init common fields */
  1113.     entry->common.arena = arena;
  1114.     entry->common.type = certDBEntryTypeNickname;
  1115.     entry->common.version = CERT_DB_FILE_VERSION;
  1116.     entry->common.flags = flags;
  1117.     /* copy the nickname */
  1118.     nnlen = PORT_Strlen(nickname) + 1;
  1119.     
  1120.     entry->nickname = (char*)PORT_ArenaAlloc(arena, nnlen);
  1121.     if ( entry->nickname == NULL ) {
  1122. goto loser;
  1123.     }
  1124.     
  1125.     PORT_Memcpy(entry->nickname, nickname, nnlen);
  1126.     
  1127.     rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
  1128.     if ( rv != SECSuccess ) {
  1129. goto loser;
  1130.     }
  1131.     
  1132.     return(entry);
  1133. loser:
  1134.     if ( arena ) {
  1135. PORT_FreeArena(arena, PR_FALSE);
  1136.     }
  1137.     
  1138.     return(NULL);
  1139. }
  1140. /*
  1141.  * delete a nickname entry
  1142.  */
  1143. static SECStatus
  1144. DeleteDBNicknameEntry(CERTCertDBHandle *handle, char *nickname)
  1145. {
  1146.     PRArenaPool *arena = NULL;
  1147.     SECStatus rv;
  1148.     SECItem dbkey;
  1149.     
  1150.     if ( nickname == NULL ) {
  1151. return(SECSuccess);
  1152.     }
  1153.     
  1154.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1155.     if ( arena == NULL ) {
  1156. goto loser;
  1157.     }
  1158.     rv = EncodeDBNicknameKey(nickname, arena, &dbkey);
  1159.     if ( rv != SECSuccess ) {
  1160. goto loser;
  1161.     }
  1162.     rv = DeleteDBEntry(handle, certDBEntryTypeNickname, &dbkey);
  1163.     if ( rv == SECFailure ) {
  1164. goto loser;
  1165.     }
  1166.     PORT_FreeArena(arena, PR_FALSE);
  1167.     return(SECSuccess);
  1168. loser:
  1169.     if ( arena ) {
  1170. PORT_FreeArena(arena, PR_FALSE);
  1171.     }
  1172.     
  1173.     return(SECFailure);
  1174. }
  1175. /*
  1176.  * Read a nickname entry
  1177.  */
  1178. static certDBEntryNickname *
  1179. ReadDBNicknameEntry(CERTCertDBHandle *handle, char *nickname)
  1180. {
  1181.     PRArenaPool *arena = NULL;
  1182.     PRArenaPool *tmparena = NULL;
  1183.     certDBEntryNickname *entry;
  1184.     SECItem dbkey;
  1185.     SECItem dbentry;
  1186.     SECStatus rv;
  1187.     
  1188.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1189.     if ( arena == NULL ) {
  1190. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1191. goto loser;
  1192.     }
  1193.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1194.     if ( tmparena == NULL ) {
  1195. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1196. goto loser;
  1197.     }
  1198.     
  1199.     entry = (certDBEntryNickname *)PORT_ArenaAlloc(arena,
  1200.  sizeof(certDBEntryNickname));
  1201.     if ( entry == NULL ) {
  1202. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1203. goto loser;
  1204.     }
  1205.     entry->common.arena = arena;
  1206.     entry->common.type = certDBEntryTypeNickname;
  1207.     rv = EncodeDBNicknameKey(nickname, tmparena, &dbkey);
  1208.     if ( rv != SECSuccess ) {
  1209. goto loser;
  1210.     }
  1211.     
  1212.     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  1213.     if ( rv == SECFailure ) {
  1214. goto loser;
  1215.     }
  1216.     /* is record long enough for header? */
  1217.     if ( dbentry.len < DB_NICKNAME_ENTRY_HEADER_LEN ) {
  1218. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1219. goto loser;
  1220.     }
  1221.     rv = DecodeDBNicknameEntry(entry, &dbentry);
  1222.     if ( rv != SECSuccess ) {
  1223. goto loser;
  1224.     }
  1225.     
  1226.     PORT_FreeArena(tmparena, PR_FALSE);
  1227.     return(entry);
  1228.     
  1229. loser:
  1230.     if ( tmparena ) {
  1231. PORT_FreeArena(tmparena, PR_FALSE);
  1232.     }
  1233.     if ( arena ) {
  1234. PORT_FreeArena(arena, PR_FALSE);
  1235.     }
  1236.     
  1237.     return(NULL);
  1238. }
  1239. /*
  1240.  * Encode a nickname entry into byte stream suitable for
  1241.  * the database
  1242.  */
  1243. static SECStatus
  1244. WriteDBNicknameEntry(CERTCertDBHandle *handle, certDBEntryNickname *entry)
  1245. {
  1246.     SECItem dbitem, dbkey;
  1247.     PRArenaPool *tmparena = NULL;
  1248.     SECStatus rv;
  1249.     
  1250.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1251.     if ( tmparena == NULL ) {
  1252. goto loser;
  1253.     }
  1254.     
  1255.     rv = EncodeDBNicknameEntry(entry, tmparena, &dbitem);
  1256.     if ( rv != SECSuccess ) {
  1257. goto loser;
  1258.     }
  1259.     rv = EncodeDBNicknameKey(entry->nickname, tmparena, &dbkey);
  1260.     if ( rv != SECSuccess ) {
  1261. goto loser;
  1262.     }
  1263.     /* now write it to the database */
  1264.     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  1265.     if ( rv != SECSuccess ) {
  1266. goto loser;
  1267.     }
  1268.     
  1269.     PORT_FreeArena(tmparena, PR_FALSE);
  1270.     return(SECSuccess);
  1271. loser:
  1272.     if ( tmparena ) {
  1273. PORT_FreeArena(tmparena, PR_FALSE);
  1274.     }
  1275.     return(SECFailure);
  1276.     
  1277. }
  1278. /*
  1279.  * Encode a database smime record
  1280.  */
  1281. static SECStatus
  1282. EncodeDBSMimeEntry(certDBEntrySMime *entry, PRArenaPool *arena,
  1283.    SECItem *dbitem)
  1284. {
  1285.     unsigned char *buf;
  1286.     
  1287.     /* allocate space for encoded database record, including space
  1288.      * for low level header
  1289.      */
  1290.     dbitem->len = entry->subjectName.len + entry->smimeOptions.len +
  1291. entry->optionsDate.len +
  1292. DB_SMIME_ENTRY_HEADER_LEN + SEC_DB_ENTRY_HEADER_LEN;
  1293.     
  1294.     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  1295.     if ( dbitem->data == NULL) {
  1296. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1297. goto loser;
  1298.     }
  1299.     
  1300.     /* fill in database record */
  1301.     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  1302.     
  1303.     buf[0] = ( entry->subjectName.len >> 8 ) & 0xff;
  1304.     buf[1] = entry->subjectName.len & 0xff;
  1305.     buf[2] = ( entry->smimeOptions.len >> 8 ) & 0xff;
  1306.     buf[3] = entry->smimeOptions.len & 0xff;
  1307.     buf[4] = ( entry->optionsDate.len >> 8 ) & 0xff;
  1308.     buf[5] = entry->optionsDate.len & 0xff;
  1309.     /* if no smime options, then there should not be an options date either */
  1310.     PORT_Assert( ! ( ( entry->smimeOptions.len == 0 ) &&
  1311.     ( entry->optionsDate.len != 0 ) ) );
  1312.     
  1313.     PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN], entry->subjectName.data,
  1314.       entry->subjectName.len);
  1315.     if ( entry->smimeOptions.len ) {
  1316. PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN+entry->subjectName.len],
  1317.     entry->smimeOptions.data,
  1318.     entry->smimeOptions.len);
  1319. PORT_Memcpy(&buf[DB_SMIME_ENTRY_HEADER_LEN + entry->subjectName.len +
  1320.  entry->smimeOptions.len],
  1321.     entry->optionsDate.data,
  1322.     entry->optionsDate.len);
  1323.     }
  1324.     return(SECSuccess);
  1325. loser:
  1326.     return(SECFailure);
  1327. }
  1328. /*
  1329.  * Encode a database key for a SMIME record
  1330.  */
  1331. static SECStatus
  1332. EncodeDBSMimeKey(char *emailAddr, PRArenaPool *arena,
  1333.  SECItem *dbkey)
  1334. {
  1335.     unsigned int addrlen;
  1336.     
  1337.     addrlen = PORT_Strlen(emailAddr) + 1; /* includes null */
  1338.     /* now get the database key and format it */
  1339.     dbkey->len = addrlen + SEC_DB_KEY_HEADER_LEN;
  1340.     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  1341.     if ( dbkey->data == NULL ) {
  1342. goto loser;
  1343.     }
  1344.     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], emailAddr, addrlen);
  1345.     dbkey->data[0] = certDBEntryTypeSMimeProfile;
  1346.     return(SECSuccess);
  1347. loser:
  1348.     return(SECFailure);
  1349. }
  1350. /*
  1351.  * Decode a database SMIME record
  1352.  */
  1353. static SECStatus
  1354. DecodeDBSMimeEntry(certDBEntrySMime *entry, SECItem *dbentry, char *emailAddr)
  1355. {
  1356.     /* is record long enough for header? */
  1357.     if ( dbentry->len < DB_SMIME_ENTRY_HEADER_LEN ) {
  1358. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1359. goto loser;
  1360.     }
  1361.     
  1362.     /* is database entry correct length? */
  1363.     entry->subjectName.len = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
  1364.     entry->smimeOptions.len = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
  1365.     entry->optionsDate.len = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] );
  1366.     if (( entry->subjectName.len + entry->smimeOptions.len +
  1367.  entry->optionsDate.len + DB_SMIME_ENTRY_HEADER_LEN ) != dbentry->len){
  1368. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1369. goto loser;
  1370.     }
  1371.     
  1372.     /* copy the subject name */
  1373.     entry->subjectName.data =
  1374. (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1375.  entry->subjectName.len);
  1376.     if ( entry->subjectName.data == NULL ) {
  1377. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1378. goto loser;
  1379.     }
  1380.     PORT_Memcpy(entry->subjectName.data,
  1381.       &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN],
  1382.       entry->subjectName.len);
  1383.     /* copy the smime options */
  1384.     if ( entry->smimeOptions.len ) {
  1385. entry->smimeOptions.data =
  1386.     (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1387.      entry->smimeOptions.len);
  1388. if ( entry->smimeOptions.data == NULL ) {
  1389.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1390.     goto loser;
  1391. }
  1392. PORT_Memcpy(entry->smimeOptions.data,
  1393.     &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
  1394.    entry->subjectName.len],
  1395.     entry->smimeOptions.len);
  1396.     }
  1397.     if ( entry->optionsDate.len ) {
  1398. entry->optionsDate.data =
  1399.     (unsigned char *)PORT_ArenaAlloc(entry->common.arena,
  1400.      entry->optionsDate.len);
  1401. if ( entry->optionsDate.data == NULL ) {
  1402.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1403.     goto loser;
  1404. }
  1405. PORT_Memcpy(entry->optionsDate.data,
  1406.     &dbentry->data[DB_SMIME_ENTRY_HEADER_LEN +
  1407.    entry->subjectName.len +
  1408.    entry->smimeOptions.len],
  1409.     entry->optionsDate.len);
  1410.     }
  1411.     /* both options and options date must either exist or not exist */
  1412.     if ( ( ( entry->optionsDate.len == 0 ) ||
  1413.   ( entry->smimeOptions.len == 0 ) ) &&
  1414. entry->smimeOptions.len != entry->optionsDate.len ) {
  1415. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1416. goto loser;
  1417.     }
  1418.     entry->emailAddr = (char *)PORT_Alloc(PORT_Strlen(emailAddr)+1);
  1419.     if ( entry->emailAddr ) {
  1420. PORT_Strcpy(entry->emailAddr, emailAddr);
  1421.     }
  1422.     
  1423.     return(SECSuccess);
  1424. loser:
  1425.     return(SECFailure);
  1426. }
  1427. /*
  1428.  * create a new SMIME entry
  1429.  */
  1430. static certDBEntrySMime *
  1431. NewDBSMimeEntry(char *emailAddr, SECItem *subjectName, SECItem *smimeOptions,
  1432. SECItem *optionsDate, unsigned int flags)
  1433. {
  1434.     PRArenaPool *arena = NULL;
  1435.     certDBEntrySMime *entry;
  1436.     int addrlen;
  1437.     SECStatus rv;
  1438.     
  1439.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1440.     if ( arena == NULL ) {
  1441. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1442. goto loser;
  1443.     }
  1444.     entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
  1445. sizeof(certDBEntrySMime));
  1446.     if ( entry == NULL ) {
  1447. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1448. goto loser;
  1449.     }
  1450.     /* init common fields */
  1451.     entry->common.arena = arena;
  1452.     entry->common.type = certDBEntryTypeSMimeProfile;
  1453.     entry->common.version = CERT_DB_FILE_VERSION;
  1454.     entry->common.flags = flags;
  1455.     /* copy the email addr */
  1456.     addrlen = PORT_Strlen(emailAddr) + 1;
  1457.     
  1458.     entry->emailAddr = (char*)PORT_ArenaAlloc(arena, addrlen);
  1459.     if ( entry->emailAddr == NULL ) {
  1460. goto loser;
  1461.     }
  1462.     
  1463.     PORT_Memcpy(entry->emailAddr, emailAddr, addrlen);
  1464.     
  1465.     /* copy the subject name */
  1466.     rv = SECITEM_CopyItem(arena, &entry->subjectName, subjectName);
  1467.     if ( rv != SECSuccess ) {
  1468. goto loser;
  1469.     }
  1470.     /* copy the smime options */
  1471.     if ( smimeOptions ) {
  1472. rv = SECITEM_CopyItem(arena, &entry->smimeOptions, smimeOptions);
  1473. if ( rv != SECSuccess ) {
  1474.     goto loser;
  1475. }
  1476.     } else {
  1477. PORT_Assert(optionsDate == NULL);
  1478. entry->smimeOptions.data = NULL;
  1479. entry->smimeOptions.len = 0;
  1480.     }
  1481.     /* copy the options date */
  1482.     if ( optionsDate ) {
  1483. rv = SECITEM_CopyItem(arena, &entry->optionsDate, optionsDate);
  1484. if ( rv != SECSuccess ) {
  1485.     goto loser;
  1486. }
  1487.     } else {
  1488. PORT_Assert(smimeOptions == NULL);
  1489. entry->optionsDate.data = NULL;
  1490. entry->optionsDate.len = 0;
  1491.     }
  1492.     
  1493.     return(entry);
  1494. loser:
  1495.     if ( arena ) {
  1496. PORT_FreeArena(arena, PR_FALSE);
  1497.     }
  1498.     
  1499.     return(NULL);
  1500. }
  1501. /*
  1502.  * delete a SMIME entry
  1503.  */
  1504. static SECStatus
  1505. DeleteDBSMimeEntry(CERTCertDBHandle *handle, char *emailAddr)
  1506. {
  1507.     PRArenaPool *arena = NULL;
  1508.     SECStatus rv;
  1509.     SECItem dbkey;
  1510.     
  1511.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1512.     if ( arena == NULL ) {
  1513. goto loser;
  1514.     }
  1515.     rv = EncodeDBSMimeKey(emailAddr, arena, &dbkey);
  1516.     if ( rv != SECSuccess ) {
  1517. goto loser;
  1518.     }
  1519.     rv = DeleteDBEntry(handle, certDBEntryTypeSMimeProfile, &dbkey);
  1520.     if ( rv == SECFailure ) {
  1521. goto loser;
  1522.     }
  1523.     PORT_FreeArena(arena, PR_FALSE);
  1524.     return(SECSuccess);
  1525. loser:
  1526.     if ( arena ) {
  1527. PORT_FreeArena(arena, PR_FALSE);
  1528.     }
  1529.     
  1530.     return(SECFailure);
  1531. }
  1532. /*
  1533.  * Read a SMIME entry
  1534.  */
  1535. static certDBEntrySMime *
  1536. ReadDBSMimeEntry(CERTCertDBHandle *handle, char *emailAddr)
  1537. {
  1538.     PRArenaPool *arena = NULL;
  1539.     PRArenaPool *tmparena = NULL;
  1540.     certDBEntrySMime *entry;
  1541.     SECItem dbkey;
  1542.     SECItem dbentry;
  1543.     SECStatus rv;
  1544.     
  1545.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1546.     if ( arena == NULL ) {
  1547. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1548. goto loser;
  1549.     }
  1550.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1551.     if ( tmparena == NULL ) {
  1552. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1553. goto loser;
  1554.     }
  1555.     
  1556.     entry = (certDBEntrySMime *)PORT_ArenaAlloc(arena,
  1557. sizeof(certDBEntrySMime));
  1558.     if ( entry == NULL ) {
  1559. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1560. goto loser;
  1561.     }
  1562.     entry->common.arena = arena;
  1563.     entry->common.type = certDBEntryTypeSMimeProfile;
  1564.     rv = EncodeDBSMimeKey(emailAddr, tmparena, &dbkey);
  1565.     if ( rv != SECSuccess ) {
  1566. goto loser;
  1567.     }
  1568.     
  1569.     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  1570.     if ( rv == SECFailure ) {
  1571. goto loser;
  1572.     }
  1573.     /* is record long enough for header? */
  1574.     if ( dbentry.len < DB_SMIME_ENTRY_HEADER_LEN ) {
  1575. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1576. goto loser;
  1577.     }
  1578.     rv = DecodeDBSMimeEntry(entry, &dbentry, emailAddr);
  1579.     if ( rv != SECSuccess ) {
  1580. goto loser;
  1581.     }
  1582.     
  1583.     PORT_FreeArena(tmparena, PR_FALSE);
  1584.     return(entry);
  1585.     
  1586. loser:
  1587.     if ( tmparena ) {
  1588. PORT_FreeArena(tmparena, PR_FALSE);
  1589.     }
  1590.     if ( arena ) {
  1591. PORT_FreeArena(arena, PR_FALSE);
  1592.     }
  1593.     
  1594.     return(NULL);
  1595. }
  1596. /*
  1597.  * Encode a SMIME entry into byte stream suitable for
  1598.  * the database
  1599.  */
  1600. static SECStatus
  1601. WriteDBSMimeEntry(CERTCertDBHandle *handle, certDBEntrySMime *entry)
  1602. {
  1603.     SECItem dbitem, dbkey;
  1604.     PRArenaPool *tmparena = NULL;
  1605.     SECStatus rv;
  1606.     
  1607.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1608.     if ( tmparena == NULL ) {
  1609. goto loser;
  1610.     }
  1611.     
  1612.     rv = EncodeDBSMimeEntry(entry, tmparena, &dbitem);
  1613.     if ( rv != SECSuccess ) {
  1614. goto loser;
  1615.     }
  1616.     rv = EncodeDBSMimeKey(entry->emailAddr, tmparena, &dbkey);
  1617.     if ( rv != SECSuccess ) {
  1618. goto loser;
  1619.     }
  1620.     /* now write it to the database */
  1621.     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  1622.     if ( rv != SECSuccess ) {
  1623. goto loser;
  1624.     }
  1625.     
  1626.     PORT_FreeArena(tmparena, PR_FALSE);
  1627.     return(SECSuccess);
  1628. loser:
  1629.     if ( tmparena ) {
  1630. PORT_FreeArena(tmparena, PR_FALSE);
  1631.     }
  1632.     return(SECFailure);
  1633.     
  1634. }
  1635. /*
  1636.  * Encode a database subject record
  1637.  */
  1638. static SECStatus
  1639. EncodeDBSubjectEntry(certDBEntrySubject *entry, PRArenaPool *arena,
  1640.      SECItem *dbitem)
  1641. {
  1642.     unsigned char *buf;
  1643.     int len;
  1644.     unsigned int ncerts;
  1645.     unsigned int i;
  1646.     unsigned char *tmpbuf;
  1647.     unsigned int nnlen = 0;
  1648.     unsigned int eaddrlen = 0;
  1649.     int keyidoff;
  1650.     SECItem *certKeys;
  1651.     SECItem *keyIDs;
  1652.     
  1653.     if ( entry->nickname ) {
  1654. nnlen = PORT_Strlen(entry->nickname) + 1;
  1655.     }
  1656.     if ( entry->emailAddr ) {
  1657. eaddrlen = PORT_Strlen(entry->emailAddr) + 1;
  1658.     }
  1659.     
  1660.     ncerts = entry->ncerts;
  1661.     
  1662.     /* compute the length of the entry */
  1663.     keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen;
  1664.     len = keyidoff + 4 * ncerts;
  1665.     for ( i = 0; i < ncerts; i++ ) {
  1666. len += entry->certKeys[i].len;
  1667. len += entry->keyIDs[i].len;
  1668.     }
  1669.     
  1670.     /* allocate space for encoded database record, including space
  1671.      * for low level header
  1672.      */
  1673.     dbitem->len = len + SEC_DB_ENTRY_HEADER_LEN;
  1674.     
  1675.     dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len);
  1676.     if ( dbitem->data == NULL) {
  1677. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1678. goto loser;
  1679.     }
  1680.     
  1681.     /* fill in database record */
  1682.     buf = &dbitem->data[SEC_DB_ENTRY_HEADER_LEN];
  1683.     
  1684.     buf[0] = ( ncerts >> 8 ) & 0xff;
  1685.     buf[1] = ncerts & 0xff;
  1686.     buf[2] = ( nnlen >> 8 ) & 0xff;
  1687.     buf[3] = nnlen & 0xff;
  1688.     buf[4] = ( eaddrlen >> 8 ) & 0xff;
  1689.     buf[5] = eaddrlen & 0xff;
  1690.     PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN], entry->nickname, nnlen);
  1691.     PORT_Memcpy(&buf[DB_SUBJECT_ENTRY_HEADER_LEN+nnlen], entry->emailAddr,
  1692. eaddrlen);
  1693.     
  1694.     for ( i = 0; i < ncerts; i++ ) {
  1695. certKeys = entry->certKeys;
  1696. keyIDs = entry->keyIDs;
  1697. buf[keyidoff+i*2] = ( certKeys[i].len >> 8 ) & 0xff;
  1698. buf[keyidoff+1+i*2] = certKeys[i].len & 0xff;
  1699. buf[keyidoff+ncerts*2+i*2] = ( keyIDs[i].len >> 8 ) & 0xff;
  1700. buf[keyidoff+1+ncerts*2+i*2] = keyIDs[i].len & 0xff;
  1701.     }
  1702.     
  1703.     /* temp pointer used to stuff certkeys and keyids into the buffer */
  1704.     tmpbuf = &buf[keyidoff+ncerts*4];
  1705.     for ( i = 0; i < ncerts; i++ ) {
  1706. certKeys = entry->certKeys;
  1707. PORT_Memcpy(tmpbuf, certKeys[i].data, certKeys[i].len);
  1708. tmpbuf = tmpbuf + certKeys[i].len;
  1709.     }
  1710.     
  1711.     for ( i = 0; i < ncerts; i++ ) {
  1712. keyIDs = entry->keyIDs;
  1713. PORT_Memcpy(tmpbuf, keyIDs[i].data, keyIDs[i].len);
  1714. tmpbuf = tmpbuf + keyIDs[i].len;
  1715.     }
  1716.     PORT_Assert(tmpbuf == &buf[len]);
  1717.     
  1718.     return(SECSuccess);
  1719. loser:
  1720.     return(SECFailure);
  1721. }
  1722. /*
  1723.  * Encode a database key for a subject record
  1724.  */
  1725. static SECStatus
  1726. EncodeDBSubjectKey(SECItem *derSubject, PRArenaPool *arena,
  1727.    SECItem *dbkey)
  1728. {
  1729.     dbkey->len = derSubject->len + SEC_DB_KEY_HEADER_LEN;
  1730.     dbkey->data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey->len);
  1731.     if ( dbkey->data == NULL ) {
  1732. goto loser;
  1733.     }
  1734.     PORT_Memcpy(&dbkey->data[SEC_DB_KEY_HEADER_LEN], derSubject->data,
  1735.       derSubject->len);
  1736.     dbkey->data[0] = certDBEntryTypeSubject;
  1737.     return(SECSuccess);
  1738. loser:
  1739.     return(SECFailure);
  1740. }
  1741. static SECStatus
  1742. DecodeDBSubjectEntry(certDBEntrySubject *entry, SECItem *dbentry,
  1743.      SECItem *derSubject)
  1744. {
  1745.     unsigned int ncerts;
  1746.     PRArenaPool *arena;
  1747.     unsigned int len, itemlen;
  1748.     unsigned char *tmpbuf;
  1749.     unsigned int i;
  1750.     SECStatus rv;
  1751.     unsigned int keyidoff;
  1752.     unsigned int nnlen, eaddrlen;
  1753.     
  1754.     arena = entry->common.arena;
  1755.     rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
  1756.     if ( rv != SECSuccess ) {
  1757. goto loser;
  1758.     }
  1759.     /* is record long enough for header? */
  1760.     if ( dbentry->len < DB_SUBJECT_ENTRY_HEADER_LEN ) {
  1761. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1762. goto loser;
  1763.     }
  1764.     
  1765.     entry->ncerts = ncerts = ( ( dbentry->data[0] << 8 ) | dbentry->data[1] );
  1766.     nnlen = ( ( dbentry->data[2] << 8 ) | dbentry->data[3] );
  1767.     eaddrlen = ( ( dbentry->data[4] << 8 ) | dbentry->data[5] );
  1768.     if ( dbentry->len < ( ncerts * 4 + DB_SUBJECT_ENTRY_HEADER_LEN +
  1769.  nnlen + eaddrlen) ) {
  1770. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1771. goto loser;
  1772.     }
  1773.     
  1774.     entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena,
  1775.  sizeof(SECItem) * ncerts);
  1776.     entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena,
  1777.        sizeof(SECItem) * ncerts);
  1778.     if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
  1779. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1780. goto loser;
  1781.     }
  1782.     if ( nnlen > 1 ) { /* null terminator is stored */
  1783. entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
  1784. if ( entry->nickname == NULL ) {
  1785.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1786.     goto loser;
  1787. }
  1788. PORT_Memcpy(entry->nickname,
  1789.     &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN],
  1790.     nnlen);
  1791.     } else {
  1792. entry->nickname = NULL;
  1793.     }
  1794.     
  1795.     if ( eaddrlen > 1 ) { /* null terminator is stored */
  1796. entry->emailAddr = (char *)PORT_ArenaAlloc(arena, eaddrlen);
  1797. if ( entry->emailAddr == NULL ) {
  1798.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1799.     goto loser;
  1800. }
  1801. PORT_Memcpy(entry->emailAddr,
  1802.     &dbentry->data[DB_SUBJECT_ENTRY_HEADER_LEN+nnlen],
  1803.     eaddrlen);
  1804.     } else {
  1805. entry->emailAddr = NULL;
  1806.     }
  1807.     
  1808.     /* collect the lengths of the certKeys and keyIDs, and total the
  1809.      * overall length.
  1810.      */
  1811.     keyidoff = DB_SUBJECT_ENTRY_HEADER_LEN + nnlen + eaddrlen;
  1812.     len = keyidoff + 4 * ncerts;
  1813.     tmpbuf = &dbentry->data[0];
  1814.     
  1815.     for ( i = 0; i < ncerts; i++ ) {
  1816. itemlen = ( tmpbuf[keyidoff + 2*i] << 8 ) | tmpbuf[keyidoff + 1 + 2*i] ;
  1817. len += itemlen;
  1818. entry->certKeys[i].len = itemlen;
  1819. itemlen = ( tmpbuf[keyidoff + 2*ncerts + 2*i] << 8 ) |
  1820.     tmpbuf[keyidoff + 1 + 2*ncerts + 2*i] ;
  1821. len += itemlen;
  1822. entry->keyIDs[i].len = itemlen;
  1823.     }
  1824.     
  1825.     /* is database entry correct length? */
  1826.     if ( len != dbentry->len ){
  1827. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1828. goto loser;
  1829.     }
  1830.     
  1831.     tmpbuf = &tmpbuf[keyidoff + 4*ncerts];
  1832.     for ( i = 0; i < ncerts; i++ ) {
  1833. entry->certKeys[i].data =
  1834.     (unsigned char *)PORT_ArenaAlloc(arena, entry->certKeys[i].len);
  1835. if ( entry->certKeys[i].data == NULL ) {
  1836.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1837.     goto loser;
  1838. }
  1839. PORT_Memcpy(entry->certKeys[i].data, tmpbuf, entry->certKeys[i].len);
  1840. tmpbuf = &tmpbuf[entry->certKeys[i].len];
  1841.     }
  1842.     for ( i = 0; i < ncerts; i++ ) {
  1843. entry->keyIDs[i].data =
  1844.     (unsigned char *)PORT_ArenaAlloc(arena, entry->keyIDs[i].len);
  1845. if ( entry->keyIDs[i].data == NULL ) {
  1846.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1847.     goto loser;
  1848. }
  1849. PORT_Memcpy(entry->keyIDs[i].data, tmpbuf, entry->keyIDs[i].len);
  1850. tmpbuf = &tmpbuf[entry->keyIDs[i].len];
  1851.     }
  1852.     
  1853.     PORT_Assert(tmpbuf == &dbentry->data[dbentry->len]);
  1854.     
  1855.     return(SECSuccess);
  1856. loser:
  1857.     return(SECFailure);
  1858. }
  1859. /*
  1860.  * create a new subject entry with a single cert
  1861.  */
  1862. static certDBEntrySubject *
  1863. NewDBSubjectEntry(SECItem *derSubject, SECItem *certKey,
  1864.   SECItem *keyID, char *nickname, char *emailAddr,
  1865.   unsigned int flags)
  1866. {
  1867.     PRArenaPool *arena = NULL;
  1868.     certDBEntrySubject *entry;
  1869.     SECStatus rv;
  1870.     unsigned int nnlen;
  1871.     unsigned int eaddrlen;
  1872.     
  1873.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1874.     if ( arena == NULL ) {
  1875. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1876. goto loser;
  1877.     }
  1878.     entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
  1879.   sizeof(certDBEntrySubject));
  1880.     if ( entry == NULL ) {
  1881. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1882. goto loser;
  1883.     }
  1884.     /* init common fields */
  1885.     entry->common.arena = arena;
  1886.     entry->common.type = certDBEntryTypeSubject;
  1887.     entry->common.version = CERT_DB_FILE_VERSION;
  1888.     entry->common.flags = flags;
  1889.     /* copy the subject */
  1890.     rv = SECITEM_CopyItem(arena, &entry->derSubject, derSubject);
  1891.     if ( rv != SECSuccess ) {
  1892. goto loser;
  1893.     }
  1894.     
  1895.     entry->ncerts = 1;
  1896.     /* copy nickname */
  1897.     if ( nickname && ( *nickname != '' ) ) {
  1898. nnlen = PORT_Strlen(nickname) + 1;
  1899. entry->nickname = (char *)PORT_ArenaAlloc(arena, nnlen);
  1900. if ( entry->nickname == NULL ) {
  1901.     goto loser;
  1902. }
  1903.   
  1904. PORT_Memcpy(entry->nickname, nickname, nnlen);
  1905.     } else {
  1906. entry->nickname = NULL;
  1907.     }
  1908.     
  1909.     /* copy email addr */
  1910.     if ( emailAddr && ( *emailAddr != '' ) ) {
  1911. emailAddr = CERT_FixupEmailAddr(emailAddr);
  1912. if ( emailAddr == NULL ) {
  1913.     entry->emailAddr = NULL;
  1914.     goto loser;
  1915. }
  1916. eaddrlen = PORT_Strlen(emailAddr) + 1;
  1917. entry->emailAddr = (char *)PORT_ArenaAlloc(arena, eaddrlen);
  1918. if ( entry->emailAddr == NULL ) {
  1919.     PORT_Free(emailAddr);
  1920.     goto loser;
  1921. }
  1922. PORT_Memcpy(entry->emailAddr, emailAddr, eaddrlen);
  1923. PORT_Free(emailAddr);
  1924.     } else {
  1925. entry->emailAddr = NULL;
  1926.     }
  1927.     
  1928.     /* allocate space for certKeys and keyIDs */
  1929.     entry->certKeys = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
  1930.     entry->keyIDs = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
  1931.     if ( ( entry->certKeys == NULL ) || ( entry->keyIDs == NULL ) ) {
  1932. goto loser;
  1933.     }
  1934.     /* copy the certKey and keyID */
  1935.     rv = SECITEM_CopyItem(arena, &entry->certKeys[0], certKey);
  1936.     if ( rv != SECSuccess ) {
  1937. goto loser;
  1938.     }
  1939.     rv = SECITEM_CopyItem(arena, &entry->keyIDs[0], keyID);
  1940.     if ( rv != SECSuccess ) {
  1941. goto loser;
  1942.     }
  1943.     
  1944.     return(entry);
  1945. loser:
  1946.     if ( arena ) {
  1947. PORT_FreeArena(arena, PR_FALSE);
  1948.     }
  1949.     
  1950.     return(NULL);
  1951. }
  1952. /*
  1953.  * delete a subject entry
  1954.  */
  1955. static SECStatus
  1956. DeleteDBSubjectEntry(CERTCertDBHandle *handle, SECItem *derSubject)
  1957. {
  1958.     SECItem dbkey;
  1959.     PRArenaPool *arena = NULL;
  1960.     SECStatus rv;
  1961.     
  1962.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1963.     if ( arena == NULL ) {
  1964. goto loser;
  1965.     }
  1966.     
  1967.     rv = EncodeDBSubjectKey(derSubject, arena, &dbkey);
  1968.     if ( rv != SECSuccess ) {
  1969. goto loser;
  1970.     }
  1971.     
  1972.     rv = DeleteDBEntry(handle, certDBEntryTypeSubject, &dbkey);
  1973.     if ( rv == SECFailure ) {
  1974. goto loser;
  1975.     }
  1976.     PORT_FreeArena(arena, PR_FALSE);
  1977.     return(SECSuccess);
  1978. loser:
  1979.     if ( arena ) {
  1980. PORT_FreeArena(arena, PR_FALSE);
  1981.     }
  1982.     
  1983.     return(SECFailure);
  1984. }
  1985. /*
  1986.  * Read the subject entry
  1987.  */
  1988. static certDBEntrySubject *
  1989. ReadDBSubjectEntry(CERTCertDBHandle *handle, SECItem *derSubject)
  1990. {
  1991.     PRArenaPool *arena = NULL;
  1992.     PRArenaPool *tmparena = NULL;
  1993.     certDBEntrySubject *entry;
  1994.     SECItem dbkey;
  1995.     SECItem dbentry;
  1996.     SECStatus rv;
  1997.     
  1998.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1999.     if ( arena == NULL ) {
  2000. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2001. goto loser;
  2002.     }
  2003.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2004.     if ( tmparena == NULL ) {
  2005. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2006. goto loser;
  2007.     }
  2008.     
  2009.     entry = (certDBEntrySubject *)PORT_ArenaAlloc(arena,
  2010. sizeof(certDBEntrySubject));
  2011.     if ( entry == NULL ) {
  2012. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2013. goto loser;
  2014.     }
  2015.     entry->common.arena = arena;
  2016.     entry->common.type = certDBEntryTypeSubject;
  2017.     rv = EncodeDBSubjectKey(derSubject, tmparena, &dbkey);
  2018.     if ( rv != SECSuccess ) {
  2019. goto loser;
  2020.     }
  2021.     
  2022.     rv = ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  2023.     if ( rv == SECFailure ) {
  2024. goto loser;
  2025.     }
  2026.     rv = DecodeDBSubjectEntry(entry, &dbentry, derSubject);
  2027.     if ( rv == SECFailure ) {
  2028. goto loser;
  2029.     }
  2030.     
  2031.     PORT_FreeArena(tmparena, PR_FALSE);
  2032.     return(entry);
  2033.     
  2034. loser:
  2035.     if ( tmparena ) {
  2036. PORT_FreeArena(tmparena, PR_FALSE);
  2037.     }
  2038.     if ( arena ) {
  2039. PORT_FreeArena(arena, PR_FALSE);
  2040.     }
  2041.     
  2042.     return(NULL);
  2043. }
  2044. /*
  2045.  * Encode a subject name entry into byte stream suitable for
  2046.  * the database
  2047.  */
  2048. static SECStatus
  2049. WriteDBSubjectEntry(CERTCertDBHandle *handle, certDBEntrySubject *entry)
  2050. {
  2051.     SECItem dbitem, dbkey;
  2052.     PRArenaPool *tmparena = NULL;
  2053.     SECStatus rv;
  2054.     
  2055.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2056.     if ( tmparena == NULL ) {
  2057. goto loser;
  2058.     }
  2059.     
  2060.     rv = EncodeDBSubjectEntry(entry, tmparena, &dbitem);
  2061.     if ( rv != SECSuccess ) {
  2062. goto loser;
  2063.     }
  2064.     
  2065.     rv = EncodeDBSubjectKey(&entry->derSubject, tmparena, &dbkey);
  2066.     if ( rv != SECSuccess ) {
  2067. goto loser;
  2068.     }
  2069.     /* now write it to the database */
  2070.     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  2071.     if ( rv != SECSuccess ) {
  2072. goto loser;
  2073.     }
  2074.     
  2075.     PORT_FreeArena(tmparena, PR_FALSE);
  2076.     return(SECSuccess);
  2077. loser:
  2078.     if ( tmparena ) {
  2079. PORT_FreeArena(tmparena, PR_FALSE);
  2080.     }
  2081.     return(SECFailure);
  2082.     
  2083. }
  2084. static SECStatus
  2085. UpdateSubjectWithEmailAddr(CERTCertificate *cert, char *emailAddr)
  2086. {
  2087.     CERTSubjectList *subjectList;
  2088.     PRBool save = PR_FALSE, delold = PR_FALSE;
  2089.     certDBEntrySubject *entry;
  2090.     SECStatus rv;
  2091.     
  2092.     emailAddr = CERT_FixupEmailAddr(emailAddr);
  2093.     if ( emailAddr == NULL ) {
  2094. return(SECFailure);
  2095.     }
  2096.     
  2097.     subjectList = cert->subjectList;
  2098.     PORT_Assert(subjectList != NULL);
  2099.     
  2100.     if ( subjectList->emailAddr ) {
  2101. if ( PORT_Strcmp(subjectList->emailAddr, emailAddr) != 0 ) {
  2102.     save = PR_TRUE;
  2103.     delold = PR_TRUE;
  2104. }
  2105.     } else {
  2106. save = PR_TRUE;
  2107.     }
  2108.     if ( delold ) {
  2109. /* delete the old smime entry, because this cert now has a new
  2110.  * smime entry pointing to it
  2111.  */
  2112. PORT_Assert(save);
  2113. PORT_Assert(subjectList->emailAddr != NULL);
  2114. DeleteDBSMimeEntry(cert->dbhandle, subjectList->emailAddr);
  2115.     }
  2116.     if ( save ) {
  2117. unsigned int len;
  2118. entry = subjectList->entry;
  2119. PORT_Assert(entry != NULL);
  2120. len = PORT_Strlen(emailAddr) + 1;
  2121. entry->emailAddr = (char *)PORT_ArenaAlloc(entry->common.arena, len);
  2122. if ( entry->emailAddr == NULL ) {
  2123.     goto loser;
  2124. }
  2125. PORT_Memcpy(entry->emailAddr, emailAddr, len);
  2126. /* delete the subject entry */
  2127. DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
  2128. /* write the new one */
  2129. rv = WriteDBSubjectEntry(cert->dbhandle, entry);
  2130. if ( rv != SECSuccess ) {
  2131.     goto loser;
  2132. }
  2133.     }
  2134.     PORT_Free(emailAddr);
  2135.     return(SECSuccess);
  2136. loser:
  2137.     PORT_Free(emailAddr);
  2138.     return(SECFailure);
  2139. }
  2140. /*
  2141.  * writes a nickname to an existing subject entry that does not currently
  2142.  * have one
  2143.  */
  2144. static SECStatus
  2145. AddNicknameToSubject(CERTCertificate *cert, char *nickname)
  2146. {
  2147.     CERTSubjectList *subjectList;
  2148.     certDBEntrySubject *entry;
  2149.     SECStatus rv;
  2150.     
  2151.     if ( nickname == NULL ) {
  2152. return(SECFailure);
  2153.     }
  2154.     
  2155.     subjectList = cert->subjectList;
  2156.     PORT_Assert(subjectList != NULL);
  2157.     if ( subjectList == NULL ) {
  2158. goto loser;
  2159.     }
  2160.     
  2161.     entry = subjectList->entry;
  2162.     PORT_Assert(entry != NULL);
  2163.     if ( entry == NULL ) {
  2164. goto loser;
  2165.     }
  2166.     
  2167.     PORT_Assert(entry->nickname == NULL);
  2168.     if ( entry->nickname != NULL ) {
  2169. goto loser;
  2170.     }
  2171.     
  2172.     entry->nickname = (nickname) ? PORT_ArenaStrdup(entry->common.arena, nickname) : NULL;
  2173.     
  2174.     if ( entry->nickname == NULL ) {
  2175. goto loser;
  2176.     }
  2177.     /* delete the subject entry */
  2178.     DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
  2179.     /* write the new one */
  2180.     rv = WriteDBSubjectEntry(cert->dbhandle, entry);
  2181.     if ( rv != SECSuccess ) {
  2182. goto loser;
  2183.     }
  2184.     return(SECSuccess);
  2185. loser:
  2186.     return(SECFailure);
  2187. }
  2188. /*
  2189.  * create a new version entry
  2190.  */
  2191. static certDBEntryVersion *
  2192. NewDBVersionEntry(unsigned int flags)
  2193. {
  2194.     PRArenaPool *arena = NULL;
  2195.     certDBEntryVersion *entry;
  2196.     
  2197.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2198.     if ( arena == NULL ) {
  2199. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2200. goto loser;
  2201.     }
  2202.     entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena,
  2203.        sizeof(certDBEntryVersion));
  2204.     if ( entry == NULL ) {
  2205. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2206. goto loser;
  2207.     }
  2208.     entry->common.arena = arena;
  2209.     entry->common.type = certDBEntryTypeVersion;
  2210.     entry->common.version = CERT_DB_FILE_VERSION;
  2211.     entry->common.flags = flags;
  2212.     return(entry);
  2213. loser:
  2214.     if ( arena ) {
  2215. PORT_FreeArena(arena, PR_FALSE);
  2216.     }
  2217.     
  2218.     return(NULL);
  2219. }
  2220. /*
  2221.  * Read the version entry
  2222.  */
  2223. static certDBEntryVersion *
  2224. ReadDBVersionEntry(CERTCertDBHandle *handle)
  2225. {
  2226.     PRArenaPool *arena = NULL;
  2227.     PRArenaPool *tmparena = NULL;
  2228.     certDBEntryVersion *entry;
  2229.     SECItem dbkey;
  2230.     SECItem dbentry;
  2231.     
  2232.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2233.     if ( arena == NULL ) {
  2234. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2235. goto loser;
  2236.     }
  2237.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2238.     if ( tmparena == NULL ) {
  2239. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2240. goto loser;
  2241.     }
  2242.     
  2243.     entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena,
  2244. sizeof(certDBEntryVersion));
  2245.     if ( entry == NULL ) {
  2246. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2247. goto loser;
  2248.     }
  2249.     entry->common.arena = arena;
  2250.     entry->common.type = certDBEntryTypeVersion;
  2251.     /* now get the database key and format it */
  2252.     dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
  2253.     dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
  2254.     if ( dbkey.data == NULL ) {
  2255. goto loser;
  2256.     }
  2257.     PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
  2258.       SEC_DB_VERSION_KEY_LEN);
  2259.     ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  2260.     PORT_FreeArena(tmparena, PR_FALSE);
  2261.     return(entry);
  2262.     
  2263. loser:
  2264.     if ( tmparena ) {
  2265. PORT_FreeArena(tmparena, PR_FALSE);
  2266.     }
  2267.     if ( arena ) {
  2268. PORT_FreeArena(arena, PR_FALSE);
  2269.     }
  2270.     
  2271.     return(NULL);
  2272. }
  2273. /*
  2274.  * Encode a version entry into byte stream suitable for
  2275.  * the database
  2276.  */
  2277. static SECStatus
  2278. WriteDBVersionEntry(CERTCertDBHandle *handle, certDBEntryVersion *entry)
  2279. {
  2280.     SECItem dbitem, dbkey;
  2281.     PRArenaPool *tmparena = NULL;
  2282.     SECStatus rv;
  2283.     
  2284.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2285.     if ( tmparena == NULL ) {
  2286. goto loser;
  2287.     }
  2288.     
  2289.     /* allocate space for encoded database record, including space
  2290.      * for low level header
  2291.      */
  2292.     dbitem.len = SEC_DB_ENTRY_HEADER_LEN;
  2293.     
  2294.     dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len);
  2295.     if ( dbitem.data == NULL) {
  2296. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2297. goto loser;
  2298.     }
  2299.     
  2300.     /* now get the database key and format it */
  2301.     dbkey.len = SEC_DB_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
  2302.     dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
  2303.     if ( dbkey.data == NULL ) {
  2304. goto loser;
  2305.     }
  2306.     PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_VERSION_KEY,
  2307.       SEC_DB_VERSION_KEY_LEN);
  2308.     /* now write it to the database */
  2309.     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  2310.     if ( rv != SECSuccess ) {
  2311. goto loser;
  2312.     }
  2313.     
  2314.     PORT_FreeArena(tmparena, PR_FALSE);
  2315.     return(SECSuccess);
  2316. loser:
  2317.     if ( tmparena ) {
  2318. PORT_FreeArena(tmparena, PR_FALSE);
  2319.     }
  2320.     return(SECFailure);
  2321. }
  2322. /*
  2323.  * create a new version entry
  2324.  */
  2325. static certDBEntryContentVersion *
  2326. NewDBContentVersionEntry(unsigned int flags)
  2327. {
  2328.     PRArenaPool *arena = NULL;
  2329.     certDBEntryContentVersion *entry;
  2330.     
  2331.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2332.     if ( arena == NULL ) {
  2333. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2334. goto loser;
  2335.     }
  2336.     entry = (certDBEntryContentVersion *)
  2337. PORT_ArenaAlloc(arena, sizeof(certDBEntryContentVersion));
  2338.     if ( entry == NULL ) {
  2339. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2340. goto loser;
  2341.     }
  2342.     entry->common.arena = arena;
  2343.     entry->common.type = certDBEntryTypeContentVersion;
  2344.     entry->common.version = CERT_DB_FILE_VERSION;
  2345.     entry->common.flags = flags;
  2346.     entry->contentVersion = CERT_DB_CONTENT_VERSION;
  2347.     
  2348.     return(entry);
  2349. loser:
  2350.     if ( arena ) {
  2351. PORT_FreeArena(arena, PR_FALSE);
  2352.     }
  2353.     
  2354.     return(NULL);
  2355. }
  2356. /*
  2357.  * Read the version entry
  2358.  */
  2359. static certDBEntryContentVersion *
  2360. ReadDBContentVersionEntry(CERTCertDBHandle *handle)
  2361. {
  2362.     PRArenaPool *arena = NULL;
  2363.     PRArenaPool *tmparena = NULL;
  2364.     certDBEntryContentVersion *entry;
  2365.     SECItem dbkey;
  2366.     SECItem dbentry;
  2367.     
  2368.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2369.     if ( arena == NULL ) {
  2370. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2371. goto loser;
  2372.     }
  2373.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2374.     if ( tmparena == NULL ) {
  2375. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2376. goto loser;
  2377.     }
  2378.     
  2379.     entry = (certDBEntryContentVersion *)
  2380. PORT_ArenaAlloc(arena, sizeof(certDBEntryContentVersion));
  2381.     if ( entry == NULL ) {
  2382. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2383. goto loser;
  2384.     }
  2385.     entry->common.arena = arena;
  2386.     entry->common.type = certDBEntryTypeContentVersion;
  2387.     /* now get the database key and format it */
  2388.     dbkey.len = SEC_DB_CONTENT_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
  2389.     dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
  2390.     if ( dbkey.data == NULL ) {
  2391. goto loser;
  2392.     }
  2393.     PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_CONTENT_VERSION_KEY,
  2394. SEC_DB_CONTENT_VERSION_KEY_LEN);
  2395.     dbentry.len = 0;
  2396.     dbentry.data = NULL;
  2397.     
  2398.     ReadDBEntry(handle, &entry->common, &dbkey, &dbentry, tmparena);
  2399.     if ( dbentry.len != 1 ) {
  2400. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  2401. goto loser;
  2402.     }
  2403.     entry->contentVersion = dbentry.data[0];
  2404.     
  2405.     PORT_FreeArena(tmparena, PR_FALSE);
  2406.     return(entry);
  2407.     
  2408. loser:
  2409.     if ( tmparena ) {
  2410. PORT_FreeArena(tmparena, PR_FALSE);
  2411.     }
  2412.     if ( arena ) {
  2413. PORT_FreeArena(arena, PR_FALSE);
  2414.     }
  2415.     
  2416.     return(NULL);
  2417. }
  2418. /*
  2419.  * Encode a version entry into byte stream suitable for
  2420.  * the database
  2421.  */
  2422. static SECStatus
  2423. WriteDBContentVersionEntry(CERTCertDBHandle *handle,
  2424.    certDBEntryContentVersion *entry)
  2425. {
  2426.     SECItem dbitem, dbkey;
  2427.     PRArenaPool *tmparena = NULL;
  2428.     SECStatus rv;
  2429.     
  2430.     tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2431.     if ( tmparena == NULL ) {
  2432. goto loser;
  2433.     }
  2434.     
  2435.     /* allocate space for encoded database record, including space
  2436.      * for low level header
  2437.      */
  2438.     dbitem.len = SEC_DB_ENTRY_HEADER_LEN + 1;
  2439.     
  2440.     dbitem.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbitem.len);
  2441.     if ( dbitem.data == NULL) {
  2442. PORT_SetError(SEC_ERROR_NO_MEMORY);
  2443. goto loser;
  2444.     }
  2445.     
  2446.     dbitem.data[SEC_DB_ENTRY_HEADER_LEN] = entry->contentVersion;
  2447.     
  2448.     /* now get the database key and format it */
  2449.     dbkey.len = SEC_DB_CONTENT_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
  2450.     dbkey.data = (unsigned char *)PORT_ArenaAlloc(tmparena, dbkey.len);
  2451.     if ( dbkey.data == NULL ) {
  2452. goto loser;
  2453.     }
  2454.     PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_CONTENT_VERSION_KEY,
  2455. SEC_DB_CONTENT_VERSION_KEY_LEN);
  2456.     /* now write it to the database */
  2457.     rv = WriteDBEntry(handle, &entry->common, &dbkey, &dbitem);
  2458.     if ( rv != SECSuccess ) {
  2459. goto loser;
  2460.     }
  2461.     
  2462.     PORT_FreeArena(tmparena, PR_FALSE);
  2463.     return(SECSuccess);
  2464. loser:
  2465.     if ( tmparena ) {
  2466. PORT_FreeArena(tmparena, PR_FALSE);
  2467.     }
  2468.     return(SECFailure);
  2469. }
  2470. /*
  2471.  * delete a content version entry
  2472.  */
  2473. static SECStatus
  2474. DeleteDBContentVersionEntry(CERTCertDBHandle *handle)
  2475. {
  2476.     SECItem dbkey;
  2477.     PRArenaPool *arena = NULL;
  2478.     SECStatus rv;
  2479.     
  2480.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2481.     if ( arena == NULL ) {
  2482. goto loser;
  2483.     }
  2484.     /* now get the database key and format it */
  2485.     dbkey.len = SEC_DB_CONTENT_VERSION_KEY_LEN + SEC_DB_KEY_HEADER_LEN;
  2486.     dbkey.data = (unsigned char *)PORT_ArenaAlloc(arena, dbkey.len);
  2487.     if ( dbkey.data == NULL ) {
  2488. goto loser;
  2489.     }
  2490.     PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], SEC_DB_CONTENT_VERSION_KEY,
  2491. SEC_DB_CONTENT_VERSION_KEY_LEN);
  2492.     
  2493.     rv = DeleteDBEntry(handle, certDBEntryTypeContentVersion, &dbkey);
  2494.     if ( rv == SECFailure ) {
  2495. goto loser;
  2496.     }
  2497.     PORT_FreeArena(arena, PR_FALSE);
  2498.     return(SECSuccess);
  2499. loser:
  2500.     if ( arena ) {
  2501. PORT_FreeArena(arena, PR_FALSE);
  2502.     }
  2503.     
  2504.     return(SECFailure);
  2505. }
  2506. /*
  2507.  * Routines and datastructures to manage the list of certificates for a
  2508.  * particular subject name.
  2509.  */
  2510. /*
  2511.  * Create a new certificate subject list.  If entry exists, then populate
  2512.  * the list with the entries from the permanent database.
  2513.  */
  2514. static CERTSubjectList *
  2515. NewSubjectList(certDBEntrySubject *entry)
  2516. {
  2517.     PRArenaPool *permarena;
  2518.     unsigned int i;
  2519.     CERTSubjectList *subjectList;
  2520.     CERTSubjectNode *node;
  2521.     SECStatus rv;
  2522.     
  2523.     permarena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2524.     if ( permarena == NULL ) {
  2525. goto loser;
  2526.     }
  2527.     subjectList = (CERTSubjectList *)PORT_ArenaAlloc(permarena,
  2528.      sizeof(CERTSubjectList));
  2529.     if ( subjectList == NULL ) {
  2530. goto loser;
  2531.     }
  2532.     subjectList->arena = permarena;
  2533.     subjectList->ncerts = 0;
  2534.     subjectList->head = NULL;
  2535.     subjectList->tail = NULL;
  2536.     subjectList->entry = entry;
  2537.     subjectList->emailAddr = NULL;
  2538.     if ( entry ) {
  2539. /* initialize the list with certs from database entry */
  2540. for ( i = 0; i < entry->ncerts; i++ ) {
  2541.     /* Init the node */
  2542.     node = (CERTSubjectNode *)PORT_ArenaAlloc(permarena,
  2543.       sizeof(CERTSubjectNode));
  2544.     if ( node == NULL ) {
  2545. goto loser;
  2546.     }
  2547.     /* copy certKey and keyID to node */
  2548.     rv = SECITEM_CopyItem(permarena, &node->certKey,
  2549.   &entry->certKeys[i]);
  2550.     if ( rv != SECSuccess ) {
  2551. goto loser;
  2552.     }
  2553.     rv = SECITEM_CopyItem(permarena, &node->keyID,
  2554.   &entry->keyIDs[i]);
  2555.     if ( rv != SECSuccess ) {
  2556. goto loser;
  2557.     }
  2558.     /* the certs are already in order, so just add them
  2559.      * to the tail.
  2560.      */
  2561.     node->next = NULL;
  2562.     if ( subjectList->tail == NULL ) {
  2563. /* first in list */
  2564. subjectList->head = node;
  2565. subjectList->tail = node;
  2566. node->prev = NULL;
  2567.     } else {
  2568. /* add to end of list */
  2569. node->prev = subjectList->tail;
  2570. subjectList->tail = node;
  2571. node->prev->next = node;
  2572.     }
  2573.     subjectList->ncerts++;
  2574. }
  2575.     }
  2576.     
  2577.     return(subjectList);
  2578. loser:
  2579.     PORT_FreeArena(permarena, PR_FALSE);
  2580.     return(NULL);
  2581. }
  2582. /*
  2583.  * Find the Subject entry in the temp database.  It it is not in the
  2584.  * temp database, then get it from the perm DB.  It its not there either,
  2585.  * then create a new one.
  2586.  */
  2587. static CERTSubjectList *
  2588. FindSubjectList(CERTCertDBHandle *handle, SECItem *subject, PRBool create)
  2589. {
  2590.     PRArenaPool *arena = NULL;
  2591.     SECItem keyitem;
  2592.     SECStatus rv;
  2593.     DBT namekey;
  2594.     DBT tmpdata;
  2595.     int ret;
  2596.     CERTSubjectList *subjectList = NULL;
  2597.     certDBEntrySubject *entry;
  2598.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2599.     if ( arena == NULL ) {
  2600. goto loser;
  2601.     }
  2602.     rv = EncodeDBSubjectKey(subject, arena, &keyitem);
  2603.     if ( rv != SECSuccess ) {
  2604. goto loser;
  2605.     }
  2606.     
  2607.     namekey.data = keyitem.data;
  2608.     namekey.size = keyitem.len;
  2609.     
  2610.     /* lookup in the temporary database */
  2611.     ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
  2612.     /* error accessing the database */
  2613.     if ( ret < 0 ) {
  2614. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  2615. goto loser;
  2616.     }
  2617.     if ( ret == 0 ) { /* found in temp database */
  2618. if ( tmpdata.size != sizeof(CERTCertificate *) ) {
  2619.     PORT_SetError(SEC_ERROR_BAD_DATABASE);
  2620.     goto loser;
  2621. }
  2622. /* copy pointer out of database */
  2623. PORT_Memcpy(&subjectList, tmpdata.data, tmpdata.size);
  2624.     } else { /* not found in temporary database */
  2625. entry = ReadDBSubjectEntry(handle, subject);
  2626. if ( entry || create ) {
  2627.     /* decode or create new subject list */
  2628.     subjectList = NewSubjectList(entry);
  2629.     /* put it in the temp database */
  2630.     if ( subjectList ) {
  2631. tmpdata.data = (unsigned char *)(&subjectList);
  2632. tmpdata.size = sizeof(subjectList);
  2633. ret = certdb_Put(handle->tempCertDB, &namekey,
  2634.  &tmpdata, R_NOOVERWRITE);
  2635. if ( ret ) {
  2636.     goto loser;
  2637. }
  2638.     }
  2639. } else {
  2640.     PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
  2641.     goto loser;
  2642. }
  2643.     }
  2644.     goto done;
  2645. loser:
  2646.     subjectList = NULL;
  2647.     
  2648. done:
  2649.     if ( arena ) {
  2650. PORT_FreeArena(arena, PR_FALSE);
  2651.     }
  2652.     
  2653.     return(subjectList);
  2654. }
  2655. /*
  2656.  * Add a temp cert to the temp subject list
  2657.  */
  2658. static SECStatus
  2659. AddTempCertToSubjectList(CERTCertificate *cert)
  2660. {
  2661.     CERTSubjectList *subjectList;
  2662.     CERTSubjectNode *node, *newnode;
  2663.     CERTCertificate *cmpcert;
  2664.     PRBool newer;
  2665.     SECStatus rv;
  2666.     
  2667.     PORT_Assert(cert->isperm == PR_FALSE);
  2668.     PORT_Assert(cert->subjectList == NULL);
  2669.     
  2670.     subjectList = FindSubjectList(cert->dbhandle, &cert->derSubject, PR_TRUE);
  2671.     
  2672.     if ( subjectList == NULL ) {
  2673. goto loser;
  2674.     }
  2675.     newnode = (CERTSubjectNode*)PORT_ArenaAlloc(subjectList->arena,
  2676. sizeof(CERTSubjectNode));
  2677.     /* copy certKey and keyID to node */
  2678.     rv = SECITEM_CopyItem(subjectList->arena, &newnode->certKey,
  2679.   &cert->certKey);
  2680.     if ( rv != SECSuccess ) {
  2681. goto loser;
  2682.     }
  2683.     rv = SECITEM_CopyItem(subjectList->arena, &newnode->keyID,
  2684.   &cert->subjectKeyID);
  2685.     if ( rv != SECSuccess ) {
  2686. goto loser;
  2687.     }
  2688.     node = subjectList->head;
  2689.     if ( node ) {
  2690. /* list is not empty */
  2691. while ( node ) {
  2692.     cmpcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
  2693.   &node->certKey);
  2694.     if ( cmpcert ) {
  2695. newer =  CERT_IsNewer(cert, cmpcert);
  2696. CERT_DestroyCertificateNoLocking(cmpcert);
  2697. if ( newer ) {
  2698.     /* insert before this cert */
  2699.     newnode->next = node;
  2700.     newnode->prev = node->prev;
  2701.     if ( newnode->prev ) {
  2702. newnode->prev->next = newnode;
  2703.     } else {
  2704. /* at the head of the list */
  2705. subjectList->head = newnode;
  2706.     }
  2707.     node->prev = newnode;
  2708.     goto done;
  2709. }
  2710.     }
  2711.     node = node->next;
  2712. }
  2713. /* if we get here, we add the node to the end of the list */
  2714. newnode->prev = subjectList->tail;
  2715. newnode->next = NULL;
  2716. subjectList->tail->next = newnode;
  2717. subjectList->tail = newnode;
  2718.     } else {
  2719. /* this is a new/empty list */
  2720. newnode->next = NULL;
  2721. newnode->prev = NULL;
  2722. subjectList->head = newnode;
  2723. subjectList->tail = newnode;
  2724.     }
  2725.     
  2726. done:
  2727.     subjectList->ncerts++;
  2728.     cert->subjectList = subjectList;
  2729.     return(SECSuccess);
  2730.     
  2731. loser:
  2732.     return(SECFailure);
  2733. }
  2734. /*
  2735.  * Find the node in a subjectList that belongs a cert
  2736.  */
  2737. static CERTSubjectNode *
  2738. FindCertSubjectNode(CERTCertificate *cert)
  2739. {
  2740.     CERTSubjectList *subjectList;
  2741.     CERTSubjectNode *node = NULL;
  2742.     
  2743.     PORT_Assert(cert->subjectList);
  2744.     
  2745.     subjectList = cert->subjectList;
  2746.     
  2747.     if ( subjectList ) {
  2748. node = subjectList->head;
  2749.     }
  2750.     
  2751.     while ( node ) {
  2752. if ( SECITEM_CompareItem(&node->certKey, &cert->certKey) == SECEqual ){
  2753.     return(node);
  2754.     break;
  2755. }
  2756. node = node->next;
  2757.     }
  2758.     return(NULL);
  2759. }
  2760. /*
  2761.  * Remove a temp cert from the temp subject list
  2762.  */
  2763. static SECStatus
  2764. RemoveTempCertFromSubjectList(CERTCertificate *cert)
  2765. {
  2766.     CERTSubjectList *subjectList;
  2767.     CERTSubjectNode *node;
  2768.     SECItem keyitem;
  2769.     DBT namekey;
  2770.     SECStatus rv;
  2771.     int ret;
  2772.     CERTCertDBHandle *handle;
  2773.     
  2774.     PORT_Assert(cert->subjectList);
  2775.     /* don't remove perm certs */
  2776.     if ( cert->isperm ) {
  2777. return(SECSuccess);
  2778.     }
  2779.     
  2780.     subjectList = cert->subjectList;
  2781.     node = FindCertSubjectNode(cert);
  2782.     
  2783.     if ( node ) {
  2784. /* found it, unlink it */
  2785. if ( node->next ) {
  2786.     node->next->prev = node->prev;
  2787. } else {
  2788.     /* removing from tail of list */
  2789.     subjectList->tail = node->prev;
  2790. }
  2791. if ( node->prev ) {
  2792.     node->prev->next = node->next;
  2793. } else {
  2794.     /* removing from head of list */
  2795.     subjectList->head = node->next;
  2796. }
  2797. subjectList->ncerts--;
  2798. /* dont need to free the node, because it is from subjectList
  2799.  * arena.
  2800.  */
  2801. /* remove reference from cert */
  2802. cert->subjectList = NULL;
  2803. /* if the list is now empty, remove the list from the db and free it */
  2804. if ( subjectList->head == NULL ) {
  2805.     PORT_Assert(subjectList->ncerts == 0);
  2806.     rv = EncodeDBSubjectKey(&cert->derSubject, subjectList->arena,
  2807.     &keyitem);
  2808.     if ( rv == SECSuccess ) {
  2809. namekey.data = keyitem.data;
  2810. namekey.size = keyitem.len;
  2811. handle = cert->dbhandle;
  2812. ret = certdb_Del(handle->tempCertDB, &namekey, 0);
  2813. /* keep going if it fails */
  2814. if ( cert->dbnickname ) {
  2815.     rv = SEC_DeleteTempNickname(handle, cert->dbnickname);
  2816. } else if ( cert->nickname ) {
  2817.     rv = SEC_DeleteTempNickname(handle, cert->nickname);
  2818. }
  2819. /* keep going if it fails */
  2820.     }
  2821.     PORT_FreeArena(subjectList->arena, PR_FALSE);
  2822. }
  2823.     }
  2824.     PORT_Assert(cert->subjectList == NULL);
  2825.     
  2826.     if ( cert->subjectList != NULL ) {
  2827. return(SECFailure);
  2828.     }
  2829.     return(SECSuccess);
  2830. }
  2831. /*
  2832.  * cert is no longer a perm cert, but will remain a temp cert
  2833.  */
  2834. static SECStatus
  2835. RemovePermSubjectNode(CERTCertificate *cert)
  2836. {
  2837.     CERTSubjectList *subjectList;
  2838.     certDBEntrySubject *entry;
  2839.     unsigned int i;
  2840.     SECStatus rv;
  2841.     PORT_Assert(cert->isperm);
  2842.     if ( !cert->isperm ) {
  2843. return(SECFailure);
  2844.     }
  2845.     
  2846.     subjectList = cert->subjectList;
  2847.     PORT_Assert(subjectList);
  2848.     if ( subjectList == NULL ) {
  2849. return(SECFailure);
  2850.     }
  2851.     entry = subjectList->entry;
  2852.     PORT_Assert(entry);
  2853.     if ( entry == NULL ) {
  2854. return(SECFailure);
  2855.     }
  2856.     PORT_Assert(entry->ncerts);
  2857.     rv = SECFailure;
  2858.     
  2859.     if ( entry->ncerts > 1 ) {
  2860. for ( i = 0; i < entry->ncerts; i++ ) {
  2861.     if ( SECITEM_CompareItem(&entry->certKeys[i], &cert->certKey) ==
  2862. SECEqual ) {
  2863. /* copy rest of list forward one entry */
  2864. for ( i = i + 1; i < entry->ncerts; i++ ) {
  2865.     entry->certKeys[i-1] = entry->certKeys[i];
  2866.     entry->keyIDs[i-1] = entry->keyIDs[i];
  2867. }
  2868. entry->ncerts--;
  2869. DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
  2870. rv = WriteDBSubjectEntry(cert->dbhandle, entry);
  2871. break;
  2872.     }
  2873. }
  2874.     } else {
  2875. /* no entries left, delete the perm entry in the DB */
  2876. if ( subjectList->entry->emailAddr ) {
  2877.     /* if the subject had an email record, then delete it too */
  2878.     DeleteDBSMimeEntry(cert->dbhandle, subjectList->entry->emailAddr);
  2879. }
  2880. DestroyDBEntry((certDBEntry *)subjectList->entry);
  2881. subjectList->entry = NULL;
  2882. DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
  2883.     }
  2884.     return(rv);
  2885. }
  2886. /*
  2887.  * add a cert to the perm subject list
  2888.  */
  2889. static SECStatus
  2890. AddPermSubjectNode(CERTCertificate *cert, char *nickname)
  2891. {
  2892.     CERTSubjectList *subjectList;
  2893.     certDBEntrySubject *entry;
  2894.     SECItem *newCertKeys, *newKeyIDs;
  2895.     int i;
  2896.     SECStatus rv;
  2897.     CERTCertificate *cmpcert;
  2898.     unsigned int nnlen;
  2899.     int ncerts;
  2900.     
  2901.     subjectList = cert->subjectList;
  2902.     
  2903.     PORT_Assert(subjectList);
  2904.     if ( subjectList == NULL ) {
  2905. return(SECFailure);
  2906.     }
  2907.     entry = subjectList->entry;
  2908.     
  2909.     if ( entry ) {
  2910. ncerts = entry->ncerts;
  2911. if ( nickname && entry->nickname ) {
  2912.     /* nicknames must be the same */
  2913.     PORT_Assert(PORT_Strcmp(nickname, entry->nickname) == 0);
  2914. }
  2915. if ( ( entry->nickname == NULL ) && ( nickname != NULL ) ) {
  2916.     /* copy nickname into the entry */
  2917.     nnlen = PORT_Strlen(nickname) + 1;
  2918.     entry->nickname = (char *)PORT_ArenaAlloc(entry->common.arena,
  2919.       nnlen);
  2920.     if ( entry->nickname == NULL ) {
  2921. return(SECFailure);
  2922.     }
  2923.     PORT_Memcpy(entry->nickname, nickname, nnlen);
  2924. }
  2925. /* a DB entry already exists, so add this cert */
  2926. newCertKeys = (SECItem *)PORT_ArenaAlloc(entry->common.arena,
  2927.  sizeof(SECItem) *
  2928.  ( ncerts + 1 ) );
  2929. newKeyIDs = (SECItem *)PORT_ArenaAlloc(entry->common.arena,
  2930.        sizeof(SECItem) *
  2931.        ( ncerts + 1 ) );
  2932. if ( ( newCertKeys == NULL ) || ( newKeyIDs == NULL ) ) {
  2933.     return(SECFailure);
  2934. }
  2935. for ( i = 0; i < ncerts; i++ ) {
  2936.     cmpcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
  2937.   &entry->certKeys[i]);
  2938.     PORT_Assert(cmpcert);
  2939.     
  2940.     if ( CERT_IsNewer(cert, cmpcert) ) {
  2941. /* insert before cmpcert */
  2942. rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[i],
  2943.       &cert->certKey);
  2944. if ( rv != SECSuccess ) {
  2945.     return(SECFailure);
  2946. }
  2947. rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[i],
  2948.       &cert->subjectKeyID);
  2949. if ( rv != SECSuccess ) {
  2950.     return(SECFailure);
  2951. }
  2952. /* copy the rest of the entry */
  2953. for ( ; i < ncerts; i++ ) {
  2954.     newCertKeys[i+1] = entry->certKeys[i];
  2955.     newKeyIDs[i+1] = entry->keyIDs[i];
  2956. }
  2957. /* update certKeys and keyIDs */
  2958. entry->certKeys = newCertKeys;
  2959. entry->keyIDs = newKeyIDs;
  2960. /* increment count */
  2961. entry->ncerts++;
  2962. break;
  2963.     }
  2964.     /* copy this cert entry */
  2965.     newCertKeys[i] = entry->certKeys[i];
  2966.     newKeyIDs[i] = entry->keyIDs[i];
  2967. }
  2968. if ( entry->ncerts == ncerts ) {
  2969.     /* insert new one at end */
  2970.     rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[ncerts],
  2971.   &cert->certKey);
  2972.     if ( rv != SECSuccess ) {
  2973. return(SECFailure);
  2974.     }
  2975.     rv = SECITEM_CopyItem(entry->common.arena, &newKeyIDs[ncerts],
  2976.   &cert->subjectKeyID);
  2977.     if ( rv != SECSuccess ) {
  2978. return(SECFailure);
  2979.     }
  2980.     /* update certKeys and keyIDs */
  2981.     entry->certKeys = newCertKeys;
  2982.     entry->keyIDs = newKeyIDs;
  2983.     /* increment count */
  2984.     entry->ncerts++;
  2985. }
  2986.     } else {
  2987. /* need to make a new DB entry */
  2988. entry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey,
  2989.   &cert->subjectKeyID, nickname,
  2990.   NULL, 0);
  2991. cert->subjectList->entry = entry;
  2992.     }
  2993.     if ( entry ) {
  2994. DeleteDBSubjectEntry(cert->dbhandle, &cert->derSubject);
  2995. rv = WriteDBSubjectEntry(cert->dbhandle, entry);
  2996.     } else {
  2997. rv = SECFailure;
  2998.     }
  2999.     
  3000.     return(rv);
  3001. }
  3002. SECStatus
  3003. CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle, SECItem *derSubject,
  3004.  CERTCertCallback cb, void *cbarg)
  3005. {
  3006.     certDBEntrySubject *entry;
  3007.     int i;
  3008.     CERTCertificate *cert;
  3009.     SECStatus rv = SECSuccess;
  3010.     
  3011.     entry = ReadDBSubjectEntry(handle, derSubject);
  3012.     if ( entry == NULL ) {
  3013. return(SECFailure);
  3014.     }
  3015.     
  3016.     for( i = 0; i < entry->ncerts; i++ ) {
  3017. cert = CERT_FindCertByKey(handle, &entry->certKeys[i]);
  3018. rv = (* cb)(cert, cbarg);
  3019. CERT_DestroyCertificate(cert);
  3020. if ( rv == SECFailure ) {
  3021.     break;
  3022. }
  3023.     }
  3024.     DestroyDBEntry((certDBEntry *)entry);
  3025.     return(rv);
  3026. }
  3027. int
  3028. CERT_NumPermCertsForSubject(CERTCertDBHandle *handle, SECItem *derSubject)
  3029. {
  3030.     certDBEntrySubject *entry;
  3031.     int ret;
  3032.     
  3033.     entry = ReadDBSubjectEntry(handle, derSubject);
  3034.     if ( entry == NULL ) {
  3035. return(SECFailure);
  3036.     }
  3037.     ret = entry->ncerts;
  3038.     
  3039.     DestroyDBEntry((certDBEntry *)entry);
  3040.     
  3041.     return(ret);
  3042. }
  3043. SECStatus
  3044. CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname,
  3045.   CERTCertCallback cb, void *cbarg)
  3046. {
  3047.     certDBEntryNickname *nnentry = NULL;
  3048.     certDBEntrySMime *smentry = NULL;
  3049.     SECStatus rv;
  3050.     SECItem *derSubject = NULL;
  3051.     
  3052.     nnentry = ReadDBNicknameEntry(handle, nickname);
  3053.     if ( nnentry ) {
  3054. derSubject = &nnentry->subjectName;
  3055.     } else {
  3056. smentry = ReadDBSMimeEntry(handle, nickname);
  3057. if ( smentry ) {
  3058.     derSubject = &smentry->subjectName;
  3059. }
  3060.     }
  3061.     
  3062.     if ( derSubject ) {
  3063. rv = CERT_TraversePermCertsForSubject(handle, derSubject,
  3064.       cb, cbarg);
  3065.     } else {
  3066. rv = SECFailure;
  3067.     }
  3068.     if ( nnentry ) {
  3069. DestroyDBEntry((certDBEntry *)nnentry);
  3070.     }
  3071.     if ( smentry ) {
  3072. DestroyDBEntry((certDBEntry *)smentry);
  3073.     }
  3074.     
  3075.     return(rv);
  3076. }
  3077. int
  3078. CERT_NumPermCertsForNickname(CERTCertDBHandle *handle, char *nickname)
  3079. {
  3080.     certDBEntryNickname *entry;
  3081.     int ret;
  3082.     
  3083.     entry = ReadDBNicknameEntry(handle, nickname);
  3084.     
  3085.     if ( entry ) {
  3086. ret = CERT_NumPermCertsForSubject(handle, &entry->subjectName);
  3087. DestroyDBEntry((certDBEntry *)entry);
  3088.     } else {
  3089. ret = 0;
  3090.     }
  3091.     return(ret);
  3092. }
  3093. int
  3094. CERT_NumCertsForCertSubject(CERTCertificate *cert)
  3095. {
  3096.     int ret = 0;
  3097.     
  3098.     if ( cert->subjectList ) {
  3099. ret = cert->subjectList->ncerts;
  3100.     }
  3101.     return(ret);
  3102. }
  3103. int
  3104. CERT_NumPermCertsForCertSubject(CERTCertificate *cert)
  3105. {
  3106.     int ret = 0;
  3107.     
  3108.     if ( cert->subjectList ) {
  3109. if ( cert->subjectList->entry ) {
  3110.     ret = cert->subjectList->entry->ncerts;
  3111. }
  3112.     }
  3113.     return(ret);
  3114. }
  3115. SECStatus
  3116. CERT_TraverseCertsForSubject(CERTCertDBHandle *handle,
  3117.      CERTSubjectList *subjectList,
  3118.      CERTCertCallback cb, void *cbarg)
  3119. {
  3120.     CERTSubjectNode *node;
  3121.     CERTCertificate *cert;
  3122.     SECStatus rv = SECSuccess;
  3123.     
  3124.     CERT_LockDB(handle);
  3125.     node = subjectList->head;
  3126.     while ( node ) {
  3127. cert = CERT_FindCertByKeyNoLocking(handle, &node->certKey);
  3128. PORT_Assert(cert != NULL);
  3129. if ( cert != NULL ) {
  3130.     rv = (* cb)(cert, cbarg);
  3131.     CERT_DestroyCertificateNoLocking(cert);
  3132.     if ( rv == SECFailure ) {
  3133. break;
  3134.     }
  3135. }
  3136. node = node->next;
  3137.     }
  3138.     CERT_UnlockDB(handle);
  3139.     return(rv);
  3140. }
  3141. /*
  3142.  * Given a cert, find the cert with the same subject name that
  3143.  * has the given key usage.  If the given cert has the correct keyUsage, then
  3144.  * return it, otherwise search the list in order.
  3145.  */
  3146. CERTCertificate *
  3147. CERT_FindCertByUsage(CERTCertificate *basecert, unsigned int requiredKeyUsage)
  3148. {
  3149.     CERTSubjectNode *node;
  3150.     CERTCertificate *cert;
  3151.     CERTSubjectList *subjectList;
  3152.     
  3153.     if ( ( basecert->keyUsage & requiredKeyUsage ) == requiredKeyUsage ) {
  3154. return(CERT_DupCertificate(basecert));
  3155.     }
  3156.     
  3157.     CERT_LockDB(basecert->dbhandle);
  3158.     subjectList = basecert->subjectList;
  3159.     node = subjectList->head;
  3160.     while ( node ) {
  3161. cert = CERT_FindCertByKeyNoLocking(basecert->dbhandle, &node->certKey);
  3162. PORT_Assert(cert != NULL);
  3163. if ( cert != NULL ) {
  3164.     if ( ( cert->keyUsage & requiredKeyUsage ) ==
  3165.  requiredKeyUsage ) {
  3166. CERT_UnlockDB(basecert->dbhandle);
  3167. return(cert);
  3168.     }
  3169.     CERT_DestroyCertificateNoLocking(cert);
  3170. }
  3171. node = node->next;
  3172.     }
  3173.     CERT_UnlockDB(basecert->dbhandle);
  3174.     return(NULL);
  3175. }
  3176. /*
  3177.  * add a nickname to a cert that doesn't have one
  3178.  */
  3179. static SECStatus
  3180. AddNicknameToPermCert(CERTCertificate *cert, char *nickname)
  3181. {
  3182.     certDBEntryCert *entry;
  3183.     int rv;
  3184.     
  3185.     PORT_Assert(cert->isperm);
  3186.     if ( !cert->isperm ) {
  3187. goto loser;
  3188.     }
  3189.     entry = cert->dbEntry;
  3190.     PORT_Assert(entry != NULL);
  3191.     if ( entry == NULL ) {
  3192. goto loser;
  3193.     }
  3194.     entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname);
  3195.     rv = WriteDBCertEntry(cert->dbhandle, entry);
  3196.     if ( rv ) {
  3197. goto loser;
  3198.     }
  3199.     cert->nickname = PORT_ArenaStrdup(cert->arena, nickname);
  3200.     return(SECSuccess);
  3201.     
  3202. loser:
  3203.     return(SECFailure);
  3204. }
  3205. /*
  3206.  * add a nickname to a cert that is already in the perm database, but doesn't
  3207.  * have one yet (it is probably an e-mail cert).
  3208.  */
  3209. SECStatus
  3210. CERT_AddPermNickname(CERTCertificate *cert, char *nickname)
  3211. {
  3212.     SECStatus rv;
  3213.     
  3214.     CERT_LockDB(cert->dbhandle);
  3215.     
  3216.     PORT_Assert(cert->nickname == NULL);
  3217.     PORT_Assert(cert->isperm);
  3218.     PORT_Assert(cert->subjectList != NULL);
  3219.     PORT_Assert(cert->subjectList->entry != NULL);
  3220.     
  3221.     if ( cert->nickname != NULL ) {
  3222. goto done;
  3223.     }
  3224.     if ( cert->subjectList == NULL ) {
  3225. goto loser;
  3226.     }
  3227.     
  3228.     if ( cert->subjectList->entry == NULL ) {
  3229. goto loser;
  3230.     }
  3231.     if ( cert->subjectList->entry->nickname == NULL ) {
  3232. /* no nickname for subject */
  3233. rv = AddNicknameToSubject(cert, nickname);
  3234. if ( rv != SECSuccess ) {
  3235.     goto loser;
  3236. }
  3237. rv = AddNicknameToPermCert(cert, nickname);
  3238. if ( rv != SECSuccess ) {
  3239.     goto loser;
  3240. }
  3241. rv = SEC_AddTempNickname(cert->dbhandle, nickname,
  3242.  &cert->derSubject);
  3243. if ( rv != SECSuccess ) {
  3244.     goto loser;
  3245. }
  3246.     } else {
  3247. /* subject already has a nickname */
  3248. rv = AddNicknameToPermCert(cert, cert->subjectList->entry->nickname);
  3249. if ( rv != SECSuccess ) {
  3250.     goto loser;
  3251. }
  3252.     }
  3253. done:
  3254.     CERT_UnlockDB(cert->dbhandle);
  3255.     return(SECSuccess);
  3256. loser:
  3257.     CERT_UnlockDB(cert->dbhandle);
  3258.     return(SECFailure);
  3259. }
  3260. static certDBEntryCert *
  3261. AddCertToPermDB(CERTCertDBHandle *handle, CERTCertificate *cert,
  3262. char *nickname, CERTCertTrust *trust)
  3263. {
  3264.     certDBEntryCert *certEntry = NULL;
  3265.     certDBEntryNickname *nicknameEntry = NULL;
  3266.     certDBEntrySubject *subjectEntry = NULL;
  3267.     int state = 0;
  3268.     SECStatus rv;
  3269.     PRBool donnentry = PR_FALSE;
  3270.     if ( nickname ) {
  3271. donnentry = PR_TRUE;
  3272.     }
  3273.     if ( cert->subjectList != NULL ) {
  3274. if ( cert->subjectList->entry != NULL ) {
  3275.     if ( cert->subjectList->entry->ncerts > 0 ) {
  3276. /* of other certs with same subject exist, then they already
  3277.  * have a nickname, so don't add a new one.
  3278.  */
  3279. donnentry = PR_FALSE;
  3280. nickname = cert->subjectList->entry->nickname;
  3281.     }
  3282. }
  3283.     }
  3284.     
  3285.     certEntry = NewDBCertEntry(&cert->derCert, nickname, trust, 0);
  3286.     if ( certEntry == NULL ) {
  3287. goto loser;
  3288.     }
  3289.     
  3290.     if ( donnentry ) {
  3291. nicknameEntry = NewDBNicknameEntry(nickname, &cert->derSubject, 0);
  3292. if ( nicknameEntry == NULL ) {
  3293.     goto loser;
  3294. }
  3295.     }
  3296.     
  3297.     rv = WriteDBCertEntry(handle, certEntry);
  3298.     if ( rv != SECSuccess ) {
  3299. goto loser;
  3300.     }
  3301.     state = 1;
  3302.     
  3303.     if ( nicknameEntry ) {
  3304. rv = WriteDBNicknameEntry(handle, nicknameEntry);
  3305. if ( rv != SECSuccess ) {
  3306.     goto loser;
  3307. }
  3308.     }
  3309.     
  3310.     state = 2;
  3311.     
  3312.     /* add to or create new subject entry */
  3313.     if ( cert->subjectList ) {
  3314. rv = AddPermSubjectNode(cert, nickname);
  3315. if ( rv != SECSuccess ) {
  3316.     goto loser;
  3317. }
  3318.     } else {