Back to index

lightning-sunbird  0.9+nobinonly
stanpcertdb.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "prtime.h"
00038 
00039 #include "cert.h"
00040 #include "mcom_db.h"
00041 #include "certdb.h"
00042 #include "secitem.h"
00043 #include "secder.h"
00044 
00045 /* Call to PK11_FreeSlot below */
00046 
00047 #include "secasn1.h"
00048 #include "secerr.h"
00049 #include "nssilock.h"
00050 #include "prmon.h"
00051 #include "nsslocks.h"
00052 #include "base64.h"
00053 #include "sechash.h"
00054 #include "plhash.h"
00055 #include "pk11func.h" /* sigh */
00056 
00057 #include "nsspki.h"
00058 #include "pki.h"
00059 #include "pkim.h"
00060 #include "pki3hack.h"
00061 #include "ckhelper.h"
00062 #include "base.h"
00063 #include "pkistore.h"
00064 #include "dev3hack.h"
00065 #include "dev.h"
00066 
00067 PRBool
00068 SEC_CertNicknameConflict(char *nickname, SECItem *derSubject,
00069                       CERTCertDBHandle *handle)
00070 {
00071     CERTCertificate *cert;
00072     PRBool conflict = PR_FALSE;
00073 
00074     cert=CERT_FindCertByNickname(handle, nickname);
00075 
00076     if (!cert) {
00077        return conflict;
00078     }
00079 
00080     conflict = !SECITEM_ItemsAreEqual(derSubject,&cert->derSubject);
00081     CERT_DestroyCertificate(cert);
00082     return conflict;
00083 }
00084 
00085 SECStatus
00086 SEC_DeletePermCertificate(CERTCertificate *cert)
00087 {
00088     PRStatus nssrv;
00089     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
00090     NSSCertificate *c = STAN_GetNSSCertificate(cert);
00091 
00092     /* get rid of the token instances */
00093     nssrv = NSSCertificate_DeleteStoredObject(c, NULL);
00094 
00095     /* get rid of the cache entry */
00096     nssTrustDomain_LockCertCache(td);
00097     nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
00098     nssTrustDomain_UnlockCertCache(td);
00099 
00100     return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
00101 }
00102 
00103 SECStatus
00104 CERT_GetCertTrust(CERTCertificate *cert, CERTCertTrust *trust)
00105 {
00106     SECStatus rv;
00107     CERT_LockCertTrust(cert);
00108     if ( cert->trust == NULL ) {
00109        rv = SECFailure;
00110     } else {
00111        *trust = *cert->trust;
00112        rv = SECSuccess;
00113     }
00114     CERT_UnlockCertTrust(cert);
00115     return(rv);
00116 }
00117 
00118 #ifdef notdef
00119 static char *
00120 cert_parseNickname(char *nickname)
00121 {
00122     char *cp;
00123     for (cp=nickname; *cp && *cp != ':'; cp++);
00124     if (*cp == ':') return cp+1;
00125     return nickname;
00126 }
00127 #endif
00128 
00129 SECStatus
00130 CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert,
00131                   CERTCertTrust *trust)
00132 {
00133     SECStatus rv = SECFailure;
00134     PRStatus ret;
00135 
00136     CERT_LockCertTrust(cert);
00137     ret = STAN_ChangeCertTrust(cert, trust);
00138     rv = (ret == PR_SUCCESS) ? SECSuccess : SECFailure;
00139     CERT_UnlockCertTrust(cert);
00140     return rv;
00141 }
00142 
00143 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
00144 
00145 SECStatus
00146 __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
00147                      CERTCertTrust *trust)
00148 {
00149     NSSUTF8 *stanNick;
00150     PK11SlotInfo *slot;
00151     NSSToken *internal;
00152     NSSCryptoContext *context;
00153     nssCryptokiObject *permInstance;
00154     NSSCertificate *c = STAN_GetNSSCertificate(cert);
00155     nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
00156     nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
00157 
00158     context = c->object.cryptoContext;
00159     if (!context) {
00160        PORT_SetError(SEC_ERROR_ADDING_CERT); 
00161        return SECFailure; /* wasn't a temp cert */
00162     }
00163     stanNick = nssCertificate_GetNickname(c, NULL);
00164     if (stanNick && nickname && strcmp(nickname, stanNick) != 0) {
00165        /* take the new nickname */
00166        cert->nickname = NULL;
00167        stanNick = NULL;
00168     }
00169     if (!stanNick && nickname) {
00170        stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, c->object.arena);
00171     }
00172     /* Delete the temp instance */
00173     nssCertificateStore_Lock(context->certStore, &lockTrace);
00174     nssCertificateStore_RemoveCertLOCKED(context->certStore, c);
00175     nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace);
00176     nssCertificateStore_Check(&lockTrace, &unlockTrace);
00177     c->object.cryptoContext = NULL;
00178     /* Import the perm instance onto the internal token */
00179     slot = PK11_GetInternalKeySlot();
00180     internal = PK11Slot_GetNSSToken(slot);
00181     permInstance = nssToken_ImportCertificate(internal, NULL,
00182                                               NSSCertificateType_PKIX,
00183                                               &c->id,
00184                                               stanNick,
00185                                               &c->encoding,
00186                                               &c->issuer,
00187                                               &c->subject,
00188                                               &c->serial,
00189                                          cert->emailAddr,
00190                                               PR_TRUE);
00191     PK11_FreeSlot(slot);
00192     if (!permInstance) {
00193        if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
00194            PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
00195        }
00196        return SECFailure;
00197     }
00198     nssPKIObject_AddInstance(&c->object, permInstance);
00199     nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
00200     /* reset the CERTCertificate fields */
00201     cert->nssCertificate = NULL;
00202     cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */
00203     if (!cert) {
00204         return SECFailure;
00205     }
00206     cert->istemp = PR_FALSE;
00207     cert->isperm = PR_TRUE;
00208     if (!trust) {
00209        return SECSuccess;
00210     }
00211     return (STAN_ChangeCertTrust(cert, trust) == PR_SUCCESS) ? 
00212                                                  SECSuccess: SECFailure;
00213 }
00214 
00215 SECStatus
00216 CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
00217                      CERTCertTrust *trust)
00218 {
00219     return __CERT_AddTempCertToPerm(cert, nickname, trust);
00220 }
00221 
00222 CERTCertificate *
00223 __CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
00224                        char *nickname, PRBool isperm, PRBool copyDER)
00225 {
00226     PRStatus nssrv;
00227     NSSCertificate *c;
00228     CERTCertificate *cc;
00229     NSSCertificate *tempCert = NULL;
00230     nssPKIObject *pkio;
00231     NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext();
00232     NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain();
00233     if (!isperm) {
00234        NSSDER encoding;
00235        NSSITEM_FROM_SECITEM(&encoding, derCert);
00236        /* First, see if it is already a temp cert */
00237        c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC, 
00238                                                               &encoding);
00239        if (!c) {
00240            /* Then, see if it is already a perm cert */
00241            c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, 
00242                                                                   &encoding);
00243        }
00244        if (c) {
00245            /* actually, that search ends up going by issuer/serial,
00246             * so it is still possible to return a cert with the same
00247             * issuer/serial but a different encoding, and we're
00248             * going to reject that
00249             */
00250            if (!nssItem_Equal(&c->encoding, &encoding, NULL)) {
00251               nssCertificate_Destroy(c);
00252               PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
00253               cc = NULL;
00254            } else {
00255               cc = STAN_GetCERTCertificateOrRelease(c);
00256            }
00257            return cc;
00258        }
00259     }
00260     pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor);
00261     if (!pkio) {
00262        return NULL;
00263     }
00264     c = nss_ZNEW(pkio->arena, NSSCertificate);
00265     if (!c) {
00266        nssPKIObject_Destroy(pkio);
00267        return NULL;
00268     }
00269     c->object = *pkio;
00270     if (copyDER) {
00271        nssItem_Create(c->object.arena, &c->encoding, 
00272                       derCert->len, derCert->data);
00273     } else {
00274        NSSITEM_FROM_SECITEM(&c->encoding, derCert);
00275     }
00276     /* Forces a decoding of the cert in order to obtain the parts used
00277      * below
00278      */
00279     /* 'c' is not adopted here, if we fail loser frees what has been
00280      * allocated so far for 'c' */
00281     cc = STAN_GetCERTCertificate(c);
00282     if (!cc) {
00283         goto loser;
00284     }
00285     nssItem_Create(c->object.arena, 
00286                    &c->issuer, cc->derIssuer.len, cc->derIssuer.data);
00287     nssItem_Create(c->object.arena, 
00288                    &c->subject, cc->derSubject.len, cc->derSubject.data);
00289     if (PR_TRUE) {
00290        /* CERTCertificate stores serial numbers decoded.  I need the DER
00291        * here.  sigh.
00292        */
00293        SECItem derSerial = { 0 };
00294        CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
00295        if (!derSerial.data) goto loser;
00296        nssItem_Create(c->object.arena, &c->serial, derSerial.len, derSerial.data);
00297        PORT_Free(derSerial.data);
00298     }
00299     if (nickname) {
00300        c->object.tempName = nssUTF8_Create(c->object.arena, 
00301                                             nssStringType_UTF8String, 
00302                                             (NSSUTF8 *)nickname, 
00303                                             PORT_Strlen(nickname));
00304     }
00305     if (cc->emailAddr && cc->emailAddr[0]) {
00306        c->email = nssUTF8_Create(c->object.arena, 
00307                                  nssStringType_PrintableString, 
00308                                  (NSSUTF8 *)cc->emailAddr, 
00309                                  PORT_Strlen(cc->emailAddr));
00310     }
00311 
00312     tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c);
00313     if (!tempCert) {
00314        goto loser;
00315     }
00316     /* destroy our copy */
00317     NSSCertificate_Destroy(c);
00318     /* and use the stored entry */
00319     c = tempCert;
00320     cc = STAN_GetCERTCertificateOrRelease(c);
00321     if (!cc) {
00322        /* STAN_GetCERTCertificateOrRelease destroys c on failure. */
00323        return NULL;
00324     }
00325 
00326     cc->istemp = PR_TRUE;
00327     cc->isperm = PR_FALSE;
00328     return cc;
00329 loser:
00330     /* Perhaps this should be nssCertificate_Destroy(c) */
00331     nssPKIObject_Destroy(&c->object);
00332     return NULL;
00333 }
00334 
00335 CERTCertificate *
00336 CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
00337                      char *nickname, PRBool isperm, PRBool copyDER)
00338 {
00339     return( __CERT_NewTempCertificate(handle, derCert, nickname,
00340                                       isperm, copyDER) );
00341 }
00342 
00343 /* maybe all the wincx's should be some const for internal token login? */
00344 CERTCertificate *
00345 CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle, CERTIssuerAndSN *issuerAndSN)
00346 {
00347     PK11SlotInfo *slot;
00348     CERTCertificate *cert;
00349 
00350     cert = PK11_FindCertByIssuerAndSN(&slot,issuerAndSN,NULL);
00351     if (cert && slot) {
00352         PK11_FreeSlot(slot);
00353     }
00354 
00355     return cert;
00356 }
00357 
00358 static NSSCertificate *
00359 get_best_temp_or_perm(NSSCertificate *ct, NSSCertificate *cp)
00360 {
00361     NSSUsage usage;
00362     NSSCertificate *arr[3];
00363     if (!ct) {
00364        return nssCertificate_AddRef(cp);
00365     } else if (!cp) {
00366        return nssCertificate_AddRef(ct);
00367     }
00368     arr[0] = ct;
00369     arr[1] = cp;
00370     arr[2] = NULL;
00371     usage.anyUsage = PR_TRUE;
00372     return nssCertificateArray_FindBestCertificate(arr, NULL, &usage, NULL);
00373 }
00374 
00375 CERTCertificate *
00376 CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name)
00377 {
00378     NSSCertificate *cp, *ct, *c;
00379     NSSDER subject;
00380     NSSUsage usage;
00381     NSSCryptoContext *cc;
00382     NSSITEM_FROM_SECITEM(&subject, name);
00383     usage.anyUsage = PR_TRUE;
00384     cc = STAN_GetDefaultCryptoContext();
00385     ct = NSSCryptoContext_FindBestCertificateBySubject(cc, &subject, 
00386                                                        NULL, &usage, NULL);
00387     cp = NSSTrustDomain_FindBestCertificateBySubject(handle, &subject, 
00388                                                      NULL, &usage, NULL);
00389     c = get_best_temp_or_perm(ct, cp);
00390     if (ct) {
00391        CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
00392     }
00393     if (cp) {
00394        CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(cp));
00395     }
00396     return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
00397 }
00398 
00399 CERTCertificate *
00400 CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID)
00401 {
00402     CERTCertList *list;
00403     CERTCertificate *cert = NULL;
00404     CERTCertListNode *node, *head;
00405 
00406     list = CERT_CreateSubjectCertList(NULL,handle,name,0,PR_FALSE);
00407     if (list == NULL) return NULL;
00408 
00409     node = head = CERT_LIST_HEAD(list);
00410     if (head) {
00411        do {
00412            if (node->cert && 
00413               SECITEM_ItemsAreEqual(&node->cert->subjectKeyID, keyID) ) {
00414               cert = CERT_DupCertificate(node->cert);
00415               goto done;
00416            }
00417            node = CERT_LIST_NEXT(node);
00418        } while (node && head != node);
00419     }
00420     PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
00421 done:
00422     if (list) {
00423         CERT_DestroyCertList(list);
00424     }
00425     return cert;
00426 }
00427 
00428 CERTCertificate *
00429 CERT_FindCertByNickname(CERTCertDBHandle *handle, char *nickname)
00430 {
00431     NSSCryptoContext *cc;
00432     NSSCertificate *c, *ct;
00433     CERTCertificate *cert;
00434     NSSUsage usage;
00435     usage.anyUsage = PR_TRUE;
00436     cc = STAN_GetDefaultCryptoContext();
00437     ct = NSSCryptoContext_FindBestCertificateByNickname(cc, nickname, 
00438                                                        NULL, &usage, NULL);
00439     cert = PK11_FindCertFromNickname(nickname, NULL);
00440     c = NULL;
00441     if (cert) {
00442        c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert));
00443        CERT_DestroyCertificate(cert);
00444        if (ct) {
00445            CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
00446        }
00447     } else {
00448        c = ct;
00449     }
00450     return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
00451 }
00452 
00453 CERTCertificate *
00454 CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert)
00455 {
00456     NSSCryptoContext *cc;
00457     NSSCertificate *c;
00458     NSSDER encoding;
00459     NSSITEM_FROM_SECITEM(&encoding, derCert);
00460     cc = STAN_GetDefaultCryptoContext();
00461     c = NSSCryptoContext_FindCertificateByEncodedCertificate(cc, &encoding);
00462     if (!c) {
00463        c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle, 
00464                                                               &encoding);
00465        if (!c) return NULL;
00466     }
00467     return STAN_GetCERTCertificateOrRelease(c);
00468 }
00469 
00470 CERTCertificate *
00471 CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, char *name)
00472 {
00473     NSSCryptoContext *cc;
00474     NSSCertificate *c, *ct;
00475     CERTCertificate *cert;
00476     NSSUsage usage;
00477 
00478     if (NULL == name) {
00479         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00480        return NULL;
00481     }
00482     usage.anyUsage = PR_TRUE;
00483     cc = STAN_GetDefaultCryptoContext();
00484     ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, 
00485                                                        NULL, &usage, NULL);
00486     if (!ct && PORT_Strchr(name, '@') != NULL) {
00487         char* lowercaseName = CERT_FixupEmailAddr(name);
00488         if (lowercaseName) {
00489            ct = NSSCryptoContext_FindBestCertificateByEmail(cc, lowercaseName, 
00490                                                      NULL, &usage, NULL);
00491             PORT_Free(lowercaseName);
00492         }
00493     }
00494     cert = PK11_FindCertFromNickname(name, NULL);
00495     if (cert) {
00496        c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert));
00497        CERT_DestroyCertificate(cert);
00498        if (ct) {
00499            CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
00500        }
00501     } else {
00502        c = ct;
00503     }
00504     return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
00505 }
00506 
00507 static void 
00508 add_to_subject_list(CERTCertList *certList, CERTCertificate *cert,
00509                     PRBool validOnly, int64 sorttime)
00510 {
00511     SECStatus secrv;
00512     if (!validOnly ||
00513        CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE) 
00514         == secCertTimeValid) {
00515            secrv = CERT_AddCertToListSorted(certList, cert, 
00516                                             CERT_SortCBValidity, 
00517                                             (void *)&sorttime);
00518            if (secrv != SECSuccess) {
00519               CERT_DestroyCertificate(cert);
00520            }
00521     } else {
00522        CERT_DestroyCertificate(cert);
00523     }
00524 }
00525 
00526 CERTCertList *
00527 CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle,
00528                         SECItem *name, int64 sorttime, PRBool validOnly)
00529 {
00530     NSSCryptoContext *cc;
00531     NSSCertificate **tSubjectCerts, **pSubjectCerts;
00532     NSSCertificate **ci;
00533     CERTCertificate *cert;
00534     NSSDER subject;
00535     PRBool myList = PR_FALSE;
00536     cc = STAN_GetDefaultCryptoContext();
00537     NSSITEM_FROM_SECITEM(&subject, name);
00538     /* Collect both temp and perm certs for the subject */
00539     tSubjectCerts = NSSCryptoContext_FindCertificatesBySubject(cc,
00540                                                                &subject,
00541                                                                NULL,
00542                                                                0,
00543                                                                NULL);
00544     pSubjectCerts = NSSTrustDomain_FindCertificatesBySubject(handle,
00545                                                              &subject,
00546                                                              NULL,
00547                                                              0,
00548                                                              NULL);
00549     if (!tSubjectCerts && !pSubjectCerts) {
00550        return NULL;
00551     }
00552     if (certList == NULL) {
00553        certList = CERT_NewCertList();
00554        myList = PR_TRUE;
00555        if (!certList) goto loser;
00556     }
00557     /* Iterate over the matching temp certs.  Add them to the list */
00558     ci = tSubjectCerts;
00559     while (ci && *ci) {
00560        cert = STAN_GetCERTCertificateOrRelease(*ci);
00561        /* *ci may be invalid at this point, don't reference it again */
00562         if (cert) {
00563            /* NOTE: add_to_subject_list adopts the incoming cert. */
00564            add_to_subject_list(certList, cert, validOnly, sorttime);
00565         }
00566        ci++;
00567     }
00568     /* Iterate over the matching perm certs.  Add them to the list */
00569     ci = pSubjectCerts;
00570     while (ci && *ci) {
00571        cert = STAN_GetCERTCertificateOrRelease(*ci);
00572        /* *ci may be invalid at this point, don't reference it again */
00573         if (cert) {
00574            /* NOTE: add_to_subject_list adopts the incoming cert. */
00575            add_to_subject_list(certList, cert, validOnly, sorttime);
00576         }
00577        ci++;
00578     }
00579     /* all the references have been adopted or freed at this point, just
00580      * free the arrays now */
00581     nss_ZFreeIf(tSubjectCerts);
00582     nss_ZFreeIf(pSubjectCerts);
00583     return certList;
00584 loser:
00585     /* need to free the references in tSubjectCerts and pSubjectCerts! */
00586     nssCertificateArray_Destroy(tSubjectCerts);
00587     nssCertificateArray_Destroy(pSubjectCerts);
00588     if (myList && certList != NULL) {
00589        CERT_DestroyCertList(certList);
00590     }
00591     return NULL;
00592 }
00593 
00594 void
00595 CERT_DestroyCertificate(CERTCertificate *cert)
00596 {
00597     if ( cert ) {
00598        /* don't use STAN_GetNSSCertificate because we don't want to
00599         * go to the trouble of translating the CERTCertificate into
00600         * an NSSCertificate just to destroy it.  If it hasn't been done
00601         * yet, don't do it at all.
00602         */
00603        NSSCertificate *tmp = cert->nssCertificate;
00604        if (tmp) {
00605            /* delete the NSSCertificate */
00606            NSSCertificate_Destroy(tmp);
00607        } else if (cert->arena) {
00608            PORT_FreeArena(cert->arena, PR_FALSE);
00609        }
00610     }
00611     return;
00612 }
00613 
00614 #ifdef notdef
00615 SECStatus
00616 CERT_ChangeCertTrustByUsage(CERTCertDBHandle *certdb,
00617                          CERTCertificate *cert, SECCertUsage usage)
00618 {
00619     SECStatus rv;
00620     CERTCertTrust trust;
00621     CERTCertTrust tmptrust;
00622     unsigned int certtype;
00623     PRBool saveit;
00624     
00625     saveit = PR_TRUE;
00626     
00627     PORT_Memset((void *)&trust, 0, sizeof(trust));
00628 
00629     certtype = cert->nsCertType;
00630 
00631     /* if no app bits in cert type, then set all app bits */
00632     if ( ! ( certtype & NS_CERT_TYPE_APP ) ) {
00633        certtype |= NS_CERT_TYPE_APP;
00634     }
00635 
00636     switch ( usage ) {
00637       case certUsageEmailSigner:
00638       case certUsageEmailRecipient:
00639        if ( certtype & NS_CERT_TYPE_EMAIL ) {
00640             trust.emailFlags = CERTDB_VALID_PEER;
00641             if ( ! ( cert->rawKeyUsage & KU_KEY_ENCIPHERMENT ) ) {
00642               /* don't save it if KeyEncipherment is not allowed */
00643               saveit = PR_FALSE;
00644            }
00645        }
00646        break;
00647       case certUsageUserCertImport:
00648        if ( certtype & NS_CERT_TYPE_EMAIL ) {
00649            trust.emailFlags = CERTDB_VALID_PEER;
00650        }
00651        /* VALID_USER is already set if the cert was imported, 
00652         * in the case that the cert was already in the database
00653         * through SMIME or other means, we should set the USER
00654         * flags, if they are not already set.
00655         */
00656        if( cert->isperm ) {
00657            if ( certtype & NS_CERT_TYPE_SSL_CLIENT ) {
00658               if( !(cert->trust->sslFlags & CERTDB_USER) ) {
00659                   trust.sslFlags |= CERTDB_USER;
00660               }
00661            }
00662            
00663            if ( certtype & NS_CERT_TYPE_EMAIL ) {
00664               if( !(cert->trust->emailFlags & CERTDB_USER) ) {
00665                   trust.emailFlags |= CERTDB_USER;
00666               }
00667            }
00668            
00669            if ( certtype & NS_CERT_TYPE_OBJECT_SIGNING ) {
00670               if( !(cert->trust->objectSigningFlags & CERTDB_USER) ) {
00671                   trust.objectSigningFlags |= CERTDB_USER;
00672               }
00673            }
00674        }
00675        break;
00676       default:       /* XXX added to quiet warnings; no other cases needed? */
00677        break;
00678     }
00679 
00680     if ( (trust.sslFlags | trust.emailFlags | trust.objectSigningFlags) == 0 ){
00681        saveit = PR_FALSE;
00682     }
00683 
00684     if ( saveit && cert->isperm ) {
00685        /* Cert already in the DB.  Just adjust flags */
00686        tmptrust = *cert->trust;
00687        tmptrust.sslFlags |= trust.sslFlags;
00688        tmptrust.emailFlags |= trust.emailFlags;
00689        tmptrust.objectSigningFlags |= trust.objectSigningFlags;
00690            
00691        rv = CERT_ChangeCertTrust(cert->dbhandle, cert,
00692                               &tmptrust);
00693        if ( rv != SECSuccess ) {
00694            goto loser;
00695        }
00696     }
00697 
00698     rv = SECSuccess;
00699     goto done;
00700 
00701 loser:
00702     rv = SECFailure;
00703 done:
00704 
00705     return(rv);
00706 }
00707 #endif
00708 
00709 int
00710 CERT_GetDBContentVersion(CERTCertDBHandle *handle)
00711 {
00712     /* should read the DB content version from the pkcs #11 device */
00713     return 0;
00714 }
00715 
00716 SECStatus
00717 certdb_SaveSingleProfile(CERTCertificate *cert, const char *emailAddr, 
00718                             SECItem *emailProfile, SECItem *profileTime)
00719 {
00720     int64 oldtime;
00721     int64 newtime;
00722     SECStatus rv = SECFailure;
00723     PRBool saveit;
00724     SECItem oldprof, oldproftime;
00725     SECItem *oldProfile = NULL;
00726     SECItem *oldProfileTime = NULL;
00727     PK11SlotInfo *slot = NULL;
00728     NSSCertificate *c;
00729     NSSCryptoContext *cc;
00730     nssSMIMEProfile *stanProfile = NULL;
00731     PRBool freeOldProfile = PR_FALSE;
00732 
00733     c = STAN_GetNSSCertificate(cert);
00734     if (!c) return SECFailure;
00735     cc = c->object.cryptoContext;
00736     if (cc != NULL) {
00737        stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c);
00738        if (stanProfile) {
00739            PORT_Assert(stanProfile->profileData);
00740            SECITEM_FROM_NSSITEM(&oldprof, stanProfile->profileData);
00741            oldProfile = &oldprof;
00742            SECITEM_FROM_NSSITEM(&oldproftime, stanProfile->profileTime);
00743            oldProfileTime = &oldproftime;
00744        }
00745     } else {
00746        oldProfile = PK11_FindSMimeProfile(&slot, (char *)emailAddr, 
00747                                    &cert->derSubject, &oldProfileTime); 
00748        freeOldProfile = PR_TRUE;
00749     }
00750 
00751     saveit = PR_FALSE;
00752     
00753     /* both profileTime and emailProfile have to exist or not exist */
00754     if ( emailProfile == NULL ) {
00755        profileTime = NULL;
00756     } else if ( profileTime == NULL ) {
00757        emailProfile = NULL;
00758     }
00759    
00760     if ( oldProfileTime == NULL ) {
00761        saveit = PR_TRUE;
00762     } else {
00763        /* there was already a profile for this email addr */
00764        if ( profileTime ) {
00765            /* we have an old and new profile - save whichever is more recent*/
00766            if ( oldProfileTime->len == 0 ) {
00767               /* always replace if old entry doesn't have a time */
00768               oldtime = LL_MININT;
00769            } else {
00770               rv = DER_UTCTimeToTime(&oldtime, oldProfileTime);
00771               if ( rv != SECSuccess ) {
00772                   goto loser;
00773               }
00774            }
00775            
00776            rv = DER_UTCTimeToTime(&newtime, profileTime);
00777            if ( rv != SECSuccess ) {
00778               goto loser;
00779            }
00780        
00781            if ( LL_CMP(newtime, >, oldtime ) ) {
00782               /* this is a newer profile, save it and cert */
00783               saveit = PR_TRUE;
00784            }
00785        } else {
00786            saveit = PR_TRUE;
00787        }
00788     }
00789 
00790 
00791     if (saveit) {
00792        if (cc) {
00793            if (stanProfile) {
00794               /* stanProfile is already stored in the crypto context,
00795                * overwrite the data
00796                */
00797               NSSArena *arena = stanProfile->object.arena;
00798               stanProfile->profileTime = nssItem_Create(arena, 
00799                                                         NULL,
00800                                                         profileTime->len,
00801                                                         profileTime->data);
00802               stanProfile->profileData = nssItem_Create(arena, 
00803                                                         NULL,
00804                                                         emailProfile->len,
00805                                                         emailProfile->data);
00806            } else if (profileTime && emailProfile) {
00807               PRStatus nssrv;
00808               NSSItem profTime, profData;
00809               NSSITEM_FROM_SECITEM(&profTime, profileTime);
00810               NSSITEM_FROM_SECITEM(&profData, emailProfile);
00811               stanProfile = nssSMIMEProfile_Create(c, &profTime, &profData);
00812               if (!stanProfile) goto loser;
00813               nssrv = nssCryptoContext_ImportSMIMEProfile(cc, stanProfile);
00814               rv = (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
00815            }
00816        } else {
00817            rv = PK11_SaveSMimeProfile(slot, (char *)emailAddr, 
00818                             &cert->derSubject, emailProfile, profileTime);
00819        }
00820     } else {
00821        rv = SECSuccess;
00822     }
00823 
00824 loser:
00825     if (oldProfile && freeOldProfile) {
00826        SECITEM_FreeItem(oldProfile,PR_TRUE);
00827     }
00828     if (oldProfileTime && freeOldProfile) {
00829        SECITEM_FreeItem(oldProfileTime,PR_TRUE);
00830     }
00831     if (stanProfile) {
00832        nssSMIMEProfile_Destroy(stanProfile);
00833     }
00834     if (slot) {
00835        PK11_FreeSlot(slot);
00836     }
00837     
00838     return(rv);
00839 }
00840 
00841 /*
00842  *
00843  * Manage S/MIME profiles
00844  *
00845  */
00846 
00847 SECStatus
00848 CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile,
00849                     SECItem *profileTime)
00850 {
00851     const char *emailAddr;
00852     SECStatus rv;
00853 
00854     if (!cert) {
00855         return SECFailure;
00856     }
00857 
00858     if (cert->slot &&  !PK11_IsInternal(cert->slot)) {
00859         /* this cert comes from an external source, we need to add it
00860         to the cert db before creating an S/MIME profile */
00861         PK11SlotInfo* internalslot = PK11_GetInternalKeySlot();
00862         if (!internalslot) {
00863             return SECFailure;
00864         }
00865         rv = PK11_ImportCert(internalslot, cert,
00866             CK_INVALID_HANDLE, NULL, PR_FALSE);
00867 
00868         PK11_FreeSlot(internalslot);
00869         if (rv != SECSuccess ) {
00870             return SECFailure;
00871         }
00872     }
00873 
00874     
00875     for (emailAddr = CERT_GetFirstEmailAddress(cert); emailAddr != NULL;
00876               emailAddr = CERT_GetNextEmailAddress(cert,emailAddr)) {
00877        rv = certdb_SaveSingleProfile(cert,emailAddr,emailProfile,profileTime);
00878        if (rv != SECSuccess) {
00879           return SECFailure;
00880        }
00881     }
00882     return SECSuccess;
00883 
00884 }
00885 
00886 
00887 SECItem *
00888 CERT_FindSMimeProfile(CERTCertificate *cert)
00889 {
00890     PK11SlotInfo *slot = NULL;
00891     NSSCertificate *c;
00892     NSSCryptoContext *cc;
00893     SECItem *rvItem = NULL;
00894 
00895     if (!cert || !cert->emailAddr || !cert->emailAddr[0]) {
00896        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00897        return NULL;
00898     }
00899     c = STAN_GetNSSCertificate(cert);
00900     if (!c) return NULL;
00901     cc = c->object.cryptoContext;
00902     if (cc != NULL) {
00903        nssSMIMEProfile *stanProfile;
00904        stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c);
00905        if (stanProfile) {
00906            rvItem = SECITEM_AllocItem(NULL, NULL, 
00907                                       stanProfile->profileData->size);
00908            if (rvItem) {
00909               rvItem->data = stanProfile->profileData->data;
00910            }
00911            nssSMIMEProfile_Destroy(stanProfile);
00912        }
00913        return rvItem;
00914     }
00915     rvItem =
00916        PK11_FindSMimeProfile(&slot, cert->emailAddr, &cert->derSubject, NULL);
00917     if (slot) {
00918        PK11_FreeSlot(slot);
00919     }
00920     return rvItem;
00921 }
00922 
00923 /*
00924  * depricated functions that are now just stubs.
00925  */
00926 /*
00927  * Close the database
00928  */
00929 void
00930 __CERT_ClosePermCertDB(CERTCertDBHandle *handle)
00931 {
00932     PORT_Assert("CERT_ClosePermCertDB is Depricated" == NULL);
00933     return;
00934 }
00935 
00936 SECStatus
00937 CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname,
00938                         PRBool readOnly)
00939 {
00940     PORT_Assert("CERT_OpenCertDBFilename is Depricated" == NULL);
00941     return SECFailure;
00942 }
00943 
00944 SECItem *
00945 SECKEY_HashPassword(char *pw, SECItem *salt)
00946 {
00947     PORT_Assert("SECKEY_HashPassword is Depricated" == NULL);
00948     return NULL;
00949 }
00950 
00951 SECStatus
00952 __CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle,
00953                                  SECItem *derSubject,
00954                                  void *cb, void *cbarg)
00955 {
00956     PORT_Assert("CERT_TraversePermCertsForSubject is Depricated" == NULL);
00957     return SECFailure;
00958 }
00959 
00960 
00961 SECStatus
00962 __CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname,
00963                                   void *cb, void *cbarg)
00964 {
00965     PORT_Assert("CERT_TraversePermCertsForNickname is Depricated" == NULL);
00966     return SECFailure;
00967 }
00968 
00969 
00970