Back to index

lightning-sunbird  0.9+nobinonly
certificate.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 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: certificate.c,v $ $Revision: 1.56.2.3 $ $Date: 2006/08/23 01:36:31 $";
00039 #endif /* DEBUG */
00040 
00041 #ifndef NSSPKI_H
00042 #include "nsspki.h"
00043 #endif /* NSSPKI_H */
00044 
00045 #ifndef PKIT_H
00046 #include "pkit.h"
00047 #endif /* PKIT_H */
00048 
00049 #ifndef PKIM_H
00050 #include "pkim.h"
00051 #endif /* PKIM_H */
00052 
00053 #ifndef DEV_H
00054 #include "dev.h"
00055 #endif /* DEV_H */
00056 
00057 #include "pkistore.h"
00058 
00059 #ifdef NSS_3_4_CODE
00060 #include "pki3hack.h"
00061 #include "pk11func.h"
00062 #include "hasht.h"
00063 #endif
00064 
00065 #ifndef BASE_H
00066 #include "base.h"
00067 #endif /* BASE_H */
00068 
00069 extern const NSSError NSS_ERROR_NOT_FOUND;
00070 
00071 /* Creates a certificate from a base object */
00072 NSS_IMPLEMENT NSSCertificate *
00073 nssCertificate_Create (
00074   nssPKIObject *object
00075 )
00076 {
00077     PRStatus status;
00078     NSSCertificate *rvCert;
00079     /* mark? */
00080     NSSArena *arena = object->arena;
00081     PR_ASSERT(object->instances != NULL && object->numInstances > 0);
00082     PR_ASSERT(object->lockType == nssPKIMonitor);
00083     rvCert = nss_ZNEW(arena, NSSCertificate);
00084     if (!rvCert) {
00085        return (NSSCertificate *)NULL;
00086     }
00087     rvCert->object = *object;
00088     /* XXX should choose instance based on some criteria */
00089     status = nssCryptokiCertificate_GetAttributes(object->instances[0],
00090                                                   NULL,  /* XXX sessionOpt */
00091                                                   arena,
00092                                                   &rvCert->type,
00093                                                   &rvCert->id,
00094                                                   &rvCert->encoding,
00095                                                   &rvCert->issuer,
00096                                                   &rvCert->serial,
00097                                                   &rvCert->subject);
00098     if (status != PR_SUCCESS) {
00099        return (NSSCertificate *)NULL;
00100     }
00101     /* all certs need an encoding value */
00102     if (rvCert->encoding.data == NULL) {
00103        return (NSSCertificate *)NULL;
00104     }
00105     return rvCert;
00106 }
00107 
00108 NSS_IMPLEMENT NSSCertificate *
00109 nssCertificate_AddRef (
00110   NSSCertificate *c
00111 )
00112 {
00113     if (c) {
00114        nssPKIObject_AddRef(&c->object);
00115     }
00116     return c;
00117 }
00118 
00119 NSS_IMPLEMENT PRStatus
00120 nssCertificate_Destroy (
00121   NSSCertificate *c
00122 )
00123 {
00124     nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
00125     nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
00126     PRBool locked = PR_FALSE;
00127 
00128     if (c) {
00129        PRUint32 i;
00130        nssDecodedCert *dc = c->decoding;
00131        NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
00132        NSSCryptoContext *cc = c->object.cryptoContext;
00133 
00134        PR_ASSERT(c->object.refCount > 0);
00135 
00136        /* --- LOCK storage --- */
00137        if (cc) {
00138            nssCertificateStore_Lock(cc->certStore, &lockTrace);
00139             locked = PR_TRUE;
00140        } else {
00141            nssTrustDomain_LockCertCache(td);
00142        }
00143        if (PR_AtomicDecrement(&c->object.refCount) == 0) {
00144            /* --- remove cert and UNLOCK storage --- */
00145            if (cc) {
00146               nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
00147               nssCertificateStore_Unlock(cc->certStore, &lockTrace,
00148                                            &unlockTrace);
00149                 nssCertificateStore_Check(&lockTrace, &unlockTrace);
00150 
00151            } else {
00152               nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
00153               nssTrustDomain_UnlockCertCache(td);
00154            }
00155            /* free cert data */
00156            for (i=0; i<c->object.numInstances; i++) {
00157               nssCryptokiObject_Destroy(c->object.instances[i]);
00158            }
00159            nssPKIObject_DestroyLock(&c->object);
00160            nssArena_Destroy(c->object.arena);
00161            nssDecodedCert_Destroy(dc);
00162        } else {
00163            /* --- UNLOCK storage --- */
00164            if (cc) {
00165               nssCertificateStore_Unlock(cc->certStore,
00166                                       &lockTrace,
00167                                       &unlockTrace);
00168               nssCertificateStore_Check(&lockTrace, &unlockTrace);
00169            } else {
00170               nssTrustDomain_UnlockCertCache(td);
00171            }
00172        }
00173     }
00174     if (locked) {
00175         nssCertificateStore_Check(&lockTrace, &unlockTrace);
00176     }
00177     return PR_SUCCESS;
00178 }
00179 
00180 NSS_IMPLEMENT PRStatus
00181 NSSCertificate_Destroy (
00182   NSSCertificate *c
00183 )
00184 {
00185     return nssCertificate_Destroy(c);
00186 }
00187 
00188 NSS_IMPLEMENT NSSDER *
00189 nssCertificate_GetEncoding (
00190   NSSCertificate *c
00191 )
00192 {
00193     if (c->encoding.size > 0 && c->encoding.data) {
00194        return &c->encoding;
00195     } else {
00196        return (NSSDER *)NULL;
00197     }
00198 }
00199 
00200 NSS_IMPLEMENT NSSDER *
00201 nssCertificate_GetIssuer (
00202   NSSCertificate *c
00203 )
00204 {
00205     if (c->issuer.size > 0 && c->issuer.data) {
00206        return &c->issuer;
00207     } else {
00208        return (NSSDER *)NULL;
00209     }
00210 }
00211 
00212 NSS_IMPLEMENT NSSDER *
00213 nssCertificate_GetSerialNumber (
00214   NSSCertificate *c
00215 )
00216 {
00217     if (c->serial.size > 0 && c->serial.data) {
00218        return &c->serial;
00219     } else {
00220        return (NSSDER *)NULL;
00221     }
00222 }
00223 
00224 NSS_IMPLEMENT NSSDER *
00225 nssCertificate_GetSubject (
00226   NSSCertificate *c
00227 )
00228 {
00229     if (c->subject.size > 0 && c->subject.data) {
00230        return &c->subject;
00231     } else {
00232        return (NSSDER *)NULL;
00233     }
00234 }
00235 
00236 NSS_IMPLEMENT NSSUTF8 *
00237 nssCertificate_GetNickname (
00238   NSSCertificate *c,
00239   NSSToken *tokenOpt
00240 )
00241 {
00242     return nssPKIObject_GetNicknameForToken(&c->object, tokenOpt);
00243 }
00244 
00245 NSS_IMPLEMENT NSSASCII7 *
00246 nssCertificate_GetEmailAddress (
00247   NSSCertificate *c
00248 )
00249 {
00250     return c->email;
00251 }
00252 
00253 NSS_IMPLEMENT PRStatus
00254 NSSCertificate_DeleteStoredObject (
00255   NSSCertificate *c,
00256   NSSCallback *uhh
00257 )
00258 {
00259     return nssPKIObject_DeleteStoredObject(&c->object, uhh, PR_TRUE);
00260 }
00261 
00262 NSS_IMPLEMENT PRStatus
00263 NSSCertificate_Validate (
00264   NSSCertificate *c,
00265   NSSTime *timeOpt, /* NULL for "now" */
00266   NSSUsage *usage,
00267   NSSPolicies *policiesOpt /* NULL for none */
00268 )
00269 {
00270     nss_SetError(NSS_ERROR_NOT_FOUND);
00271     return PR_FAILURE;
00272 }
00273 
00274 NSS_IMPLEMENT void ** /* void *[] */
00275 NSSCertificate_ValidateCompletely (
00276   NSSCertificate *c,
00277   NSSTime *timeOpt, /* NULL for "now" */
00278   NSSUsage *usage,
00279   NSSPolicies *policiesOpt, /* NULL for none */
00280   void **rvOpt, /* NULL for allocate */
00281   PRUint32 rvLimit, /* zero for no limit */
00282   NSSArena *arenaOpt /* NULL for heap */
00283 )
00284 {
00285     nss_SetError(NSS_ERROR_NOT_FOUND);
00286     return NULL;
00287 }
00288 
00289 NSS_IMPLEMENT PRStatus
00290 NSSCertificate_ValidateAndDiscoverUsagesAndPolicies (
00291   NSSCertificate *c,
00292   NSSTime **notBeforeOutOpt,
00293   NSSTime **notAfterOutOpt,
00294   void *allowedUsages,
00295   void *disallowedUsages,
00296   void *allowedPolicies,
00297   void *disallowedPolicies,
00298   /* more args.. work on this fgmr */
00299   NSSArena *arenaOpt
00300 )
00301 {
00302     nss_SetError(NSS_ERROR_NOT_FOUND);
00303     return PR_FAILURE;
00304 }
00305 
00306 NSS_IMPLEMENT NSSDER *
00307 NSSCertificate_Encode (
00308   NSSCertificate *c,
00309   NSSDER *rvOpt,
00310   NSSArena *arenaOpt
00311 )
00312 {
00313     /* Item, DER, BER are all typedefs now... */
00314     return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt);
00315 }
00316 
00317 NSS_IMPLEMENT nssDecodedCert *
00318 nssCertificate_GetDecoding (
00319   NSSCertificate *c
00320 )
00321 {
00322     nssDecodedCert* deco = NULL;
00323     nssPKIObject_Lock(&c->object);
00324     if (!c->decoding) {
00325        deco = nssDecodedCert_Create(NULL, &c->encoding, c->type);
00326        PORT_Assert(!c->decoding); 
00327         c->decoding = deco;
00328     } else {
00329         deco = c->decoding;
00330     }
00331     nssPKIObject_Unlock(&c->object);
00332     return deco;
00333 }
00334 
00335 static NSSCertificate **
00336 filter_subject_certs_for_id (
00337   NSSCertificate **subjectCerts, 
00338   void *id
00339 )
00340 {
00341     NSSCertificate **si;
00342     nssDecodedCert *dcp;
00343     int nextOpenSlot = 0;
00344     int i;
00345     nssCertIDMatch matchLevel = nssCertIDMatch_Unknown;
00346     nssCertIDMatch match;
00347 
00348     /* walk the subject certs */
00349     for (si = subjectCerts; *si; si++) {
00350        dcp = nssCertificate_GetDecoding(*si);
00351        if (!dcp) {
00352            NSSCertificate_Destroy(*si);
00353            continue;
00354        }
00355        match = dcp->matchIdentifier(dcp, id);
00356        switch (match) {
00357        case nssCertIDMatch_Yes:
00358            if (matchLevel == nssCertIDMatch_Unknown) {
00359               /* we have non-definitive matches, forget them */
00360               for (i = 0; i < nextOpenSlot; i++) {
00361                   NSSCertificate_Destroy(subjectCerts[i]);
00362                   subjectCerts[i] = NULL;
00363               }
00364               nextOpenSlot = 0;
00365               /* only keep definitive matches from now on */
00366               matchLevel = nssCertIDMatch_Yes;
00367            }
00368            /* keep the cert */
00369            subjectCerts[nextOpenSlot++] = *si;
00370            break;
00371        case nssCertIDMatch_Unknown:
00372            if (matchLevel == nssCertIDMatch_Unknown) {
00373               /* only have non-definitive matches so far, keep it */
00374               subjectCerts[nextOpenSlot++] = *si;
00375               break;
00376            }
00377            /* else fall through, we have a definitive match already */
00378        case nssCertIDMatch_No:
00379        default:
00380            NSSCertificate_Destroy(*si);
00381            *si = NULL;
00382        }
00383     }
00384     subjectCerts[nextOpenSlot] = NULL;
00385     return subjectCerts;
00386 }
00387 
00388 static NSSCertificate **
00389 filter_certs_for_valid_issuers (
00390   NSSCertificate **certs
00391 )
00392 {
00393     NSSCertificate **cp;
00394     nssDecodedCert *dcp;
00395     int nextOpenSlot = 0;
00396 
00397     for (cp = certs; *cp; cp++) {
00398        dcp = nssCertificate_GetDecoding(*cp);
00399        if (dcp && dcp->isValidIssuer(dcp)) {
00400            certs[nextOpenSlot++] = *cp;
00401        } else {
00402            NSSCertificate_Destroy(*cp);
00403        }
00404     }
00405     certs[nextOpenSlot] = NULL;
00406     return certs;
00407 }
00408 
00409 static NSSCertificate *
00410 find_cert_issuer (
00411   NSSCertificate *c,
00412   NSSTime *timeOpt,
00413   NSSUsage *usage,
00414   NSSPolicies *policiesOpt,
00415   NSSTrustDomain *td,
00416   NSSCryptoContext *cc
00417 )
00418 {
00419     NSSArena *arena;
00420     NSSCertificate **certs = NULL;
00421     NSSCertificate **ccIssuers = NULL;
00422     NSSCertificate **tdIssuers = NULL;
00423     NSSCertificate *issuer = NULL;
00424 
00425     if (!cc)
00426        cc = c->object.cryptoContext;
00427     if (!td)
00428        td = NSSCertificate_GetTrustDomain(c);
00429     arena = nssArena_Create();
00430     if (!arena) {
00431        return (NSSCertificate *)NULL;
00432     }
00433     if (cc) {
00434        ccIssuers = nssCryptoContext_FindCertificatesBySubject(cc,
00435                                                               &c->issuer,
00436                                                               NULL,
00437                                                               0,
00438                                                               arena);
00439     }
00440     if (td)
00441        tdIssuers = nssTrustDomain_FindCertificatesBySubject(td,
00442                                                          &c->issuer,
00443                                                          NULL,
00444                                                          0,
00445                                                          arena);
00446     certs = nssCertificateArray_Join(ccIssuers, tdIssuers);
00447     if (certs) {
00448        nssDecodedCert *dc = NULL;
00449        void *issuerID = NULL;
00450        dc = nssCertificate_GetDecoding(c);
00451        if (dc) {
00452            issuerID = dc->getIssuerIdentifier(dc);
00453        }
00454        /* XXX review based on CERT_FindCertIssuer
00455         * this function is not using the authCertIssuer field as a fallback
00456         * if authority key id does not exist
00457         */
00458        if (issuerID) {
00459            certs = filter_subject_certs_for_id(certs, issuerID);
00460        }
00461        certs = filter_certs_for_valid_issuers(certs);
00462        issuer = nssCertificateArray_FindBestCertificate(certs,
00463                                                         timeOpt,
00464                                                         usage,
00465                                                         policiesOpt);
00466        nssCertificateArray_Destroy(certs);
00467     }
00468     nssArena_Destroy(arena);
00469     return issuer;
00470 }
00471 
00472 /* This function returns the built chain, as far as it gets,
00473 ** even if/when it fails to find an issuer, and returns PR_FAILURE
00474 */
00475 NSS_IMPLEMENT NSSCertificate **
00476 nssCertificate_BuildChain (
00477   NSSCertificate *c,
00478   NSSTime *timeOpt,
00479   NSSUsage *usage,
00480   NSSPolicies *policiesOpt,
00481   NSSCertificate **rvOpt,
00482   PRUint32 rvLimit,
00483   NSSArena *arenaOpt,
00484   PRStatus *statusOpt,
00485   NSSTrustDomain *td,
00486   NSSCryptoContext *cc 
00487 )
00488 {
00489     NSSCertificate **rvChain = NULL;
00490     NSSUsage issuerUsage = *usage;
00491     nssPKIObjectCollection *collection = NULL;
00492     PRUint32  rvCount = 0;
00493     PRStatus  st;
00494     PRStatus  ret = PR_SUCCESS;
00495 
00496     if (!td)
00497        td = NSSCertificate_GetTrustDomain(c);
00498     if (!td || !c || !cc) 
00499        goto loser;
00500 #ifdef NSS_3_4_CODE
00501     /* bump the usage up to CA level */
00502     issuerUsage.nss3lookingForCA = PR_TRUE;
00503 #endif
00504     collection = nssCertificateCollection_Create(td, NULL);
00505     if (!collection)
00506        goto loser;
00507     st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
00508     if (st != PR_SUCCESS)
00509        goto loser;
00510     /* XXX This breaks code for which NSS_3_4_CODE is not defined (pure
00511      *     4.0 builds).  That won't affect the tip.  But be careful
00512      *     when merging 4.0!!!
00513      */
00514     for (rvCount = 1; (!rvLimit || rvCount < rvLimit); ++rvCount) {
00515 #ifdef NSS_3_4_CODE
00516        CERTCertificate *cCert = STAN_GetCERTCertificate(c);
00517        if (cCert->isRoot) {
00518            /* not including the issuer of the self-signed cert, which is,
00519             * of course, itself
00520             */
00521            break;
00522        }
00523 #endif
00524        c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt, td, cc);
00525        if (!c) {
00526            ret = PR_FAILURE;
00527            break;
00528        }
00529        st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
00530        nssCertificate_Destroy(c); /* collection has it */
00531        if (st != PR_SUCCESS)
00532            goto loser;
00533     }
00534     rvChain = nssPKIObjectCollection_GetCertificates(collection, 
00535                                                      rvOpt, 
00536                                                      rvLimit, 
00537                                                      arenaOpt);
00538     if (rvChain) {
00539        nssPKIObjectCollection_Destroy(collection);
00540        if (statusOpt) 
00541            *statusOpt = ret;
00542        if (ret != PR_SUCCESS)
00543            nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
00544        return rvChain;
00545     }
00546 
00547 loser:
00548     if (collection)
00549        nssPKIObjectCollection_Destroy(collection);
00550     if (statusOpt) 
00551        *statusOpt = PR_FAILURE;
00552     nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
00553     return rvChain;
00554 }
00555 
00556 NSS_IMPLEMENT NSSCertificate **
00557 NSSCertificate_BuildChain (
00558   NSSCertificate *c,
00559   NSSTime *timeOpt,
00560   NSSUsage *usage,
00561   NSSPolicies *policiesOpt,
00562   NSSCertificate **rvOpt,
00563   PRUint32 rvLimit, /* zero for no limit */
00564   NSSArena *arenaOpt,
00565   PRStatus *statusOpt,
00566   NSSTrustDomain *td,
00567   NSSCryptoContext *cc 
00568 )
00569 {
00570     return nssCertificate_BuildChain(c, timeOpt, usage, policiesOpt,
00571                                      rvOpt, rvLimit, arenaOpt, statusOpt,
00572                                  td, cc);
00573 }
00574 
00575 NSS_IMPLEMENT NSSCryptoContext *
00576 nssCertificate_GetCryptoContext (
00577   NSSCertificate *c
00578 )
00579 {
00580     return c->object.cryptoContext;
00581 }
00582 
00583 NSS_IMPLEMENT NSSTrustDomain *
00584 nssCertificate_GetTrustDomain (
00585   NSSCertificate *c
00586 )
00587 {
00588     return c->object.trustDomain;
00589 }
00590 
00591 NSS_IMPLEMENT NSSTrustDomain *
00592 NSSCertificate_GetTrustDomain (
00593   NSSCertificate *c
00594 )
00595 {
00596     return nssCertificate_GetTrustDomain(c);
00597 }
00598 
00599 NSS_IMPLEMENT NSSToken *
00600 NSSCertificate_GetToken (
00601   NSSCertificate *c,
00602   PRStatus *statusOpt
00603 )
00604 {
00605     return (NSSToken *)NULL;
00606 }
00607 
00608 NSS_IMPLEMENT NSSSlot *
00609 NSSCertificate_GetSlot (
00610   NSSCertificate *c,
00611   PRStatus *statusOpt
00612 )
00613 {
00614     return (NSSSlot *)NULL;
00615 }
00616 
00617 NSS_IMPLEMENT NSSModule *
00618 NSSCertificate_GetModule (
00619   NSSCertificate *c,
00620   PRStatus *statusOpt
00621 )
00622 {
00623     return (NSSModule *)NULL;
00624 }
00625 
00626 NSS_IMPLEMENT NSSItem *
00627 NSSCertificate_Encrypt (
00628   NSSCertificate *c,
00629   NSSAlgorithmAndParameters *apOpt,
00630   NSSItem *data,
00631   NSSTime *timeOpt,
00632   NSSUsage *usage,
00633   NSSPolicies *policiesOpt,
00634   NSSCallback *uhh,
00635   NSSItem *rvOpt,
00636   NSSArena *arenaOpt
00637 )
00638 {
00639     nss_SetError(NSS_ERROR_NOT_FOUND);
00640     return NULL;
00641 }
00642 
00643 NSS_IMPLEMENT PRStatus
00644 NSSCertificate_Verify (
00645   NSSCertificate *c,
00646   NSSAlgorithmAndParameters *apOpt,
00647   NSSItem *data,
00648   NSSItem *signature,
00649   NSSTime *timeOpt,
00650   NSSUsage *usage,
00651   NSSPolicies *policiesOpt,
00652   NSSCallback *uhh
00653 )
00654 {
00655     nss_SetError(NSS_ERROR_NOT_FOUND);
00656     return PR_FAILURE;
00657 }
00658 
00659 NSS_IMPLEMENT NSSItem *
00660 NSSCertificate_VerifyRecover (
00661   NSSCertificate *c,
00662   NSSAlgorithmAndParameters *apOpt,
00663   NSSItem *signature,
00664   NSSTime *timeOpt,
00665   NSSUsage *usage,
00666   NSSPolicies *policiesOpt,
00667   NSSCallback *uhh,
00668   NSSItem *rvOpt,
00669   NSSArena *arenaOpt
00670 )
00671 {
00672     nss_SetError(NSS_ERROR_NOT_FOUND);
00673     return NULL;
00674 }
00675 
00676 NSS_IMPLEMENT NSSItem *
00677 NSSCertificate_WrapSymmetricKey (
00678   NSSCertificate *c,
00679   NSSAlgorithmAndParameters *apOpt,
00680   NSSSymmetricKey *keyToWrap,
00681   NSSTime *timeOpt,
00682   NSSUsage *usage,
00683   NSSPolicies *policiesOpt,
00684   NSSCallback *uhh,
00685   NSSItem *rvOpt,
00686   NSSArena *arenaOpt
00687 )
00688 {
00689     nss_SetError(NSS_ERROR_NOT_FOUND);
00690     return NULL;
00691 }
00692 
00693 NSS_IMPLEMENT NSSCryptoContext *
00694 NSSCertificate_CreateCryptoContext (
00695   NSSCertificate *c,
00696   NSSAlgorithmAndParameters *apOpt,
00697   NSSTime *timeOpt,
00698   NSSUsage *usage,
00699   NSSPolicies *policiesOpt,
00700   NSSCallback *uhh  
00701 )
00702 {
00703     nss_SetError(NSS_ERROR_NOT_FOUND);
00704     return NULL;
00705 }
00706 
00707 NSS_IMPLEMENT NSSPublicKey *
00708 NSSCertificate_GetPublicKey (
00709   NSSCertificate *c
00710 )
00711 {
00712 #if 0
00713     CK_ATTRIBUTE pubktemplate[] = {
00714        { CKA_CLASS,   NULL, 0 },
00715        { CKA_ID,      NULL, 0 },
00716        { CKA_SUBJECT, NULL, 0 }
00717     };
00718     PRStatus nssrv;
00719     CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]);
00720     NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey);
00721     if (c->id.size > 0) {
00722        /* CKA_ID */
00723        NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]);
00724     } else {
00725        /* failure, yes? */
00726        return (NSSPublicKey *)NULL;
00727     }
00728     if (c->subject.size > 0) {
00729        /* CKA_SUBJECT */
00730        NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]);
00731     } else {
00732        /* failure, yes? */
00733        return (NSSPublicKey *)NULL;
00734     }
00735     /* Try the cert's token first */
00736     if (c->token) {
00737        nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count);
00738     }
00739 #endif
00740     /* Try all other key tokens */
00741     return (NSSPublicKey *)NULL;
00742 }
00743 
00744 NSS_IMPLEMENT NSSPrivateKey *
00745 NSSCertificate_FindPrivateKey (
00746   NSSCertificate *c,
00747   NSSCallback *uhh
00748 )
00749 {
00750     nss_SetError(NSS_ERROR_NOT_FOUND);
00751     return NULL;
00752 }
00753 
00754 NSS_IMPLEMENT PRBool
00755 NSSCertificate_IsPrivateKeyAvailable (
00756   NSSCertificate *c,
00757   NSSCallback *uhh,
00758   PRStatus *statusOpt
00759 )
00760 {
00761     PRBool isUser = PR_FALSE;
00762     nssCryptokiObject **ip;
00763     nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
00764     if (!instances) {
00765        return PR_FALSE;
00766     }
00767     for (ip = instances; *ip; ip++) {
00768        nssCryptokiObject *instance = *ip;
00769        if (nssToken_IsPrivateKeyAvailable(instance->token, c, instance)) {
00770            isUser = PR_TRUE;
00771        }
00772     }
00773     nssCryptokiObjectArray_Destroy(instances);
00774     return isUser;
00775 }
00776 
00777 /* sort the subject cert list from newest to oldest */
00778 PRIntn
00779 nssCertificate_SubjectListSort (
00780   void *v1,
00781   void *v2
00782 )
00783 {
00784     NSSCertificate *c1 = (NSSCertificate *)v1;
00785     NSSCertificate *c2 = (NSSCertificate *)v2;
00786     nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1);
00787     nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2);
00788     if (!dc1) {
00789        return dc2 ? 1 : 0;
00790     } else if (!dc2) {
00791        return -1;
00792     } else {
00793        return dc1->isNewerThan(dc1, dc2) ? -1 : 1;
00794     }
00795 }
00796 
00797 NSS_IMPLEMENT PRBool
00798 NSSUserCertificate_IsStillPresent (
00799   NSSUserCertificate *uc,
00800   PRStatus *statusOpt
00801 )
00802 {
00803     nss_SetError(NSS_ERROR_NOT_FOUND);
00804     return PR_FALSE;
00805 }
00806 
00807 NSS_IMPLEMENT NSSItem *
00808 NSSUserCertificate_Decrypt (
00809   NSSUserCertificate *uc,
00810   NSSAlgorithmAndParameters *apOpt,
00811   NSSItem *data,
00812   NSSTime *timeOpt,
00813   NSSUsage *usage,
00814   NSSPolicies *policiesOpt,
00815   NSSCallback *uhh,
00816   NSSItem *rvOpt,
00817   NSSArena *arenaOpt
00818 )
00819 {
00820     nss_SetError(NSS_ERROR_NOT_FOUND);
00821     return NULL;
00822 }
00823 
00824 NSS_IMPLEMENT NSSItem *
00825 NSSUserCertificate_Sign (
00826   NSSUserCertificate *uc,
00827   NSSAlgorithmAndParameters *apOpt,
00828   NSSItem *data,
00829   NSSTime *timeOpt,
00830   NSSUsage *usage,
00831   NSSPolicies *policiesOpt,
00832   NSSCallback *uhh,
00833   NSSItem *rvOpt,
00834   NSSArena *arenaOpt
00835 )
00836 {
00837     nss_SetError(NSS_ERROR_NOT_FOUND);
00838     return NULL;
00839 }
00840 
00841 NSS_IMPLEMENT NSSItem *
00842 NSSUserCertificate_SignRecover (
00843   NSSUserCertificate *uc,
00844   NSSAlgorithmAndParameters *apOpt,
00845   NSSItem *data,
00846   NSSTime *timeOpt,
00847   NSSUsage *usage,
00848   NSSPolicies *policiesOpt,
00849   NSSCallback *uhh,
00850   NSSItem *rvOpt,
00851   NSSArena *arenaOpt
00852 )
00853 {
00854     nss_SetError(NSS_ERROR_NOT_FOUND);
00855     return NULL;
00856 }
00857 
00858 NSS_IMPLEMENT NSSSymmetricKey *
00859 NSSUserCertificate_UnwrapSymmetricKey (
00860   NSSUserCertificate *uc,
00861   NSSAlgorithmAndParameters *apOpt,
00862   NSSItem *wrappedKey,
00863   NSSTime *timeOpt,
00864   NSSUsage *usage,
00865   NSSPolicies *policiesOpt,
00866   NSSCallback *uhh,
00867   NSSItem *rvOpt,
00868   NSSArena *arenaOpt
00869 )
00870 {
00871     nss_SetError(NSS_ERROR_NOT_FOUND);
00872     return NULL;
00873 }
00874 
00875 NSS_IMPLEMENT NSSSymmetricKey *
00876 NSSUserCertificate_DeriveSymmetricKey (
00877   NSSUserCertificate *uc, /* provides private key */
00878   NSSCertificate *c, /* provides public key */
00879   NSSAlgorithmAndParameters *apOpt,
00880   NSSOID *target,
00881   PRUint32 keySizeOpt, /* zero for best allowed */
00882   NSSOperations operations,
00883   NSSCallback *uhh
00884 )
00885 {
00886     nss_SetError(NSS_ERROR_NOT_FOUND);
00887     return NULL;
00888 }
00889 
00890 NSS_IMPLEMENT nssSMIMEProfile *
00891 nssSMIMEProfile_Create (
00892   NSSCertificate *cert,
00893   NSSItem *profileTime,
00894   NSSItem *profileData
00895 )
00896 {
00897     NSSArena *arena;
00898     nssSMIMEProfile *rvProfile;
00899     nssPKIObject *object;
00900     NSSTrustDomain *td = nssCertificate_GetTrustDomain(cert);
00901     NSSCryptoContext *cc = nssCertificate_GetCryptoContext(cert);
00902     arena = nssArena_Create();
00903     if (!arena) {
00904        return NULL;
00905     }
00906     object = nssPKIObject_Create(arena, NULL, td, cc, nssPKILock);
00907     if (!object) {
00908        goto loser;
00909     }
00910     rvProfile = nss_ZNEW(arena, nssSMIMEProfile);
00911     if (!rvProfile) {
00912        goto loser;
00913     }
00914     rvProfile->object = *object;
00915     rvProfile->certificate = cert;
00916     rvProfile->email = nssUTF8_Duplicate(cert->email, arena);
00917     rvProfile->subject = nssItem_Duplicate(&cert->subject, arena, NULL);
00918     if (profileTime) {
00919        rvProfile->profileTime = nssItem_Duplicate(profileTime, arena, NULL);
00920     }
00921     if (profileData) {
00922        rvProfile->profileData = nssItem_Duplicate(profileData, arena, NULL);
00923     }
00924     return rvProfile;
00925 loser:
00926     if (object) nssPKIObject_Destroy(object);
00927     else if (arena)  nssArena_Destroy(arena);
00928     return (nssSMIMEProfile *)NULL;
00929 }
00930 
00931 /* execute a callback function on all members of a cert list */
00932 NSS_EXTERN PRStatus
00933 nssCertificateList_DoCallback (
00934   nssList *certList, 
00935   PRStatus (* callback)(NSSCertificate *c, void *arg),
00936   void *arg
00937 )
00938 {
00939     nssListIterator *certs;
00940     NSSCertificate *cert;
00941     PRStatus nssrv;
00942     certs = nssList_CreateIterator(certList);
00943     for (cert  = (NSSCertificate *)nssListIterator_Start(certs);
00944          cert != (NSSCertificate *)NULL;
00945          cert  = (NSSCertificate *)nssListIterator_Next(certs))
00946     {
00947        nssrv = (*callback)(cert, arg);
00948     }
00949     nssListIterator_Finish(certs);
00950     nssListIterator_Destroy(certs);
00951     return PR_SUCCESS;
00952 }
00953 
00954 static PRStatus add_ref_callback(NSSCertificate *c, void *a)
00955 {
00956     nssCertificate_AddRef(c);
00957     return PR_SUCCESS;
00958 }
00959 
00960 NSS_IMPLEMENT void
00961 nssCertificateList_AddReferences (
00962   nssList *certList
00963 )
00964 {
00965     (void)nssCertificateList_DoCallback(certList, add_ref_callback, NULL);
00966 }
00967 
00968 NSS_IMPLEMENT NSSTrust *
00969 nssTrust_Create (
00970   nssPKIObject *object,
00971   NSSItem *certData
00972 )
00973 {
00974     PRStatus status;
00975     PRUint32 i;
00976     PRUint32 lastTrustOrder, myTrustOrder;
00977     unsigned char sha1_hashcmp[SHA1_LENGTH];
00978     unsigned char sha1_hashin[SHA1_LENGTH];
00979     NSSItem sha1_hash;
00980     NSSTrust *rvt;
00981     nssCryptokiObject *instance;
00982     nssTrustLevel serverAuth, clientAuth, codeSigning, emailProtection;
00983     SECStatus rv; /* Should be stan flavor */
00984     PRBool stepUp;
00985 
00986     lastTrustOrder = 1<<16; /* just make it big */
00987     PR_ASSERT(object->instances != NULL && object->numInstances > 0);
00988     rvt = nss_ZNEW(object->arena, NSSTrust);
00989     if (!rvt) {
00990        return (NSSTrust *)NULL;
00991     }
00992     rvt->object = *object;
00993 
00994     /* should be stan flavor of Hashbuf */
00995     rv = PK11_HashBuf(SEC_OID_SHA1,sha1_hashcmp,certData->data,certData->size);
00996     if (rv != SECSuccess) {
00997        return (NSSTrust *)NULL;
00998     }
00999     sha1_hash.data = sha1_hashin;
01000     sha1_hash.size = sizeof (sha1_hashin);
01001     /* trust has to peek into the base object members */
01002     nssPKIObject_Lock(object);
01003     for (i=0; i<object->numInstances; i++) {
01004        instance = object->instances[i];
01005        myTrustOrder = nssToken_GetTrustOrder(instance->token);
01006        status = nssCryptokiTrust_GetAttributes(instance, NULL,
01007                                           &sha1_hash,
01008                                                &serverAuth,
01009                                                &clientAuth,
01010                                                &codeSigning,
01011                                                &emailProtection,
01012                                                &stepUp);
01013        if (status != PR_SUCCESS) {
01014            nssPKIObject_Unlock(object);
01015            return (NSSTrust *)NULL;
01016        }
01017        if (PORT_Memcmp(sha1_hashin,sha1_hashcmp,SHA1_LENGTH) != 0) {
01018            nssPKIObject_Unlock(object);
01019            return (NSSTrust *)NULL;
01020        }
01021        if (rvt->serverAuth == nssTrustLevel_Unknown ||
01022            myTrustOrder < lastTrustOrder) 
01023        {
01024            rvt->serverAuth = serverAuth;
01025        }
01026        if (rvt->clientAuth == nssTrustLevel_Unknown ||
01027            myTrustOrder < lastTrustOrder) 
01028        {
01029            rvt->clientAuth = clientAuth;
01030        }
01031        if (rvt->emailProtection == nssTrustLevel_Unknown ||
01032            myTrustOrder < lastTrustOrder) 
01033        {
01034            rvt->emailProtection = emailProtection;
01035        }
01036        if (rvt->codeSigning == nssTrustLevel_Unknown ||
01037            myTrustOrder < lastTrustOrder) 
01038        {
01039            rvt->codeSigning = codeSigning;
01040        }
01041        rvt->stepUpApproved = stepUp;
01042        lastTrustOrder = myTrustOrder;
01043     }
01044     nssPKIObject_Unlock(object);
01045     return rvt;
01046 }
01047 
01048 NSS_IMPLEMENT NSSTrust *
01049 nssTrust_AddRef (
01050   NSSTrust *trust
01051 )
01052 {
01053     if (trust) {
01054        nssPKIObject_AddRef(&trust->object);
01055     }
01056     return trust;
01057 }
01058 
01059 NSS_IMPLEMENT PRStatus
01060 nssTrust_Destroy (
01061   NSSTrust *trust
01062 )
01063 {
01064     if (trust) {
01065        (void)nssPKIObject_Destroy(&trust->object);
01066     }
01067     return PR_SUCCESS;
01068 }
01069 
01070 NSS_IMPLEMENT nssSMIMEProfile *
01071 nssSMIMEProfile_AddRef (
01072   nssSMIMEProfile *profile
01073 )
01074 {
01075     if (profile) {
01076        nssPKIObject_AddRef(&profile->object);
01077     }
01078     return profile;
01079 }
01080 
01081 NSS_IMPLEMENT PRStatus
01082 nssSMIMEProfile_Destroy (
01083   nssSMIMEProfile *profile
01084 )
01085 {
01086     if (profile) {
01087        (void)nssPKIObject_Destroy(&profile->object);
01088     }
01089     return PR_SUCCESS;
01090 }
01091 
01092 NSS_IMPLEMENT NSSCRL *
01093 nssCRL_Create (
01094   nssPKIObject *object
01095 )
01096 {
01097     PRStatus status;
01098     NSSCRL *rvCRL;
01099     NSSArena *arena = object->arena;
01100     PR_ASSERT(object->instances != NULL && object->numInstances > 0);
01101     rvCRL = nss_ZNEW(arena, NSSCRL);
01102     if (!rvCRL) {
01103        return (NSSCRL *)NULL;
01104     }
01105     rvCRL->object = *object;
01106     /* XXX should choose instance based on some criteria */
01107     status = nssCryptokiCRL_GetAttributes(object->instances[0],
01108                                           NULL,  /* XXX sessionOpt */
01109                                           arena,
01110                                           &rvCRL->encoding,
01111                                           NULL, /* subject */
01112                                           NULL, /* class */
01113                                           &rvCRL->url,
01114                                           &rvCRL->isKRL);
01115     if (status != PR_SUCCESS) {
01116        return (NSSCRL *)NULL;
01117     }
01118     return rvCRL;
01119 }
01120 
01121 NSS_IMPLEMENT NSSCRL *
01122 nssCRL_AddRef (
01123   NSSCRL *crl
01124 )
01125 {
01126     if (crl) {
01127        nssPKIObject_AddRef(&crl->object);
01128     }
01129     return crl;
01130 }
01131 
01132 NSS_IMPLEMENT PRStatus
01133 nssCRL_Destroy (
01134   NSSCRL *crl
01135 )
01136 {
01137     if (crl) {
01138        (void)nssPKIObject_Destroy(&crl->object);
01139     }
01140     return PR_SUCCESS;
01141 }
01142 
01143 NSS_IMPLEMENT PRStatus
01144 nssCRL_DeleteStoredObject (
01145   NSSCRL *crl,
01146   NSSCallback *uhh
01147 )
01148 {
01149     return nssPKIObject_DeleteStoredObject(&crl->object, uhh, PR_TRUE);
01150 }
01151 
01152 NSS_IMPLEMENT NSSDER *
01153 nssCRL_GetEncoding (
01154   NSSCRL *crl
01155 )
01156 {
01157     if (crl->encoding.data != NULL && crl->encoding.size > 0) {
01158        return &crl->encoding;
01159     } else {
01160        return (NSSDER *)NULL;
01161     }
01162 }