pcertdb.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:171k
- /* make a new subject entry - this case is only used when updating
- * an old version of the database. This is OK because the oldnickname
- * db format didn't allow multiple certs with the same subject.
- */
- subjectEntry = NewDBSubjectEntry(&cert->derSubject, &cert->certKey,
- &cert->subjectKeyID, nickname,
- NULL, 0);
- if ( subjectEntry == NULL ) {
- goto loser;
- }
- rv = WriteDBSubjectEntry(handle, subjectEntry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
-
- state = 3;
-
- if ( nicknameEntry ) {
- DestroyDBEntry((certDBEntry *)nicknameEntry);
- }
-
- if ( subjectEntry ) {
- DestroyDBEntry((certDBEntry *)subjectEntry);
- }
- return(certEntry);
- loser:
- /* don't leave partial entry in the database */
- if ( state > 0 ) {
- rv = DeleteDBCertEntry(handle, &cert->certKey);
- }
- if ( ( state > 1 ) && donnentry ) {
- rv = DeleteDBNicknameEntry(handle, nickname);
- }
- if ( state > 2 ) {
- rv = DeleteDBSubjectEntry(handle, &cert->derSubject);
- }
- if ( certEntry ) {
- DestroyDBEntry((certDBEntry *)certEntry);
- }
- if ( nicknameEntry ) {
- DestroyDBEntry((certDBEntry *)nicknameEntry);
- }
- if ( subjectEntry ) {
- DestroyDBEntry((certDBEntry *)subjectEntry);
- }
- return(NULL);
- }
- /*
- * NOTE - Version 6 DB did not go out to the real world in a release,
- * so we can remove this function in a later release.
- */
- static SECStatus
- UpdateV6DB(CERTCertDBHandle *handle, DB *updatedb)
- {
- int ret;
- DBT key, data;
- unsigned char *buf, *tmpbuf = NULL;
- certDBEntryType type;
- certDBEntryNickname *nnEntry = NULL;
- certDBEntrySubject *subjectEntry = NULL;
- certDBEntrySMime *emailEntry = NULL;
- char *nickname;
- char *emailAddr;
- SECStatus rv;
-
- /*
- * Sequence through the old database and copy all of the entries
- * to the new database. Subject name entries will have the new
- * fields inserted into them (with zero length).
- */
- ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
- if ( ret ) {
- return(SECFailure);
- }
- do {
- buf = (unsigned char *)data.data;
-
- if ( data.size >= 3 ) {
- if ( buf[0] == 6 ) { /* version number */
- type = (certDBEntryType)buf[1];
- if ( type == certDBEntryTypeSubject ) {
- /* expando subjecto entrieo */
- tmpbuf = (unsigned char *)PORT_Alloc(data.size + 4);
- if ( tmpbuf ) {
- /* copy header stuff */
- PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN + 2);
- /* insert 4 more bytes of zero'd header */
- PORT_Memset(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 2],
- 0, 4);
- /* copy rest of the data */
- PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
- &buf[SEC_DB_ENTRY_HEADER_LEN + 2],
- data.size - (SEC_DB_ENTRY_HEADER_LEN + 2));
- data.data = (void *)tmpbuf;
- data.size += 4;
- buf = tmpbuf;
- }
- } else if ( type == certDBEntryTypeCert ) {
- /* expando certo entrieo */
- tmpbuf = (unsigned char *)PORT_Alloc(data.size + 3);
- if ( tmpbuf ) {
- /* copy header stuff */
- PORT_Memcpy(tmpbuf, buf, SEC_DB_ENTRY_HEADER_LEN);
- /* copy trust flage, setting msb's to 0 */
- tmpbuf[SEC_DB_ENTRY_HEADER_LEN] = 0;
- tmpbuf[SEC_DB_ENTRY_HEADER_LEN+1] =
- buf[SEC_DB_ENTRY_HEADER_LEN];
- tmpbuf[SEC_DB_ENTRY_HEADER_LEN+2] = 0;
- tmpbuf[SEC_DB_ENTRY_HEADER_LEN+3] =
- buf[SEC_DB_ENTRY_HEADER_LEN+1];
- tmpbuf[SEC_DB_ENTRY_HEADER_LEN+4] = 0;
- tmpbuf[SEC_DB_ENTRY_HEADER_LEN+5] =
- buf[SEC_DB_ENTRY_HEADER_LEN+2];
-
- /* copy rest of the data */
- PORT_Memcpy(&tmpbuf[SEC_DB_ENTRY_HEADER_LEN + 6],
- &buf[SEC_DB_ENTRY_HEADER_LEN + 3],
- data.size - (SEC_DB_ENTRY_HEADER_LEN + 3));
- data.data = (void *)tmpbuf;
- data.size += 3;
- buf = tmpbuf;
- }
- }
- /* update the record version number */
- buf[0] = CERT_DB_FILE_VERSION;
- /* copy to the new database */
- ret = certdb_Put(handle->permCertDB, &key, &data, 0);
- if ( tmpbuf ) {
- PORT_Free(tmpbuf);
- tmpbuf = NULL;
- }
- }
- }
- } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
- ret = certdb_Sync(handle->permCertDB, 0);
- ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
- if ( ret ) {
- return(SECFailure);
- }
- do {
- buf = (unsigned char *)data.data;
-
- if ( data.size >= 3 ) {
- if ( buf[0] == CERT_DB_FILE_VERSION ) { /* version number */
- type = (certDBEntryType)buf[1];
- if ( type == certDBEntryTypeNickname ) {
- nickname = &((char *)key.data)[1];
- /* get the matching nickname entry in the new DB */
- nnEntry = ReadDBNicknameEntry(handle, nickname);
- if ( nnEntry == NULL ) {
- goto endloop;
- }
-
- /* find the subject entry pointed to by nickname */
- subjectEntry = ReadDBSubjectEntry(handle,
- &nnEntry->subjectName);
- if ( subjectEntry == NULL ) {
- goto endloop;
- }
-
- subjectEntry->nickname =
- (char *)PORT_ArenaAlloc(subjectEntry->common.arena,
- key.size - 1);
- if ( subjectEntry->nickname ) {
- PORT_Memcpy(subjectEntry->nickname, nickname,
- key.size - 1);
- rv = WriteDBSubjectEntry(handle, subjectEntry);
- }
- } else if ( type == certDBEntryTypeSMimeProfile ) {
- emailAddr = &((char *)key.data)[1];
- /* get the matching smime entry in the new DB */
- emailEntry = ReadDBSMimeEntry(handle, emailAddr);
- if ( emailEntry == NULL ) {
- goto endloop;
- }
-
- /* find the subject entry pointed to by nickname */
- subjectEntry = ReadDBSubjectEntry(handle,
- &emailEntry->subjectName);
- if ( subjectEntry == NULL ) {
- goto endloop;
- }
-
- subjectEntry->nickname =
- (char *)PORT_ArenaAlloc(subjectEntry->common.arena,
- key.size - 1);
- if ( subjectEntry->emailAddr ) {
- PORT_Memcpy(subjectEntry->emailAddr, emailAddr,
- key.size - 1);
- rv = WriteDBSubjectEntry(handle, subjectEntry);
- }
- }
-
- endloop:
- if ( subjectEntry ) {
- DestroyDBEntry((certDBEntry *)subjectEntry);
- subjectEntry = NULL;
- }
- if ( nnEntry ) {
- DestroyDBEntry((certDBEntry *)nnEntry);
- nnEntry = NULL;
- }
- if ( emailEntry ) {
- DestroyDBEntry((certDBEntry *)emailEntry);
- emailEntry = NULL;
- }
- }
- }
- } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
- ret = certdb_Sync(handle->permCertDB, 0);
- (* updatedb->close)(updatedb);
- return(SECSuccess);
- }
- static SECStatus
- updateV5Callback(CERTCertificate *cert, SECItem *k, void *pdata)
- {
- CERTCertDBHandle *handle;
- certDBEntryCert *entry;
- CERTCertTrust *trust;
-
- handle = (CERTCertDBHandle *)pdata;
- trust = &cert->dbEntry->trust;
- /* SSL user certs can be used for email if they have an email addr */
- if ( cert->emailAddr && ( trust->sslFlags & CERTDB_USER ) &&
- ( trust->emailFlags == 0 ) ) {
- trust->emailFlags = CERTDB_USER;
- }
-
- entry = AddCertToPermDB(handle, cert, cert->dbEntry->nickname,
- &cert->dbEntry->trust);
- if ( entry ) {
- DestroyDBEntry((certDBEntry *)entry);
- }
-
- return(SECSuccess);
- }
- static SECStatus
- UpdateV5DB(CERTCertDBHandle *handle, DB *updatedb)
- {
- CERTCertDBHandle updatehandle;
- SECStatus rv;
-
- updatehandle.permCertDB = updatedb;
- updatehandle.dbMon = PR_NewMonitor();
-
- rv = SEC_TraversePermCerts(&updatehandle, updateV5Callback,
- (void *)handle);
-
- PR_DestroyMonitor(updatehandle.dbMon);
-
- return(rv);
- }
- static SECStatus
- UpdateV4DB(CERTCertDBHandle *handle, DB *updatedb)
- {
- DBT key, data;
- certDBEntryCert *entry, *entry2;
- SECItem derSubject;
- int ret;
- PRArenaPool *arena = NULL;
- CERTCertificate *cert;
- ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
- if ( ret ) {
- return(SECFailure);
- }
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) {
- return(SECFailure);
- }
-
- do {
- if ( data.size != 1 ) { /* skip version number */
- /* decode the old DB entry */
- entry = (certDBEntryCert *)DecodeV4DBCertEntry((unsigned char*)data.data, data.size);
- derSubject.data = NULL;
-
- if ( entry ) {
- cert = CERT_DecodeDERCertificate(&entry->derCert, PR_TRUE,
- entry->nickname);
- if ( cert != NULL ) {
- /* add to new database */
- entry2 = AddCertToPermDB(handle, cert, entry->nickname,
- &entry->trust);
-
- CERT_DestroyCertificate(cert);
- if ( entry2 ) {
- DestroyDBEntry((certDBEntry *)entry2);
- }
- }
- DestroyDBEntry((certDBEntry *)entry);
- }
- }
- } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
- PORT_FreeArena(arena, PR_FALSE);
- (* updatedb->close)(updatedb);
- return(SECSuccess);
- }
- /*
- * return true if a database key conflict exists
- */
- PRBool
- SEC_CertDBKeyConflict(SECItem *derCert, CERTCertDBHandle *handle)
- {
- SECStatus rv;
- DBT tmpdata;
- DBT namekey;
- int ret;
- SECItem keyitem;
- PRArenaPool *arena = NULL;
- SECItem derKey;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- /* get the db key of the cert */
- rv = CERT_KeyFromDERCert(arena, derCert, &derKey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = EncodeDBCertKey(&derKey, arena, &keyitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- namekey.data = keyitem.data;
- namekey.size = keyitem.len;
-
- /* lookup in the temporary database */
- ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
- if ( ret == 0 ) { /* found in temp database */
- goto loser;
- } else { /* not found in temporary database */
- ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0);
- if ( ret == 0 ) {
- goto loser;
- }
- }
- PORT_FreeArena(arena, PR_FALSE);
-
- return(PR_FALSE);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(PR_TRUE);
- }
- #ifdef NOTDEF
- /*
- * return true if a subject name conflict exists
- * NOTE: caller must have already made sure that this exact cert
- * doesn't exist in the DB
- */
- PRBool
- SEC_CertSubjectConflict(SECItem *derCert, CERTCertDBHandle *handle)
- {
- SECStatus rv;
- DBT tmpdata;
- DBT namekey;
- int ret;
- SECItem keyitem;
- PRArenaPool *arena = NULL;
- SECItem derName;
-
- derName.data = NULL;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- /* get the subject name of the cert */
- rv = CERT_NameFromDERCert(derCert, &derName);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- rv = EncodeDBSubjectKey(&derName, arena, &keyitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- namekey.data = keyitem.data;
- namekey.size = keyitem.len;
-
- /* lookup in the temporary database */
- ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
- if ( ret == 0 ) { /* found in temp database */
- return(PR_TRUE);
- } else { /* not found in temporary database */
- ret = certdb_Get(handle->permCertDB, &namekey, &tmpdata, 0);
- if ( ret == 0 ) {
- return(PR_TRUE);
- }
- }
- PORT_FreeArena(arena, PR_FALSE);
- PORT_Free(derName.data);
-
- return(PR_FALSE);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- if ( derName.data ) {
- PORT_Free(derName.data);
- }
-
- return(PR_TRUE);
- }
- #endif
- /*
- * return true if a nickname conflict exists
- * NOTE: caller must have already made sure that this exact cert
- * doesn't exist in the DB
- */
- PRBool
- SEC_CertNicknameConflict(char *nickname, SECItem *derSubject,
- CERTCertDBHandle *handle)
- {
- PRBool rv;
- certDBEntryNickname *entry;
-
- if ( nickname == NULL ) {
- return(PR_FALSE);
- }
-
- entry = ReadDBNicknameEntry(handle, nickname);
- if ( entry == NULL ) {
- /* no entry for this nickname, so no conflict */
- return(PR_FALSE);
- }
- rv = PR_TRUE;
- if ( SECITEM_CompareItem(derSubject, &entry->subjectName) == SECEqual ) {
- /* if subject names are the same, then no conflict */
- rv = PR_FALSE;
- }
- DestroyDBEntry((certDBEntry *)entry);
- return(rv);
- }
- /*
- * Open the certificate database and index databases. Create them if
- * they are not there or bad.
- */
- SECStatus
- SEC_OpenPermCertDB(CERTCertDBHandle *handle, PRBool readOnly,
- CERTDBNameFunc namecb, void *cbarg)
- {
- SECStatus rv;
- int openflags;
- certDBEntryVersion *versionEntry = NULL;
- DB *updatedb = NULL;
- char *tmpname;
- char *certdbname;
- PRBool updated = PR_FALSE;
- PRBool forceUpdate = PR_FALSE;
-
- certdbname = (* namecb)(cbarg, CERT_DB_FILE_VERSION);
- if ( certdbname == NULL ) {
- return(SECFailure);
- }
-
- if ( readOnly ) {
- openflags = O_RDONLY;
- } else {
- openflags = O_RDWR;
- }
-
- /*
- * first open the permanent file based database.
- */
- handle->permCertDB = dbopen( certdbname, openflags, 0600, DB_HASH, 0 );
- /* check for correct version number */
- if ( handle->permCertDB ) {
- versionEntry = ReadDBVersionEntry(handle);
- if ( versionEntry == NULL ) {
- /* no version number */
- certdb_Close(handle->permCertDB);
- handle->permCertDB = 0;
- } else if ( versionEntry->common.version != CERT_DB_FILE_VERSION ) {
- /* wrong version number, can't update in place */
- DestroyDBEntry((certDBEntry *)versionEntry);
- PORT_Free(certdbname);
- return(SECFailure);
- }
- }
- /* if first open fails, try to create a new DB */
- if ( handle->permCertDB == NULL ) {
- /* don't create if readonly */
- if ( readOnly ) {
- goto loser;
- }
-
- handle->permCertDB = dbopen(certdbname,
- O_RDWR | O_CREAT | O_TRUNC,
- 0600, DB_HASH, 0);
- /* if create fails then we lose */
- if ( handle->permCertDB == 0 ) {
- goto loser;
- }
- versionEntry = NewDBVersionEntry(0);
- if ( versionEntry == NULL ) {
- goto loser;
- }
-
- rv = WriteDBVersionEntry(handle, versionEntry);
- DestroyDBEntry((certDBEntry *)versionEntry);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* try to upgrade old db here */
- tmpname = (* namecb)(cbarg, 6); /* get v6 db name */
- if ( tmpname ) {
- updatedb = dbopen( tmpname, O_RDONLY, 0600, DB_HASH, 0 );
- PORT_Free(tmpname);
- if ( updatedb ) {
- rv = UpdateV6DB(handle, updatedb);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- updated = PR_TRUE;
- } else { /* no v6 db, so try v5 db */
- tmpname = (* namecb)(cbarg, 5); /* get v5 db name */
- if ( tmpname ) {
- updatedb = dbopen( tmpname, O_RDONLY, 0600, DB_HASH, 0 );
- PORT_Free(tmpname);
- if ( updatedb ) {
- rv = UpdateV5DB(handle, updatedb);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- updated = PR_TRUE;
- } else { /* no v5 db, so try v4 db */
- /* try to upgrade v4 db */
- tmpname = (* namecb)(cbarg, 4); /* get v4 db name */
- if ( tmpname ) {
- updatedb = dbopen( tmpname, O_RDONLY, 0600,
- DB_HASH, 0 );
- PORT_Free(tmpname);
- if ( updatedb ) {
- rv = UpdateV4DB(handle, updatedb);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- forceUpdate = PR_TRUE;
- updated = PR_TRUE;
- }
- }
- }
- }
- }
- }
- /* initialize the database with our well known certificates
- * or in the case of update, just fall down to CERT_AddNewCerts()
- * below.
- * Note - if we are updating a really old database, then we try
- * to push all of the certs into it.
- */
- if ( ( !updated ) || forceUpdate ) {
- rv = CERT_InitCertDB(handle);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
- }
- rv = CERT_AddNewCerts(handle);
- PORT_Free(certdbname);
-
- return (SECSuccess);
-
- loser:
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
-
- if ( handle->permCertDB ) {
- certdb_Close(handle->permCertDB);
- handle->permCertDB = 0;
- }
- PORT_Free(certdbname);
- return(SECFailure);
- }
- /*
- * delete all DB records associated with a particular certificate
- */
- static SECStatus
- DeletePermCert(CERTCertificate *cert)
- {
- SECStatus rv;
- SECStatus ret;
- ret = SECSuccess;
-
- rv = DeleteDBCertEntry(cert->dbhandle, &cert->certKey);
- if ( rv != SECSuccess ) {
- ret = SECFailure;
- }
-
- if ( cert->nickname ) {
- rv = DeleteDBNicknameEntry(cert->dbhandle, cert->nickname);
- if ( rv != SECSuccess ) {
- ret = SECFailure;
- }
- }
-
- rv = RemovePermSubjectNode(cert);
- return(ret);
- }
- /*
- * Delete a certificate from the permanent database.
- */
- SECStatus
- SEC_DeletePermCertificate(CERTCertificate *cert)
- {
- SECStatus rv;
-
- if ( !cert->isperm ) {
- return(SECSuccess);
- }
- CERT_LockDB(cert->dbhandle);
- /* delete the records from the permanent database */
- rv = DeletePermCert(cert);
-
- /* no longer permanent */
- cert->isperm = PR_FALSE;
- /* get rid of dbcert and stuff pointing to it */
- DestroyDBEntry((certDBEntry *)cert->dbEntry);
- cert->dbEntry = NULL;
- cert->trust = NULL;
- /* delete it from the temporary database too. It will remain in
- * memory until all references go away.
- */
- if (cert->slot) {
- /* If it's owned by a PKCS #11 slot, don't deleted if from the temp DB just
- * yet... rv inherited from DeletePermCert (as if anyone checks the return
- * code from this function anyway. */
- CERT_DestroyCertificateNoLocking(cert);
- rv = SECSuccess;
- } else {
- rv = CERT_DeleteTempCertificate(cert);
- }
- CERT_UnlockDB(cert->dbhandle);
- return(rv);
- }
- /*
- * Lookup a certificate in the databases.
- */
- certDBEntryCert *
- SEC_FindPermCertByKey(CERTCertDBHandle *handle, SECItem *key)
- {
- return(ReadDBCertEntry(handle, key));
- }
- /*
- * Lookup a certificate in the database by name
- */
- certDBEntryCert *
- SEC_FindPermCertByName(CERTCertDBHandle *handle, SECItem *derSubject)
- {
- certDBEntrySubject *subjectEntry;
- certDBEntryCert *certEntry;
-
- subjectEntry = ReadDBSubjectEntry(handle, derSubject);
-
- if ( subjectEntry == NULL ) {
- goto loser;
- }
- certEntry = ReadDBCertEntry(handle, &subjectEntry->certKeys[0]);
- DestroyDBEntry((certDBEntry *)subjectEntry);
-
- return(certEntry);
- loser:
- return(NULL);
- }
- /*
- * Lookup a certificate in the database by nickname
- */
- certDBEntryCert *
- SEC_FindPermCertByNickname(CERTCertDBHandle *handle, char *nickname)
- {
- certDBEntryNickname *nicknameEntry;
- certDBEntryCert *certEntry;
-
- nicknameEntry = ReadDBNicknameEntry(handle, nickname);
-
- if ( nicknameEntry == NULL ) {
- goto loser;
- }
- certEntry = SEC_FindPermCertByName(handle, &nicknameEntry->subjectName);
- DestroyDBEntry((certDBEntry *)nicknameEntry);
-
- return(certEntry);
- loser:
- return(NULL);
- }
- /*
- * Traverse all of the entries in the database of a particular type
- * call the given function for each one.
- */
- SECStatus
- SEC_TraverseDBEntries(CERTCertDBHandle *handle,
- certDBEntryType type,
- SECStatus (* callback)(SECItem *data, SECItem *key,
- certDBEntryType type, void *pdata),
- void *udata )
- {
- DBT data;
- DBT key;
- SECStatus rv;
- int ret;
- SECItem dataitem;
- SECItem keyitem;
- unsigned char *buf;
- unsigned char *keybuf;
-
- ret = certdb_Seq(handle->permCertDB, &key, &data, R_FIRST);
- if ( ret ) {
- return(SECFailure);
- }
-
- do {
- buf = (unsigned char *)data.data;
-
- if ( buf[1] == (unsigned char)type ) {
- dataitem.len = data.size;
- dataitem.data = buf;
- dataitem.type = siBuffer;
- keyitem.len = key.size - SEC_DB_KEY_HEADER_LEN;
- keybuf = (unsigned char *)key.data;
- keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN];
- keyitem.type = siBuffer;
-
- rv = (* callback)(&dataitem, &keyitem, type, udata);
- if ( rv != SECSuccess ) {
- return(rv);
- }
- }
- } while ( certdb_Seq(handle->permCertDB, &key, &data, R_NEXT) == 0 );
- return(SECSuccess);
- }
- typedef struct {
- PermCertCallback certfunc;
- CERTCertDBHandle *handle;
- void *data;
- } PermCertCallbackState;
- /*
- * traversal callback to decode certs and call callers callback
- */
- static SECStatus
- certcallback(SECItem *dbdata, SECItem *dbkey, certDBEntryType type, void *data)
- {
- PermCertCallbackState *mystate;
- SECStatus rv;
- certDBEntryCert entry;
- SECItem entryitem;
- CERTCertificate *cert;
- PRArenaPool *arena = NULL;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- mystate = (PermCertCallbackState *)data;
- entry.common.version = (unsigned int)dbdata->data[0];
- entry.common.type = (certDBEntryType)dbdata->data[1];
- entry.common.flags = (unsigned int)dbdata->data[2];
- entry.common.arena = arena;
-
- entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN;
- entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN];
-
- rv = DecodeDBCertEntry(&entry, &entryitem);
- if (rv != SECSuccess ) {
- goto loser;
- }
- entry.derCert.type = siBuffer;
-
- cert = CERT_DecodeDERCertificate(&entry.derCert, PR_FALSE,
- entry.nickname);
- cert->dbEntry = &entry;
- cert->trust = &entry.trust;
- cert->dbhandle = mystate->handle;
- if ( CERT_IsCACert(cert, NULL) ||
- (( cert->trust->sslFlags & CERTDB_VALID_CA ) ||
- ( cert->trust->emailFlags & CERTDB_VALID_CA ) ||
- ( cert->trust->objectSigningFlags & CERTDB_VALID_CA)) ) {
- cert->nsCertType |= EXT_KEY_USAGE_STATUS_RESPONDER;
- }
- rv = (* mystate->certfunc)(cert, dbkey, mystate->data);
- /* arena destroyed by SEC_DestroyCert */
- CERT_DestroyCertificateNoLocking(cert);
- return(rv);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * Traverse all of the certificates in the permanent database and
- * call the given function for each one; expect the caller to have lock.
- */
- static SECStatus
- TraversePermCertsNoLocking(CERTCertDBHandle *handle,
- SECStatus (* certfunc)(CERTCertificate *cert,
- SECItem *k,
- void *pdata),
- void *udata )
- {
- SECStatus rv;
- PermCertCallbackState mystate;
- mystate.certfunc = certfunc;
- mystate.handle = handle;
- mystate.data = udata;
- rv = SEC_TraverseDBEntries(handle, certDBEntryTypeCert, certcallback,
- (void *)&mystate);
-
- return(rv);
- }
- /*
- * Traverse all of the certificates in the permanent database and
- * call the given function for each one.
- */
- SECStatus
- SEC_TraversePermCerts(CERTCertDBHandle *handle,
- SECStatus (* certfunc)(CERTCertificate *cert, SECItem *k,
- void *pdata),
- void *udata )
- {
- SECStatus rv;
- CERT_LockDB(handle);
- rv = TraversePermCertsNoLocking(handle, certfunc, udata);
- CERT_UnlockDB(handle);
-
- return(rv);
- }
- /*
- * Close the database
- */
- void
- CERT_ClosePermCertDB(CERTCertDBHandle *handle)
- {
- if ( handle ) {
- if ( handle->permCertDB ) {
- if ( handle->statusConfig ) {
- PORT_Assert(handle->statusConfig->statusDestroy != NULL);
- (void) (* handle->statusConfig->statusDestroy)(handle->statusConfig);
- handle->statusConfig = NULL; /* Destroy frees the structure */
- PORT_Assert(handle->statusConfig == NULL);
- }
- certdb_Close( handle->permCertDB );
- handle->permCertDB = 0;
- }
- }
- return;
- }
- /*
- * Get the trust attributes from a certificate
- */
- SECStatus
- CERT_GetCertTrust(CERTCertificate *cert, CERTCertTrust *trust)
- {
- SECStatus rv;
-
- CERT_LockCertTrust(cert);
-
- if ( cert->trust == NULL ) {
- rv = SECFailure;
- } else {
- *trust = *cert->trust;
- rv = SECSuccess;
- }
-
- CERT_UnlockCertTrust(cert);
- return(rv);
- }
- static char *
- cert_parseNickname(char *nickname)
- {
- char *cp;
- for (cp=nickname; *cp && *cp != ':'; cp++);
- if (*cp == ':') return cp++;
- return nickname;
- }
- /*
- * Change the trust attributes of a certificate and make them permanent
- * in the database.
- */
- SECStatus
- CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert,
- CERTCertTrust *trust)
- {
- certDBEntryCert *entry;
- int rv;
- SECStatus ret;
-
- CERT_LockDB(handle);
- CERT_LockCertTrust(cert);
- /* only set the trust on permanent certs */
- if ( cert->trust == NULL ) {
- ret = SECFailure;
- goto done;
- }
- *cert->trust = *trust;
- if ( cert->dbEntry == NULL ) {
- ret = SECSuccess; /* not in permanent database */
- if ((cert->slot) && PK11_IsReadOnly(cert->slot)) {
- char *nickname = cert_parseNickname(cert->nickname);
- ret = CERT_AddTempCertToPerm(cert, nickname, trust);
- }
- goto done;
- }
-
- entry = cert->dbEntry;
- entry->trust = *trust;
-
- rv = WriteDBCertEntry(handle, entry);
- if ( rv ) {
- ret = SECFailure;
- goto done;
- }
- ret = SECSuccess;
-
- done:
- CERT_UnlockCertTrust(cert);
- CERT_UnlockDB(handle);
- return(ret);
- }
- SECStatus
- CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
- CERTCertTrust *trust)
- {
- char *oldnn;
- certDBEntryCert *entry;
- SECStatus rv;
- PRBool conflict;
- SECStatus ret;
- PORT_Assert(cert->dbhandle);
- CERT_LockDB(cert->dbhandle);
-
- PORT_Assert(cert->istemp);
- PORT_Assert(!cert->isperm);
- PORT_Assert(!cert->dbEntry);
- /* don't add a conflicting nickname */
- conflict = SEC_CertNicknameConflict(nickname, &cert->derSubject,
- cert->dbhandle);
- if ( conflict ) {
- ret = SECFailure;
- goto done;
- }
-
- /* save old nickname so that we can delete it */
- oldnn = cert->nickname;
- entry = AddCertToPermDB(cert->dbhandle, cert, nickname, trust);
-
- if ( entry == NULL ) {
- ret = SECFailure;
- goto done;
- }
-
- cert->nickname = (entry->nickname) ? PORT_ArenaStrdup(cert->arena,entry->nickname) : NULL;
- cert->trust = &entry->trust;
- cert->isperm = PR_TRUE;
- cert->dbEntry = entry;
- if ( nickname && oldnn && ( PORT_Strcmp(nickname, oldnn) != 0 ) ) {
- /* only delete the old one if they are not the same */
- /* delete old nickname from temp database */
- rv = SEC_DeleteTempNickname(cert->dbhandle, oldnn);
- if ( rv != SECSuccess ) {
- /* do we care?? */
- }
- }
- /* add new nickname to temp database */
- if ( cert->nickname ) {
- rv = SEC_AddTempNickname(cert->dbhandle, cert->nickname,
- &cert->derSubject);
- if ( rv != SECSuccess ) {
- ret = SECFailure;
- goto done;
- }
- }
-
- ret = SECSuccess;
- done:
- CERT_UnlockDB(cert->dbhandle);
- return(ret);
- }
- /*
- * Open the certificate database and index databases. Create them if
- * they are not there or bad.
- */
- SECStatus
- CERT_OpenCertDB(CERTCertDBHandle *handle, PRBool readOnly,
- CERTDBNameFunc namecb, void *cbarg)
- {
- int rv;
- certdb_InitDBLock();
-
- handle->dbMon = PR_NewMonitor();
- PORT_Assert(handle->dbMon != NULL);
- handle->spkDigestInfo = NULL;
- handle->statusConfig = NULL;
- /*
- * Open the memory resident decoded cert database.
- */
- handle->tempCertDB = dbopen( 0, O_RDWR | O_CREAT, 0600, DB_HASH, 0 );
- if ( !handle->tempCertDB ) {
- goto loser;
- }
- rv = SEC_OpenPermCertDB(handle, readOnly, namecb, cbarg);
- if ( rv ) {
- goto loser;
- }
- return (SECSuccess);
-
- loser:
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
-
- if ( handle->tempCertDB ) {
- certdb_Close(handle->tempCertDB);
- handle->tempCertDB = 0;
- }
- return(SECFailure);
- }
- static char *
- certDBFilenameCallback(void *arg, int dbVersion)
- {
- return(PORT_Strdup((char *)arg));
- }
- SECStatus
- CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname,
- PRBool readOnly)
- {
- return(CERT_OpenCertDB(handle, readOnly, certDBFilenameCallback,
- (void *)certdbname));
- }
- /*
- * Add a nickname to the temp database
- */
- SECStatus
- SEC_AddTempNickname(CERTCertDBHandle *handle, char *nickname,
- SECItem *subjectName)
- {
- DBT namekey;
- int ret;
- SECItem nameitem;
- SECStatus rv;
- DBT keydata;
- PRArenaPool *arena = NULL;
- SECItem tmpitem;
-
- PORT_Assert(nickname != NULL);
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- rv = EncodeDBNicknameKey(nickname, arena, &nameitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- namekey.data = nameitem.data;
- namekey.size = nameitem.len;
- /* see if an entry already exists */
- ret = certdb_Get(handle->tempCertDB, &namekey, &keydata, 0);
- if ( ret == 0 ) {
- /* found in temp database */
- tmpitem.data = (unsigned char*)keydata.data;
- tmpitem.len = keydata.size;
- if ( SECITEM_CompareItem(subjectName, &tmpitem) == SECEqual ) {
- /* same subject name */
- goto done;
- } else {
- /* different subject name is an error */
- goto loser;
- }
- }
-
- keydata.data = subjectName->data;
- keydata.size = subjectName->len;
-
- /* put into temp byname index */
- ret = certdb_Put(handle->tempCertDB, &namekey, &keydata, R_NOOVERWRITE);
- if ( ret ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- done:
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- return(SECFailure);
- }
- SECStatus
- SEC_DeleteTempNickname(CERTCertDBHandle *handle, char *nickname)
- {
- DBT namekey;
- SECStatus rv;
- PRArenaPool *arena = NULL;
- SECItem nameitem;
- int ret;
-
- PORT_Assert(nickname != NULL);
- if ( nickname == NULL ) {
- return(SECSuccess);
- }
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- /* format a database key based on the nickname */
- if ( nickname ) {
- rv = EncodeDBNicknameKey(nickname, arena, &nameitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- namekey.data = nameitem.data;
- namekey.size = nameitem.len;
- ret = certdb_Del(handle->tempCertDB, &namekey, 0);
- if ( ret ) {
- goto loser;
- }
- }
- PORT_FreeArena(arena, PR_FALSE);
-
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * Decode a certificate and enter it into the temporary certificate database.
- * Deal with nicknames correctly
- *
- * nickname is only used if isperm == PR_TRUE
- *
- * This is the private entry point, and locking is optional
- */
- static CERTCertificate *
- NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert, char *nickname,
- PRBool isperm, PRBool copyDER, PRBool lockdb)
- {
- DBT key;
- DBT data;
- int status;
- CERTCertificate *cert = NULL;
- PRBool promoteError = PR_TRUE;
- PRArenaPool *arena = NULL;
- SECItem keyitem;
- SECStatus rv;
-
- if ( isperm == PR_FALSE ) {
- cert = CERT_FindCertByDERCert(handle, derCert);
- if ( cert ) {
- return(cert);
- }
- nickname = NULL;
- }
- if ( lockdb ) {
- CERT_LockDB(handle);
- }
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- cert = CERT_DecodeDERCertificate(derCert, copyDER, nickname );
-
- if ( cert == NULL ) {
- /* We want to save the decoding error here */
- promoteError = PR_FALSE;
- goto loser;
- }
- cert->dbhandle = handle;
- /* only save pointer to cert in database */
- data.data = &cert;
- data.size = sizeof(cert);
- /* if this is a perm cert, then it is already in the subject db */
- if ( isperm == PR_FALSE ) {
- /* enter into the subject index */
- rv = AddTempCertToSubjectList(cert);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /*
- * Since it's not a perm cert, add it to the key hash lookup; if it
- * is permanent it will either already be there or will get put there
- * later along with the rest of the perm certs. A failure of the
- * addition does not seem to warrant failing this whole function,
- * so we intentionally ignore the returned status.
- */
- (void) AddCertToSPKDigestTable(handle, cert);
- } else {
- cert->subjectList = FindSubjectList(cert->dbhandle, &cert->derSubject,
- PR_FALSE);
- }
-
- rv = EncodeDBCertKey(&cert->certKey, arena, &keyitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- key.data = keyitem.data;
- key.size = keyitem.len;
-
- /* enter into main db */
- status = certdb_Put(handle->tempCertDB, &key, &data, R_NOOVERWRITE);
- if ( status ) {
- goto loser;
- }
- if ( cert->nickname ) {
- status = SEC_AddTempNickname(handle, cert->nickname,
- &cert->derSubject);
- if ( status ) {
- promoteError = PR_FALSE;
- goto loser;
- }
- }
- cert->isperm = isperm;
- cert->istemp = PR_TRUE;
-
- PORT_FreeArena(arena, PR_FALSE);
- if ( lockdb ) {
- CERT_UnlockDB(handle);
- }
- return(cert);
- loser:
- if ( cert ) {
- CERT_DestroyCertificateNoLocking(cert);
- }
-
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- if ( promoteError ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- }
- if ( lockdb ) {
- CERT_UnlockDB(handle);
- }
- return(0);
- }
- /*
- * Decode a certificate and enter it into the temporary certificate database.
- * Deal with nicknames correctly
- *
- * nickname is only used if isperm == PR_TRUE
- *
- * This is the public entry point and does locking.
- */
- CERTCertificate *
- CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
- char *nickname, PRBool isperm, PRBool copyDER)
- {
- return( NewTempCertificate(handle, derCert, nickname, isperm, copyDER,
- PR_TRUE) );
- }
- /*
- * Decode a permanent certificate and enter it into the temporary certificate
- * database.
- */
- static CERTCertificate *
- SEC_AddPermCertToTemp(CERTCertDBHandle *handle, certDBEntryCert *entry)
- {
- CERTCertificate *cert;
- /* we already hold the lock */
- cert = NewTempCertificate(handle, &entry->derCert, entry->nickname,
- PR_TRUE, PR_TRUE, PR_FALSE);
- if ( !cert ) {
- return(0);
- }
- cert->dbEntry = entry;
- cert->trust = &entry->trust;
-
- return(cert);
- }
- SECStatus
- CERT_DeleteTempCertificate(CERTCertificate *cert)
- {
- SECStatus rv;
- DBT nameKey;
- CERTCertDBHandle *handle;
- SECItem keyitem;
- PRArenaPool *arena;
- int ret;
-
- handle = cert->dbhandle;
- if ( !cert->istemp ) {
- return(SECSuccess);
- }
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- if (cert->slot) {
- PK11_FreeSlot(cert->slot);
- cert->slot = NULL;
- cert->pkcs11ID = CK_INVALID_KEY;
- }
-
- /* delete from subject list (also takes care of nickname) */
- rv = RemoveTempCertFromSubjectList(cert);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- if ( !cert->isperm ) {
- /*
- * Remove the cert from the subject public key digest table,
- * though we do not care if the removal fails (perhaps meaning
- * the cert wasn't even there).
- */
- (void) RemoveCertFromSPKDigestTable(handle, cert);
- }
- rv = EncodeDBCertKey(&cert->certKey, arena, &keyitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- nameKey.data = keyitem.data;
- nameKey.size = keyitem.len;
- /* delete the cert */
- ret = certdb_Del(handle->tempCertDB, &nameKey, 0);
- if ( ret ) {
- goto loser;
- }
- cert->istemp = PR_FALSE;
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * Lookup a certificate in the databases.
- */
- static CERTCertificate *
- FindCertByKey(CERTCertDBHandle *handle, SECItem *certKey, PRBool lockdb)
- {
- DBT tmpdata;
- int ret;
- SECItem keyitem;
- DBT key;
- SECStatus rv;
- CERTCertificate *cert = NULL;
- PRArenaPool *arena = NULL;
- certDBEntryCert *entry;
- PRBool locked = PR_FALSE;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- rv = EncodeDBCertKey(certKey, arena, &keyitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- key.data = keyitem.data;
- key.size = keyitem.len;
-
- if ( lockdb ) {
- locked = PR_TRUE;
- CERT_LockDB(handle);
- }
-
- /* lookup in the temporary database */
- ret = certdb_Get( handle->tempCertDB, &key, &tmpdata, 0 );
- /* error accessing the database */
- if ( ret < 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- if ( ret == 0 ) { /* found in temp database */
- if ( tmpdata.size != sizeof(CERTCertificate *) ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- PORT_Memcpy(&cert, tmpdata.data, tmpdata.size);
- CERT_LockCertRefCount(cert);
- cert->referenceCount++;
- CERT_UnlockCertRefCount(cert);
- }
- if ( ret != 0 ) {
- /* not found in temporary database */
- /* find in perm database */
- entry = SEC_FindPermCertByKey(handle, certKey);
-
- if ( entry == NULL ) {
- goto loser;
- }
-
- cert = SEC_AddPermCertToTemp(handle, entry);
- }
- loser:
- if ( locked ) {
- CERT_UnlockDB(handle);
- }
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(cert);
- }
- /*
- * Lookup a certificate in the databases, with locking
- */
- CERTCertificate *
- CERT_FindCertByKey(CERTCertDBHandle *handle, SECItem *certKey)
- {
- return(FindCertByKey(handle, certKey, PR_TRUE));
- }
- /*
- * Lookup a certificate in the databases without locking
- */
- CERTCertificate *
- CERT_FindCertByKeyNoLocking(CERTCertDBHandle *handle, SECItem *certKey)
- {
- return(FindCertByKey(handle, certKey, PR_FALSE));
- }
- /*
- * Generate a key from an issuerAndSerialNumber, and find the
- * associated cert in the database.
- */
- CERTCertificate *
- CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle, CERTIssuerAndSN *issuerAndSN)
- {
- SECItem certKey;
- CERTCertificate *cert;
-
- certKey.len = issuerAndSN->serialNumber.len + issuerAndSN->derIssuer.len;
- certKey.data = (unsigned char*)PORT_Alloc(certKey.len);
-
- if ( certKey.data == NULL ) {
- return(0);
- }
- /* copy the serialNumber */
- PORT_Memcpy(certKey.data, issuerAndSN->serialNumber.data,
- issuerAndSN->serialNumber.len);
- /* copy the issuer */
- PORT_Memcpy( &certKey.data[issuerAndSN->serialNumber.len],
- issuerAndSN->derIssuer.data, issuerAndSN->derIssuer.len);
- cert = CERT_FindCertByKey(handle, &certKey);
-
- PORT_Free(certKey.data);
-
- return(cert);
- }
- /*
- * Lookup a certificate in the database by name
- */
- CERTCertificate *
- CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name)
- {
- CERTCertificate *cert = NULL;
- CERTSubjectList *subjectList;
-
- CERT_LockDB(handle);
- subjectList = FindSubjectList(handle, name, PR_FALSE);
- if ( subjectList ) {
- PORT_Assert(subjectList->head);
- cert = CERT_FindCertByKeyNoLocking(handle,
- &subjectList->head->certKey);
- }
-
- CERT_UnlockDB(handle);
- return(cert);
- }
- /*
- * Lookup a certificate in the database by name and key ID
- */
- CERTCertificate *
- CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID)
- {
- CERTCertificate *cert = NULL;
- CERTSubjectList *subjectList;
- CERTSubjectNode *node;
- CERT_LockDB(handle);
- /* find the list of certs for the given subject */
- subjectList = FindSubjectList(handle, name, PR_FALSE);
- if ( subjectList ) {
- PORT_Assert(subjectList->head);
- node = subjectList->head;
- /* walk through the certs until we find one with a matching key ID */
- while ( node ) {
- if ( SECITEM_CompareItem(keyID, &node->keyID) == SECEqual ) {
- cert = CERT_FindCertByKeyNoLocking(handle, &node->certKey);
- break;
- }
- node = node->next;
- }
- }
- CERT_UnlockDB(handle);
- return(cert);
- }
- /*
- * look up a cert by its nickname string
- */
- CERTCertificate *
- CERT_FindCertByNickname(CERTCertDBHandle *handle, char *nickname)
- {
- DBT tmpdata;
- DBT namekey;
- CERTCertificate *cert;
- SECStatus rv;
- int ret;
- SECItem keyitem;
- PRArenaPool *arena = NULL;
- certDBEntryCert *entry;
-
- PORT_Assert(nickname != NULL);
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- rv = EncodeDBNicknameKey(nickname, arena, &keyitem);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- namekey.data = keyitem.data;
- namekey.size = keyitem.len;
-
- /* lookup in the temporary database */
- ret = certdb_Get(handle->tempCertDB, &namekey, &tmpdata, 0);
- /* error accessing the database */
- if ( ret < 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- if ( ret == 0 ) { /* found in temp database */
- SECItem nameitem;
-
- nameitem.len = tmpdata.size;
- nameitem.data = (unsigned char *)PORT_Alloc(tmpdata.size);
- if ( nameitem.data == NULL ) {
- goto loser;
- }
- PORT_Memcpy(nameitem.data, tmpdata.data, nameitem.len);
- cert = CERT_FindCertByName(handle, &nameitem);
- PORT_Free(nameitem.data);
- } else { /* not found in temporary database */
- CERT_LockDB(handle);
-
- entry = SEC_FindPermCertByNickname(handle, nickname);
-
- if ( entry == NULL ) {
- CERT_UnlockDB(handle);
- goto loser;
- }
-
- cert = SEC_AddPermCertToTemp(handle, entry);
- CERT_UnlockDB(handle);
- }
- PORT_FreeArena(arena, PR_FALSE);
- return(cert);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(0);
- }
- /*
- * look for the given DER certificate in the database
- */
- CERTCertificate *
- CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert)
- {
- PRArenaPool *arena;
- SECItem certKey;
- SECStatus rv;
- CERTCertificate *cert = NULL;
-
- /* create a scratch arena */
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- return(NULL);
- }
-
- /* extract the database key from the cert */
- rv = CERT_KeyFromDERCert(arena, derCert, &certKey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* find the certificate */
- cert = CERT_FindCertByKey(handle, &certKey);
-
- loser:
- PORT_FreeArena(arena, PR_FALSE);
- return(cert);
- }
- /*
- * The following is bunch of types and code to allow looking up a certificate
- * by a hash of its subject public key. Because the words "hash" and "key"
- * are overloaded and thus terribly confusing, I tried to disambiguate things.
- * - Where I could, I used "digest" instead of "hash" when referring to
- * hashing of the subject public key. The PLHashTable interfaces and
- * our own HASH_Foo interfaces had to be left as is, obviously. The latter
- * should be thought of as "digest" in this case.
- * - There are three keys in use here -- the subject public key, the key
- * used to do a lookup in the PLHashTable, and the key used to do a lookup
- * in the cert database. As the latter is a fairly pervasive interface,
- * I left it alone. The other two uses I changed to "spk" or "SPK" when
- * referring to the subject public key, and "index" when referring to the
- * key into the PLHashTable.
- */
- typedef struct SPKDigestInfoStr {
- PLHashTable *table;
- PRBool permPopulated;
- } SPKDigestInfo;
- /*
- * Since the key hash information is "hidden" (in a void pointer in the handle)
- * these macros with the appropriate casts make it easy to get at the parts.
- */
- #define SPK_DIGEST_TABLE(handle)
- (((SPKDigestInfo *)(handle->spkDigestInfo))->table)
- /*
- ** Hash allocator ops for the SPKDigest hash table. The rules are:
- ** + The index and value fields are "owned" by the hash table, and are
- ** freed when the table entry is deleted.
- ** + Replacing a value in the table is not allowed, since the caller can't
- ** tell whether the index field was used or not, resulting in a memory
- ** leak. (This is a bug in the PL_Hash routines.
- */
- static void * PR_CALLBACK
- spkAllocTable(void *pool, PRSize size)
- {
- #if defined(XP_MAC)
- #pragma unused (pool)
- #endif
- return PR_MALLOC(size);
- }
- static void PR_CALLBACK
- spkFreeTable(void *pool, void *item)
- {
- #if defined(XP_MAC)
- #pragma unused (pool)
- #endif
- PR_Free(item);
- }
- /* NOTE: the key argument here appears to be useless, since the RawAdd
- * routine in PL_Hash just uses the original anyway.
- */
- static PLHashEntry * PR_CALLBACK
- spkAllocEntry(void *pool, const void *key)
- {
- #if defined(XP_MAC)
- #pragma unused (pool,key)
- #endif
- return PR_NEW(PLHashEntry);
- }
- static void PR_CALLBACK
- spkFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
- {
- #if defined(XP_MAC)
- #pragma unused (pool)
- #endif
- SECItem *value = (SECItem *)he->value;
- /* The flag should always be to free the whole entry. Otherwise the
- * index field gets leaked because the caller can't tell whether
- * the "new" value (which is the same as the old) was used or not.
- */
- PORT_Assert(flag == HT_FREE_ENTRY);
- /* We always free the value */
- SECITEM_FreeItem(value, PR_TRUE);
-
- if (flag == HT_FREE_ENTRY)
- {
- /* Comes from BTOA, is this the right free call? */
- PORT_Free((char *)he->key);
- PR_Free(he);
- }
- }
- static PLHashAllocOps spkHashAllocOps = {
- spkAllocTable, spkFreeTable,
- spkAllocEntry, spkFreeEntry
- };
- /*
- * Create the key hash lookup table. Note that the table, and the
- * structure which holds it and a little more information, is never freed.
- * This is because the temporary database is never actually closed out,
- * so there is no safe/obvious place to free the whole thing.
- *
- * The database must be locked already.
- */
- static SECStatus
- InitDBspkDigestInfo(CERTCertDBHandle *handle)
- {
- SPKDigestInfo *spkDigestInfo;
- PLHashTable *table;
- PORT_Assert(handle != NULL);
- PORT_Assert(handle->spkDigestInfo == NULL);
- spkDigestInfo = PORT_ZAlloc(sizeof(SPKDigestInfo));
- if ( spkDigestInfo == NULL ) {
- return(SECFailure);
- }
- table = PL_NewHashTable(128, PL_HashString, PL_CompareStrings,
- (PLHashComparator) SECITEM_ItemsAreEqual,
- &spkHashAllocOps, NULL);
- if ( table == NULL ) {
- PORT_Free(spkDigestInfo);
- return(SECFailure);
- }
- spkDigestInfo->table = table;
- handle->spkDigestInfo = spkDigestInfo;
- return(SECSuccess);
- }
- static SECHashObject *
- OidTagToRawDigestObject(SECOidTag digestAlg)
- {
- SECHashObject *rawDigestObject;
- switch (digestAlg) {
- case SEC_OID_MD2:
- rawDigestObject = &SECRawHashObjects[HASH_AlgMD2];
- break;
- case SEC_OID_MD5:
- rawDigestObject = &SECRawHashObjects[HASH_AlgMD5];
- break;
- case SEC_OID_SHA1:
- rawDigestObject = &SECRawHashObjects[HASH_AlgSHA1];
- break;
- default:
- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
- rawDigestObject = NULL;
- break;
- }
- return(rawDigestObject);
- }
- /*
- * Digest the cert's subject public key using the specified algorithm.
- * The necessary storage for the digest data is allocated. If "fill" is
- * non-null, the data is put there, otherwise a SECItem is allocated.
- * Allocation from "arena" if it is non-null, heap otherwise. Any problem
- * results in a NULL being returned (and an appropriate error set).
- */
- SECItem *
- CERT_SPKDigestValueForCert(PRArenaPool *arena, CERTCertificate *cert,
- SECOidTag digestAlg, SECItem *fill)
- {
- SECHashObject *digestObject;
- void *digestContext;
- SECItem *result = NULL;
- void *mark = NULL;
- SECItem spk;
- if ( arena != NULL ) {
- mark = PORT_ArenaMark(arena);
- }
- /*
- * This can end up being called before PKCS #11 is initialized,
- * so we have to use the raw digest functions.
- */
- digestObject = OidTagToRawDigestObject(digestAlg);
- if ( digestObject == NULL ) {
- goto loser;
- }
- result = SECITEM_AllocItem(arena, fill, digestObject->length);
- if ( result == NULL ) {
- goto loser;
- }
- /*
- * Copy just the length and data pointer (nothing needs to be freed)
- * of the subject public key so we can convert the length from bits
- * to bytes, which is what the digest function expects.
- */
- spk = cert->subjectPublicKeyInfo.subjectPublicKey;
- DER_ConvertBitString(&spk);
- /*
- * Now digest the value, using the specified algorithm.
- */
- digestContext = digestObject->create();
- if ( digestContext == NULL ) {
- goto loser;
- }
- digestObject->begin(digestContext);
- digestObject->update(digestContext, spk.data, spk.len);
- digestObject->end(digestContext, result->data, &(result->len), result->len);
- digestObject->destroy(digestContext, PR_TRUE);
- if ( arena != NULL ) {
- PORT_ArenaUnmark(arena, mark);
- }
- return(result);
- loser:
- if ( arena != NULL ) {
- PORT_ArenaRelease(arena, mark);
- } else {
- if ( result != NULL ) {
- SECITEM_FreeItem(result, (fill == NULL) ? PR_TRUE : PR_FALSE);
- }
- }
- return(NULL);
- }
- /*
- * Return the index for the spk digest lookup table for "spkDigest".
- *
- * Caller is responsible for freeing the returned string.
- */
- static char *
- spkDigestIndexFromDigest(SECItem *spkDigest)
- {
- return BTOA_ConvertItemToAscii(spkDigest);
- }
- /*
- * Return the index for the spk digest lookup table for this certificate,
- * based on the specified digest algorithm.
- *
- * Caller is responsible for freeing the returned string.
- */
- static char *
- spkDigestIndexFromCert(CERTCertificate *cert, SECOidTag digestAlg)
- {
- SECItem *spkDigest;
- char *index;
- spkDigest = CERT_SPKDigestValueForCert(NULL, cert, digestAlg, NULL);
- if ( spkDigest == NULL )
- return(NULL);
- index = spkDigestIndexFromDigest(spkDigest);
- SECITEM_FreeItem(spkDigest, PR_TRUE);
- return(index);
- }
- /*
- * Remove the spk digest for the given cert from the spk digest table,
- * based on the given digest algorithm.
- *
- * The database must be locked already.
- */
- static SECStatus
- RemoveCertFromSPKDigestTableForAlg(CERTCertDBHandle *handle,
- CERTCertificate *cert, SECOidTag digestAlg)
- {
- SECStatus rv = SECSuccess;
- char *index = NULL;
- PLHashTable *table;
- /* Expect to only be called if there is a table to work with. */
- PORT_Assert(handle->spkDigestInfo != NULL);
- table = SPK_DIGEST_TABLE(handle);
- PORT_Assert(table != NULL);
- index = spkDigestIndexFromCert(cert, digestAlg);
- if ( index == NULL ) {
- rv = SECFailure;
- goto done;
- }
- if ( PL_HashTableRemove(table, index) != PR_TRUE ) {
- /* not found means nothing to remove, which is fine */
- }
- done:
- if ( index != NULL ) {
- PORT_Free(index);
- }
- return(rv);
- }
- /*
- * Remove the spk digests for the given cert from the spk digest table,
- * for all known digest algorithms.
- *
- * The database must be locked already.
- */
- static SECStatus
- RemoveCertFromSPKDigestTable(CERTCertDBHandle *handle, CERTCertificate *cert)
- {
- /*
- * If no certs have been added yet, then nothing to do.
- */
- if ( handle->spkDigestInfo == NULL ) {
- return(SECSuccess);
- }
- (void) RemoveCertFromSPKDigestTableForAlg(handle, cert, SEC_OID_MD2);
- (void) RemoveCertFromSPKDigestTableForAlg(handle, cert, SEC_OID_MD5);
- return RemoveCertFromSPKDigestTableForAlg(handle, cert, SEC_OID_SHA1);
- }
- /*
- * Add the spk digest for the given cert to the spk digest table,
- * based on the given digest algorithm.
- *
- * If a cert for the same spk digest is already in the table, choose whichever
- * cert is "newer". (The other cert cannot be found via spk digest.)
- *
- * The database must be locked already.
- *
- * XXX Note that this implementation results in leaking the index value.
- * Fixing that did not seem worth the trouble, given we will only leak
- * once per cert. This whole thing should be done differently in the
- * new rewrite (Stan), and then the problem will go away.
- */
- static SECStatus
- AddCertToSPKDigestTableForAlg(CERTCertDBHandle *handle, CERTCertificate *cert,
- SECItem *certDBKey, SECOidTag digestAlg)
- {
- SECStatus rv = SECFailure;
- SECItem *oldCertDBKey;
- PRBool addit = PR_TRUE;
- CERTCertificate *oldCert = NULL;
- char *index = NULL;
- PLHashTable *table;
- /*
- * After running some testing doing key hash lookups (like using OCSP),
- * if these are never hit, they can probably be removed.
- */
- PORT_Assert(handle != NULL);
- PORT_Assert(handle == cert->dbhandle);
- PORT_Assert(handle->spkDigestInfo != NULL);
- PORT_Assert((certDBKey == &cert->certKey)
- || (SECITEM_CompareItem(certDBKey,
- &cert->certKey) == SECEqual));
- table = SPK_DIGEST_TABLE(handle);
- PORT_Assert(table != NULL);
- index = spkDigestIndexFromCert(cert, digestAlg);
- if ( index == NULL ) {
- goto loser;
- }
- /*
- * See if this cert's spk digest is already in the table.
- */
- oldCertDBKey = PL_HashTableLookup(table, index);
- if ( oldCertDBKey != NULL ) {
- /*
- * The spk digest *is* already in the table. We need to find that
- * cert and see -- if it is the same, then we can just leave as is.
- * Otherwise we have to choose which cert we want represented;
- * in that case the best plan I can think of is to hang onto the
- * most recent one.
- */
- oldCert = CERT_FindCertByKey(handle, oldCertDBKey);
- if ( oldCert != NULL ) {
- if ( cert == oldCert ) {
- /* They are the same cert, so we are done. */
- addit = PR_FALSE;
- } else if ( CERT_IsNewer(cert, oldCert) ) {
- if ( PL_HashTableRemove(table, index) != PR_TRUE ) {
- goto loser;
- }
- } else {
- /* oldCert is "newer", so we are done. */
- addit = PR_FALSE;
- }
- }
- }
- if ( addit ) {
- certDBKey = SECITEM_DupItem(certDBKey);
- if ( certDBKey == NULL ) {
- goto loser;
- }
- if ( PL_HashTableAdd(table, index, certDBKey) == NULL ) {
- SECITEM_FreeItem(certDBKey, PR_TRUE);
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
- index = NULL; /* don't want to free it */
- }
- rv = SECSuccess;
- loser:
- if ( index != NULL ) {
- PORT_Free(index);
- }
- if ( oldCert != NULL ) {
- CERT_DestroyCertificate(oldCert);
- }
- return(rv);
- }
- /*
- * Add the spk digest for the given cert to the spk digest table,
- * for all known digest algorithms.
- *
- * The database must be locked already, and the digest table already created.
- */
- static SECStatus
- AddCertToSPKDigestTableForAllAlgs(CERTCertDBHandle *handle,
- CERTCertificate *cert, SECItem *certDBKey)
- {
- (void) AddCertToSPKDigestTableForAlg(handle, cert, certDBKey, SEC_OID_MD2);
- (void) AddCertToSPKDigestTableForAlg(handle, cert, certDBKey, SEC_OID_MD5);
- return AddCertToSPKDigestTableForAlg(handle, cert, certDBKey, SEC_OID_SHA1);
- }
- /*
- * Add the spk digests for the given cert to the spk digest table,
- * for all known digest algorithms. (This function is called when a
- * new cert is added to the temporary database.)
- *
- * If the spk digest table does not yet exist, create it.
- *
- * In an ideal world, we would not hardwire the digest algorithms.
- * But it is the case that we do not currently support any digest
- * algorithms outside of these three. In the newer, cleaned-up world,
- * this may be done differently.
- *
- * The database must be locked already.
- */
- static SECStatus
- AddCertToSPKDigestTable(CERTCertDBHandle *handle, CERTCertificate *cert)
- {
- SECStatus rv;
- if ( handle->spkDigestInfo == NULL ) {
- rv = InitDBspkDigestInfo(handle);
- if ( rv != SECSuccess ) {
- return(rv);
- }
- }
- return AddCertToSPKDigestTableForAllAlgs(handle, cert, &cert->certKey);
- }
- /*
- * Add the spk digest for the given cert to the spk digest table,
- * for all known digest algorithms. This function is called while
- * traversing all of the certs in the permanent database -- since
- * that imposes some constraints on its arguments this routine is a
- * simple cover for the "real" interface.
- *
- * The database must be locked already, and the digest table already created.
- */
- static SECStatus
- AddCertToSPKDigestTableInTraversal(CERTCertificate *cert, SECItem *certDBKey,
- void *data)
- {
- CERTCertDBHandle *handle = data;
- return AddCertToSPKDigestTableForAllAlgs(handle, cert, certDBKey);
- }
- /*
- * Add the spk digests for the all permanent certs to the spk digest table,
- * for all known digest algorithms.
- *
- * This locks the database, and then checks to make sure that the work
- * actually needs to get done.
- *
- * If the spk digest table does not yet exist, it is created.
- */
- static SECStatus
- PopulateSPKDigestTable(CERTCertDBHandle *handle)
- {
- SPKDigestInfo *spkDigestInfo;
- SECStatus rv = SECSuccess;
- CERT_LockDB(handle);
- spkDigestInfo = handle->spkDigestInfo;
- if ( spkDigestInfo == NULL ) {
- rv = InitDBspkDigestInfo(handle);
- if ( rv != SECSuccess ) {
- return(rv);
- }
- spkDigestInfo = handle->spkDigestInfo;
- PORT_Assert(spkDigestInfo != NULL);
- } else {
- /*
- * Check to see if someone already did it; it is important to do
- * this after getting the lock.
- */
- if ( spkDigestInfo->permPopulated == PR_TRUE ) {
- goto done;
- }
- }
- rv = TraversePermCertsNoLocking(handle, AddCertToSPKDigestTableInTraversal,
- handle);
- if ( rv != SECSuccess ) {
- goto done;
- }
- spkDigestInfo->permPopulated = PR_TRUE;
- done:
- CERT_UnlockDB(handle);
- return(rv);
- }
- /*
- * Lookup a certificate by a digest of a subject public key. If it is
- * found, it is returned (and must then be destroyed by the caller).
- * NULL is returned otherwise -- if there was a problem performing the
- * lookup, an appropriate error is set (e.g. SEC_ERROR_NO_MEMORY);
- * if the cert simply was not found, the error is SEC_ERROR_UNKNOWN_CERT.
- *
- * If the lookup table has not yet been created or populated, do that first.
- */
- CERTCertificate *
- CERT_FindCertBySPKDigest(CERTCertDBHandle *handle, SECItem *spkDigest)
- {
- SPKDigestInfo *spkDigestInfo;
- char *index = NULL;
- SECItem *certDBKey;
- CERTCertificate *cert = NULL;
- PORT_Assert(handle != NULL);
- spkDigestInfo = handle->spkDigestInfo;
- if ( spkDigestInfo == NULL || spkDigestInfo->permPopulated != PR_TRUE ) {
- if ( PopulateSPKDigestTable(handle) != SECSuccess ) {
- goto loser;
- }
- }
- index = spkDigestIndexFromDigest(spkDigest);
- if ( index == NULL ) {
- goto loser;
- }
- certDBKey = PL_HashTableLookup(SPK_DIGEST_TABLE(handle), index);
- if ( certDBKey != NULL ) {
- cert = CERT_FindCertByKey(handle, certDBKey);
- }
- if ( cert == NULL ) {
- PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
- }
- loser:
- if ( index != NULL ) {
- PORT_Free(index);
- }
- return(cert);
- }
- static void
- DestroyCertificate(CERTCertificate *cert, PRBool lockdb)
- {
- int refCount;
- CERTCertDBHandle *handle;
-
- if ( cert ) {
- handle = cert->dbhandle;
- /*
- * handle may be NULL, for example if the cert was created with
- * CERT_DecodeDERCertificate.
- */
- if ( lockdb && handle ) {
- CERT_LockDB(handle);
- }
- CERT_LockCertRefCount(cert);
- PORT_Assert(cert->referenceCount > 0);
- refCount = --cert->referenceCount;
- CERT_UnlockCertRefCount(cert);
- if ( ( refCount == 0 ) && !cert->keepSession ) {
- certDBEntryCert *entry = cert->dbEntry;
- PRArenaPool * arena = cert->arena;
- if ( cert->istemp ) {
- CERT_DeleteTempCertificate(cert);
- }
- if ( entry ) {
- DestroyDBEntry((certDBEntry *)entry);
- }
- /* zero cert before freeing. Any stale references to this cert
- * after this point will probably cause an exception. */
- PORT_Memset(cert, 0, sizeof *cert);
- cert = NULL;
-
- /* free the arena that contains the cert. */
- PORT_FreeArena(arena, PR_FALSE);
- }
- if ( lockdb && handle ) {
- CERT_UnlockDB(handle);
- }
- }
- return;
- }
- void
- CERT_DestroyCertificate(CERTCertificate *cert)
- {
- DestroyCertificate(cert, PR_TRUE);
- return;
- }
- void
- CERT_DestroyCertificateNoLocking(CERTCertificate *cert)
- {
- DestroyCertificate(cert, PR_FALSE);
- return;
- }
- /*
- * cache a CRL from the permanent database into the temporary database
- */
- CERTSignedCrl *
- SEC_AddPermCrlToTemp(CERTCertDBHandle *handle, certDBEntryRevocation *entry)
- {
- CERTSignedCrl *crl = NULL;
- DBT key;
- DBT data;
- int status;
- PRArenaPool *arena = NULL;
- SECItem keyitem;
- SECStatus rv;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- crl = CERT_DecodeDERCrl(NULL, &entry->derCrl,
- entry->common.type == certDBEntryTypeRevocation ?
- SEC_CRL_TYPE : SEC_KRL_TYPE);
-
- if ( crl == NULL ) {
- goto loser;
- }
- /* only save pointer to cert in database */
- data.data = &crl;
- data.size = sizeof(crl);
- rv = EncodeDBGenericKey(&(crl->crl.derName), arena,
- &keyitem, entry->common.type);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- if (entry->url) {
- int nnlen = PORT_Strlen(entry->url) + 1;
- crl->url = (char *)PORT_ArenaAlloc(crl->arena, nnlen);
- if ( !crl->url ) {
- goto loser;
- }
- PORT_Memcpy(crl->url, entry->url, nnlen);
- } else {
- crl->url = NULL;
- }
-
- key.data = keyitem.data;
- key.size = keyitem.len;
-
- /* enter into main db */
- status = certdb_Put(handle->tempCertDB, &key, &data, R_NOOVERWRITE);
- if ( status ) {
- goto loser;
- }
- crl->istemp = PR_TRUE;
- crl->isperm = PR_TRUE;
- crl->dbhandle = handle;
- crl->dbEntry = entry;
-
- PORT_FreeArena(arena, PR_FALSE);
- crl->keep = PR_TRUE;
- return(crl);
- loser:
- if ( crl ) {
- SEC_DestroyCrl(crl);
- }
-
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- return(0);
- }
- SECStatus
- SEC_DeleteTempCrl(CERTSignedCrl *crl)
- {
- SECStatus rv;
- DBT nameKey;
- CERTCertDBHandle *handle;
- SECItem keyitem;
- PRArenaPool *arena;
- int ret;
-
- handle = crl->dbhandle;
- if ( !crl->istemp ) {
- return(SECSuccess);
- }
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
- rv = EncodeDBGenericKey
- (&crl->crl.derName, arena, &keyitem, crl->dbEntry->common.type);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- nameKey.data = keyitem.data;
- nameKey.size = keyitem.len;
- /* delete the cert */
- ret = certdb_Del(handle->tempCertDB, &nameKey, 0);
- if ( ret ) {
- goto loser;
- }
- crl->istemp = PR_FALSE;
- PORT_FreeArena(arena, PR_FALSE);
- return(SECSuccess);
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- return(SECFailure);
- }
- /*
- * Lookup a CRL in the databases. We mirror the same fast caching data base
- * caching stuff used by certificates....?
- */
- CERTSignedCrl *
- SEC_FindCrlByKey(CERTCertDBHandle *handle, SECItem *crlKey, int type)
- {
- DBT tmpdata;
- int ret;
- SECItem keyitem;
- DBT key;
- SECStatus rv;
- CERTSignedCrl *crl = NULL;
- PRArenaPool *arena = NULL;
- certDBEntryRevocation *entry;
- certDBEntryType crlType = (type == SEC_CRL_TYPE) ?
- certDBEntryTypeRevocation : certDBEntryTypeKeyRevocation;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- rv = EncodeDBGenericKey(crlKey, arena, &keyitem, crlType);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- key.data = keyitem.data;
- key.size = keyitem.len;
-
- /* lookup in the temporary database */
- ret = certdb_Get( handle->tempCertDB, &key, &tmpdata, 0 );
- /* error accessing the database */
- if ( ret < 0 ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
- if ( ret == 0 ) { /* found in temp database */
- if ( tmpdata.size != sizeof(CERTSignedCrl *) ) {
- PORT_SetError(SEC_ERROR_BAD_DATABASE);
- goto loser;
- }
-
- PORT_Memcpy(&crl, tmpdata.data, tmpdata.size);
- crl->referenceCount++;
- } else { /* not found in temporary database */
- /* find in perm database */
- entry = ReadDBCrlEntry(handle, crlKey, crlType);
-
- if ( entry == NULL ) {
- goto loser;
- }
-
- crl = SEC_AddPermCrlToTemp(handle, entry);
- }
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
-
- return(crl);
- }
- CERTSignedCrl *
- SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
- {
- return SEC_FindCrlByKey(handle,crlKey,type);
- }
- CERTSignedCrl *
- SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
- {
- PRArenaPool *arena;
- SECItem crlKey;
- SECStatus rv;
- CERTSignedCrl *crl = NULL;
-
- /* create a scratch arena */
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- return(NULL);
- }
-
- /* extract the database key from the cert */
- rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- /* find the crl */
- crl = SEC_FindCrlByKey(handle, &crlKey, type);
-
- loser:
- PORT_FreeArena(arena, PR_FALSE);
- return(crl);
- }
- SECStatus
- SEC_DestroyCrl(CERTSignedCrl *crl)
- {
- if (crl) {
- if (crl->referenceCount-- <= 1) {
- if (!crl->keep) {
- SEC_DeleteTempCrl(crl);
- if (crl->dbEntry) {
- DestroyDBEntry((certDBEntry *)crl->dbEntry);
- }
- PORT_FreeArena(crl->arena, PR_FALSE);
- }
- }
- }
- return SECSuccess;
- }
- CERTSignedCrl *
- cert_DBInsertCRL (CERTCertDBHandle *handle, char *url,
- CERTSignedCrl *newCrl, SECItem *derCrl, int type)
- {
- CERTSignedCrl *oldCrl = NULL, *crl = NULL;
- certDBEntryRevocation *entry = NULL;
- PRArenaPool *arena = NULL;
- SECCertTimeValidity validity;
- certDBEntryType crlType = (type == SEC_CRL_TYPE) ?
- certDBEntryTypeRevocation : certDBEntryTypeKeyRevocation;
- SECStatus rv;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL) goto done;
- validity = SEC_CheckCrlTimes(&newCrl->crl,PR_Now());
- if ( validity == secCertTimeExpired) {
- if (type == SEC_CRL_TYPE) {
- PORT_SetError(SEC_ERROR_CRL_EXPIRED);
- } else {
- PORT_SetError(SEC_ERROR_KRL_EXPIRED);
- }
- goto done;
- } else if (validity == secCertTimeNotValidYet) {
- if (type == SEC_CRL_TYPE) {
- PORT_SetError(SEC_ERROR_CRL_NOT_YET_VALID);
- } else {
- PORT_SetError(SEC_ERROR_KRL_NOT_YET_VALID);
- }
- goto done;
- }
- oldCrl = SEC_FindCrlByKey(handle, &newCrl->crl.derName, type);
- /* if there is an old crl, make sure the one we are installing
- * is newer. If not, exit out, otherwise delete the old crl.
- */
- if (oldCrl != NULL) {
- if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
- if (type == SEC_CRL_TYPE) {
- PORT_SetError(SEC_ERROR_OLD_CRL);
- } else {
- PORT_SetError(SEC_ERROR_OLD_KRL);
- }
- goto done;
- }
- if ((SECITEM_CompareItem(&newCrl->crl.derName,
- &oldCrl->crl.derName) != SECEqual) &&
- (type == SEC_KRL_TYPE) ) {
-
- PORT_SetError(SEC_ERROR_CKL_CONFLICT);
- goto done;
- }
- /* if we have a url in the database, use that one */
- if (oldCrl->url) {
- int nnlen = PORT_Strlen(oldCrl->url) + 1;
- url = (char *)PORT_ArenaAlloc(arena, nnlen);
- if ( url != NULL ) {
- PORT_Memcpy(url, oldCrl->url, nnlen);
- }
- }
- /* really destroy this crl */
- /* first drum it out of the permanment Data base */
- SEC_DeletePermCRL(oldCrl);
- /* then get rid of our reference to it... */
- SEC_DestroyCrl(oldCrl);
- oldCrl = NULL;
- }
- /* Write the new entry into the data base */
- entry = NewDBCrlEntry(derCrl, url, crlType, 0);
- if (entry == NULL) goto done;
- rv = WriteDBCrlEntry(handle, entry);
- if (rv != SECSuccess) goto done;
- crl = SEC_AddPermCrlToTemp(handle, entry);
- if (crl) entry = NULL; /*crl->dbEntry now points to entry data */
- crl->isperm = PR_TRUE;
- done:
- if (entry) DestroyDBEntry((certDBEntry *)entry);
- if (arena) PORT_FreeArena(arena, PR_FALSE);
- if (oldCrl) SEC_DestroyCrl(oldCrl);
- return crl;
- }
- /*
- * create a new CRL from DER material.
- *
- * The signature on this CRL must be checked before you
- * load it. ???
- */
- CERTSignedCrl *
- SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
- {
- CERTSignedCrl *newCrl = NULL, *crl = NULL;
- /* make this decode dates! */
- newCrl = CERT_DecodeDERCrl(NULL, derCrl, type);
- if (newCrl == NULL) {
- if (type == SEC_CRL_TYPE) {
- PORT_SetError(SEC_ERROR_CRL_INVALID);
- } else {
- PORT_SetError(SEC_ERROR_KRL_INVALID);
- }
- goto done;
- }
- crl = cert_DBInsertCRL (handle, url, newCrl, derCrl, type);
- done:
- if (newCrl) PORT_FreeArena(newCrl->arena, PR_FALSE);
- return crl;
- }
- /*
- * replace the existing URL in the data base with a new one
- */
- SECStatus
- SEC_CrlReplaceUrl(CERTSignedCrl *crl,char *url) {
- SECStatus rv = SECFailure;
- certDBEntryRevocation *entry = NULL;
- int nnlen=0;
- SEC_DeletePermCRL(crl);
- /* Write the new entry into the data base */
- entry = NewDBCrlEntry(&crl->dbEntry->derCrl, url, crl->dbEntry->common.type, 0);
- if (entry == NULL) goto done;
- rv = WriteDBCrlEntry(crl->dbhandle, entry);
- if (rv != SECSuccess) goto done;
- if (url) {
- nnlen = PORT_Strlen(url) + 1;
- crl->url = (char *)PORT_ArenaAlloc(crl->arena, nnlen);
- if ( !crl->url ) {
- goto done;
- }
- PORT_Memcpy(crl->url, url, nnlen);
- } else {
- crl->url = NULL;
- }
- done:
- return rv;
- }
-
- /*
- * collect a linked list of CRL's
- */
- static SECStatus CollectCrls(SECItem *dbdata, SECItem *dbkey,
- certDBEntryType type, void *data) {
- SECStatus rv;
- certDBEntryRevocation entry;
- SECItem entryitem;
- PRArenaPool *arena = NULL;
- CERTCrlHeadNode *head;
- CERTCrlNode *new_node;
-
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- goto loser;
- }
-
- head = (CERTCrlHeadNode *)data;
- entry.common.version = (unsigned int)dbdata->data[0];
- entry.common.type = (certDBEntryType)dbdata->data[1];
- entry.common.flags = (unsigned int)dbdata->data[2];
- entry.common.arena = arena;
-
- entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN;
- entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN];
-
- rv = DecodeDBCrlEntry(&entry, &entryitem);
- if (rv != SECSuccess ) {
- goto loser;
- }
- new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
- if (new_node == NULL) {
- goto loser;
- }
- new_node->type = (entry.common.type == certDBEntryTypeRevocation) ?
- SEC_CRL_TYPE : SEC_KRL_TYPE;
- new_node->crl=CERT_DecodeDERCrl(head->arena,&entry.derCrl,new_node->type);
- if (entry.url) {
- int nnlen = PORT_Strlen(entry.url) + 1;
- new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen);
- if ( !new_node->crl->url ) {
- goto loser;
- }
- PORT_Memcpy(new_node->crl->url, entry.url, nnlen);
- } else {
- new_node->crl->url = NULL;
- }
-
- new_node->next = NULL;
- if (head->last) {
- head->last->next = new_node;
- head->last = new_node;
- } else {
- head->first = head->last = new_node;
- }
- return (SECSuccess);
-
- loser:
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- }
- return(SECFailure);
- }
-
- SECStatus
- SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
- {
- CERTCrlHeadNode *head;
- PRArenaPool *arena = NULL;
- SECStatus rv;
- *nodes = NULL;
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if ( arena == NULL ) {
- return SECFailure;
- }
- /* build a head structure */
- head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
- head->arena = arena;
- head->first = NULL;
- head->last = NULL;
- head->dbhandle = handle;
- /* Look up the proper crl types */
- *nodes = head;
-
- CERT_LockDB(handle);
-
- switch (type) {
- case SEC_CRL_TYPE:
- rv = SEC_TraverseDBEntries(handle, certDBEntryTypeRevocation,
- CollectCrls, (void *)head);
- break;
- case SEC_KRL_TYPE:
- rv = SEC_TraverseDBEntries(handle, certDBEntryTypeKeyRevocation,
- CollectCrls, (void *)head);
- break;
- case -1:
- rv = SEC_TraverseDBEntries(handle, certDBEntryTypeKeyRevocation,
- CollectCrls, (void *)head);
- if (rv != SECSuccess) break;
- rv = SEC_TraverseDBEntries(handle, certDBEntryTypeRevocation,
- CollectCrls, (void *)head);
- break;
- default:
- rv = SECFailure;
- break;
- }
- CERT_UnlockDB(handle);
-
- if (rv != SECSuccess) {
- if ( arena ) {
- PORT_FreeArena(arena, PR_FALSE);
- *nodes = NULL;
- }
- }
- return rv;
- }
-
- SECStatus
- SEC_DeletePermCRL(CERTSignedCrl *crl) {
- SECStatus rv;
- if (crl == NULL) {
- return SECFailure;
- }
-
- rv = DeleteDBCrlEntry(crl->dbhandle, &crl->crl.derName,
- crl->dbEntry->common.type);
- if (rv != SECSuccess) goto done;
- /* now force it to be freed when all the reference counts go */
- crl->keep = PR_FALSE;
- /* force it out of the temporary data base */
- SEC_DeleteTempCrl(crl);
-
- done:
- return rv;
- }
- /*
- * find a cert by email address
- *
- * pick one that is a valid recipient, meaning that it is an encryption
- * cert.
- *
- */
- static CERTCertificate*
- find_smime_recipient_cert(CERTCertDBHandle* handle, const char* email_addr)
- {
- CERTCertificate* cert = NULL;
- CERTCertList* certList = NULL;
- SECStatus rv;
- certList = CERT_CreateEmailAddrCertList(NULL, handle, (char*)email_addr,
- PR_Now(), PR_TRUE);
- if (certList == NULL) {
- return NULL;
- }
- rv = CERT_FilterCertListByUsage(certList, certUsageEmailRecipient,
- PR_FALSE);
- if (!CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
- cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
- }
- CERT_DestroyCertList(certList);
- return cert; /* cert may point to a cert or may be NULL */
- }
- /*
- * This function has the logic that decides if another person's cert and
- * email profile from an S/MIME message should be saved. It can deal with
- * the case when there is no profile.
- */
- SECStatus
- CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile,
- SECItem *profileTime)
- {
- certDBEntrySMime *entry = NULL, *oldentry = NULL;
- int64 oldtime;
- int64 newtime;
- SECStatus rv;
- CERTCertificate *oldcert = NULL;
- PRBool saveit;
- CERTCertTrust trust;
- CERTCertTrust tmptrust;
- char *emailAddr;
-
- emailAddr = cert->emailAddr;
-
- PORT_Assert(emailAddr);
- if ( emailAddr == NULL ) {
- goto loser;
- }
- saveit = PR_FALSE;
-
- oldcert = find_smime_recipient_cert(cert->dbhandle, emailAddr);
- if (oldcert) {
- /* see if there is an entry already */
- oldentry = ReadDBSMimeEntry(cert->dbhandle, emailAddr);
- }
-
- /* both profileTime and emailProfile have to exist or not exist */
- if ( emailProfile == NULL ) {
- profileTime = NULL;
- } else if ( profileTime == NULL ) {
- emailProfile = NULL;
- }
-
- if ( oldentry == NULL ) {
- /* no old entry for this address */
- PORT_Assert(oldcert == NULL);
- saveit = PR_TRUE;
- } else {
- /* there was already a profile for this email addr */
- if ( profileTime ) {
- /* we have an old and new profile - save whichever is more recent*/
- if ( oldentry->optionsDate.len == 0 ) {
- /* always replace if old entry doesn't have a time */
- oldtime = LL_MININT;
- } else {
- rv = DER_UTCTimeToTime(&oldtime, &oldentry->optionsDate);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
-
- rv = DER_UTCTimeToTime(&newtime, profileTime);
- if ( rv != SECSuccess ) {
- goto loser;
- }
-
- if ( LL_CMP(newtime, >, oldtime ) ) {
- /* this is a newer profile, save it and cert */
- saveit = PR_TRUE;
- }
- } else {
- /* we don't have a new profile or time */
- if ( oldentry->optionsDate.len == 0 ) {
- /* the old entry doesn't have a time either, so compare certs*/
- if ( CERT_IsNewer(cert, oldcert) ) {
- /* new cert is newer, use it instead */
- saveit = PR_TRUE;
- }
- } else {
- if (oldcert) {
- if (CERT_IsNewer(cert, oldcert)) {
- saveit = PR_TRUE;
- }
- } else {
- saveit = PR_TRUE;
- }
- }
- }
- }
- if ( saveit ) {
- if ( oldcert && ( oldcert != cert ) ) {
- /* old cert is different from new cert */
- if ( PORT_Memcmp(oldcert->trust, &trust, sizeof(trust)) == 0 ) {
- /* old cert is only for e-mail, so delete it */
- SEC_DeletePermCertificate(oldcert);
- } else {
- /* old cert is for other things too, so just change trust */
- tmptrust = *oldcert->trust;
- tmptrust.emailFlags &= ( ~CERTDB_VALID_PEER );
- rv = CERT_ChangeCertTrust(oldcert->dbhandle, oldcert,
- &tmptrust);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
- }
- /* Subroutine */
- /* now save the entry */
- entry = NewDBSMimeEntry(emailAddr, &cert->derSubject, emailProfile,
- profileTime, 0);
- if ( entry == NULL ) {
- goto loser;
- }
- CERT_LockDB(cert->dbhandle);
- rv = DeleteDBSMimeEntry(cert->dbhandle, emailAddr);
- /* if delete fails, try to write new entry anyway... */
-
- rv = WriteDBSMimeEntry(cert->dbhandle, entry);
- if ( rv != SECSuccess ) {
- CERT_UnlockDB(cert->dbhandle);
- goto loser;
- }
- /* link subject entry back here */
- rv = UpdateSubjectWithEmailAddr(cert, emailAddr);
- if ( rv != SECSuccess ) {
- CERT_UnlockDB(cert->dbhandle);
- goto loser;
- }
- CERT_UnlockDB(cert->dbhandle);
- /* End Subroutine */
- }
- rv = SECSuccess;
- goto done;
-
- loser:
- rv = SECFailure;
-
- done:
- if ( oldcert ) {
- CERT_DestroyCertificate(oldcert);
- }
-
- if ( entry ) {
- DestroyDBEntry((certDBEntry *)entry);
- }
- if ( oldentry ) {
- DestroyDBEntry((certDBEntry *)oldentry);
- }
-
- return(rv);
- }
- CERTCertificate *
- CERT_FindCertByEmailAddr(CERTCertDBHandle *handle, char *emailAddr)
- {
- certDBEntrySMime *entry;
- CERTCertificate *cert = NULL;
- emailAddr = CERT_FixupEmailAddr(emailAddr);
- if ( emailAddr == NULL ) {
- return(NULL);
- }
-
- entry = ReadDBSMimeEntry(handle, emailAddr);
- /* XXX - this will have to change when multiple certs per subject
- * are allowed
- */
- if ( entry != NULL ) {
- cert = CERT_FindCertByName(handle, &entry->subjectName);
- }
- if ( entry ) {
- DestroyDBEntry((certDBEntry *)entry);
- }
- PORT_Free(emailAddr);
-
- return(cert);
- }
- /*
- * find the smime symmetric capabilities profile for a given cert
- */
- SECItem *
- CERT_FindSMimeProfile(CERTCertificate *cert)
- {
- certDBEntrySMime *entry;
- SECItem *retitem = NULL;
-
- PORT_Assert(cert->emailAddr != NULL);
-
- if ( cert->emailAddr == NULL ) {
- return(NULL);
- }
-
- entry = ReadDBSMimeEntry(cert->dbhandle, cert->emailAddr);
- if ( entry ) {
- retitem = SECITEM_DupItem(&entry->smimeOptions);
- DestroyDBEntry((certDBEntry *)entry);
- }
- return(retitem);
- }
- CERTCertificate *
- CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, char *name)
- {
- CERTCertificate *cert;
- cert = CERT_FindCertByNickname(handle, name);
- if ( cert == NULL ) {
- cert = CERT_FindCertByEmailAddr(handle, name);
- }
- return(cert);
- }
- PRBool
- CERT_IsCertRevoked(CERTCertificate *cert)
- {
- return(PR_FALSE);
- }
- CERTCertificate *
- CERT_NextSubjectCert(CERTCertificate *cert)
- {
- CERTSubjectNode *node;
- CERTCertificate *retcert = NULL;
- CERT_LockDB(cert->dbhandle);
-
- node = FindCertSubjectNode(cert);
- PORT_Assert(node != NULL);
-
- if ( node->next != NULL ) {
- retcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
- &node->next->certKey);
- }
- CERT_UnlockDB(cert->dbhandle);
- return(retcert);
- }
- CERTCertificate *
- CERT_PrevSubjectCert(CERTCertificate *cert)
- {
- CERTSubjectNode *node;
- CERTCertificate *retcert = NULL;
-
- CERT_LockDB(cert->dbhandle);
- node = FindCertSubjectNode(cert);
- PORT_Assert(node != NULL);
-
- if ( node->prev != NULL ) {
- retcert = CERT_FindCertByKeyNoLocking(cert->dbhandle,
- &node->prev->certKey);
- }
- CERT_UnlockDB(cert->dbhandle);
- return(retcert);
- }
- SECStatus
- CERT_SaveImportedCert(CERTCertificate *cert, SECCertUsage usage,
- PRBool caOnly, char *nickname)
- {
- SECStatus rv;
- PRBool saveit;
- CERTCertTrust trust;
- CERTCertTrust tmptrust;
- PRBool isCA;
- unsigned int certtype;
- PRBool freeNickname = PR_FALSE;
-
- isCA = CERT_IsCACert(cert, NULL);
- if ( caOnly && ( !isCA ) ) {
- return(SECSuccess);
- }
-
- saveit = PR_TRUE;
-
- PORT_Memset((void *)&trust, 0, sizeof(trust));
- certtype = cert->nsCertType;
- /* if no CA bits in cert type, then set all CA bits */
- if ( isCA && ( ! ( certtype & NS_CERT_TYPE_CA ) ) ) {
- certtype |= NS_CERT_TYPE_CA;
- }
- /* if no app bits in cert type, then set all app bits */
- if ( ( !isCA ) && ( ! ( certtype & NS_CERT_TYPE_APP ) ) ) {
- certtype |= NS_CERT_TYPE_APP;
- }
- if ( isCA && !nickname ) {
- nickname = CERT_MakeCANickname(cert);
- if ( nickname != NULL ) {
- freeNickname = PR_TRUE;
- }
- }
-
- switch ( usage ) {
- case certUsageEmailSigner:
- case certUsageEmailRecipient:
- if ( isCA ) {
- if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
- trust.emailFlags = CERTDB_VALID_CA;
- }
- } else {
- PORT_Assert(nickname == NULL);
- if ( cert->emailAddr == NULL ) {
- saveit = PR_FALSE;
- }
-
- if ( certtype & NS_CERT_TYPE_EMAIL ) {
- trust.emailFlags = CERTDB_VALID_PEER;
- if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
- /* don't save it if KeyEncipherment is not allowed */
- saveit = PR_FALSE;
- }
- }
- }
- break;
- case certUsageUserCertImport:
- if ( isCA ) {
- if ( certtype & NS_CERT_TYPE_SSL_CA ) {
- trust.sslFlags = CERTDB_VALID_CA;
- }
-
- if ( certtype & NS_CERT_TYPE_EMAIL_CA ) {
- trust.emailFlags = CERTDB_VALID_CA;
- }
-
- if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA ) {
- trust.objectSigningFlags = CERTDB_VALID_CA;
- }
-
- } else {
- if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
- trust.sslFlags = CERTDB_VALID_PEER;
- }
-
- if ( certtype & NS_CERT_TYPE_EMAIL ) {
- trust.emailFlags = CERTDB_VALID_PEER;
- }
-
- if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
- trust.objectSigningFlags = CERTDB_VALID_PEER;
- }
- }
- break;
- default: /* XXX added to quiet warnings; no other cases needed? */
- break;
- }
- if ( (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags) == 0 ){
- saveit = PR_FALSE;
- }
- if ( saveit ) {
- if ( cert->isperm ) {
- /* Cert already in the DB. Just adjust flags */
- tmptrust = *cert->trust;
- tmptrust.sslFlags |= trust.sslFlags;
- tmptrust.emailFlags |= trust.emailFlags;
- tmptrust.objectSigningFlags |= trust.objectSigningFlags;
-
- rv = CERT_ChangeCertTrust(cert->dbhandle, cert,
- &tmptrust);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- } else {
- /* Cert not already in the DB. Add it */
- rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
- }
- rv = SECSuccess;
- goto done;
- loser:
- rv = SECFailure;
- done:
- if ( freeNickname ) {
- PORT_Free(nickname);
- }
-
- return(rv);
- }
- SECStatus
- CERT_ChangeCertTrustByUsage(CERTCertDBHandle *certdb,
- CERTCertificate *cert, SECCertUsage usage)
- {
- SECStatus rv;
- CERTCertTrust trust;
- CERTCertTrust tmptrust;
- unsigned int certtype;
- PRBool saveit;
-
- saveit = PR_TRUE;
-
- PORT_Memset((void *)&trust, 0, sizeof(trust));
- certtype = cert->nsCertType;
- /* if no app bits in cert type, then set all app bits */
- if ( ! ( certtype & NS_CERT_TYPE_APP ) ) {
- certtype |= NS_CERT_TYPE_APP;
- }
- switch ( usage ) {
- case certUsageEmailSigner:
- case certUsageEmailRecipient:
- if ( certtype & NS_CERT_TYPE_EMAIL ) {
- trust.emailFlags = CERTDB_VALID_PEER;
- if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
- /* don't save it if KeyEncipherment is not allowed */
- saveit = PR_FALSE;
- }
- }
- break;
- case certUsageUserCertImport:
- if ( certtype & NS_CERT_TYPE_EMAIL ) {
- trust.emailFlags = CERTDB_VALID_PEER;
- }
- /* VALID_USER is already set if the cert was imported,
- * in the case that the cert was already in the database
- * through SMIME or other means, we should set the USER
- * flags, if they are not already set.
- */
- if( cert->isperm ) {
- if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
- if( !(cert->trust->sslFlags & CERTDB_USER) ) {
- trust.sslFlags |= CERTDB_USER;
- }
- }
-
- if ( certtype & NS_CERT_TYPE_EMAIL ) {
- if( !(cert->trust->emailFlags & CERTDB_USER) ) {
- trust.emailFlags |= CERTDB_USER;
- }
- }
-
- if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
- if( !(cert->trust->objectSigningFlags & CERTDB_USER) ) {
- trust.objectSigningFlags |= CERTDB_USER;
- }
- }
- }
- break;
- default: /* XXX added to quiet warnings; no other cases needed? */
- break;
- }
- if ( (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags) == 0 ){
- saveit = PR_FALSE;
- }
- if ( saveit && cert->isperm ) {
- /* Cert already in the DB. Just adjust flags */
- tmptrust = *cert->trust;
- tmptrust.sslFlags |= trust.sslFlags;
- tmptrust.emailFlags |= trust.emailFlags;
- tmptrust.objectSigningFlags |= trust.objectSigningFlags;
-
- rv = CERT_ChangeCertTrust(cert->dbhandle, cert,
- &tmptrust);
- if ( rv != SECSuccess ) {
- goto loser;
- }
- }
- rv = SECSuccess;
- goto done;
- loser:
- rv = SECFailure;
- done:
- return(rv);
- }
- int
- CERT_GetDBContentVersion(CERTCertDBHandle *handle)
- {
- certDBEntryContentVersion *entry;
- int ret;
-
- entry = ReadDBContentVersionEntry(handle);
-
- if ( entry == NULL ) {
- return(0);
- }
- ret = entry->contentVersion;
- DestroyDBEntry((certDBEntry *)entry);
- return(ret);
- }
- void
- CERT_SetDBContentVersion(int version, CERTCertDBHandle *handle)
- {
- SECStatus rv;
- certDBEntryContentVersion *entry;
-
- entry = NewDBContentVersionEntry(0);
-
- if ( entry == NULL ) {
- return;
- }
-
- rv = DeleteDBContentVersionEntry(handle);
- rv = WriteDBContentVersionEntry(handle, entry);
-
- DestroyDBEntry((certDBEntry *)entry);
-
- return;
- }
- /*
- * Creates or adds to a list of all certs with a give subject name, sorted by
- * validity time, newest first. Invalid certs are considered older than
- * valid certs. If validOnly is set, do not include invalid certs on list.
- */
- CERTCertList *
- CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle,
- SECItem *name, int64 sorttime, PRBool validOnly)
- {
- CERTCertificate *cert = NULL;
- CERTSubjectList *subjectList = NULL;
- CERTSubjectNode *node;
- SECStatus rv;
- if ( certList == NULL ) {
- certList = CERT_NewCertList();
- }
-
- if ( certList == NULL ) {
- goto loser;
- }
-
- subjectList = FindSubjectList(handle, name, PR_FALSE);
- if ( subjectList != NULL ) {
- node = subjectList->head;
- PORT_Assert(node);
- while (node) {
- cert = CERT_FindCertByKey(handle, &node->certKey);
- /* if validOnly, then check validity period before adding to list*/
- if ( ( !validOnly ) ||
- ( CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE)
- == secCertTimeValid ) ) {
- rv = CERT_AddCertToListSorted(certList, cert,
- CERT_SortCBValidity,
- (void *)&sorttime);
- if ( rv != SECSuccess ) {
- CERT_DestroyCertificate(cert);
- goto loser;
- }
- } else {
- CERT_DestroyCertificate(cert);
- }
- node = node->next;
- }
- }
- return(certList);
- loser:
- if ( certList != NULL ) {
- CERT_DestroyCertList(certList);
- }
-
- return(NULL);
- }
- /*
- * Creates or adds to a list of all certs with a give nickname, sorted by
- * validity time, newest first. Invalid certs are considered older than valid
- * certs. If validOnly is set, do not include invalid certs on list.
- */
- CERTCertList *
- CERT_CreateNicknameCertList(CERTCertList *certList, CERTCertDBHandle *handle,
- char *nickname, int64 sorttime, PRBool validOnly)
- {
- CERTCertificate *cert;
- CERTCertList *ret;
-
- cert = CERT_FindCertByNickname(handle, nickname);
- if ( cert == NULL ) {
- return(NULL);
- }
-
- ret = CERT_CreateSubjectCertList(certList, handle, &cert->derSubject,
- sorttime, validOnly);
- CERT_DestroyCertificate(cert);
-
- return(ret);
- }
- /*
- * Creates or adds to a list of all certs with a give email addr, sorted by
- * validity time, newest first. Invalid certs are considered older than valid
- * certs. If validOnly is set, do not include invalid certs on list.
- */
- CERTCertList *
- CERT_CreateEmailAddrCertList(CERTCertList *certList, CERTCertDBHandle *handle,
- char *emailAddr, int64 sorttime, PRBool validOnly)
- {
- CERTCertificate *cert;
- CERTCertList *ret;
-
- cert = CERT_FindCertByEmailAddr(handle, emailAddr);
- if ( cert == NULL ) {
- return(NULL);
- }
-
- ret = CERT_CreateSubjectCertList(certList, handle, &cert->derSubject,
- sorttime, validOnly);
- CERT_DestroyCertificate(cert);
-
- return(ret);
- }