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

CA认证

开发平台:

WINDOWS

  1. /* make a new subject entry - this case is only used when updating
  2.  * an old version of the database.  This is OK because the oldnickname
  3.  * db format didn't allow multiple certs with the same subject.
  4.  */
  5. subjectEntry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey,
  6.  &cert->subjectKeyID, nickname,
  7.  NULL, 0);
  8. if ( subjectEntry == NULL ) {
  9.     goto loser;
  10. }
  11. rv = WriteDBSubjectEntry(handle, subjectEntry);
  12. if ( rv != SECSuccess ) {
  13.     goto loser;
  14. }
  15.     }
  16.     
  17.     state = 3;
  18.     
  19.     if ( nicknameEntry ) {
  20. DestroyDBEntry((certDBEntry *)nicknameEntry);
  21.     }
  22.     
  23.     if ( subjectEntry ) {
  24. DestroyDBEntry((certDBEntry *)subjectEntry);
  25.     }
  26.     return(certEntry);
  27. loser:
  28.     /* don't leave partial entry in the database */
  29.     if ( state > 0 ) {
  30. rv = DeleteDBCertEntry(handle, &cert->certKey);
  31.     }
  32.     if ( ( state > 1 ) && donnentry ) {
  33. rv = DeleteDBNicknameEntry(handle, nickname);
  34.     }
  35.     if ( state > 2 ) {
  36. rv = DeleteDBSubjectEntry(handle, &cert->derSubject);
  37.     }
  38.     if ( certEntry ) {
  39. DestroyDBEntry((certDBEntry *)certEntry);
  40.     }
  41.     if ( nicknameEntry ) {
  42. DestroyDBEntry((certDBEntry *)nicknameEntry);
  43.     }
  44.     if ( subjectEntry ) {
  45. DestroyDBEntry((certDBEntry *)subjectEntry);
  46.     }
  47.     return(NULL);
  48. }
  49. /*
  50.  * NOTE - Version 6 DB did not go out to the real world in a release,
  51.  * so we can remove this function in a later release.
  52.  */
  53. static SECStatus
  54. UpdateV6DB(CERTCertDBHandle *handle, DB *updatedb)
  55. {
  56.     int ret;
  57.     DBT key, data;
  58.     unsigned char *buf, *tmpbuf = NULL;
  59.     certDBEntryType type;
  60.     certDBEntryNickname *nnEntry = NULL;
  61.     certDBEntrySubject *subjectEntry = NULL;
  62.     certDBEntrySMime *emailEntry = NULL;
  63.     char *nickname;
  64.     char *emailAddr;
  65.     SECStatus rv;
  66.     
  67.     /*
  68.      * Sequence through the old database and copy all of the entries
  69.      * to the new database.  Subject name entries will have the new
  70.      * fields inserted into them (with zero length).
  71.      */
  72.     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
  73.     if ( ret ) {
  74. return(SECFailure);
  75.     }
  76.     do {
  77. buf = (unsigned char *)data.data;
  78. if ( data.size >= 3 ) {
  79.     if ( buf[0] == 6 ) { /* version number */
  80. type = (certDBEntryType)buf[1];
  81. if ( type == certDBEntryTypeSubject ) {
  82.     /* expando subjecto entrieo */
  83.     tmpbuf = (unsigned char *)PORT_Alloc(data.size + 4);
  84.     if ( tmpbuf ) {
  85. /* copy header stuff */
  86. PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN + 2);
  87. /* insert 4 more bytes of zero'd header */
  88. PORT_Memset(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 2],
  89.     0, 4);
  90. /* copy rest of the data */
  91. PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
  92.     &buf[SEC_DB_ENTRY_HEADER_LEN + 2],
  93.     data.size - (SEC_DB_ENTRY_HEADER_LEN + 2));
  94. data.data = (void *)tmpbuf;
  95. data.size += 4;
  96. buf = tmpbuf;
  97.     }
  98. } else if ( type == certDBEntryTypeCert ) {
  99.     /* expando certo entrieo */
  100.     tmpbuf = (unsigned char *)PORT_Alloc(data.size + 3);
  101.     if ( tmpbuf ) {
  102. /* copy header stuff */
  103. PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN);
  104. /* copy trust flage, setting msb's to 0 */
  105. tmpbuf[SEC_DB_ENTRY_HEADER_LEN] = 0;
  106. tmpbuf[SEC_DB_ENTRY_HEADER_LEN+1] =
  107.     buf[SEC_DB_ENTRY_HEADER_LEN];
  108. tmpbuf[SEC_DB_ENTRY_HEADER_LEN+2] = 0;
  109. tmpbuf[SEC_DB_ENTRY_HEADER_LEN+3] =
  110.     buf[SEC_DB_ENTRY_HEADER_LEN+1];
  111. tmpbuf[SEC_DB_ENTRY_HEADER_LEN+4] = 0;
  112. tmpbuf[SEC_DB_ENTRY_HEADER_LEN+5] =
  113.     buf[SEC_DB_ENTRY_HEADER_LEN+2];
  114. /* copy rest of the data */
  115. PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
  116.     &buf[SEC_DB_ENTRY_HEADER_LEN + 3],
  117.     data.size - (SEC_DB_ENTRY_HEADER_LEN + 3));
  118. data.data = (void *)tmpbuf;
  119. data.size += 3;
  120. buf = tmpbuf;
  121.     }
  122. }
  123. /* update the record version number */
  124. buf[0] = CERT_DB_FILE_VERSION;
  125. /* copy to the new database */
  126. ret = certdb_Put(handle->permCertDB, &key, &data, 0);
  127. if ( tmpbuf ) {
  128.     PORT_Free(tmpbuf);
  129.     tmpbuf = NULL;
  130. }
  131.     }
  132. }
  133.     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
  134.     ret = certdb_Sync(handle->permCertDB, 0);
  135.     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
  136.     if ( ret ) {
  137. return(SECFailure);
  138.     }
  139.     do {
  140. buf = (unsigned char *)data.data;
  141. if ( data.size >= 3 ) {
  142.     if ( buf[0] == CERT_DB_FILE_VERSION ) { /* version number */
  143. type = (certDBEntryType)buf[1];
  144. if ( type == certDBEntryTypeNickname ) {
  145.     nickname = &((char *)key.data)[1];
  146.     /* get the matching nickname entry in the new DB */
  147.     nnEntry = ReadDBNicknameEntry(handle, nickname);
  148.     if ( nnEntry == NULL ) {
  149. goto endloop;
  150.     }
  151.     
  152.     /* find the subject entry pointed to by nickname */
  153.     subjectEntry = ReadDBSubjectEntry(handle,
  154.       &nnEntry->subjectName);
  155.     if ( subjectEntry == NULL ) {
  156. goto endloop;
  157.     }
  158.     
  159.     subjectEntry->nickname =
  160. (char *)PORT_ArenaAlloc(subjectEntry->common.arena,
  161. key.size - 1);
  162.     if ( subjectEntry->nickname ) {
  163. PORT_Memcpy(subjectEntry->nickname, nickname,
  164.     key.size - 1);
  165. rv = WriteDBSubjectEntry(handle, subjectEntry);
  166.     }
  167. } else if ( type == certDBEntryTypeSMimeProfile ) {
  168.     emailAddr = &((char *)key.data)[1];
  169.     /* get the matching smime entry in the new DB */
  170.     emailEntry = ReadDBSMimeEntry(handle, emailAddr);
  171.     if ( emailEntry == NULL ) {
  172. goto endloop;
  173.     }
  174.     
  175.     /* find the subject entry pointed to by nickname */
  176.     subjectEntry = ReadDBSubjectEntry(handle,
  177.       &emailEntry->subjectName);
  178.     if ( subjectEntry == NULL ) {
  179. goto endloop;
  180.     }
  181.     
  182.     subjectEntry->nickname =
  183. (char *)PORT_ArenaAlloc(subjectEntry->common.arena,
  184. key.size - 1);
  185.     if ( subjectEntry->emailAddr ) {
  186. PORT_Memcpy(subjectEntry->emailAddr, emailAddr,
  187.     key.size - 1);
  188. rv = WriteDBSubjectEntry(handle, subjectEntry);
  189.     }
  190. }
  191. endloop:
  192. if ( subjectEntry ) {
  193.     DestroyDBEntry((certDBEntry *)subjectEntry);
  194.     subjectEntry = NULL;
  195. }
  196. if ( nnEntry ) {
  197.     DestroyDBEntry((certDBEntry *)nnEntry);
  198.     nnEntry = NULL;
  199. }
  200. if ( emailEntry ) {
  201.     DestroyDBEntry((certDBEntry *)emailEntry);
  202.     emailEntry = NULL;
  203. }
  204.     }
  205. }
  206.     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
  207.     ret = certdb_Sync(handle->permCertDB, 0);
  208.     (* updatedb->close)(updatedb);
  209.     return(SECSuccess);
  210. }
  211. static SECStatus
  212. updateV5Callback(CERTCertificate *cert, SECItem *k, void *pdata)
  213. {
  214.     CERTCertDBHandle *handle;
  215.     certDBEntryCert *entry;
  216.     CERTCertTrust *trust;
  217.     
  218.     handle = (CERTCertDBHandle *)pdata;
  219.     trust = &cert->dbEntry->trust;
  220.     /* SSL user certs can be used for email if they have an email addr */
  221.     if ( cert->emailAddr && ( trust->sslFlags & CERTDB_USER ) &&
  222. ( trust->emailFlags == 0 ) ) {
  223. trust->emailFlags = CERTDB_USER;
  224.     }
  225.     
  226.     entry = AddCertToPermDB(handle, cert, cert->dbEntry->nickname,
  227.     &cert->dbEntry->trust);
  228.     if ( entry ) {
  229. DestroyDBEntry((certDBEntry *)entry);
  230.     }
  231.     
  232.     return(SECSuccess);
  233. }
  234. static SECStatus
  235. UpdateV5DB(CERTCertDBHandle *handle, DB *updatedb)
  236. {
  237.     CERTCertDBHandle updatehandle;
  238.     SECStatus rv;
  239.     
  240.     updatehandle.permCertDB = updatedb;
  241.     updatehandle.dbMon = PR_NewMonitor();
  242.     
  243.     rv = SEC_TraversePermCerts(&updatehandle, updateV5Callback,
  244.        (void *)handle);
  245.     
  246.     PR_DestroyMonitor(updatehandle.dbMon);
  247.     
  248.     return(rv);
  249. }
  250. static SECStatus
  251. UpdateV4DB(CERTCertDBHandle *handle, DB *updatedb)
  252. {
  253.     DBT key, data;
  254.     certDBEntryCert *entry, *entry2;
  255.     SECItem derSubject;
  256.     int ret;
  257.     PRArenaPool *arena = NULL;
  258.     CERTCertificate *cert;
  259.     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
  260.     if ( ret ) {
  261. return(SECFailure);
  262.     }
  263.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  264.     if (arena == NULL) {
  265. return(SECFailure);
  266.     }
  267.     
  268.     do {
  269. if ( data.size != 1 ) { /* skip version number */
  270.     /* decode the old DB entry */
  271.     entry = (certDBEntryCert *)DecodeV4DBCertEntry((unsigned char*)data.data, data.size);
  272.     derSubject.data = NULL;
  273.     
  274.     if ( entry ) {
  275. cert = CERT_DecodeDERCertificate(&entry->derCert, PR_TRUE,
  276.  entry->nickname);
  277. if ( cert != NULL ) {
  278.     /* add to new database */
  279.     entry2 = AddCertToPermDB(handle, cert, entry->nickname,
  280.      &entry->trust);
  281.     
  282.     CERT_DestroyCertificate(cert);
  283.     if ( entry2 ) {
  284. DestroyDBEntry((certDBEntry *)entry2);
  285.     }
  286. }
  287. DestroyDBEntry((certDBEntry *)entry);
  288.     }
  289. }
  290.     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
  291.     PORT_FreeArena(arena, PR_FALSE);
  292.     (* updatedb->close)(updatedb);
  293.     return(SECSuccess);
  294. }
  295. /*
  296.  * return true if a database key conflict exists
  297.  */
  298. PRBool
  299. SEC_CertDBKeyConflict(SECItem *derCert, CERTCertDBHandle *handle)
  300. {
  301.     SECStatus rv;
  302.     DBT tmpdata;
  303.     DBT namekey;
  304.     int ret;
  305.     SECItem keyitem;
  306.     PRArenaPool *arena = NULL;
  307.     SECItem derKey;
  308.     
  309.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  310.     if ( arena == NULL ) {
  311. goto loser;
  312.     }
  313.     /* get the db key of the cert */
  314.     rv = CERT_KeyFromDERCert(arena, derCert, &derKey);
  315.     if ( rv != SECSuccess ) {
  316.         goto loser;
  317.     }
  318.     rv = EncodeDBCertKey(&derKey, arena, &keyitem);
  319.     if ( rv != SECSuccess ) {
  320. goto loser;
  321.     }
  322.     
  323.     namekey.data = keyitem.data;
  324.     namekey.size = keyitem.len;
  325.     
  326.     /* lookup in the temporary database */
  327.     ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
  328.     if ( ret == 0 ) { /* found in temp database */
  329. goto loser;
  330.     } else { /* not found in temporary database */
  331. ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0);
  332. if ( ret == 0 ) {
  333.     goto loser;
  334. }
  335.     }
  336.     PORT_FreeArena(arena, PR_FALSE);
  337.     
  338.     return(PR_FALSE);
  339. loser:
  340.     if ( arena ) {
  341. PORT_FreeArena(arena, PR_FALSE);
  342.     }
  343.     
  344.     return(PR_TRUE);
  345. }
  346. #ifdef NOTDEF
  347. /*
  348.  * return true if a subject name conflict exists
  349.  * NOTE: caller must have already made sure that this exact cert
  350.  * doesn't exist in the DB
  351.  */
  352. PRBool
  353. SEC_CertSubjectConflict(SECItem *derCert, CERTCertDBHandle *handle)
  354. {
  355.     SECStatus rv;
  356.     DBT tmpdata;
  357.     DBT namekey;
  358.     int ret;
  359.     SECItem keyitem;
  360.     PRArenaPool *arena = NULL;
  361.     SECItem derName;
  362.     
  363.     derName.data = NULL;
  364.     
  365.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  366.     if ( arena == NULL ) {
  367. goto loser;
  368.     }
  369.     /* get the subject name of the cert */
  370.     rv = CERT_NameFromDERCert(derCert, &derName);
  371.     if ( rv != SECSuccess ) {
  372.         goto loser;
  373.     }
  374.     rv = EncodeDBSubjectKey(&derName, arena, &keyitem);
  375.     if ( rv != SECSuccess ) {
  376. goto loser;
  377.     }
  378.     
  379.     namekey.data = keyitem.data;
  380.     namekey.size = keyitem.len;
  381.     
  382.     /* lookup in the temporary database */
  383.     ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
  384.     if ( ret == 0 ) { /* found in temp database */
  385. return(PR_TRUE);
  386.     } else { /* not found in temporary database */
  387. ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0);
  388. if ( ret == 0 ) {
  389.     return(PR_TRUE);
  390. }
  391.     }
  392.     PORT_FreeArena(arena, PR_FALSE);
  393.     PORT_Free(derName.data);
  394.     
  395.     return(PR_FALSE);
  396. loser:
  397.     if ( arena ) {
  398. PORT_FreeArena(arena, PR_FALSE);
  399.     }
  400.     if ( derName.data ) {
  401. PORT_Free(derName.data);
  402.     }
  403.     
  404.     return(PR_TRUE);
  405. }
  406. #endif
  407. /*
  408.  * return true if a nickname conflict exists
  409.  * NOTE: caller must have already made sure that this exact cert
  410.  * doesn't exist in the DB
  411.  */
  412. PRBool
  413. SEC_CertNicknameConflict(char *nickname, SECItem *derSubject,
  414.  CERTCertDBHandle *handle)
  415. {
  416.     PRBool rv;
  417.     certDBEntryNickname *entry;
  418.     
  419.     if ( nickname == NULL ) {
  420. return(PR_FALSE);
  421.     }
  422.     
  423.     entry = ReadDBNicknameEntry(handle, nickname);
  424.     if ( entry == NULL ) {
  425. /* no entry for this nickname, so no conflict */
  426. return(PR_FALSE);
  427.     }
  428.     rv = PR_TRUE;
  429.     if ( SECITEM_CompareItem(derSubject, &entry->subjectName) == SECEqual ) {
  430. /* if subject names are the same, then no conflict */
  431. rv = PR_FALSE;
  432.     }
  433.     DestroyDBEntry((certDBEntry *)entry);
  434.     return(rv);
  435. }
  436. /*
  437.  * Open the certificate database and index databases.  Create them if
  438.  * they are not there or bad.
  439.  */
  440. SECStatus
  441. SEC_OpenPermCertDB(CERTCertDBHandle *handle, PRBool readOnly,
  442.    CERTDBNameFunc namecb, void *cbarg)
  443. {
  444.     SECStatus rv;
  445.     int openflags;
  446.     certDBEntryVersion *versionEntry = NULL;
  447.     DB *updatedb = NULL;
  448.     char *tmpname;
  449.     char *certdbname;
  450.     PRBool updated = PR_FALSE;
  451.     PRBool forceUpdate = PR_FALSE;
  452.     
  453.     certdbname = (* namecb)(cbarg, CERT_DB_FILE_VERSION);
  454.     if ( certdbname == NULL ) {
  455. return(SECFailure);
  456.     }
  457.     
  458.     if ( readOnly ) {
  459. openflags = O_RDONLY;
  460.     } else {
  461. openflags = O_RDWR;
  462.     }
  463.     
  464.     /*
  465.      * first open the permanent file based database.
  466.      */
  467.     handle->permCertDB = dbopen( certdbname, openflags, 0600, DB_HASH, 0 );
  468.     /* check for correct version number */
  469.     if ( handle->permCertDB ) {
  470. versionEntry = ReadDBVersionEntry(handle);
  471. if ( versionEntry == NULL ) {
  472.     /* no version number */
  473.     certdb_Close(handle->permCertDB);
  474.     handle->permCertDB = 0;
  475. } else if ( versionEntry->common.version != CERT_DB_FILE_VERSION ) {
  476.     /* wrong version number, can't update in place */
  477.     DestroyDBEntry((certDBEntry *)versionEntry);
  478.     PORT_Free(certdbname);
  479.     return(SECFailure);
  480. }
  481.     }
  482.     /* if first open fails, try to create a new DB */
  483.     if ( handle->permCertDB == NULL ) {
  484. /* don't create if readonly */
  485. if ( readOnly ) {
  486.     goto loser;
  487. }
  488. handle->permCertDB = dbopen(certdbname,
  489.     O_RDWR | O_CREAT | O_TRUNC,
  490.     0600, DB_HASH, 0);
  491. /* if create fails then we lose */
  492. if ( handle->permCertDB == 0 ) {
  493.     goto loser;
  494. }
  495. versionEntry = NewDBVersionEntry(0);
  496. if ( versionEntry == NULL ) {
  497.     goto loser;
  498. }
  499. rv = WriteDBVersionEntry(handle, versionEntry);
  500. DestroyDBEntry((certDBEntry *)versionEntry);
  501. if ( rv != SECSuccess ) {
  502.     goto loser;
  503. }
  504. /* try to upgrade old db here */
  505. tmpname = (* namecb)(cbarg, 6); /* get v6 db name */
  506. if ( tmpname ) {
  507.     updatedb = dbopen( tmpname, O_RDONLY, 0600, DB_HASH, 0 );
  508.     PORT_Free(tmpname);
  509.     if ( updatedb ) {
  510. rv = UpdateV6DB(handle, updatedb);
  511. if ( rv != SECSuccess ) {
  512.     goto loser;
  513. }
  514. updated = PR_TRUE;
  515.     } else { /* no v6 db, so try v5 db */
  516. tmpname = (* namecb)(cbarg, 5); /* get v5 db name */
  517. if ( tmpname ) {
  518.     updatedb = dbopen( tmpname, O_RDONLY, 0600, DB_HASH, 0 );
  519.     PORT_Free(tmpname);
  520.     if ( updatedb ) {
  521. rv = UpdateV5DB(handle, updatedb);
  522. if ( rv != SECSuccess ) {
  523.     goto loser;
  524. }
  525. updated = PR_TRUE;
  526.     } else { /* no v5 db, so try v4 db */
  527. /* try to upgrade v4 db */
  528. tmpname = (* namecb)(cbarg, 4); /* get v4 db name */
  529. if ( tmpname ) {
  530.     updatedb = dbopen( tmpname, O_RDONLY, 0600,
  531.       DB_HASH, 0 );
  532.     PORT_Free(tmpname);
  533.     if ( updatedb ) {
  534. rv = UpdateV4DB(handle, updatedb);
  535. if ( rv != SECSuccess ) {
  536.     goto loser;
  537. }
  538. forceUpdate = PR_TRUE;
  539. updated = PR_TRUE;
  540.     }
  541. }
  542.     }
  543. }
  544.     }
  545. }
  546. /* initialize the database with our well known certificates
  547.  * or in the case of update, just fall down to CERT_AddNewCerts()
  548.  * below.
  549.  * Note - if we are updating a really old database, then we try
  550.  * to push all of the certs into it.
  551.  */
  552. if ( ( !updated ) || forceUpdate ) {
  553.     rv = CERT_InitCertDB(handle);
  554.     if ( rv != SECSuccess ) {
  555. goto loser;
  556.     }
  557. }
  558.     }
  559.     rv = CERT_AddNewCerts(handle);
  560.     PORT_Free(certdbname);
  561.     
  562.     return (SECSuccess);
  563.     
  564. loser:
  565.     PORT_SetError(SEC_ERROR_BAD_DATABASE);
  566.     
  567.     if ( handle->permCertDB ) {
  568. certdb_Close(handle->permCertDB);
  569. handle->permCertDB = 0;
  570.     }
  571.     PORT_Free(certdbname);
  572.     return(SECFailure);
  573. }
  574. /*
  575.  * delete all DB records associated with a particular certificate
  576.  */
  577. static SECStatus
  578. DeletePermCert(CERTCertificate *cert)
  579. {
  580.     SECStatus rv;
  581.     SECStatus ret;
  582.     ret = SECSuccess;
  583.     
  584.     rv = DeleteDBCertEntry(cert->dbhandle, &cert->certKey);
  585.     if ( rv != SECSuccess ) {
  586. ret = SECFailure;
  587.     }
  588.     
  589.     if ( cert->nickname ) {
  590. rv = DeleteDBNicknameEntry(cert->dbhandle, cert->nickname);
  591. if ( rv != SECSuccess ) {
  592.     ret = SECFailure;
  593. }
  594.     }
  595.     
  596.     rv = RemovePermSubjectNode(cert);
  597.     return(ret);
  598. }
  599. /*
  600.  * Delete a certificate from the permanent database.
  601.  */
  602. SECStatus
  603. SEC_DeletePermCertificate(CERTCertificate *cert)
  604. {
  605.     SECStatus rv;
  606.     
  607.     if ( !cert->isperm ) {
  608. return(SECSuccess);
  609.     }
  610.     CERT_LockDB(cert->dbhandle);
  611.     /* delete the records from the permanent database */
  612.     rv = DeletePermCert(cert);
  613.     
  614.     /* no longer permanent */
  615.     cert->isperm = PR_FALSE;
  616.     /* get rid of dbcert and stuff pointing to it */
  617.     DestroyDBEntry((certDBEntry *)cert->dbEntry);
  618.     cert->dbEntry = NULL;
  619.     cert->trust = NULL;
  620.     /* delete it from the temporary database too.  It will remain in
  621.      * memory until all references go away.
  622.      */
  623.     if (cert->slot) {
  624.     /* If it's owned by a PKCS #11 slot, don't deleted if from the temp DB just
  625.      * yet... rv inherited from DeletePermCert (as if anyone checks the return
  626.      * code from this function anyway. */
  627. CERT_DestroyCertificateNoLocking(cert);
  628. rv = SECSuccess;
  629.     } else {
  630. rv = CERT_DeleteTempCertificate(cert);
  631.     }
  632.     CERT_UnlockDB(cert->dbhandle);
  633.     return(rv);
  634. }
  635. /*
  636.  * Lookup a certificate in the databases.
  637.  */
  638. certDBEntryCert *
  639. SEC_FindPermCertByKey(CERTCertDBHandle *handle, SECItem *key)
  640. {
  641.     return(ReadDBCertEntry(handle, key));
  642. }
  643. /*
  644.  * Lookup a certificate in the database by name
  645.  */
  646. certDBEntryCert *
  647. SEC_FindPermCertByName(CERTCertDBHandle *handle, SECItem *derSubject)
  648. {
  649.     certDBEntrySubject *subjectEntry;
  650.     certDBEntryCert *certEntry;
  651.     
  652.     subjectEntry = ReadDBSubjectEntry(handle, derSubject);
  653.     
  654.     if ( subjectEntry == NULL ) {
  655. goto loser;
  656.     }
  657.     certEntry = ReadDBCertEntry(handle, &subjectEntry->certKeys[0]);
  658.     DestroyDBEntry((certDBEntry *)subjectEntry);
  659.     
  660.     return(certEntry);
  661. loser:
  662.     return(NULL);
  663. }
  664. /*
  665.  * Lookup a certificate in the database by nickname
  666.  */
  667. certDBEntryCert *
  668. SEC_FindPermCertByNickname(CERTCertDBHandle *handle, char *nickname)
  669. {
  670.     certDBEntryNickname *nicknameEntry;
  671.     certDBEntryCert *certEntry;
  672.     
  673.     nicknameEntry = ReadDBNicknameEntry(handle, nickname);
  674.     
  675.     if ( nicknameEntry == NULL ) {
  676. goto loser;
  677.     }
  678.     certEntry = SEC_FindPermCertByName(handle, &nicknameEntry->subjectName);
  679.     DestroyDBEntry((certDBEntry *)nicknameEntry);
  680.     
  681.     return(certEntry);
  682. loser:
  683.     return(NULL);
  684. }
  685. /*
  686.  * Traverse all of the entries in the database of a particular type
  687.  * call the given function for each one.
  688.  */
  689. SECStatus
  690. SEC_TraverseDBEntries(CERTCertDBHandle *handle,
  691.       certDBEntryType type,
  692.       SECStatus (* callback)(SECItem *data, SECItem *key,
  693.     certDBEntryType type, void *pdata),
  694.       void *udata )
  695. {
  696.     DBT data;
  697.     DBT key;
  698.     SECStatus rv;
  699.     int ret;
  700.     SECItem dataitem;
  701.     SECItem keyitem;
  702.     unsigned char *buf;
  703.     unsigned char *keybuf;
  704.     
  705.     ret = certdb_Seq(handle->permCertDB, &key, &data, R_FIRST);
  706.     if ( ret ) {
  707. return(SECFailure);
  708.     }
  709.     
  710.     do {
  711. buf = (unsigned char *)data.data;
  712. if ( buf[1] == (unsigned char)type ) {
  713.     dataitem.len = data.size;
  714.     dataitem.data = buf;
  715.             dataitem.type = siBuffer;
  716.     keyitem.len = key.size - SEC_DB_KEY_HEADER_LEN;
  717.     keybuf = (unsigned char *)key.data;
  718.     keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN];
  719.             keyitem.type = siBuffer;
  720.     
  721.     rv = (* callback)(&dataitem, &keyitem, type, udata);
  722.     if ( rv != SECSuccess ) {
  723. return(rv);
  724.     }
  725. }
  726.     } while ( certdb_Seq(handle->permCertDB, &key, &data, R_NEXT) == 0 );
  727.     return(SECSuccess);
  728. }
  729. typedef struct {
  730.     PermCertCallback certfunc;
  731.     CERTCertDBHandle *handle;
  732.     void *data;
  733. } PermCertCallbackState;
  734. /*
  735.  * traversal callback to decode certs and call callers callback
  736.  */
  737. static SECStatus
  738. certcallback(SECItem *dbdata, SECItem *dbkey, certDBEntryType type, void *data)
  739. {
  740.     PermCertCallbackState *mystate;
  741.     SECStatus rv;
  742.     certDBEntryCert entry;
  743.     SECItem entryitem;
  744.     CERTCertificate *cert;
  745.     PRArenaPool *arena = NULL;
  746.     
  747.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  748.     if ( arena == NULL ) {
  749. goto loser;
  750.     }
  751.     
  752.     mystate = (PermCertCallbackState *)data;
  753.     entry.common.version = (unsigned int)dbdata->data[0];
  754.     entry.common.type = (certDBEntryType)dbdata->data[1];
  755.     entry.common.flags = (unsigned int)dbdata->data[2];
  756.     entry.common.arena = arena;
  757.     
  758.     entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN;
  759.     entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN];
  760.     
  761.     rv = DecodeDBCertEntry(&entry, &entryitem);
  762.     if (rv != SECSuccess ) {
  763. goto loser;
  764.     }
  765.     entry.derCert.type = siBuffer;
  766.     
  767.     cert = CERT_DecodeDERCertificate(&entry.derCert, PR_FALSE,
  768.     entry.nickname);
  769.     cert->dbEntry = &entry;
  770.     cert->trust = &entry.trust;
  771.     cert->dbhandle = mystate->handle;
  772.     if ( CERT_IsCACert(cert, NULL) ||
  773.          (( cert->trust->sslFlags & CERTDB_VALID_CA ) ||
  774.           ( cert->trust->emailFlags & CERTDB_VALID_CA ) ||
  775.           ( cert->trust->objectSigningFlags & CERTDB_VALID_CA)) ) {
  776.         cert->nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
  777.     }
  778.     rv = (* mystate->certfunc)(cert, dbkey, mystate->data);
  779.     /* arena destroyed by SEC_DestroyCert */
  780.     CERT_DestroyCertificateNoLocking(cert);
  781.     return(rv);
  782. loser:
  783.     if ( arena ) {
  784. PORT_FreeArena(arena, PR_FALSE);
  785.     }
  786.     return(SECFailure);
  787. }
  788. /*
  789.  * Traverse all of the certificates in the permanent database and
  790.  * call the given function for each one; expect the caller to have lock.
  791.  */
  792. static SECStatus
  793. TraversePermCertsNoLocking(CERTCertDBHandle *handle,
  794.    SECStatus (* certfunc)(CERTCertificate *cert,
  795.   SECItem *k,
  796.   void *pdata),
  797.    void *udata )
  798. {
  799.     SECStatus rv;
  800.     PermCertCallbackState mystate;
  801.     mystate.certfunc = certfunc;
  802.     mystate.handle = handle;
  803.     mystate.data = udata;
  804.     rv = SEC_TraverseDBEntries(handle, certDBEntryTypeCert, certcallback,
  805.        (void *)&mystate);
  806.     
  807.     return(rv);
  808. }
  809. /*
  810.  * Traverse all of the certificates in the permanent database and
  811.  * call the given function for each one.
  812.  */
  813. SECStatus
  814. SEC_TraversePermCerts(CERTCertDBHandle *handle,
  815.       SECStatus (* certfunc)(CERTCertificate *cert, SECItem *k,
  816.     void *pdata),
  817.       void *udata )
  818. {
  819.     SECStatus rv;
  820.     CERT_LockDB(handle);
  821.     rv = TraversePermCertsNoLocking(handle, certfunc, udata);
  822.     CERT_UnlockDB(handle);
  823.     
  824.     return(rv);
  825. }
  826. /*
  827.  * Close the database
  828.  */
  829. void
  830. CERT_ClosePermCertDB(CERTCertDBHandle *handle)
  831. {
  832.     if ( handle ) {
  833. if ( handle->permCertDB ) {
  834.     if ( handle->statusConfig ) {
  835. PORT_Assert(handle->statusConfig->statusDestroy != NULL);
  836. (void) (* handle->statusConfig->statusDestroy)(handle->statusConfig);
  837. handle->statusConfig = NULL; /* Destroy frees the structure */
  838. PORT_Assert(handle->statusConfig == NULL);
  839.     }
  840.     certdb_Close( handle->permCertDB );
  841.     handle->permCertDB = 0;
  842. }
  843.     }
  844.     return;
  845. }
  846. /*
  847.  * Get the trust attributes from a certificate
  848.  */
  849. SECStatus
  850. CERT_GetCertTrust(CERTCertificate *cert, CERTCertTrust *trust)
  851. {
  852.     SECStatus rv;
  853.     
  854.     CERT_LockCertTrust(cert);
  855.     
  856.     if ( cert->trust == NULL ) {
  857. rv = SECFailure;
  858.     } else {
  859. *trust = *cert->trust;
  860. rv = SECSuccess;
  861.     }
  862.     
  863.     CERT_UnlockCertTrust(cert);
  864.     return(rv);
  865. }
  866. static char *
  867. cert_parseNickname(char *nickname)
  868. {
  869. char *cp;
  870. for (cp=nickname; *cp && *cp != ':'; cp++);
  871. if (*cp == ':') return cp++;
  872. return nickname;
  873. }
  874. /*
  875.  * Change the trust attributes of a certificate and make them permanent
  876.  * in the database.
  877.  */
  878. SECStatus
  879. CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert,
  880.     CERTCertTrust *trust)
  881. {
  882.     certDBEntryCert *entry;
  883.     int rv;
  884.     SECStatus ret;
  885.     
  886.     CERT_LockDB(handle);
  887.     CERT_LockCertTrust(cert);
  888.     /* only set the trust on permanent certs */
  889.     if ( cert->trust == NULL ) {
  890. ret = SECFailure;
  891. goto done;
  892.     }
  893.     *cert->trust = *trust;
  894.     if ( cert->dbEntry == NULL ) {
  895. ret = SECSuccess; /* not in permanent database */
  896. if ((cert->slot)  && PK11_IsReadOnly(cert->slot)) {
  897.     char *nickname = cert_parseNickname(cert->nickname);
  898.     ret = CERT_AddTempCertToPerm(cert, nickname, trust);
  899. goto done;
  900.     }
  901.     
  902.     entry = cert->dbEntry;
  903.     entry->trust = *trust;
  904.     
  905.     rv = WriteDBCertEntry(handle, entry);
  906.     if ( rv ) {
  907. ret = SECFailure;
  908. goto done;
  909.     }
  910.     ret = SECSuccess;
  911.     
  912. done:
  913.     CERT_UnlockCertTrust(cert);
  914.     CERT_UnlockDB(handle);
  915.     return(ret);
  916. }
  917. SECStatus
  918. CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
  919.        CERTCertTrust *trust)
  920. {
  921.     char *oldnn;
  922.     certDBEntryCert *entry;
  923.     SECStatus rv;
  924.     PRBool conflict;
  925.     SECStatus ret;
  926.     PORT_Assert(cert->dbhandle);
  927.     CERT_LockDB(cert->dbhandle);
  928.     
  929.     PORT_Assert(cert->istemp);
  930.     PORT_Assert(!cert->isperm);
  931.     PORT_Assert(!cert->dbEntry);
  932.     /* don't add a conflicting nickname */
  933.     conflict = SEC_CertNicknameConflict(nickname, &cert->derSubject,
  934. cert->dbhandle);
  935.     if ( conflict ) {
  936. ret = SECFailure;
  937. goto done;
  938.     }
  939.     
  940.     /* save old nickname so that we can delete it */
  941.     oldnn = cert->nickname;
  942.     entry = AddCertToPermDB(cert->dbhandle, cert, nickname, trust);
  943.     
  944.     if ( entry == NULL ) {
  945. ret = SECFailure;
  946. goto done;
  947.     }
  948.     
  949.     cert->nickname = (entry->nickname) ? PORT_ArenaStrdup(cert->arena,entry->nickname) : NULL;
  950.     cert->trust = &entry->trust;
  951.     cert->isperm = PR_TRUE;
  952.     cert->dbEntry = entry;
  953.     if ( nickname && oldnn && ( PORT_Strcmp(nickname, oldnn) != 0 ) ) {
  954. /* only delete the old one if they are not the same */
  955. /* delete old nickname from temp database */
  956. rv = SEC_DeleteTempNickname(cert->dbhandle, oldnn);
  957. if ( rv != SECSuccess ) {
  958.     /* do we care?? */
  959. }
  960.     }
  961.     /* add new nickname to temp database */
  962.     if ( cert->nickname ) {
  963. rv = SEC_AddTempNickname(cert->dbhandle, cert->nickname,
  964.  &cert->derSubject);
  965. if ( rv != SECSuccess ) {
  966.     ret = SECFailure;
  967.     goto done;
  968. }
  969.     }
  970.     
  971.     ret = SECSuccess;
  972. done:
  973.     CERT_UnlockDB(cert->dbhandle);
  974.     return(ret);
  975. }
  976. /*
  977.  * Open the certificate database and index databases.  Create them if
  978.  * they are not there or bad.
  979.  */
  980. SECStatus
  981. CERT_OpenCertDB(CERTCertDBHandle *handle, PRBool readOnly,
  982. CERTDBNameFunc namecb, void *cbarg)
  983. {
  984.     int rv;
  985.     certdb_InitDBLock();
  986.     
  987.     handle->dbMon = PR_NewMonitor();
  988.     PORT_Assert(handle->dbMon != NULL);
  989.     handle->spkDigestInfo = NULL;
  990.     handle->statusConfig = NULL;
  991.     /*
  992.      * Open the memory resident decoded cert database.
  993.      */
  994.     handle->tempCertDB = dbopen( 0, O_RDWR | O_CREAT, 0600, DB_HASH, 0 );
  995.     if ( !handle->tempCertDB ) {
  996. goto loser;
  997.     }
  998.     rv = SEC_OpenPermCertDB(handle, readOnly, namecb, cbarg);
  999.     if ( rv ) {
  1000. goto loser;
  1001.     }
  1002.     return (SECSuccess);
  1003.     
  1004. loser:
  1005.     PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1006.     
  1007.     if ( handle->tempCertDB ) {
  1008. certdb_Close(handle->tempCertDB);
  1009. handle->tempCertDB = 0;
  1010.     }
  1011.     return(SECFailure);
  1012. }
  1013. static char *
  1014. certDBFilenameCallback(void *arg, int dbVersion)
  1015. {
  1016.     return(PORT_Strdup((char *)arg));
  1017. }
  1018. SECStatus
  1019. CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname,
  1020. PRBool readOnly)
  1021. {
  1022.     return(CERT_OpenCertDB(handle, readOnly, certDBFilenameCallback,
  1023.    (void *)certdbname));
  1024. }
  1025. /*
  1026.  * Add a nickname to the temp database
  1027.  */
  1028. SECStatus
  1029. SEC_AddTempNickname(CERTCertDBHandle *handle, char *nickname,
  1030.     SECItem *subjectName)
  1031. {
  1032.     DBT namekey;
  1033.     int ret;
  1034.     SECItem nameitem;
  1035.     SECStatus rv;
  1036.     DBT keydata;
  1037.     PRArenaPool *arena = NULL;
  1038.     SECItem tmpitem;
  1039.     
  1040.     PORT_Assert(nickname != NULL);
  1041.     
  1042.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1043.     if ( arena == NULL ) {
  1044. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1045. goto loser;
  1046.     }
  1047.     rv = EncodeDBNicknameKey(nickname, arena, &nameitem);
  1048.     if ( rv != SECSuccess ) {
  1049. goto loser;
  1050.     }
  1051.     namekey.data = nameitem.data;
  1052.     namekey.size = nameitem.len;
  1053.     /* see if an entry already exists */
  1054.     ret = certdb_Get(handle->tempCertDB, &namekey, &keydata, 0);
  1055.     if ( ret == 0 ) {
  1056. /* found in temp database */
  1057. tmpitem.data = (unsigned char*)keydata.data;
  1058. tmpitem.len = keydata.size;
  1059. if ( SECITEM_CompareItem(subjectName, &tmpitem) == SECEqual ) {
  1060.     /* same subject name */
  1061.     goto done;
  1062. } else {
  1063.     /* different subject name is an error */
  1064.     goto loser;
  1065. }
  1066.     }
  1067.     
  1068.     keydata.data = subjectName->data;
  1069.     keydata.size = subjectName->len;
  1070.     
  1071.     /* put into temp byname index */
  1072.     ret = certdb_Put(handle->tempCertDB, &namekey, &keydata, R_NOOVERWRITE);
  1073.     if ( ret ) {
  1074. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1075. goto loser;
  1076.     }
  1077. done:
  1078.     PORT_FreeArena(arena, PR_FALSE);
  1079.     return(SECSuccess);
  1080. loser:
  1081.     if ( arena ) {
  1082. PORT_FreeArena(arena, PR_FALSE);
  1083.     }
  1084.     return(SECFailure);
  1085. }
  1086. SECStatus
  1087. SEC_DeleteTempNickname(CERTCertDBHandle *handle, char *nickname)
  1088. {
  1089.     DBT namekey;
  1090.     SECStatus rv;
  1091.     PRArenaPool *arena = NULL;
  1092.     SECItem nameitem;
  1093.     int ret;
  1094.     
  1095.     PORT_Assert(nickname != NULL);
  1096.     if ( nickname == NULL ) {
  1097. return(SECSuccess);
  1098.     }
  1099.     
  1100.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1101.     if ( arena == NULL ) {
  1102. PORT_SetError(SEC_ERROR_NO_MEMORY);
  1103. goto loser;
  1104.     }
  1105.     /* format a database key based on the nickname */
  1106.     if ( nickname ) {
  1107. rv = EncodeDBNicknameKey(nickname, arena, &nameitem);
  1108. if ( rv != SECSuccess ) {
  1109.     goto loser;
  1110. }
  1111. namekey.data = nameitem.data;
  1112. namekey.size = nameitem.len;
  1113. ret = certdb_Del(handle->tempCertDB, &namekey, 0);
  1114. if ( ret ) {
  1115.     goto loser;
  1116. }
  1117.     }
  1118.     PORT_FreeArena(arena, PR_FALSE);
  1119.     
  1120.     return(SECSuccess);
  1121. loser:
  1122.     if ( arena ) {
  1123. PORT_FreeArena(arena, PR_FALSE);
  1124.     }
  1125.     return(SECFailure);
  1126. }
  1127. /*
  1128.  * Decode a certificate and enter it into the temporary certificate database.
  1129.  * Deal with nicknames correctly
  1130.  *
  1131.  * nickname is only used if isperm == PR_TRUE
  1132.  *
  1133.  * This is the private entry point, and locking is optional
  1134.  */
  1135. static CERTCertificate *
  1136. NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, char *nickname,
  1137.    PRBool isperm, PRBool copyDER, PRBool lockdb)
  1138. {
  1139.     DBT key;
  1140.     DBT data;
  1141.     int status;
  1142.     CERTCertificate *cert = NULL;
  1143.     PRBool promoteError = PR_TRUE;
  1144.     PRArenaPool *arena = NULL;
  1145.     SECItem keyitem;
  1146.     SECStatus rv;
  1147.     
  1148.     if ( isperm == PR_FALSE ) {
  1149. cert = CERT_FindCertByDERCert(handle, derCert);
  1150. if ( cert ) {
  1151.     return(cert);
  1152. }
  1153. nickname = NULL;
  1154.     }
  1155.     if ( lockdb ) {
  1156. CERT_LockDB(handle);
  1157.     }
  1158.     
  1159.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1160.     if ( arena == NULL ) {
  1161. goto loser;
  1162.     }
  1163.     
  1164.     cert = CERT_DecodeDERCertificate(derCert, copyDER, nickname );
  1165.     
  1166.     if ( cert == NULL ) {
  1167. /* We want to save the decoding error here */
  1168. promoteError = PR_FALSE;
  1169. goto loser;
  1170.     }
  1171.     cert->dbhandle = handle;
  1172.     /* only save pointer to cert in database */
  1173.     data.data = &cert;
  1174.     data.size = sizeof(cert);
  1175.     /* if this is a perm cert, then it is already in the subject db */
  1176.     if ( isperm == PR_FALSE ) {
  1177. /* enter into the subject index */
  1178. rv = AddTempCertToSubjectList(cert);
  1179. if ( rv != SECSuccess ) {
  1180.     goto loser;
  1181. }
  1182. /*
  1183.  * Since it's not a perm cert, add it to the key hash lookup; if it
  1184.  * is permanent it will either already be there or will get put there
  1185.  * later along with the rest of the perm certs.  A failure of the
  1186.  * addition does not seem to warrant failing this whole function,
  1187.  * so we intentionally ignore the returned status.
  1188.  */
  1189. (void) AddCertToSPKDigestTable(handle, cert);
  1190.     } else {
  1191. cert->subjectList = FindSubjectList(cert->dbhandle, &cert->derSubject,
  1192.     PR_FALSE);
  1193.     }
  1194.     
  1195.     rv = EncodeDBCertKey(&cert->certKey, arena, &keyitem);
  1196.     if ( rv != SECSuccess ) {
  1197. goto loser;
  1198.     }
  1199.     
  1200.     key.data = keyitem.data;
  1201.     key.size = keyitem.len;
  1202.     
  1203.     /* enter into main db */
  1204.     status = certdb_Put(handle->tempCertDB, &key, &data, R_NOOVERWRITE);
  1205.     if ( status ) {
  1206. goto loser;
  1207.     }
  1208.     if ( cert->nickname ) {
  1209. status = SEC_AddTempNickname(handle, cert->nickname,
  1210.      &cert->derSubject);
  1211. if ( status ) {
  1212.     promoteError = PR_FALSE;
  1213.     goto loser;
  1214. }
  1215.     }
  1216.     cert->isperm = isperm;
  1217.     cert->istemp = PR_TRUE;
  1218.     
  1219.     PORT_FreeArena(arena, PR_FALSE);
  1220.     if ( lockdb ) {
  1221. CERT_UnlockDB(handle);
  1222.     }
  1223.     return(cert);
  1224. loser:
  1225.     if ( cert ) {
  1226. CERT_DestroyCertificateNoLocking(cert);
  1227.     }
  1228.     
  1229.     if ( arena ) {
  1230. PORT_FreeArena(arena, PR_FALSE);
  1231.     }
  1232.     if ( promoteError ) {
  1233. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1234.     }
  1235.     if ( lockdb ) {
  1236. CERT_UnlockDB(handle);
  1237.     }
  1238.     return(0);
  1239. }
  1240. /*
  1241.  * Decode a certificate and enter it into the temporary certificate database.
  1242.  * Deal with nicknames correctly
  1243.  *
  1244.  * nickname is only used if isperm == PR_TRUE
  1245.  *
  1246.  * This is the public entry point and does locking.
  1247.  */
  1248. CERTCertificate *
  1249. CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
  1250. char *nickname, PRBool isperm, PRBool copyDER)
  1251. {
  1252.     return( NewTempCertificate(handle, derCert, nickname, isperm, copyDER,
  1253.        PR_TRUE) );
  1254. }
  1255. /*
  1256.  * Decode a permanent certificate and enter it into the temporary certificate
  1257.  * database.
  1258.  */
  1259. static CERTCertificate *
  1260. SEC_AddPermCertToTemp(CERTCertDBHandle *handle, certDBEntryCert *entry)
  1261. {
  1262.     CERTCertificate *cert;
  1263.     /* we already hold the lock */
  1264.     cert = NewTempCertificate(handle, &entry->derCert, entry->nickname,
  1265.       PR_TRUE, PR_TRUE, PR_FALSE);
  1266.     if ( !cert ) {
  1267. return(0);
  1268.     }
  1269.     cert->dbEntry = entry;
  1270.     cert->trust = &entry->trust;
  1271.     
  1272.     return(cert);
  1273. }
  1274. SECStatus
  1275. CERT_DeleteTempCertificate(CERTCertificate *cert)
  1276. {
  1277.     SECStatus rv;
  1278.     DBT nameKey;
  1279.     CERTCertDBHandle *handle;
  1280.     SECItem keyitem;
  1281.     PRArenaPool *arena;
  1282.     int ret;
  1283.     
  1284.     handle = cert->dbhandle;
  1285.     if ( !cert->istemp ) {
  1286. return(SECSuccess);
  1287.     }
  1288.     
  1289.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1290.     if ( arena == NULL ) {
  1291. goto loser;
  1292.     }
  1293.    
  1294.     if (cert->slot) {
  1295. PK11_FreeSlot(cert->slot);
  1296. cert->slot = NULL;
  1297. cert->pkcs11ID = CK_INVALID_KEY;
  1298.     }
  1299.     
  1300.     /* delete from subject list (also takes care of nickname) */
  1301.     rv = RemoveTempCertFromSubjectList(cert);
  1302.     if ( rv != SECSuccess ) {
  1303. goto loser;
  1304.     }
  1305.     
  1306.     if ( !cert->isperm ) {
  1307. /*
  1308.  * Remove the cert from the subject public key digest table,
  1309.  * though we do not care if the removal fails (perhaps meaning
  1310.  * the cert wasn't even there).
  1311.  */
  1312. (void) RemoveCertFromSPKDigestTable(handle, cert);
  1313.     }
  1314.     rv = EncodeDBCertKey(&cert->certKey, arena, &keyitem);
  1315.     if ( rv != SECSuccess ) {
  1316. goto loser;
  1317.     }
  1318.     
  1319.     nameKey.data = keyitem.data;
  1320.     nameKey.size = keyitem.len;
  1321.     /* delete the cert */
  1322.     ret = certdb_Del(handle->tempCertDB, &nameKey, 0);
  1323.     if ( ret ) {
  1324. goto loser;
  1325.     }
  1326.     cert->istemp = PR_FALSE;
  1327.     PORT_FreeArena(arena, PR_FALSE);
  1328.     return(SECSuccess);
  1329. loser:
  1330.     if ( arena ) {
  1331. PORT_FreeArena(arena, PR_FALSE);
  1332.     }
  1333.     return(SECFailure);
  1334. }
  1335. /*
  1336.  * Lookup a certificate in the databases.
  1337.  */
  1338. static CERTCertificate *
  1339. FindCertByKey(CERTCertDBHandle *handle, SECItem *certKey, PRBool lockdb)
  1340. {
  1341.     DBT tmpdata;
  1342.     int ret;
  1343.     SECItem keyitem;
  1344.     DBT key;
  1345.     SECStatus rv;
  1346.     CERTCertificate *cert = NULL;
  1347.     PRArenaPool *arena = NULL;
  1348.     certDBEntryCert *entry;
  1349.     PRBool locked = PR_FALSE;
  1350.     
  1351.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1352.     if ( arena == NULL ) {
  1353. goto loser;
  1354.     }
  1355.     
  1356.     rv = EncodeDBCertKey(certKey, arena, &keyitem);
  1357.     if ( rv != SECSuccess ) {
  1358. goto loser;
  1359.     }
  1360.     
  1361.     key.data = keyitem.data;
  1362.     key.size = keyitem.len;
  1363.     
  1364.     if ( lockdb ) {
  1365. locked = PR_TRUE;
  1366. CERT_LockDB(handle);
  1367.     }
  1368.     /* lookup in the temporary database */
  1369.     ret = certdb_Get( handle->tempCertDB, &key, &tmpdata, 0 );
  1370.     /* error accessing the database */
  1371.     if ( ret < 0 ) {
  1372. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1373. goto loser;
  1374.     }
  1375.     if ( ret == 0 ) { /* found in temp database */
  1376. if ( tmpdata.size != sizeof(CERTCertificate *) ) {
  1377.     PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1378.     goto loser;
  1379. }
  1380. PORT_Memcpy(&cert, tmpdata.data, tmpdata.size);
  1381. CERT_LockCertRefCount(cert);
  1382. cert->referenceCount++;
  1383. CERT_UnlockCertRefCount(cert);
  1384.     }
  1385.     if ( ret != 0 ) {
  1386. /* not found in temporary database */
  1387. /* find in perm database */
  1388. entry = SEC_FindPermCertByKey(handle, certKey);
  1389. if ( entry == NULL ) {
  1390.     goto loser;
  1391. }
  1392.     
  1393. cert = SEC_AddPermCertToTemp(handle, entry);
  1394.     }
  1395. loser:
  1396.     if ( locked ) {
  1397. CERT_UnlockDB(handle);
  1398.     }
  1399.     if ( arena ) {
  1400. PORT_FreeArena(arena, PR_FALSE);
  1401.     }
  1402.     
  1403.     return(cert);
  1404. }
  1405. /*
  1406.  * Lookup a certificate in the databases, with locking
  1407.  */
  1408. CERTCertificate *
  1409. CERT_FindCertByKey(CERTCertDBHandle *handle, SECItem *certKey)
  1410. {
  1411.     return(FindCertByKey(handle, certKey, PR_TRUE));
  1412. }
  1413. /*
  1414.  * Lookup a certificate in the databases without locking
  1415.  */
  1416. CERTCertificate *
  1417. CERT_FindCertByKeyNoLocking(CERTCertDBHandle *handle, SECItem *certKey)
  1418. {
  1419.     return(FindCertByKey(handle, certKey, PR_FALSE));
  1420. }
  1421. /*
  1422.  * Generate a key from an issuerAndSerialNumber, and find the
  1423.  * associated cert in the database.
  1424.  */
  1425. CERTCertificate *
  1426. CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle, CERTIssuerAndSN *issuerAndSN)
  1427. {
  1428.     SECItem certKey;
  1429.     CERTCertificate *cert;
  1430.     
  1431.     certKey.len = issuerAndSN->serialNumber.len + issuerAndSN->derIssuer.len;
  1432.     certKey.data = (unsigned char*)PORT_Alloc(certKey.len);
  1433.     
  1434.     if ( certKey.data == NULL ) {
  1435. return(0);
  1436.     }
  1437.     /* copy the serialNumber */
  1438.     PORT_Memcpy(certKey.data, issuerAndSN->serialNumber.data,
  1439.       issuerAndSN->serialNumber.len);
  1440.     /* copy the issuer */
  1441.     PORT_Memcpy( &certKey.data[issuerAndSN->serialNumber.len],
  1442.       issuerAndSN->derIssuer.data, issuerAndSN->derIssuer.len);
  1443.     cert = CERT_FindCertByKey(handle, &certKey);
  1444.     
  1445.     PORT_Free(certKey.data);
  1446.     
  1447.     return(cert);
  1448. }
  1449. /*
  1450.  * Lookup a certificate in the database by name
  1451.  */
  1452. CERTCertificate *
  1453. CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name)
  1454. {
  1455.     CERTCertificate *cert = NULL;
  1456.     CERTSubjectList *subjectList;
  1457.     
  1458.     CERT_LockDB(handle);
  1459.     subjectList = FindSubjectList(handle, name, PR_FALSE);
  1460.     if ( subjectList ) {
  1461. PORT_Assert(subjectList->head);
  1462. cert = CERT_FindCertByKeyNoLocking(handle,
  1463.    &subjectList->head->certKey);
  1464.     }
  1465.     CERT_UnlockDB(handle);
  1466.     return(cert);
  1467. }
  1468. /*
  1469.  * Lookup a certificate in the database by name and key ID
  1470.  */
  1471. CERTCertificate *
  1472. CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID)
  1473. {
  1474.     CERTCertificate *cert = NULL;
  1475.     CERTSubjectList *subjectList;
  1476.     CERTSubjectNode *node;
  1477.     CERT_LockDB(handle);
  1478.     /* find the list of certs for the given subject */
  1479.     subjectList = FindSubjectList(handle, name, PR_FALSE);
  1480.     if ( subjectList ) {
  1481. PORT_Assert(subjectList->head);
  1482. node = subjectList->head;
  1483. /* walk through the certs until we find one with a matching key ID */
  1484. while ( node ) {
  1485.     if ( SECITEM_CompareItem(keyID, &node->keyID) == SECEqual ) {
  1486. cert = CERT_FindCertByKeyNoLocking(handle, &node->certKey);
  1487. break;
  1488.     }
  1489.     node = node->next;
  1490. }
  1491.     }
  1492.     CERT_UnlockDB(handle);
  1493.     return(cert);
  1494. }
  1495. /*
  1496.  * look up a cert by its nickname string
  1497.  */
  1498. CERTCertificate *
  1499. CERT_FindCertByNickname(CERTCertDBHandle *handle, char *nickname)
  1500. {
  1501.     DBT tmpdata;
  1502.     DBT namekey;
  1503.     CERTCertificate *cert;
  1504.     SECStatus rv;
  1505.     int ret;
  1506.     SECItem keyitem;
  1507.     PRArenaPool *arena = NULL;
  1508.     certDBEntryCert *entry;
  1509.     
  1510.     PORT_Assert(nickname != NULL);
  1511.     
  1512.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1513.     if ( arena == NULL ) {
  1514. goto loser;
  1515.     }
  1516.     rv = EncodeDBNicknameKey(nickname, arena, &keyitem);
  1517.     if ( rv != SECSuccess ) {
  1518. goto loser;
  1519.     }
  1520.     
  1521.     namekey.data = keyitem.data;
  1522.     namekey.size = keyitem.len;
  1523.     
  1524.     /* lookup in the temporary database */
  1525.     ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
  1526.     /* error accessing the database */
  1527.     if ( ret < 0 ) {
  1528. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  1529. goto loser;
  1530.     }
  1531.     if ( ret == 0 ) { /* found in temp database */
  1532. SECItem nameitem;
  1533. nameitem.len = tmpdata.size;
  1534. nameitem.data = (unsigned char *)PORT_Alloc(tmpdata.size);
  1535. if ( nameitem.data == NULL ) {
  1536.     goto loser;
  1537. }
  1538. PORT_Memcpy(nameitem.data, tmpdata.data, nameitem.len);
  1539. cert = CERT_FindCertByName(handle, &nameitem);
  1540. PORT_Free(nameitem.data);
  1541.     } else { /* not found in temporary database */
  1542. CERT_LockDB(handle);
  1543. entry = SEC_FindPermCertByNickname(handle, nickname);
  1544. if ( entry == NULL ) {
  1545.     CERT_UnlockDB(handle);
  1546.     goto loser;
  1547. }
  1548.     
  1549. cert = SEC_AddPermCertToTemp(handle, entry);
  1550. CERT_UnlockDB(handle);
  1551.     }
  1552.     PORT_FreeArena(arena, PR_FALSE);
  1553.     return(cert);
  1554. loser:
  1555.     if ( arena ) {
  1556. PORT_FreeArena(arena, PR_FALSE);
  1557.     }
  1558.     
  1559.     return(0);
  1560. }
  1561. /*
  1562.  * look for the given DER certificate in the database
  1563.  */
  1564. CERTCertificate *
  1565. CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert)
  1566. {
  1567.     PRArenaPool *arena;
  1568.     SECItem certKey;
  1569.     SECStatus rv;
  1570.     CERTCertificate *cert = NULL;
  1571.     
  1572.     /* create a scratch arena */
  1573.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1574.     if ( arena == NULL ) {
  1575. return(NULL);
  1576.     }
  1577.     
  1578.     /* extract the database key from the cert */
  1579.     rv = CERT_KeyFromDERCert(arena, derCert, &certKey);
  1580.     if ( rv != SECSuccess ) {
  1581. goto loser;
  1582.     }
  1583.     /* find the certificate */
  1584.     cert = CERT_FindCertByKey(handle, &certKey);
  1585.     
  1586. loser:
  1587.     PORT_FreeArena(arena, PR_FALSE);
  1588.     return(cert);
  1589. }
  1590. /*
  1591.  * The following is bunch of types and code to allow looking up a certificate
  1592.  * by a hash of its subject public key.  Because the words "hash" and "key"
  1593.  * are overloaded and thus terribly confusing, I tried to disambiguate things.
  1594.  * - Where I could, I used "digest" instead of "hash" when referring to
  1595.  *   hashing of the subject public key.  The PLHashTable interfaces and
  1596.  *   our own HASH_Foo interfaces had to be left as is, obviously.  The latter
  1597.  *   should be thought of as "digest" in this case.
  1598.  * - There are three keys in use here -- the subject public key, the key
  1599.  *   used to do a lookup in the PLHashTable, and the key used to do a lookup
  1600.  *   in the cert database.  As the latter is a fairly pervasive interface,
  1601.  *   I left it alone.  The other two uses I changed to "spk" or "SPK" when
  1602.  *   referring to the subject public key, and "index" when referring to the
  1603.  *   key into the PLHashTable.
  1604.  */
  1605. typedef struct SPKDigestInfoStr {
  1606.     PLHashTable *table;
  1607.     PRBool permPopulated;
  1608. } SPKDigestInfo;
  1609. /*
  1610.  * Since the key hash information is "hidden" (in a void pointer in the handle)
  1611.  * these macros with the appropriate casts make it easy to get at the parts.
  1612.  */
  1613. #define SPK_DIGEST_TABLE(handle)
  1614. (((SPKDigestInfo *)(handle->spkDigestInfo))->table)
  1615. /*
  1616. ** Hash allocator ops for the SPKDigest hash table.  The rules are:
  1617. **   + The index and value fields are "owned" by the hash table, and are
  1618. **     freed when the table entry is deleted.
  1619. **   + Replacing a value in the table is not allowed, since the caller can't
  1620. **     tell whether the index field was used or not, resulting in a memory
  1621. **     leak.  (This is a bug in the PL_Hash routines.
  1622. */
  1623. static void * PR_CALLBACK
  1624. spkAllocTable(void *pool, PRSize size)
  1625. {
  1626. #if defined(XP_MAC)
  1627. #pragma unused (pool)
  1628. #endif
  1629.     return PR_MALLOC(size);
  1630. }
  1631. static void PR_CALLBACK
  1632. spkFreeTable(void *pool, void *item)
  1633. {
  1634. #if defined(XP_MAC)
  1635. #pragma unused (pool)
  1636. #endif
  1637.     PR_Free(item);
  1638. }
  1639. /* NOTE: the key argument here appears to be useless, since the RawAdd
  1640.  * routine in PL_Hash just uses the original anyway.
  1641.  */
  1642. static PLHashEntry * PR_CALLBACK
  1643. spkAllocEntry(void *pool, const void *key)
  1644. {
  1645. #if defined(XP_MAC)
  1646. #pragma unused (pool,key)
  1647. #endif
  1648.     return PR_NEW(PLHashEntry);
  1649. }
  1650. static void PR_CALLBACK
  1651. spkFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
  1652. {
  1653. #if defined(XP_MAC)
  1654. #pragma unused (pool)
  1655. #endif
  1656.     SECItem *value = (SECItem *)he->value;
  1657.     /* The flag should always be to free the whole entry.  Otherwise the
  1658.      * index field gets leaked because the caller can't tell whether
  1659.      * the "new" value (which is the same as the old) was used or not.
  1660.      */
  1661.     PORT_Assert(flag == HT_FREE_ENTRY);
  1662.     /* We always free the value */
  1663.     SECITEM_FreeItem(value, PR_TRUE);
  1664.     
  1665.     if (flag == HT_FREE_ENTRY)
  1666.     {
  1667.         /* Comes from BTOA, is this the right free call? */
  1668.         PORT_Free((char *)he->key);
  1669.         PR_Free(he);
  1670.     }
  1671. }
  1672. static PLHashAllocOps spkHashAllocOps = {
  1673.     spkAllocTable, spkFreeTable,
  1674.     spkAllocEntry, spkFreeEntry
  1675. };
  1676. /*
  1677.  * Create the key hash lookup table.  Note that the table, and the
  1678.  * structure which holds it and a little more information, is never freed.
  1679.  * This is because the temporary database is never actually closed out,
  1680.  * so there is no safe/obvious place to free the whole thing.
  1681.  *
  1682.  * The database must be locked already.
  1683.  */
  1684. static SECStatus
  1685. InitDBspkDigestInfo(CERTCertDBHandle *handle)
  1686. {
  1687.     SPKDigestInfo *spkDigestInfo;
  1688.     PLHashTable *table;
  1689.     PORT_Assert(handle != NULL);
  1690.     PORT_Assert(handle->spkDigestInfo == NULL);
  1691.     spkDigestInfo = PORT_ZAlloc(sizeof(SPKDigestInfo));
  1692.     if ( spkDigestInfo == NULL ) {
  1693. return(SECFailure);
  1694.     }
  1695.     table = PL_NewHashTable(128, PL_HashString, PL_CompareStrings,
  1696.     (PLHashComparator) SECITEM_ItemsAreEqual,
  1697.     &spkHashAllocOps, NULL);
  1698.     if ( table == NULL ) {
  1699. PORT_Free(spkDigestInfo);
  1700. return(SECFailure);
  1701.     }
  1702.     spkDigestInfo->table = table;
  1703.     handle->spkDigestInfo = spkDigestInfo;
  1704.     return(SECSuccess);
  1705. }
  1706. static SECHashObject *
  1707. OidTagToRawDigestObject(SECOidTag digestAlg)
  1708. {
  1709.     SECHashObject *rawDigestObject;
  1710.     switch (digestAlg) {
  1711.       case SEC_OID_MD2:
  1712. rawDigestObject = &SECRawHashObjects[HASH_AlgMD2];
  1713. break;
  1714.       case SEC_OID_MD5:
  1715. rawDigestObject = &SECRawHashObjects[HASH_AlgMD5];
  1716. break;
  1717.       case SEC_OID_SHA1:
  1718. rawDigestObject = &SECRawHashObjects[HASH_AlgSHA1];
  1719. break;
  1720.       default:
  1721. PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
  1722. rawDigestObject = NULL;
  1723. break;
  1724.     }
  1725.     return(rawDigestObject);
  1726. }
  1727. /*
  1728.  * Digest the cert's subject public key using the specified algorithm.
  1729.  * The necessary storage for the digest data is allocated.  If "fill" is
  1730.  * non-null, the data is put there, otherwise a SECItem is allocated.
  1731.  * Allocation from "arena" if it is non-null, heap otherwise.  Any problem
  1732.  * results in a NULL being returned (and an appropriate error set).
  1733.  */ 
  1734. SECItem *
  1735. CERT_SPKDigestValueForCert(PRArenaPool *arena, CERTCertificate *cert,
  1736.    SECOidTag digestAlg, SECItem *fill)
  1737. {
  1738.     SECHashObject *digestObject;
  1739.     void *digestContext;
  1740.     SECItem *result = NULL;
  1741.     void *mark = NULL;
  1742.     SECItem spk;
  1743.     if ( arena != NULL ) {
  1744. mark = PORT_ArenaMark(arena);
  1745.     }
  1746.     /*
  1747.      * This can end up being called before PKCS #11 is initialized,
  1748.      * so we have to use the raw digest functions.
  1749.      */
  1750.     digestObject = OidTagToRawDigestObject(digestAlg);
  1751.     if ( digestObject == NULL ) {
  1752. goto loser;
  1753.     }
  1754.     result = SECITEM_AllocItem(arena, fill, digestObject->length);
  1755.     if ( result == NULL ) {
  1756. goto loser;
  1757.     }
  1758.     /*
  1759.      * Copy just the length and data pointer (nothing needs to be freed)
  1760.      * of the subject public key so we can convert the length from bits
  1761.      * to bytes, which is what the digest function expects.
  1762.      */
  1763.     spk = cert->subjectPublicKeyInfo.subjectPublicKey;
  1764.     DER_ConvertBitString(&spk);
  1765.     /*
  1766.      * Now digest the value, using the specified algorithm.
  1767.      */
  1768.     digestContext = digestObject->create();
  1769.     if ( digestContext == NULL ) {
  1770. goto loser;
  1771.     }
  1772.     digestObject->begin(digestContext);
  1773.     digestObject->update(digestContext, spk.data, spk.len);
  1774.     digestObject->end(digestContext, result->data, &(result->len), result->len);
  1775.     digestObject->destroy(digestContext, PR_TRUE);
  1776.     if ( arena != NULL ) {
  1777. PORT_ArenaUnmark(arena, mark);
  1778.     }
  1779.     return(result);
  1780. loser:
  1781.     if ( arena != NULL ) {
  1782. PORT_ArenaRelease(arena, mark);
  1783.     } else {
  1784. if ( result != NULL ) {
  1785.     SECITEM_FreeItem(result, (fill == NULL) ? PR_TRUE : PR_FALSE);
  1786. }
  1787.     }
  1788.     return(NULL);
  1789. }
  1790. /*
  1791.  * Return the index for the spk digest lookup table for "spkDigest".
  1792.  *
  1793.  * Caller is responsible for freeing the returned string.
  1794.  */
  1795. static char *
  1796. spkDigestIndexFromDigest(SECItem *spkDigest)
  1797. {
  1798.     return BTOA_ConvertItemToAscii(spkDigest);
  1799. }
  1800. /*
  1801.  * Return the index for the spk digest lookup table for this certificate,
  1802.  * based on the specified digest algorithm.
  1803.  *
  1804.  * Caller is responsible for freeing the returned string.
  1805.  */
  1806. static char *
  1807. spkDigestIndexFromCert(CERTCertificate *cert, SECOidTag digestAlg)
  1808. {
  1809.     SECItem *spkDigest;
  1810.     char *index;
  1811.     spkDigest = CERT_SPKDigestValueForCert(NULL, cert, digestAlg, NULL);
  1812.     if ( spkDigest == NULL )
  1813. return(NULL);
  1814.     index = spkDigestIndexFromDigest(spkDigest);
  1815.     SECITEM_FreeItem(spkDigest, PR_TRUE);
  1816.     return(index);
  1817. }
  1818. /*
  1819.  * Remove the spk digest for the given cert from the spk digest table,
  1820.  * based on the given digest algorithm.
  1821.  *
  1822.  * The database must be locked already.
  1823.  */
  1824. static SECStatus
  1825. RemoveCertFromSPKDigestTableForAlg(CERTCertDBHandle *handle,
  1826.    CERTCertificate *cert, SECOidTag digestAlg)
  1827. {
  1828.     SECStatus rv = SECSuccess;
  1829.     char *index = NULL;
  1830.     PLHashTable *table;
  1831.     /* Expect to only be called if there is a table to work with. */
  1832.     PORT_Assert(handle->spkDigestInfo != NULL);
  1833.     table = SPK_DIGEST_TABLE(handle);
  1834.     PORT_Assert(table != NULL);
  1835.     index = spkDigestIndexFromCert(cert, digestAlg);
  1836.     if ( index == NULL ) {
  1837. rv = SECFailure;
  1838. goto done;
  1839.     }
  1840.     if ( PL_HashTableRemove(table, index) != PR_TRUE ) {
  1841. /* not found means nothing to remove, which is fine */
  1842.     }
  1843. done:
  1844.     if ( index != NULL ) {
  1845. PORT_Free(index);
  1846.     }
  1847.     return(rv);
  1848. }
  1849. /*
  1850.  * Remove the spk digests for the given cert from the spk digest table,
  1851.  * for all known digest algorithms.
  1852.  *
  1853.  * The database must be locked already.
  1854.  */
  1855. static SECStatus
  1856. RemoveCertFromSPKDigestTable(CERTCertDBHandle *handle, CERTCertificate *cert)
  1857. {
  1858.     /*
  1859.      * If no certs have been added yet, then nothing to do.
  1860.      */
  1861.     if ( handle->spkDigestInfo == NULL ) {
  1862. return(SECSuccess);
  1863.     }
  1864.     (void) RemoveCertFromSPKDigestTableForAlg(handle, cert, SEC_OID_MD2);
  1865.     (void) RemoveCertFromSPKDigestTableForAlg(handle, cert, SEC_OID_MD5);
  1866.     return RemoveCertFromSPKDigestTableForAlg(handle, cert, SEC_OID_SHA1);
  1867. }
  1868. /*
  1869.  * Add the spk digest for the given cert to the spk digest table,
  1870.  * based on the given digest algorithm.
  1871.  *
  1872.  * If a cert for the same spk digest is already in the table, choose whichever
  1873.  * cert is "newer".  (The other cert cannot be found via spk digest.)
  1874.  *
  1875.  * The database must be locked already.
  1876.  * 
  1877.  * XXX Note that this implementation results in leaking the index value.
  1878.  * Fixing that did not seem worth the trouble, given we will only leak
  1879.  * once per cert.  This whole thing should be done differently in the
  1880.  * new rewrite (Stan), and then the problem will go away.
  1881.  */
  1882. static SECStatus
  1883. AddCertToSPKDigestTableForAlg(CERTCertDBHandle *handle, CERTCertificate *cert,
  1884.       SECItem *certDBKey, SECOidTag digestAlg)
  1885. {
  1886.     SECStatus rv = SECFailure;
  1887.     SECItem *oldCertDBKey;
  1888.     PRBool addit = PR_TRUE;
  1889.     CERTCertificate *oldCert = NULL;
  1890.     char *index = NULL;
  1891.     PLHashTable *table;
  1892.     /*
  1893.      * After running some testing doing key hash lookups (like using OCSP),
  1894.      * if these are never hit, they can probably be removed.
  1895.      */
  1896.     PORT_Assert(handle != NULL);
  1897.     PORT_Assert(handle == cert->dbhandle);
  1898.     PORT_Assert(handle->spkDigestInfo != NULL);
  1899.     PORT_Assert((certDBKey == &cert->certKey)
  1900. || (SECITEM_CompareItem(certDBKey,
  1901. &cert->certKey) == SECEqual));
  1902.     table = SPK_DIGEST_TABLE(handle);
  1903.     PORT_Assert(table != NULL);
  1904.     index = spkDigestIndexFromCert(cert, digestAlg);
  1905.     if ( index == NULL ) {
  1906. goto loser;
  1907.     }
  1908.     /*
  1909.      * See if this cert's spk digest is already in the table.
  1910.      */
  1911.     oldCertDBKey = PL_HashTableLookup(table, index);
  1912.     if ( oldCertDBKey != NULL ) {
  1913. /*
  1914.  * The spk digest *is* already in the table.  We need to find that
  1915.  * cert and see -- if it is the same, then we can just leave as is.
  1916.  * Otherwise we have to choose which cert we want represented;
  1917.  * in that case the best plan I can think of is to hang onto the
  1918.  * most recent one.
  1919.  */
  1920. oldCert = CERT_FindCertByKey(handle, oldCertDBKey);
  1921. if ( oldCert != NULL ) {
  1922.     if ( cert == oldCert ) {
  1923. /* They are the same cert, so we are done. */
  1924. addit = PR_FALSE;
  1925.     } else if ( CERT_IsNewer(cert, oldCert) ) {
  1926. if ( PL_HashTableRemove(table, index) != PR_TRUE ) {
  1927.     goto loser;
  1928. }
  1929.     } else {
  1930. /* oldCert is "newer", so we are done. */
  1931. addit = PR_FALSE;
  1932.     }
  1933. }
  1934.     }
  1935.     if ( addit ) {
  1936. certDBKey = SECITEM_DupItem(certDBKey);
  1937. if ( certDBKey == NULL ) {
  1938.     goto loser;
  1939. }
  1940. if ( PL_HashTableAdd(table, index, certDBKey) == NULL ) {
  1941.     SECITEM_FreeItem(certDBKey, PR_TRUE);
  1942.     PORT_SetError(SEC_ERROR_NO_MEMORY);
  1943.     goto loser;
  1944. }
  1945. index = NULL; /* don't want to free it */
  1946.     }
  1947.     rv = SECSuccess;
  1948. loser:
  1949.     if ( index != NULL ) {
  1950. PORT_Free(index);
  1951.     }
  1952.     if ( oldCert != NULL ) {
  1953. CERT_DestroyCertificate(oldCert);
  1954.     }
  1955.     return(rv);
  1956. }
  1957. /*
  1958.  * Add the spk digest for the given cert to the spk digest table,
  1959.  * for all known digest algorithms.
  1960.  *
  1961.  * The database must be locked already, and the digest table already created.
  1962.  */
  1963. static SECStatus
  1964. AddCertToSPKDigestTableForAllAlgs(CERTCertDBHandle *handle,
  1965.   CERTCertificate *cert, SECItem *certDBKey)
  1966. {
  1967.     (void) AddCertToSPKDigestTableForAlg(handle, cert, certDBKey, SEC_OID_MD2);
  1968.     (void) AddCertToSPKDigestTableForAlg(handle, cert, certDBKey, SEC_OID_MD5);
  1969.     return AddCertToSPKDigestTableForAlg(handle, cert, certDBKey, SEC_OID_SHA1);
  1970. }
  1971. /*
  1972.  * Add the spk digests for the given cert to the spk digest table,
  1973.  * for all known digest algorithms.  (This function is called when a
  1974.  * new cert is added to the temporary database.)
  1975.  *
  1976.  * If the spk digest table does not yet exist, create it.
  1977.  *
  1978.  * In an ideal world, we would not hardwire the digest algorithms.
  1979.  * But it is the case that we do not currently support any digest
  1980.  * algorithms outside of these three.  In the newer, cleaned-up world,
  1981.  * this may be done differently.
  1982.  *
  1983.  * The database must be locked already.
  1984.  */
  1985. static SECStatus
  1986. AddCertToSPKDigestTable(CERTCertDBHandle *handle, CERTCertificate *cert)
  1987. {
  1988.     SECStatus rv;
  1989.     if ( handle->spkDigestInfo == NULL ) {
  1990. rv = InitDBspkDigestInfo(handle);
  1991. if ( rv != SECSuccess ) {
  1992.     return(rv);
  1993. }
  1994.     }
  1995.     return AddCertToSPKDigestTableForAllAlgs(handle, cert, &cert->certKey);
  1996. }
  1997. /*
  1998.  * Add the spk digest for the given cert to the spk digest table,
  1999.  * for all known digest algorithms.  This function is called while
  2000.  * traversing all of the certs in the permanent database -- since
  2001.  * that imposes some constraints on its arguments this routine is a
  2002.  * simple cover for the "real" interface.
  2003.  *
  2004.  * The database must be locked already, and the digest table already created.
  2005.  */
  2006. static SECStatus
  2007. AddCertToSPKDigestTableInTraversal(CERTCertificate *cert, SECItem *certDBKey,
  2008.    void *data)
  2009. {
  2010.     CERTCertDBHandle *handle = data;
  2011.     return AddCertToSPKDigestTableForAllAlgs(handle, cert, certDBKey);
  2012. }
  2013. /*
  2014.  * Add the spk digests for the all permanent certs to the spk digest table,
  2015.  * for all known digest algorithms.
  2016.  *
  2017.  * This locks the database, and then checks to make sure that the work
  2018.  * actually needs to get done.
  2019.  *
  2020.  * If the spk digest table does not yet exist, it is created.
  2021.  */
  2022. static SECStatus
  2023. PopulateSPKDigestTable(CERTCertDBHandle *handle)
  2024. {
  2025.     SPKDigestInfo *spkDigestInfo;
  2026.     SECStatus rv = SECSuccess;
  2027.     CERT_LockDB(handle);
  2028.     spkDigestInfo = handle->spkDigestInfo;
  2029.     if ( spkDigestInfo == NULL ) {
  2030. rv = InitDBspkDigestInfo(handle);
  2031. if ( rv != SECSuccess ) {
  2032.     return(rv);
  2033. }
  2034. spkDigestInfo = handle->spkDigestInfo;
  2035. PORT_Assert(spkDigestInfo != NULL);
  2036.     } else {
  2037. /*
  2038.  * Check to see if someone already did it; it is important to do
  2039.  * this after getting the lock.
  2040.  */
  2041. if ( spkDigestInfo->permPopulated == PR_TRUE ) {
  2042.     goto done;
  2043. }
  2044.     }
  2045.     rv = TraversePermCertsNoLocking(handle, AddCertToSPKDigestTableInTraversal,
  2046.     handle);
  2047.     if ( rv != SECSuccess ) {
  2048. goto done;
  2049.     }
  2050.     spkDigestInfo->permPopulated = PR_TRUE;
  2051. done:
  2052.     CERT_UnlockDB(handle);
  2053.     return(rv);
  2054. }
  2055. /*
  2056.  * Lookup a certificate by a digest of a subject public key.  If it is
  2057.  * found, it is returned (and must then be destroyed by the caller).
  2058.  * NULL is returned otherwise -- if there was a problem performing the
  2059.  * lookup, an appropriate error is set (e.g. SEC_ERROR_NO_MEMORY);
  2060.  * if the cert simply was not found, the error is SEC_ERROR_UNKNOWN_CERT.
  2061.  *
  2062.  * If the lookup table has not yet been created or populated, do that first.
  2063.  */
  2064. CERTCertificate *
  2065. CERT_FindCertBySPKDigest(CERTCertDBHandle *handle, SECItem *spkDigest)
  2066. {
  2067.     SPKDigestInfo *spkDigestInfo;
  2068.     char *index = NULL;
  2069.     SECItem *certDBKey;
  2070.     CERTCertificate *cert = NULL;
  2071.     PORT_Assert(handle != NULL);
  2072.     spkDigestInfo = handle->spkDigestInfo;
  2073.     if ( spkDigestInfo == NULL || spkDigestInfo->permPopulated != PR_TRUE ) {
  2074. if ( PopulateSPKDigestTable(handle) != SECSuccess ) {
  2075.     goto loser;
  2076. }
  2077.     }
  2078.     index = spkDigestIndexFromDigest(spkDigest);
  2079.     if ( index == NULL ) {
  2080. goto loser;
  2081.     }
  2082.     certDBKey = PL_HashTableLookup(SPK_DIGEST_TABLE(handle), index);
  2083.     if ( certDBKey != NULL ) {
  2084. cert = CERT_FindCertByKey(handle, certDBKey);
  2085.     }
  2086.     if ( cert == NULL ) {
  2087. PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
  2088.     }
  2089. loser:
  2090.     if ( index != NULL ) {
  2091. PORT_Free(index);
  2092.     }
  2093.     return(cert);
  2094. }
  2095. static void
  2096. DestroyCertificate(CERTCertificate *cert, PRBool lockdb)
  2097. {
  2098.     int refCount;
  2099.     CERTCertDBHandle *handle;
  2100.     
  2101.     if ( cert ) {
  2102. handle = cert->dbhandle;
  2103. /*
  2104.  * handle may be NULL, for example if the cert was created with
  2105.  * CERT_DecodeDERCertificate.
  2106.  */
  2107. if ( lockdb && handle ) {
  2108.     CERT_LockDB(handle);
  2109. }
  2110.         CERT_LockCertRefCount(cert);
  2111. PORT_Assert(cert->referenceCount > 0);
  2112. refCount = --cert->referenceCount;
  2113.         CERT_UnlockCertRefCount(cert);
  2114. if ( ( refCount == 0 ) && !cert->keepSession ) {
  2115.     certDBEntryCert *entry  = cert->dbEntry;
  2116.     PRArenaPool *    arena  = cert->arena;
  2117.     if ( cert->istemp ) {
  2118. CERT_DeleteTempCertificate(cert);
  2119.     }
  2120.     if ( entry ) {
  2121. DestroyDBEntry((certDBEntry *)entry);
  2122.             }
  2123.     /* zero cert before freeing. Any stale references to this cert
  2124.      * after this point will probably cause an exception.  */
  2125.     PORT_Memset(cert, 0, sizeof *cert);
  2126.     cert = NULL;
  2127.     
  2128.     /* free the arena that contains the cert. */
  2129.     PORT_FreeArena(arena, PR_FALSE);
  2130.         }
  2131. if ( lockdb && handle ) {
  2132.     CERT_UnlockDB(handle);
  2133. }
  2134.     }
  2135.     return;
  2136. }
  2137. void
  2138. CERT_DestroyCertificate(CERTCertificate *cert)
  2139. {
  2140.     DestroyCertificate(cert, PR_TRUE);
  2141.     return;
  2142. }
  2143. void
  2144. CERT_DestroyCertificateNoLocking(CERTCertificate *cert)
  2145. {
  2146.     DestroyCertificate(cert, PR_FALSE);
  2147.     return;
  2148. }
  2149. /*
  2150.  * cache a CRL from the permanent database into the temporary database
  2151.  */
  2152. CERTSignedCrl *
  2153. SEC_AddPermCrlToTemp(CERTCertDBHandle *handle, certDBEntryRevocation *entry)
  2154. {
  2155.     CERTSignedCrl *crl = NULL;
  2156.     DBT key;
  2157.     DBT data;
  2158.     int status;
  2159.     PRArenaPool *arena = NULL;
  2160.     SECItem keyitem;
  2161.     SECStatus rv;
  2162.     
  2163.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2164.     if ( arena == NULL ) {
  2165. goto loser;
  2166.     }
  2167.     
  2168.     crl = CERT_DecodeDERCrl(NULL, &entry->derCrl, 
  2169.        entry->common.type == certDBEntryTypeRevocation ? 
  2170. SEC_CRL_TYPE : SEC_KRL_TYPE);
  2171.     
  2172.     if ( crl == NULL ) {
  2173. goto loser;
  2174.     }
  2175.     /* only save pointer to cert in database */
  2176.     data.data = &crl;
  2177.     data.size = sizeof(crl);
  2178.     rv = EncodeDBGenericKey(&(crl->crl.derName), arena, 
  2179. &keyitem, entry->common.type);
  2180.     if ( rv != SECSuccess ) {
  2181. goto loser;
  2182.     }
  2183.     if (entry->url) {
  2184. int nnlen = PORT_Strlen(entry->url) + 1;
  2185. crl->url  = (char *)PORT_ArenaAlloc(crl->arena, nnlen);
  2186. if ( !crl->url ) {
  2187.     goto loser;
  2188. }
  2189. PORT_Memcpy(crl->url, entry->url, nnlen);
  2190.     } else {
  2191. crl->url = NULL;
  2192.     }
  2193.     
  2194.     key.data = keyitem.data;
  2195.     key.size = keyitem.len;
  2196.     
  2197.     /* enter into main db */
  2198.     status = certdb_Put(handle->tempCertDB, &key, &data, R_NOOVERWRITE);
  2199.     if ( status ) {
  2200. goto loser;
  2201.     }
  2202.     crl->istemp = PR_TRUE;
  2203.     crl->isperm = PR_TRUE;    
  2204.     crl->dbhandle = handle;
  2205.     crl->dbEntry = entry;
  2206.     
  2207.     PORT_FreeArena(arena, PR_FALSE);
  2208.     crl->keep = PR_TRUE;
  2209.     return(crl);
  2210. loser:
  2211.     if ( crl ) {
  2212. SEC_DestroyCrl(crl);
  2213.     }
  2214.     
  2215.     if ( arena ) {
  2216. PORT_FreeArena(arena, PR_FALSE);
  2217.     }
  2218.     
  2219.     PORT_SetError(SEC_ERROR_BAD_DATABASE);
  2220.     return(0);
  2221. }
  2222. SECStatus
  2223. SEC_DeleteTempCrl(CERTSignedCrl *crl)
  2224. {
  2225.     SECStatus rv;
  2226.     DBT nameKey;
  2227.     CERTCertDBHandle *handle;
  2228.     SECItem keyitem;
  2229.     PRArenaPool *arena;
  2230.     int ret;
  2231.     
  2232.     handle = crl->dbhandle;
  2233.     if ( !crl->istemp ) {
  2234. return(SECSuccess);
  2235.     }
  2236.     
  2237.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2238.     if ( arena == NULL ) {
  2239. goto loser;
  2240.     }
  2241.     rv = EncodeDBGenericKey
  2242.  (&crl->crl.derName, arena, &keyitem, crl->dbEntry->common.type);
  2243.     if ( rv != SECSuccess ) {
  2244. goto loser;
  2245.     }
  2246.     
  2247.     nameKey.data = keyitem.data;
  2248.     nameKey.size = keyitem.len;
  2249.     /* delete the cert */
  2250.     ret = certdb_Del(handle->tempCertDB, &nameKey, 0);
  2251.     if ( ret ) {
  2252. goto loser;
  2253.     }
  2254.     crl->istemp = PR_FALSE;
  2255.     PORT_FreeArena(arena, PR_FALSE);
  2256.     return(SECSuccess);
  2257. loser:
  2258.     if ( arena ) {
  2259. PORT_FreeArena(arena, PR_FALSE);
  2260.     }
  2261.     return(SECFailure);
  2262. }
  2263. /*
  2264.  * Lookup a CRL in the databases. We mirror the same fast caching data base
  2265.  *  caching stuff used by certificates....?
  2266.  */
  2267. CERTSignedCrl *
  2268. SEC_FindCrlByKey(CERTCertDBHandle *handle, SECItem *crlKey, int type)
  2269. {
  2270.     DBT tmpdata;
  2271.     int ret;
  2272.     SECItem keyitem;
  2273.     DBT key;
  2274.     SECStatus rv;
  2275.     CERTSignedCrl *crl = NULL;
  2276.     PRArenaPool *arena = NULL;
  2277.     certDBEntryRevocation *entry;
  2278.     certDBEntryType crlType = (type == SEC_CRL_TYPE) ?
  2279.  certDBEntryTypeRevocation : certDBEntryTypeKeyRevocation;
  2280.     
  2281.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2282.     if ( arena == NULL ) {
  2283. goto loser;
  2284.     }
  2285.     
  2286.     rv = EncodeDBGenericKey(crlKey, arena, &keyitem, crlType);
  2287.     if ( rv != SECSuccess ) {
  2288. goto loser;
  2289.     }
  2290.     
  2291.     key.data = keyitem.data;
  2292.     key.size = keyitem.len;
  2293.     
  2294.     /* lookup in the temporary database */
  2295.     ret = certdb_Get( handle->tempCertDB, &key, &tmpdata, 0 );
  2296.     /* error accessing the database */
  2297.     if ( ret < 0 ) {
  2298. PORT_SetError(SEC_ERROR_BAD_DATABASE);
  2299. goto loser;
  2300.     }
  2301.     if ( ret == 0 ) { /* found in temp database */
  2302. if ( tmpdata.size != sizeof(CERTSignedCrl *) ) {
  2303.     PORT_SetError(SEC_ERROR_BAD_DATABASE);
  2304.     goto loser;
  2305. }
  2306. PORT_Memcpy(&crl, tmpdata.data, tmpdata.size);
  2307. crl->referenceCount++;
  2308.     } else { /* not found in temporary database */
  2309. /* find in perm database */
  2310. entry = ReadDBCrlEntry(handle, crlKey, crlType);
  2311. if ( entry == NULL ) {
  2312.     goto loser;
  2313. }
  2314.     
  2315. crl = SEC_AddPermCrlToTemp(handle, entry);
  2316.     }
  2317. loser:
  2318.     if ( arena ) {
  2319. PORT_FreeArena(arena, PR_FALSE);
  2320.     }
  2321.     
  2322.     return(crl);
  2323. }
  2324. CERTSignedCrl *
  2325. SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
  2326. {
  2327. return SEC_FindCrlByKey(handle,crlKey,type);
  2328. }
  2329. CERTSignedCrl *
  2330. SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
  2331. {
  2332.     PRArenaPool *arena;
  2333.     SECItem crlKey;
  2334.     SECStatus rv;
  2335.     CERTSignedCrl *crl = NULL;
  2336.     
  2337.     /* create a scratch arena */
  2338.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2339.     if ( arena == NULL ) {
  2340. return(NULL);
  2341.     }
  2342.     
  2343.     /* extract the database key from the cert */
  2344.     rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
  2345.     if ( rv != SECSuccess ) {
  2346. goto loser;
  2347.     }
  2348.     /* find the crl */
  2349.     crl = SEC_FindCrlByKey(handle, &crlKey, type);
  2350.     
  2351. loser:
  2352.     PORT_FreeArena(arena, PR_FALSE);
  2353.     return(crl);
  2354. }
  2355. SECStatus
  2356. SEC_DestroyCrl(CERTSignedCrl *crl)
  2357. {
  2358.     if (crl) {
  2359. if (crl->referenceCount-- <= 1) {
  2360.     if (!crl->keep) {
  2361. SEC_DeleteTempCrl(crl);
  2362. if (crl->dbEntry) {
  2363.     DestroyDBEntry((certDBEntry *)crl->dbEntry);
  2364. }
  2365. PORT_FreeArena(crl->arena, PR_FALSE);
  2366.     }
  2367. }
  2368.     }
  2369.     return SECSuccess;
  2370. }
  2371. CERTSignedCrl *
  2372. cert_DBInsertCRL (CERTCertDBHandle *handle, char *url,
  2373.   CERTSignedCrl *newCrl, SECItem *derCrl, int type)
  2374. {
  2375.     CERTSignedCrl *oldCrl = NULL, *crl = NULL;
  2376.     certDBEntryRevocation *entry = NULL;
  2377.     PRArenaPool *arena = NULL;
  2378.     SECCertTimeValidity validity;
  2379.     certDBEntryType crlType = (type == SEC_CRL_TYPE) ?
  2380.  certDBEntryTypeRevocation : certDBEntryTypeKeyRevocation;
  2381.     SECStatus rv;
  2382.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2383.     if (arena == NULL) goto done;
  2384.     validity = SEC_CheckCrlTimes(&newCrl->crl,PR_Now());
  2385.     if ( validity == secCertTimeExpired) {
  2386. if (type == SEC_CRL_TYPE) {
  2387.     PORT_SetError(SEC_ERROR_CRL_EXPIRED);
  2388. } else {
  2389.     PORT_SetError(SEC_ERROR_KRL_EXPIRED);
  2390. }
  2391. goto done;
  2392.     } else if (validity == secCertTimeNotValidYet) {
  2393. if (type == SEC_CRL_TYPE) {
  2394.     PORT_SetError(SEC_ERROR_CRL_NOT_YET_VALID);
  2395. } else {
  2396.     PORT_SetError(SEC_ERROR_KRL_NOT_YET_VALID);
  2397. }
  2398. goto done;
  2399.     }
  2400.     oldCrl = SEC_FindCrlByKey(handle, &newCrl->crl.derName, type);
  2401.     /* if there is an old crl, make sure the one we are installing
  2402.      * is newer. If not, exit out, otherwise delete the old crl.
  2403.      */
  2404.     if (oldCrl != NULL) {
  2405. if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
  2406.     if (type == SEC_CRL_TYPE) {
  2407. PORT_SetError(SEC_ERROR_OLD_CRL);
  2408.     } else {
  2409. PORT_SetError(SEC_ERROR_OLD_KRL);
  2410.     }
  2411.     goto done;
  2412. }
  2413. if ((SECITEM_CompareItem(&newCrl->crl.derName, 
  2414.         &oldCrl->crl.derName) != SECEqual) &&
  2415.     (type == SEC_KRL_TYPE) ) {
  2416.     
  2417.     PORT_SetError(SEC_ERROR_CKL_CONFLICT);
  2418.     goto done;
  2419. }
  2420. /* if we have a url in the database, use that one */
  2421. if (oldCrl->url) {
  2422.     int nnlen = PORT_Strlen(oldCrl->url) + 1;
  2423.     url  = (char *)PORT_ArenaAlloc(arena, nnlen);
  2424.     if ( url != NULL ) {
  2425.         PORT_Memcpy(url, oldCrl->url, nnlen);
  2426.     }
  2427. }
  2428. /* really destroy this crl */
  2429. /* first drum it out of the permanment Data base */
  2430. SEC_DeletePermCRL(oldCrl);
  2431. /* then get rid of our reference to it... */
  2432. SEC_DestroyCrl(oldCrl);
  2433. oldCrl = NULL;
  2434.     }
  2435.     /* Write the new entry into the data base */
  2436.     entry = NewDBCrlEntry(derCrl, url, crlType, 0);
  2437.     if (entry == NULL) goto done;
  2438.     rv = WriteDBCrlEntry(handle, entry);
  2439.     if (rv != SECSuccess) goto done;
  2440.     crl = SEC_AddPermCrlToTemp(handle, entry);
  2441.     if (crl) entry = NULL; /*crl->dbEntry now points to entry data */
  2442.     crl->isperm = PR_TRUE;
  2443. done:
  2444.     if (entry) DestroyDBEntry((certDBEntry *)entry);
  2445.     if (arena) PORT_FreeArena(arena, PR_FALSE);
  2446.     if (oldCrl) SEC_DestroyCrl(oldCrl);
  2447.     return crl;
  2448. }
  2449. /*
  2450.  * create a new CRL from DER material.
  2451.  *
  2452.  * The signature on this CRL must be checked before you
  2453.  * load it. ???
  2454.  */
  2455. CERTSignedCrl *
  2456. SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
  2457. {
  2458.     CERTSignedCrl *newCrl = NULL, *crl = NULL;
  2459.     /* make this decode dates! */
  2460.     newCrl = CERT_DecodeDERCrl(NULL, derCrl, type);
  2461.     if (newCrl == NULL) {
  2462. if (type == SEC_CRL_TYPE) {
  2463.     PORT_SetError(SEC_ERROR_CRL_INVALID);
  2464. } else {
  2465.     PORT_SetError(SEC_ERROR_KRL_INVALID);
  2466. }
  2467. goto done;
  2468.     }
  2469.     crl = cert_DBInsertCRL (handle, url, newCrl, derCrl, type);
  2470. done:
  2471.     if (newCrl) PORT_FreeArena(newCrl->arena, PR_FALSE);
  2472.     return crl;
  2473. }
  2474. /*
  2475.  * replace the existing URL in the data base with a new one
  2476.  */
  2477. SECStatus
  2478. SEC_CrlReplaceUrl(CERTSignedCrl *crl,char *url) {
  2479.     SECStatus rv = SECFailure;
  2480.     certDBEntryRevocation *entry = NULL;
  2481.     int nnlen=0;
  2482.     SEC_DeletePermCRL(crl);
  2483.     /* Write the new entry into the data base */
  2484.     entry = NewDBCrlEntry(&crl->dbEntry->derCrl, url, crl->dbEntry->common.type, 0);
  2485.     if (entry == NULL) goto done;
  2486.     rv = WriteDBCrlEntry(crl->dbhandle, entry);
  2487.     if (rv != SECSuccess) goto done;
  2488.     if (url) {
  2489. nnlen = PORT_Strlen(url) + 1;
  2490. crl->url  = (char *)PORT_ArenaAlloc(crl->arena, nnlen);
  2491. if ( !crl->url ) {
  2492.     goto done;
  2493. }
  2494. PORT_Memcpy(crl->url, url, nnlen);
  2495.     } else {
  2496. crl->url = NULL;
  2497.     }
  2498. done:
  2499.     return rv;
  2500. }
  2501.     
  2502. /*
  2503.  * collect a linked list of CRL's
  2504.  */
  2505. static SECStatus CollectCrls(SECItem *dbdata, SECItem *dbkey, 
  2506. certDBEntryType type, void *data) {
  2507.     SECStatus rv;
  2508.     certDBEntryRevocation entry;
  2509.     SECItem entryitem;
  2510.     PRArenaPool *arena = NULL;
  2511.     CERTCrlHeadNode *head;
  2512.     CERTCrlNode *new_node;
  2513.     
  2514.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2515.     if ( arena == NULL ) {
  2516. goto loser;
  2517.     }
  2518.     
  2519.     head = (CERTCrlHeadNode *)data;
  2520.     entry.common.version = (unsigned int)dbdata->data[0];
  2521.     entry.common.type = (certDBEntryType)dbdata->data[1];
  2522.     entry.common.flags = (unsigned int)dbdata->data[2];
  2523.     entry.common.arena = arena;
  2524.     
  2525.     entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN;
  2526.     entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN];
  2527.     
  2528.     rv = DecodeDBCrlEntry(&entry, &entryitem);
  2529.     if (rv != SECSuccess ) {
  2530. goto loser;
  2531.     }
  2532.     new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
  2533.     if (new_node == NULL) {
  2534. goto loser;
  2535.     }
  2536.     new_node->type = (entry.common.type == certDBEntryTypeRevocation) ? 
  2537. SEC_CRL_TYPE : SEC_KRL_TYPE;
  2538.     new_node->crl=CERT_DecodeDERCrl(head->arena,&entry.derCrl,new_node->type);
  2539.     if (entry.url) {
  2540. int nnlen = PORT_Strlen(entry.url) + 1;
  2541. new_node->crl->url  = (char *)PORT_ArenaAlloc(head->arena, nnlen);
  2542. if ( !new_node->crl->url ) {
  2543.     goto loser;
  2544. }
  2545. PORT_Memcpy(new_node->crl->url, entry.url, nnlen);
  2546.     } else {
  2547. new_node->crl->url = NULL;
  2548.     }
  2549.     
  2550.     new_node->next = NULL;
  2551.     if (head->last) {
  2552. head->last->next = new_node;
  2553. head->last = new_node;
  2554.     } else {
  2555. head->first = head->last = new_node;
  2556.     }
  2557.     return (SECSuccess);
  2558.     
  2559. loser:
  2560.     if ( arena ) {
  2561. PORT_FreeArena(arena, PR_FALSE);
  2562.     }
  2563.     return(SECFailure);
  2564. }
  2565. SECStatus
  2566. SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
  2567. {
  2568.     CERTCrlHeadNode *head;
  2569.     PRArenaPool *arena = NULL;
  2570.     SECStatus rv;
  2571.     *nodes = NULL;
  2572.     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  2573.     if ( arena == NULL ) {
  2574. return SECFailure;
  2575.     }
  2576.     /* build a head structure */
  2577.     head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
  2578.     head->arena = arena;
  2579.     head->first = NULL;
  2580.     head->last = NULL;
  2581.     head->dbhandle = handle;
  2582.     /* Look up the proper crl types */
  2583.     *nodes = head;
  2584.     
  2585.     CERT_LockDB(handle);
  2586.     
  2587.     switch (type) {
  2588.     case SEC_CRL_TYPE:
  2589. rv = SEC_TraverseDBEntries(handle, certDBEntryTypeRevocation,
  2590. CollectCrls, (void *)head);
  2591. break;
  2592.     case SEC_KRL_TYPE:
  2593. rv = SEC_TraverseDBEntries(handle, certDBEntryTypeKeyRevocation,
  2594. CollectCrls, (void *)head);
  2595. break;
  2596.     case -1:
  2597. rv = SEC_TraverseDBEntries(handle, certDBEntryTypeKeyRevocation,
  2598. CollectCrls, (void *)head);
  2599. if (rv != SECSuccess) break;
  2600. rv = SEC_TraverseDBEntries(handle, certDBEntryTypeRevocation,
  2601. CollectCrls, (void *)head);
  2602. break;
  2603.     default:
  2604. rv = SECFailure;
  2605. break;
  2606.     }
  2607.     CERT_UnlockDB(handle);
  2608.     
  2609.     if (rv != SECSuccess) {
  2610. if ( arena ) {
  2611.     PORT_FreeArena(arena, PR_FALSE);
  2612.     *nodes = NULL;
  2613. }
  2614.     }
  2615.     return rv;
  2616. }
  2617. SECStatus
  2618. SEC_DeletePermCRL(CERTSignedCrl *crl) {
  2619.     SECStatus rv;
  2620.     if (crl == NULL) {
  2621. return SECFailure;
  2622.     }
  2623.     
  2624.     rv = DeleteDBCrlEntry(crl->dbhandle, &crl->crl.derName, 
  2625. crl->dbEntry->common.type);
  2626.     if (rv != SECSuccess) goto done;
  2627.     /* now force it to be freed when all the reference counts go */
  2628.     crl->keep = PR_FALSE;
  2629.     /* force it out of the temporary data base */
  2630.     SEC_DeleteTempCrl(crl);
  2631.   
  2632. done:
  2633.     return rv;
  2634. }
  2635. /*
  2636.  * find a cert by email address
  2637.  *
  2638.  * pick one that is a valid recipient, meaning that it is an encryption
  2639.  * cert.
  2640.  *
  2641.  */
  2642. static CERTCertificate*
  2643. find_smime_recipient_cert(CERTCertDBHandle* handle, const char* email_addr)
  2644. {
  2645.     CERTCertificate* cert = NULL;
  2646.     CERTCertList* certList = NULL;
  2647.     SECStatus rv;
  2648.     certList = CERT_CreateEmailAddrCertList(NULL, handle, (char*)email_addr,
  2649.     PR_Now(), PR_TRUE);
  2650.     if (certList == NULL) {
  2651. return NULL;
  2652.     }
  2653.     rv = CERT_FilterCertListByUsage(certList, certUsageEmailRecipient,
  2654.     PR_FALSE);
  2655.     if (!CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
  2656. cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
  2657.     }
  2658.     CERT_DestroyCertList(certList);
  2659.     return cert;    /* cert may point to a cert or may be NULL */
  2660. }
  2661. /*
  2662.  * This function has the logic that decides if another person's cert and
  2663.  * email profile from an S/MIME message should be saved.  It can deal with
  2664.  * the case when there is no profile.
  2665.  */
  2666. SECStatus
  2667. CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile,
  2668.       SECItem *profileTime)
  2669. {
  2670.     certDBEntrySMime *entry = NULL, *oldentry = NULL;
  2671.     int64 oldtime;
  2672.     int64 newtime;
  2673.     SECStatus rv;
  2674.     CERTCertificate *oldcert = NULL;
  2675.     PRBool saveit;
  2676.     CERTCertTrust trust;
  2677.     CERTCertTrust tmptrust;
  2678.     char *emailAddr;
  2679.     
  2680.     emailAddr = cert->emailAddr;
  2681.     
  2682.     PORT_Assert(emailAddr);
  2683.     if ( emailAddr == NULL ) {
  2684. goto loser;
  2685.     }
  2686.     saveit = PR_FALSE;
  2687.     
  2688.     oldcert = find_smime_recipient_cert(cert->dbhandle, emailAddr);
  2689. if (oldcert) {
  2690.     /* see if there is an entry already */
  2691. oldentry = ReadDBSMimeEntry(cert->dbhandle, emailAddr);
  2692. }
  2693.     
  2694.     /* both profileTime and emailProfile have to exist or not exist */
  2695.     if ( emailProfile == NULL ) {
  2696. profileTime = NULL;
  2697.     } else if ( profileTime == NULL ) {
  2698. emailProfile = NULL;
  2699.     }
  2700.    
  2701.     if ( oldentry == NULL ) {
  2702. /* no old entry for this address */
  2703. PORT_Assert(oldcert == NULL);
  2704. saveit = PR_TRUE;
  2705.     } else {
  2706. /* there was already a profile for this email addr */
  2707. if ( profileTime ) {
  2708.     /* we have an old and new profile - save whichever is more recent*/
  2709.     if ( oldentry->optionsDate.len == 0 ) {
  2710. /* always replace if old entry doesn't have a time */
  2711. oldtime = LL_MININT;
  2712.     } else {
  2713. rv = DER_UTCTimeToTime(&oldtime, &oldentry->optionsDate);
  2714. if ( rv != SECSuccess ) {
  2715.     goto loser;
  2716. }
  2717.     }
  2718.     
  2719.     rv = DER_UTCTimeToTime(&newtime, profileTime);
  2720.     if ( rv != SECSuccess ) {
  2721. goto loser;
  2722.     }
  2723.     if ( LL_CMP(newtime, >, oldtime ) ) {
  2724. /* this is a newer profile, save it and cert */
  2725. saveit = PR_TRUE;
  2726.     }
  2727. } else {
  2728.     /* we don't have a new profile or time */
  2729.     if ( oldentry->optionsDate.len == 0 ) {
  2730. /* the old entry doesn't have a time either, so compare certs*/
  2731. if ( CERT_IsNewer(cert, oldcert) ) {
  2732.     /* new cert is newer, use it instead */
  2733.     saveit = PR_TRUE;
  2734. }
  2735.     } else {
  2736. if (oldcert) {
  2737. if (CERT_IsNewer(cert, oldcert)) {
  2738. saveit = PR_TRUE;
  2739. }
  2740. } else {
  2741. saveit = PR_TRUE;
  2742. }
  2743.     }
  2744. }
  2745.     }
  2746.     if ( saveit ) {
  2747. if ( oldcert && ( oldcert != cert ) ) {
  2748.     /* old cert is different from new cert */
  2749.     if ( PORT_Memcmp(oldcert->trust, &trust, sizeof(trust)) == 0 ) {
  2750. /* old cert is only for e-mail, so delete it */
  2751. SEC_DeletePermCertificate(oldcert);
  2752.     } else {
  2753. /* old cert is for other things too, so just change trust */
  2754. tmptrust = *oldcert->trust;
  2755. tmptrust.emailFlags &= ( ~CERTDB_VALID_PEER );
  2756. rv = CERT_ChangeCertTrust(oldcert->dbhandle, oldcert,
  2757.   &tmptrust);
  2758. if ( rv != SECSuccess ) {
  2759.     goto loser;
  2760. }
  2761.     }
  2762. }
  2763. /* Subroutine */
  2764. /* now save the entry */
  2765. entry = NewDBSMimeEntry(emailAddr, &cert->derSubject, emailProfile,
  2766. profileTime, 0);
  2767. if ( entry == NULL ) {
  2768.     goto loser;
  2769. }
  2770. CERT_LockDB(cert->dbhandle);
  2771. rv = DeleteDBSMimeEntry(cert->dbhandle, emailAddr);
  2772. /* if delete fails, try to write new entry anyway... */
  2773. rv = WriteDBSMimeEntry(cert->dbhandle, entry);
  2774. if ( rv != SECSuccess ) {
  2775.     CERT_UnlockDB(cert->dbhandle);
  2776.     goto loser;
  2777. }
  2778. /* link subject entry back here */
  2779. rv = UpdateSubjectWithEmailAddr(cert, emailAddr);
  2780. if ( rv != SECSuccess ) {
  2781.     CERT_UnlockDB(cert->dbhandle);
  2782.     goto loser;
  2783. }
  2784. CERT_UnlockDB(cert->dbhandle);
  2785. /* End Subroutine */
  2786.     }
  2787.     rv = SECSuccess;
  2788.     goto done;
  2789.     
  2790. loser:
  2791.     rv = SECFailure;
  2792.     
  2793. done:
  2794.     if ( oldcert ) {
  2795. CERT_DestroyCertificate(oldcert);
  2796.     }
  2797.     
  2798.     if ( entry ) {
  2799. DestroyDBEntry((certDBEntry *)entry);
  2800.     }
  2801.     if ( oldentry ) {
  2802. DestroyDBEntry((certDBEntry *)oldentry);
  2803.     }
  2804.     
  2805.     return(rv);
  2806. }
  2807. CERTCertificate *
  2808. CERT_FindCertByEmailAddr(CERTCertDBHandle *handle, char *emailAddr)
  2809. {
  2810.     certDBEntrySMime *entry;
  2811.     CERTCertificate *cert = NULL;
  2812.     emailAddr = CERT_FixupEmailAddr(emailAddr);
  2813.     if ( emailAddr == NULL ) {
  2814. return(NULL);
  2815.     }
  2816.     
  2817.     entry = ReadDBSMimeEntry(handle, emailAddr);
  2818.     /* XXX - this will have to change when multiple certs per subject
  2819.      * are allowed
  2820.      */
  2821.     if ( entry != NULL ) {
  2822. cert = CERT_FindCertByName(handle, &entry->subjectName);
  2823.     }
  2824.     if ( entry ) {
  2825. DestroyDBEntry((certDBEntry *)entry);
  2826.     }
  2827.     PORT_Free(emailAddr);
  2828.     
  2829.     return(cert);
  2830. }
  2831. /*
  2832.  * find the smime symmetric capabilities profile for a given cert
  2833.  */
  2834. SECItem *
  2835. CERT_FindSMimeProfile(CERTCertificate *cert)
  2836. {
  2837.     certDBEntrySMime *entry;
  2838.     SECItem *retitem = NULL;
  2839.     
  2840.     PORT_Assert(cert->emailAddr != NULL);
  2841.     
  2842.     if ( cert->emailAddr == NULL ) {
  2843. return(NULL);
  2844.     }
  2845.     
  2846.     entry = ReadDBSMimeEntry(cert->dbhandle, cert->emailAddr);
  2847.     if ( entry ) {
  2848. retitem = SECITEM_DupItem(&entry->smimeOptions);
  2849. DestroyDBEntry((certDBEntry *)entry);
  2850.     }
  2851.     return(retitem);
  2852. }
  2853. CERTCertificate *
  2854. CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, char *name)
  2855. {
  2856.     CERTCertificate *cert;
  2857.     cert = CERT_FindCertByNickname(handle, name);
  2858.     if ( cert == NULL ) {
  2859. cert = CERT_FindCertByEmailAddr(handle, name);
  2860.     }
  2861.     return(cert);
  2862. }
  2863. PRBool
  2864. CERT_IsCertRevoked(CERTCertificate *cert)
  2865. {
  2866.     return(PR_FALSE);
  2867. }
  2868. CERTCertificate *
  2869. CERT_NextSubjectCert(CERTCertificate *cert)
  2870. {
  2871.     CERTSubjectNode *node;
  2872.     CERTCertificate *retcert = NULL;
  2873.     CERT_LockDB(cert->dbhandle);
  2874.     
  2875.     node = FindCertSubjectNode(cert);
  2876.     PORT_Assert(node != NULL);
  2877.     
  2878.     if ( node->next != NULL ) {
  2879. retcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
  2880.       &node->next->certKey);
  2881.     }
  2882.     CERT_UnlockDB(cert->dbhandle);
  2883.     return(retcert);
  2884. }
  2885. CERTCertificate *
  2886. CERT_PrevSubjectCert(CERTCertificate *cert)
  2887. {
  2888.     CERTSubjectNode *node;
  2889.     CERTCertificate *retcert = NULL;
  2890.     
  2891.     CERT_LockDB(cert->dbhandle);
  2892.     node = FindCertSubjectNode(cert);
  2893.     PORT_Assert(node != NULL);
  2894.     
  2895.     if ( node->prev != NULL ) {
  2896. retcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
  2897.       &node->prev->certKey);
  2898.     }
  2899.     CERT_UnlockDB(cert->dbhandle);
  2900.     return(retcert);
  2901. }
  2902. SECStatus
  2903. CERT_SaveImportedCert(CERTCertificate *cert, SECCertUsage usage,
  2904.       PRBool caOnly, char *nickname)
  2905. {
  2906.     SECStatus rv;
  2907.     PRBool saveit;
  2908.     CERTCertTrust trust;
  2909.     CERTCertTrust tmptrust;
  2910.     PRBool isCA;
  2911.     unsigned int certtype;
  2912.     PRBool freeNickname = PR_FALSE;
  2913.     
  2914.     isCA = CERT_IsCACert(cert, NULL);
  2915.     if ( caOnly && ( !isCA ) ) {
  2916. return(SECSuccess);
  2917.     }
  2918.     
  2919.     saveit = PR_TRUE;
  2920.     
  2921.     PORT_Memset((void *)&trust, 0, sizeof(trust));
  2922.     certtype = cert->nsCertType;
  2923.     /* if no CA bits in cert type, then set all CA bits */
  2924.     if ( isCA && ( ! ( certtype & NS_CERT_TYPE_CA ) ) ) {
  2925. certtype |= NS_CERT_TYPE_CA;
  2926.     }
  2927.     /* if no app bits in cert type, then set all app bits */
  2928.     if ( ( !isCA ) && ( ! ( certtype & NS_CERT_TYPE_APP ) ) ) {
  2929. certtype |= NS_CERT_TYPE_APP;
  2930.     }
  2931.     if ( isCA && !nickname ) {
  2932. nickname = CERT_MakeCANickname(cert);
  2933. if ( nickname != NULL ) {
  2934.     freeNickname = PR_TRUE;
  2935. }
  2936.     }
  2937.     
  2938.     switch ( usage ) {
  2939.       case certUsageEmailSigner:
  2940.       case certUsageEmailRecipient:
  2941. if ( isCA ) {
  2942.     if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
  2943. trust.emailFlags = CERTDB_VALID_CA;
  2944.     }
  2945. } else {
  2946.     PORT_Assert(nickname == NULL);
  2947.     if ( cert->emailAddr == NULL ) {
  2948. saveit = PR_FALSE;
  2949.     }
  2950.     
  2951.     if ( certtype & NS_CERT_TYPE_EMAIL ) {
  2952. trust.emailFlags = CERTDB_VALID_PEER;
  2953. if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
  2954.     /* don't save it if KeyEncipherment is not allowed */
  2955.     saveit = PR_FALSE;
  2956. }
  2957.     }
  2958. }
  2959. break;
  2960.       case certUsageUserCertImport:
  2961. if ( isCA ) {
  2962.     if ( certtype & NS_CERT_TYPE_SSL_CA ) {
  2963. trust.sslFlags = CERTDB_VALID_CA;
  2964.     }
  2965.     
  2966.     if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
  2967. trust.emailFlags = CERTDB_VALID_CA;
  2968.     }
  2969.     
  2970.     if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
  2971. trust.objectSigningFlags = CERTDB_VALID_CA;
  2972.     }
  2973.     
  2974. } else {
  2975.     if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
  2976. trust.sslFlags = CERTDB_VALID_PEER;
  2977.     }
  2978.     
  2979.     if ( certtype & NS_CERT_TYPE_EMAIL ) {
  2980. trust.emailFlags = CERTDB_VALID_PEER;
  2981.     }
  2982.     
  2983.     if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
  2984. trust.objectSigningFlags = CERTDB_VALID_PEER;
  2985.     }
  2986. }
  2987. break;
  2988.       default: /* XXX added to quiet warnings; no other cases needed? */
  2989. break;
  2990.     }
  2991.     if ( (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags) == 0 ){
  2992. saveit = PR_FALSE;
  2993.     }
  2994.     if ( saveit ) {
  2995. if ( cert->isperm ) {
  2996.     /* Cert already in the DB.  Just adjust flags */
  2997.     tmptrust = *cert->trust;
  2998.     tmptrust.sslFlags |= trust.sslFlags;
  2999.     tmptrust.emailFlags |= trust.emailFlags;
  3000.     tmptrust.objectSigningFlags |= trust.objectSigningFlags;
  3001.     
  3002.     rv = CERT_ChangeCertTrust(cert->dbhandle, cert,
  3003.       &tmptrust);
  3004.     if ( rv != SECSuccess ) {
  3005. goto loser;
  3006.     }
  3007. } else {
  3008.     /* Cert not already in the DB.  Add it */
  3009.     rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
  3010.     if ( rv != SECSuccess ) {
  3011. goto loser;
  3012.     }
  3013. }
  3014.     }
  3015.     rv = SECSuccess;
  3016.     goto done;
  3017. loser:
  3018.     rv = SECFailure;
  3019. done:
  3020.     if ( freeNickname ) {
  3021. PORT_Free(nickname);
  3022.     }
  3023.     
  3024.     return(rv);
  3025. }
  3026. SECStatus
  3027. CERT_ChangeCertTrustByUsage(CERTCertDBHandle *certdb,
  3028.     CERTCertificate *cert, SECCertUsage usage)
  3029. {
  3030.     SECStatus rv;
  3031.     CERTCertTrust trust;
  3032.     CERTCertTrust tmptrust;
  3033.     unsigned int certtype;
  3034.     PRBool saveit;
  3035.     
  3036.     saveit = PR_TRUE;
  3037.     
  3038.     PORT_Memset((void *)&trust, 0, sizeof(trust));
  3039.     certtype = cert->nsCertType;
  3040.     /* if no app bits in cert type, then set all app bits */
  3041.     if ( ! ( certtype & NS_CERT_TYPE_APP ) ) {
  3042. certtype |= NS_CERT_TYPE_APP;
  3043.     }
  3044.     switch ( usage ) {
  3045.       case certUsageEmailSigner:
  3046.       case certUsageEmailRecipient:
  3047. if ( certtype & NS_CERT_TYPE_EMAIL ) {
  3048.      trust.emailFlags = CERTDB_VALID_PEER;
  3049.      if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
  3050. /* don't save it if KeyEncipherment is not allowed */
  3051. saveit = PR_FALSE;
  3052.     }
  3053. }
  3054. break;
  3055.       case certUsageUserCertImport:
  3056. if ( certtype & NS_CERT_TYPE_EMAIL ) {
  3057.     trust.emailFlags = CERTDB_VALID_PEER;
  3058. }
  3059. /* VALID_USER is already set if the cert was imported, 
  3060.  * in the case that the cert was already in the database
  3061.  * through SMIME or other means, we should set the USER
  3062.  * flags, if they are not already set.
  3063.  */
  3064. if( cert->isperm ) {
  3065.     if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
  3066. if( !(cert->trust->sslFlags & CERTDB_USER) ) {
  3067.     trust.sslFlags |= CERTDB_USER;
  3068. }
  3069.     }
  3070.     
  3071.     if ( certtype & NS_CERT_TYPE_EMAIL ) {
  3072. if( !(cert->trust->emailFlags & CERTDB_USER) ) {
  3073.     trust.emailFlags |= CERTDB_USER;
  3074. }
  3075.     }
  3076.     
  3077.     if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
  3078. if( !(cert->trust->objectSigningFlags & CERTDB_USER) ) {
  3079.     trust.objectSigningFlags |= CERTDB_USER;
  3080. }
  3081.     }
  3082. }
  3083. break;
  3084.       default: /* XXX added to quiet warnings; no other cases needed? */
  3085. break;
  3086.     }
  3087.     if ( (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags) == 0 ){
  3088. saveit = PR_FALSE;
  3089.     }
  3090.     if ( saveit && cert->isperm ) {
  3091. /* Cert already in the DB.  Just adjust flags */
  3092. tmptrust = *cert->trust;
  3093. tmptrust.sslFlags |= trust.sslFlags;
  3094. tmptrust.emailFlags |= trust.emailFlags;
  3095. tmptrust.objectSigningFlags |= trust.objectSigningFlags;
  3096.     
  3097. rv = CERT_ChangeCertTrust(cert->dbhandle, cert,
  3098.   &tmptrust);
  3099. if ( rv != SECSuccess ) {
  3100.     goto loser;
  3101. }
  3102.     }
  3103.     rv = SECSuccess;
  3104.     goto done;
  3105. loser:
  3106.     rv = SECFailure;
  3107. done:
  3108.     return(rv);
  3109. }
  3110. int
  3111. CERT_GetDBContentVersion(CERTCertDBHandle *handle)
  3112. {
  3113.     certDBEntryContentVersion *entry;
  3114.     int ret;
  3115.     
  3116.     entry = ReadDBContentVersionEntry(handle);
  3117.     
  3118.     if ( entry == NULL ) {
  3119. return(0);
  3120.     }
  3121.     ret = entry->contentVersion;
  3122.     DestroyDBEntry((certDBEntry *)entry);
  3123.     return(ret);
  3124. }
  3125. void
  3126. CERT_SetDBContentVersion(int version, CERTCertDBHandle *handle)
  3127. {
  3128.     SECStatus rv;
  3129.     certDBEntryContentVersion *entry;
  3130.     
  3131.     entry = NewDBContentVersionEntry(0);
  3132.     
  3133.     if ( entry == NULL ) {
  3134. return;
  3135.     }
  3136.     
  3137.     rv = DeleteDBContentVersionEntry(handle);
  3138.     rv = WriteDBContentVersionEntry(handle, entry);
  3139.     
  3140.     DestroyDBEntry((certDBEntry *)entry);
  3141.     
  3142.     return;
  3143. }
  3144. /*
  3145.  * Creates or adds to a list of all certs with a give subject name, sorted by
  3146.  * validity time, newest first.  Invalid certs are considered older than
  3147.  * valid certs. If validOnly is set, do not include invalid certs on list.
  3148.  */
  3149. CERTCertList *
  3150. CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle,
  3151.    SECItem *name, int64 sorttime, PRBool validOnly)
  3152. {
  3153.     CERTCertificate *cert = NULL;
  3154.     CERTSubjectList *subjectList = NULL;
  3155.     CERTSubjectNode *node;
  3156.     SECStatus rv;
  3157.     if ( certList == NULL ) {
  3158. certList = CERT_NewCertList();
  3159.     }
  3160.     
  3161.     if ( certList == NULL ) {
  3162. goto loser;
  3163.     }
  3164.     
  3165.     subjectList = FindSubjectList(handle, name, PR_FALSE);
  3166.     if ( subjectList != NULL ) {
  3167. node = subjectList->head;
  3168. PORT_Assert(node);
  3169. while (node) {
  3170.     cert = CERT_FindCertByKey(handle, &node->certKey);
  3171.     /* if validOnly, then check validity period before adding to list*/
  3172.     if ( ( !validOnly ) ||
  3173. ( CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE)
  3174.     == secCertTimeValid ) ) {
  3175. rv = CERT_AddCertToListSorted(certList, cert,
  3176.       CERT_SortCBValidity,
  3177.       (void *)&sorttime);
  3178. if ( rv != SECSuccess ) {
  3179.     CERT_DestroyCertificate(cert);
  3180.     goto loser;
  3181. }
  3182.     } else {
  3183. CERT_DestroyCertificate(cert);
  3184.     }
  3185.     node = node->next;
  3186. }
  3187.     }
  3188.     return(certList);
  3189. loser:
  3190.     if ( certList != NULL ) {
  3191. CERT_DestroyCertList(certList);
  3192.     }
  3193.     
  3194.     return(NULL);
  3195. }
  3196. /*
  3197.  * Creates or adds to a list of all certs with a give nickname, sorted by
  3198.  * validity time, newest first.  Invalid certs are considered older than valid
  3199.  * certs. If validOnly is set, do not include invalid certs on list.
  3200.  */
  3201. CERTCertList *
  3202. CERT_CreateNicknameCertList(CERTCertList *certList, CERTCertDBHandle *handle,
  3203.     char *nickname, int64 sorttime, PRBool validOnly)
  3204. {
  3205.     CERTCertificate *cert;
  3206.     CERTCertList *ret;
  3207.     
  3208.     cert = CERT_FindCertByNickname(handle, nickname);
  3209.     if ( cert == NULL ) {
  3210. return(NULL);
  3211.     }
  3212.     
  3213.     ret = CERT_CreateSubjectCertList(certList, handle, &cert->derSubject,
  3214.      sorttime, validOnly);
  3215.     CERT_DestroyCertificate(cert);
  3216.     
  3217.     return(ret);
  3218. }
  3219. /*
  3220.  * Creates or adds to a list of all certs with a give email addr, sorted by
  3221.  * validity time, newest first.  Invalid certs are considered older than valid
  3222.  * certs. If validOnly is set, do not include invalid certs on list.
  3223.  */
  3224. CERTCertList *
  3225. CERT_CreateEmailAddrCertList(CERTCertList *certList, CERTCertDBHandle *handle,
  3226.      char *emailAddr, int64 sorttime, PRBool validOnly)
  3227. {
  3228.     CERTCertificate *cert;
  3229.     CERTCertList *ret;
  3230.     
  3231.     cert = CERT_FindCertByEmailAddr(handle, emailAddr);
  3232.     if ( cert == NULL ) {
  3233. return(NULL);
  3234.     }
  3235.     
  3236.     ret = CERT_CreateSubjectCertList(certList, handle, &cert->derSubject,
  3237.      sorttime, validOnly);
  3238.     CERT_DestroyCertificate(cert);
  3239.     
  3240.     return(ret);
  3241. }