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