andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * certi.h - private data structures for the certificate library andre@0: */ andre@0: #ifndef _CERTI_H_ andre@0: #define _CERTI_H_ andre@0: andre@0: #include "certt.h" andre@0: #include "nssrwlkt.h" andre@0: andre@0: /* andre@0: #define GLOBAL_RWLOCK 1 andre@0: */ andre@0: andre@0: #define DPC_RWLOCK 1 andre@0: andre@0: /* all definitions in this file are subject to change */ andre@0: andre@0: typedef struct OpaqueCRLFieldsStr OpaqueCRLFields; andre@0: typedef struct CRLEntryCacheStr CRLEntryCache; andre@0: typedef struct CRLDPCacheStr CRLDPCache; andre@0: typedef struct CRLIssuerCacheStr CRLIssuerCache; andre@0: typedef struct CRLCacheStr CRLCache; andre@0: typedef struct CachedCrlStr CachedCrl; andre@0: typedef struct NamedCRLCacheStr NamedCRLCache; andre@0: typedef struct NamedCRLCacheEntryStr NamedCRLCacheEntry; andre@0: andre@0: struct OpaqueCRLFieldsStr { andre@0: PRBool partial; andre@0: PRBool decodingError; andre@0: PRBool badEntries; andre@0: PRBool badDER; andre@0: PRBool badExtensions; andre@0: PRBool heapDER; andre@0: }; andre@0: andre@0: typedef struct PreAllocatorStr PreAllocator; andre@0: andre@0: struct PreAllocatorStr andre@0: { andre@0: PRSize len; andre@0: void* data; andre@0: PRSize used; andre@0: PLArenaPool* arena; andre@0: PRSize extra; andre@0: }; andre@0: andre@0: /* CRL entry cache. andre@0: This is the same as an entry plus the next/prev pointers for the hash table andre@0: */ andre@0: andre@0: struct CRLEntryCacheStr { andre@0: CERTCrlEntry entry; andre@0: CRLEntryCache *prev, *next; andre@0: }; andre@0: andre@0: #define CRL_CACHE_INVALID_CRLS 0x0001 /* this state will be set andre@0: if we have CRL objects with an invalid DER or signature. Can be andre@0: cleared if the invalid objects are deleted from the token */ andre@0: #define CRL_CACHE_LAST_FETCH_FAILED 0x0002 /* this state will be set andre@0: if the last CRL fetch encountered an error. Can be cleared if a andre@0: new fetch succeeds */ andre@0: andre@0: #define CRL_CACHE_OUT_OF_MEMORY 0x0004 /* this state will be set andre@0: if we don't have enough memory to build the hash table of entries */ andre@0: andre@0: typedef enum { andre@0: CRL_OriginToken = 0, /* CRL came from PKCS#11 token */ andre@0: CRL_OriginExplicit = 1 /* CRL was explicitly added to the cache, from RAM */ andre@0: } CRLOrigin; andre@0: andre@0: typedef enum { andre@0: dpcacheNoEntry = 0, /* no entry found for this SN */ andre@0: dpcacheFoundEntry = 1, /* entry found for this SN */ andre@0: dpcacheCallerError = 2, /* invalid args */ andre@0: dpcacheInvalidCacheError = 3, /* CRL in cache may be bad DER */ andre@0: /* or unverified */ andre@0: dpcacheEmpty = 4, /* no CRL in cache */ andre@0: dpcacheLookupError = 5 /* internal error */ andre@0: } dpcacheStatus; andre@0: andre@0: andre@0: struct CachedCrlStr { andre@0: CERTSignedCrl* crl; andre@0: CRLOrigin origin; andre@0: /* hash table of entries. We use a PLHashTable and pre-allocate the andre@0: required amount of memory in one shot, so that our allocator can andre@0: simply pass offsets into it when hashing. andre@0: andre@0: This won't work anymore when we support delta CRLs and iCRLs, because andre@0: the size of the hash table will vary over time. At that point, the best andre@0: solution will be to allocate large CRLEntry structures by modifying andre@0: the DER decoding template. The extra space would be for next/prev andre@0: pointers. This would allow entries from different CRLs to be mixed in andre@0: the same hash table. andre@0: */ andre@0: PLHashTable* entries; andre@0: PreAllocator* prebuffer; /* big pre-allocated buffer mentioned above */ andre@0: PRBool sigChecked; /* this CRL signature has already been checked */ andre@0: PRBool sigValid; /* signature verification status . andre@0: Only meaningful if checked is PR_TRUE . */ andre@0: PRBool unbuildable; /* Avoid using assosiated CRL is it fails andre@0: * a decoding step */ andre@0: }; andre@0: andre@0: /* CRL distribution point cache object andre@0: This is a cache of CRL entries for a given distribution point of an issuer andre@0: It is built from a collection of one full and 0 or more delta CRLs. andre@0: */ andre@0: andre@0: struct CRLDPCacheStr { andre@0: #ifdef DPC_RWLOCK andre@0: NSSRWLock* lock; andre@0: #else andre@0: PRLock* lock; andre@0: #endif andre@0: CERTCertificate* issuer; /* issuer cert andre@0: XXX there may be multiple issuer certs, andre@0: with different validity dates. Also andre@0: need to deal with SKID/AKID . See andre@0: bugzilla 217387, 233118 */ andre@0: SECItem* subject; /* DER of issuer subject */ andre@0: SECItem* distributionPoint; /* DER of distribution point. This may be andre@0: NULL when distribution points aren't andre@0: in use (ie. the CA has a single CRL). andre@0: Currently not used. */ andre@0: andre@0: /* array of full CRLs matching this distribution point */ andre@0: PRUint32 ncrls; /* total number of CRLs in crls */ andre@0: CachedCrl** crls; /* array of all matching CRLs */ andre@0: /* XCRL With iCRLs and multiple DPs, the CRL can be shared accross several andre@0: issuers. In the future, we'll need to globally recycle the CRL in a andre@0: separate list in order to avoid extra lookups, decodes, and copies */ andre@0: andre@0: /* pointers to good decoded CRLs used to build the cache */ andre@0: CachedCrl* selected; /* full CRL selected for use in the cache */ andre@0: #if 0 andre@0: /* for future use */ andre@0: PRInt32 numdeltas; /* number of delta CRLs used for the cache */ andre@0: CachedCrl** deltas; /* delta CRLs used for the cache */ andre@0: #endif andre@0: /* cache invalidity bitflag */ andre@0: PRUint16 invalid; /* this state will be set if either andre@0: CRL_CACHE_INVALID_CRLS or CRL_CACHE_LAST_FETCH_FAILED is set. andre@0: In those cases, all certs are considered to have unknown status. andre@0: The invalid state can only be cleared during an update if all andre@0: error states are cleared */ andre@0: PRBool refresh; /* manual refresh from tokens has been forced */ andre@0: PRBool mustchoose; /* trigger reselection algorithm, for case when andre@0: RAM CRL objects are dropped from the cache */ andre@0: PRTime lastfetch; /* time a CRL token fetch was last performed */ andre@0: PRTime lastcheck; /* time CRL token objects were last checked for andre@0: existence */ andre@0: }; andre@0: andre@0: /* CRL issuer cache object andre@0: This object tracks all the distribution point caches for a given issuer. andre@0: XCRL once we support multiple issuing distribution points, this object andre@0: will be a hash table. For now, it just holds the single CRL distribution andre@0: point cache structure. andre@0: */ andre@0: andre@0: struct CRLIssuerCacheStr { andre@0: SECItem* subject; /* DER of issuer subject */ andre@0: CRLDPCache* dpp; andre@0: #if 0 andre@0: /* XCRL for future use. andre@0: We don't need to lock at the moment because we only have one DP, andre@0: which gets created at the same time as this object */ andre@0: NSSRWLock* lock; andre@0: CRLDPCache** dps; andre@0: PLHashTable* distributionpoints; andre@0: CERTCertificate* issuer; andre@0: #endif andre@0: }; andre@0: andre@0: /* CRL revocation cache object andre@0: This object tracks all the issuer caches andre@0: */ andre@0: andre@0: struct CRLCacheStr { andre@0: #ifdef GLOBAL_RWLOCK andre@0: NSSRWLock* lock; andre@0: #else andre@0: PRLock* lock; andre@0: #endif andre@0: /* hash table of issuer to CRLIssuerCacheStr, andre@0: indexed by issuer DER subject */ andre@0: PLHashTable* issuers; andre@0: }; andre@0: andre@0: SECStatus InitCRLCache(void); andre@0: SECStatus ShutdownCRLCache(void); andre@0: andre@0: /* Returns a pointer to an environment-like string, a series of andre@0: ** null-terminated strings, terminated by a zero-length string. andre@0: ** This function is intended to be internal to NSS. andre@0: */ andre@0: extern char * cert_GetCertificateEmailAddresses(CERTCertificate *cert); andre@0: andre@0: /* andre@0: * These functions are used to map subjectKeyID extension values to certs andre@0: * and to keep track of the checks for user certificates in each slot andre@0: */ andre@0: SECStatus andre@0: cert_CreateSubjectKeyIDHashTable(void); andre@0: andre@0: SECStatus andre@0: cert_AddSubjectKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert); andre@0: andre@0: SECStatus andre@0: cert_UpdateSubjectKeyIDSlotCheck(SECItem *slotid, int series); andre@0: andre@0: int andre@0: cert_SubjectKeyIDSlotCheckSeries(SECItem *slotid); andre@0: andre@0: /* andre@0: * Call this function to remove an entry from the mapping table. andre@0: */ andre@0: SECStatus andre@0: cert_RemoveSubjectKeyIDMapping(SECItem *subjKeyID); andre@0: andre@0: SECStatus andre@0: cert_DestroySubjectKeyIDHashTable(void); andre@0: andre@0: SECItem* andre@0: cert_FindDERCertBySubjectKeyID(SECItem *subjKeyID); andre@0: andre@0: /* return maximum length of AVA value based on its type OID tag. */ andre@0: extern int cert_AVAOidTagToMaxLen(SECOidTag tag); andre@0: andre@0: /* Make an AVA, allocated from pool, from OID and DER encoded value */ andre@0: extern CERTAVA * CERT_CreateAVAFromRaw(PLArenaPool *pool, andre@0: const SECItem * OID, const SECItem * value); andre@0: andre@0: /* Make an AVA from binary input specified by SECItem */ andre@0: extern CERTAVA * CERT_CreateAVAFromSECItem(PLArenaPool *arena, SECOidTag kind, andre@0: int valueType, SECItem *value); andre@0: andre@0: /* andre@0: * get a DPCache object for the given issuer subject and dp andre@0: * Automatically creates the cache object if it doesn't exist yet. andre@0: */ andre@0: SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject, andre@0: const SECItem* dp, PRTime t, void* wincx, andre@0: CRLDPCache** dpcache, PRBool* writeLocked); andre@0: andre@0: /* check if a particular SN is in the CRL cache and return its entry */ andre@0: dpcacheStatus DPCache_Lookup(CRLDPCache* cache, const SECItem* sn, andre@0: CERTCrlEntry** returned); andre@0: andre@0: /* release a DPCache object that was previously acquired */ andre@0: void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked); andre@0: andre@0: /* andre@0: * map Stan errors into NSS errors andre@0: * This function examines the stan error stack and automatically sets andre@0: * PORT_SetError(); to the appropriate SEC_ERROR value. andre@0: */ andre@0: void CERT_MapStanError(); andre@0: andre@0: /* Like CERT_VerifyCert, except with an additional argument, flags. The andre@0: * flags are defined immediately below. andre@0: */ andre@0: SECStatus andre@0: cert_VerifyCertWithFlags(CERTCertDBHandle *handle, CERTCertificate *cert, andre@0: PRBool checkSig, SECCertUsage certUsage, PRTime t, andre@0: PRUint32 flags, void *wincx, CERTVerifyLog *log); andre@0: andre@0: /* Use the default settings. andre@0: * cert_VerifyCertWithFlags(..., CERT_VERIFYCERT_USE_DEFAULTS, ...) is andre@0: * equivalent to CERT_VerifyCert(...); andre@0: */ andre@0: #define CERT_VERIFYCERT_USE_DEFAULTS 0 andre@0: andre@0: /* Skip all the OCSP checks during certificate verification, regardless of andre@0: * the global OCSP settings. By default, certificate |cert| will have its andre@0: * revocation status checked via OCSP according to the global OCSP settings. andre@0: * andre@0: * OCSP checking is always skipped when certUsage is certUsageStatusResponder. andre@0: */ andre@0: #define CERT_VERIFYCERT_SKIP_OCSP 1 andre@0: andre@0: /* Interface function for libpkix cert validation engine: andre@0: * cert_verify wrapper. */ andre@0: SECStatus andre@0: cert_VerifyCertChainPkix(CERTCertificate *cert, andre@0: PRBool checkSig, andre@0: SECCertUsage requiredUsage, andre@0: PRTime time, andre@0: void *wincx, andre@0: CERTVerifyLog *log, andre@0: PRBool *sigError, andre@0: PRBool *revoked); andre@0: andre@0: SECStatus cert_InitLocks(void); andre@0: andre@0: SECStatus cert_DestroyLocks(void); andre@0: andre@0: /* andre@0: * fill in nsCertType field of the cert based on the cert extension andre@0: */ andre@0: extern SECStatus cert_GetCertType(CERTCertificate *cert); andre@0: andre@0: /* andre@0: * compute and return the value of nsCertType for cert, but do not andre@0: * update the CERTCertificate. andre@0: */ andre@0: extern PRUint32 cert_ComputeCertType(CERTCertificate *cert); andre@0: andre@0: void cert_AddToVerifyLog(CERTVerifyLog *log,CERTCertificate *cert, andre@0: long errorCode, unsigned int depth, andre@0: void *arg); andre@0: andre@0: /* Insert a DER CRL into the CRL cache, and take ownership of it. andre@0: * andre@0: * cert_CacheCRLByGeneralName takes ownership of the memory in crl argument andre@0: * completely. crl must be freeable by SECITEM_FreeItem. It will be freed andre@0: * immediately if it is rejected from the CRL cache, or later during cache andre@0: * updates when a new crl is available, or at shutdown time. andre@0: * andre@0: * canonicalizedName represents the source of the CRL, a GeneralName. andre@0: * The format of the encoding is not restricted, but all callers of andre@0: * cert_CacheCRLByGeneralName and cert_FindCRLByGeneralName must use andre@0: * the same encoding. To facilitate X.500 name matching, a canonicalized andre@0: * encoding of the GeneralName should be used, if available. andre@0: */ andre@0: andre@0: SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl, andre@0: const SECItem* canonicalizedName); andre@0: andre@0: struct NamedCRLCacheStr { andre@0: PRLock* lock; andre@0: PLHashTable* entries; andre@0: }; andre@0: andre@0: /* NamedCRLCacheEntryStr is filled in by cert_CacheCRLByGeneralName, andre@0: * and read by cert_FindCRLByGeneralName */ andre@0: struct NamedCRLCacheEntryStr { andre@0: SECItem* canonicalizedName; andre@0: SECItem* crl; /* DER, kept only if CRL andre@0: * is successfully cached */ andre@0: PRBool inCRLCache; andre@0: PRTime successfulInsertionTime; /* insertion time */ andre@0: PRTime lastAttemptTime; /* time of last call to andre@0: cert_CacheCRLByGeneralName with this name */ andre@0: PRBool badDER; /* ASN.1 error */ andre@0: PRBool dupe; /* matching DER CRL already in CRL cache */ andre@0: PRBool unsupported; /* IDP, delta, any other reason */ andre@0: }; andre@0: andre@0: typedef enum { andre@0: certRevocationStatusRevoked = 0, andre@0: certRevocationStatusValid = 1, andre@0: certRevocationStatusUnknown = 2 andre@0: } CERTRevocationStatus; andre@0: andre@0: /* Returns detailed status of the cert(revStatus variable). Tells if andre@0: * issuer cache has OriginFetchedWithTimeout crl in it. */ andre@0: SECStatus andre@0: cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer, andre@0: const SECItem* dp, PRTime t, void *wincx, andre@0: CERTRevocationStatus *revStatus, andre@0: CERTCRLEntryReasonCode *revReason); andre@0: andre@0: andre@0: SECStatus cert_AcquireNamedCRLCache(NamedCRLCache** returned); andre@0: andre@0: /* cert_FindCRLByGeneralName must be called only while the named cache is andre@0: * acquired, and the entry is only valid until cache is released. andre@0: */ andre@0: SECStatus cert_FindCRLByGeneralName(NamedCRLCache* ncc, andre@0: const SECItem* canonicalizedName, andre@0: NamedCRLCacheEntry** retEntry); andre@0: andre@0: SECStatus cert_ReleaseNamedCRLCache(NamedCRLCache* ncc); andre@0: andre@0: /* This is private for now. Maybe shoule be public. */ andre@0: CERTGeneralName * andre@0: cert_GetSubjectAltNameList(const CERTCertificate *cert, PLArenaPool *arena); andre@0: andre@0: /* Count DNS names and IP addresses in a list of GeneralNames */ andre@0: PRUint32 andre@0: cert_CountDNSPatterns(CERTGeneralName *firstName); andre@0: andre@0: /* andre@0: * returns the trust status of the leaf certificate based on usage. andre@0: * If the leaf is explicitly untrusted, this function will fail and andre@0: * failedFlags will be set to the trust bit value that lead to the failure. andre@0: * If the leaf is trusted, isTrusted is set to true and the function returns andre@0: * SECSuccess. This function does not check if the cert is fit for a andre@0: * particular usage. andre@0: */ andre@0: SECStatus andre@0: cert_CheckLeafTrust(CERTCertificate *cert, andre@0: SECCertUsage usage, andre@0: unsigned int *failedFlags, andre@0: PRBool *isTrusted); andre@0: andre@0: #endif /* _CERTI_H_ */ andre@0: