import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,48 @@
#! gmake
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################
include manifest.mn
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
include config.mk
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
export:: private_export

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'certdb',
'type': 'static_library',
'sources': [
'alg1485.c',
'certdb.c',
'certv3.c',
'certxutl.c',
'crl.c',
'genname.c',
'polcyxtn.c',
'secname.c',
'stanpcertdb.c',
'xauthkid.c',
'xbsconst.c',
'xconst.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
]
}
],
'variables': {
'module': 'nss'
}
}

View file

@ -0,0 +1,89 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _CERTDB_H_
#define _CERTDB_H_
/* common flags for all types of certificates */
#define CERTDB_TERMINAL_RECORD (1u << 0)
#define CERTDB_TRUSTED (1u << 1)
#define CERTDB_SEND_WARN (1u << 2)
#define CERTDB_VALID_CA (1u << 3)
#define CERTDB_TRUSTED_CA (1u << 4) /* trusted for issuing server certs */
#define CERTDB_NS_TRUSTED_CA (1u << 5)
#define CERTDB_USER (1u << 6)
#define CERTDB_TRUSTED_CLIENT_CA (1u << 7) /* trusted for issuing client certs */
#define CERTDB_INVISIBLE_CA (1u << 8) /* don't show in UI */
#define CERTDB_GOVT_APPROVED_CA (1u << 9) /* can do strong crypto in export ver */
/* old usage, to keep old programs compiling */
/* On Windows, Mac, and Linux (and other gcc platforms), we can give compile
* time deprecation warnings when applications use the old CERTDB_VALID_PEER
* define */
#if __GNUC__ > 3
#if (__GNUC__ == 4) && (__GNUC_MINOR__ < 5)
typedef unsigned int __CERTDB_VALID_PEER __attribute__((deprecated));
#else
typedef unsigned int __CERTDB_VALID_PEER __attribute__((
deprecated("CERTDB_VALID_PEER is now CERTDB_TERMINAL_RECORD")));
#endif
#define CERTDB_VALID_PEER ((__CERTDB_VALID_PEER)CERTDB_TERMINAL_RECORD)
#else
#ifdef _WIN32
#pragma deprecated(CERTDB_VALID_PEER)
#endif
#define CERTDB_VALID_PEER CERTDB_TERMINAL_RECORD
#endif
SEC_BEGIN_PROTOS
CERTSignedCrl *SEC_FindCrlByKey(CERTCertDBHandle *handle, SECItem *crlKey,
int type);
CERTSignedCrl *SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey,
int type);
CERTSignedCrl *SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl,
int type);
PRBool SEC_CertNicknameConflict(const char *nickname, const SECItem *derSubject,
CERTCertDBHandle *handle);
CERTSignedCrl *SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl,
int type);
SECStatus SEC_DeletePermCRL(CERTSignedCrl *crl);
SECStatus SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes,
int type);
SECStatus SEC_DestroyCrl(CERTSignedCrl *crl);
CERTSignedCrl *SEC_DupCrl(CERTSignedCrl *acrl);
SECStatus CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
CERTCertTrust *trust);
SECStatus SEC_DeletePermCertificate(CERTCertificate *cert);
PRBool SEC_CrlIsNewer(CERTCrl *inNew, CERTCrl *old);
/*
** Extract the validity times from a CRL
** "crl" is the CRL
** "notBefore" is the start of the validity period (last update)
** "notAfter" is the end of the validity period (next update)
*/
SECStatus SEC_GetCrlTimes(CERTCrl *crl, PRTime *notBefore, PRTime *notAfter);
/*
** Check the validity times of a crl vs. time 't', allowing
** some slop for broken clocks and stuff.
** "crl" is the certificate to be checked
** "t" is the time to check against
*/
SECCertTimeValidity SEC_CheckCrlTimes(CERTCrl *crl, PRTime t);
SEC_END_PROTOS
#endif /* _CERTDB_H_ */

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,222 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Code for dealing with X509.V3 extensions.
*/
#include "cert.h"
#include "secitem.h"
#include "secoid.h"
#include "secder.h"
#include "secasn1.h"
#include "certxutl.h"
#include "secerr.h"
SECStatus
CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid, SECItem *value)
{
return (cert_FindExtensionByOID(cert->extensions, oid, value));
}
SECStatus
CERT_FindCertExtension(const CERTCertificate *cert, int tag, SECItem *value)
{
return (cert_FindExtension(cert->extensions, tag, value));
}
static void
SetExts(void *object, CERTCertExtension **exts)
{
CERTCertificate *cert = (CERTCertificate *)object;
cert->extensions = exts;
DER_SetUInteger(cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3);
}
void *
CERT_StartCertExtensions(CERTCertificate *cert)
{
return (cert_StartExtensions((void *)cert, cert->arena, SetExts));
}
/*
* get the value of the Netscape Certificate Type Extension
*/
SECStatus
CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem)
{
return (CERT_FindBitStringExtension(
cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem));
}
/*
* get the value of a string type extension
*/
char *
CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
{
SECItem wrapperItem, tmpItem = { siBuffer, 0 };
SECStatus rv;
PLArenaPool *arena = NULL;
char *retstring = NULL;
wrapperItem.data = NULL;
tmpItem.data = NULL;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
goto loser;
}
rv = cert_FindExtension(cert->extensions, oidtag, &wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
rv = SEC_QuickDERDecodeItem(
arena, &tmpItem, SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
retstring = (char *)PORT_Alloc(tmpItem.len + 1);
if (retstring == NULL) {
goto loser;
}
PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
retstring[tmpItem.len] = '\0';
loser:
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
if (wrapperItem.data) {
PORT_Free(wrapperItem.data);
}
return (retstring);
}
/*
* get the value of the X.509 v3 Key Usage Extension
*/
SECStatus
CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
{
return (CERT_FindBitStringExtension(cert->extensions,
SEC_OID_X509_KEY_USAGE, retItem));
}
/*
* get the value of the X.509 v3 Key Usage Extension
*/
SECStatus
CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
{
SECStatus rv;
SECItem encodedValue = { siBuffer, NULL, 0 };
SECItem decodedValue = { siBuffer, NULL, 0 };
rv = cert_FindExtension(cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID,
&encodedValue);
if (rv == SECSuccess) {
PORTCheapArenaPool tmpArena;
PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodedValue,
SEC_ASN1_GET(SEC_OctetStringTemplate),
&encodedValue);
if (rv == SECSuccess) {
rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
}
PORT_DestroyCheapArena(&tmpArena);
}
SECITEM_FreeItem(&encodedValue, PR_FALSE);
return rv;
}
SECStatus
CERT_FindBasicConstraintExten(CERTCertificate *cert,
CERTBasicConstraints *value)
{
SECItem encodedExtenValue;
SECStatus rv;
encodedExtenValue.data = NULL;
encodedExtenValue.len = 0;
rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
&encodedExtenValue);
if (rv != SECSuccess) {
return (rv);
}
rv = CERT_DecodeBasicConstraintValue(value, &encodedExtenValue);
/* free the raw extension data */
PORT_Free(encodedExtenValue.data);
encodedExtenValue.data = NULL;
return (rv);
}
CERTAuthKeyID *
CERT_FindAuthKeyIDExten(PLArenaPool *arena, CERTCertificate *cert)
{
SECItem encodedExtenValue;
SECStatus rv;
CERTAuthKeyID *ret;
encodedExtenValue.data = NULL;
encodedExtenValue.len = 0;
rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
&encodedExtenValue);
if (rv != SECSuccess) {
return (NULL);
}
ret = CERT_DecodeAuthKeyID(arena, &encodedExtenValue);
PORT_Free(encodedExtenValue.data);
encodedExtenValue.data = NULL;
return (ret);
}
SECStatus
CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
{
SECItem keyUsage;
SECStatus rv;
/* There is no extension, v1 or v2 certificate */
if (cert->extensions == NULL) {
return (SECSuccess);
}
keyUsage.data = NULL;
/* This code formerly ignored the Key Usage extension if it was
** marked non-critical. That was wrong. Since we do understand it,
** we are obligated to honor it, whether or not it is critical.
*/
rv = CERT_FindKeyUsageExtension(cert, &keyUsage);
if (rv == SECFailure) {
rv = (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) ? SECSuccess
: SECFailure;
} else if (!(keyUsage.data[0] & usage)) {
PORT_SetError(SEC_ERROR_CERT_USAGES_INVALID);
rv = SECFailure;
}
PORT_Free(keyUsage.data);
return (rv);
}

View file

@ -0,0 +1,493 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Certificate Extensions handling code
*
*/
#include "cert.h"
#include "secitem.h"
#include "secoid.h"
#include "secder.h"
#include "secasn1.h"
#include "certxutl.h"
#include "secerr.h"
#ifdef OLD
#include "ocspti.h" /* XXX a better extensions interface would not
* require knowledge of data structures of callers */
#endif
static CERTCertExtension *
GetExtension(CERTCertExtension **extensions, SECItem *oid)
{
CERTCertExtension **exts;
CERTCertExtension *ext = NULL;
SECComparison comp;
exts = extensions;
if (exts) {
while (*exts) {
ext = *exts;
comp = SECITEM_CompareItem(oid, &ext->id);
if (comp == SECEqual)
break;
exts++;
}
return (*exts ? ext : NULL);
}
return (NULL);
}
SECStatus
cert_FindExtensionByOID(CERTCertExtension **extensions, SECItem *oid,
SECItem *value)
{
CERTCertExtension *ext;
SECStatus rv = SECSuccess;
ext = GetExtension(extensions, oid);
if (ext == NULL) {
PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
return (SECFailure);
}
if (value)
rv = SECITEM_CopyItem(NULL, value, &ext->value);
return (rv);
}
SECStatus
CERT_GetExtenCriticality(CERTCertExtension **extensions, int tag,
PRBool *isCritical)
{
CERTCertExtension *ext;
SECOidData *oid;
if (!isCritical)
return (SECSuccess);
/* find the extension in the extensions list */
oid = SECOID_FindOIDByTag((SECOidTag)tag);
if (!oid) {
return (SECFailure);
}
ext = GetExtension(extensions, &oid->oid);
if (ext == NULL) {
PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
return (SECFailure);
}
/* If the criticality is omitted, then it is false by default.
ex->critical.data is NULL */
if (ext->critical.data == NULL)
*isCritical = PR_FALSE;
else
*isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
return (SECSuccess);
}
SECStatus
cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
{
SECOidData *oid;
oid = SECOID_FindOIDByTag((SECOidTag)tag);
if (!oid) {
return (SECFailure);
}
return (cert_FindExtensionByOID(extensions, &oid->oid, value));
}
typedef struct _extNode {
struct _extNode *next;
CERTCertExtension *ext;
} extNode;
typedef struct {
void (*setExts)(void *object, CERTCertExtension **exts);
void *object;
PLArenaPool *ownerArena;
PLArenaPool *arena;
extNode *head;
int count;
} extRec;
/*
* cert_StartExtensions
*
* NOTE: This interface changed significantly to remove knowledge
* about callers data structures (owner objects)
*/
void *
cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
void (*setExts)(void *object, CERTCertExtension **exts))
{
PLArenaPool *arena;
extRec *handle;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
return (0);
}
handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
if (!handle) {
PORT_FreeArena(arena, PR_FALSE);
return (0);
}
handle->object = owner;
handle->ownerArena = ownerArena;
handle->setExts = setExts;
handle->arena = arena;
handle->head = 0;
handle->count = 0;
return (handle);
}
static unsigned char hextrue = 0xff;
/*
* Note - assumes that data pointed to by oid->data will not move
*/
SECStatus
CERT_AddExtensionByOID(void *exthandle, SECItem *oid, SECItem *value,
PRBool critical, PRBool copyData)
{
CERTCertExtension *ext;
SECStatus rv;
extNode *node;
extRec *handle;
handle = (extRec *)exthandle;
/* allocate space for extension and list node */
ext = (CERTCertExtension *)PORT_ArenaZAlloc(handle->ownerArena,
sizeof(CERTCertExtension));
if (!ext) {
return (SECFailure);
}
node = (extNode *)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
if (!node) {
return (SECFailure);
}
/* add to list */
node->next = handle->head;
handle->head = node;
/* point to ext struct */
node->ext = ext;
/* set critical field */
if (critical) {
ext->critical.data = (unsigned char *)&hextrue;
ext->critical.len = 1;
}
/* set object ID of the extension and its value */
if (copyData) {
rv = SECITEM_CopyItem(handle->ownerArena, &ext->id, oid);
if (rv) {
return (SECFailure);
}
rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
if (rv) {
return (SECFailure);
}
} else {
ext->id = *oid;
ext->value = *value;
}
handle->count++;
return (SECSuccess);
}
SECStatus
CERT_AddExtension(void *exthandle, int idtag, SECItem *value, PRBool critical,
PRBool copyData)
{
SECOidData *oid;
oid = SECOID_FindOIDByTag((SECOidTag)idtag);
if (!oid) {
return (SECFailure);
}
return (CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical,
copyData));
}
SECStatus
CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
PRBool critical, const SEC_ASN1Template *atemplate)
{
extRec *handle;
SECItem *encitem;
handle = (extRec *)exthandle;
encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
if (encitem == NULL) {
return (SECFailure);
}
return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
}
void
PrepareBitStringForEncoding(SECItem *bitsmap, SECItem *value)
{
unsigned char onebyte;
unsigned int i, len = 0;
/* to prevent warning on some platform at compile time */
onebyte = '\0';
/* Get the position of the right-most turn-on bit */
for (i = 0; i < (value->len) * 8; ++i) {
if (i % 8 == 0)
onebyte = value->data[i / 8];
if (onebyte & 0x80)
len = i;
onebyte <<= 1;
}
bitsmap->data = value->data;
/* Add one here since we work with base 1 */
bitsmap->len = len + 1;
}
SECStatus
CERT_EncodeAndAddBitStrExtension(void *exthandle, int idtag, SECItem *value,
PRBool critical)
{
SECItem bitsmap;
PrepareBitStringForEncoding(&bitsmap, value);
return (CERT_EncodeAndAddExtension(exthandle, idtag, &bitsmap, critical,
SEC_ASN1_GET(SEC_BitStringTemplate)));
}
SECStatus
CERT_FinishExtensions(void *exthandle)
{
extRec *handle;
extNode *node;
CERTCertExtension **exts;
SECStatus rv = SECFailure;
handle = (extRec *)exthandle;
/* allocate space for extensions array */
exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
handle->count + 1);
if (exts == NULL) {
goto loser;
}
/* put extensions in owner object and update its version number */
#ifdef OLD
switch (handle->type) {
case CertificateExtensions:
handle->owner.cert->extensions = exts;
DER_SetUInteger(ownerArena, &(handle->owner.cert->version),
SEC_CERTIFICATE_VERSION_3);
break;
case CrlExtensions:
handle->owner.crl->extensions = exts;
DER_SetUInteger(ownerArena, &(handle->owner.crl->version),
SEC_CRL_VERSION_2);
break;
case OCSPRequestExtensions:
handle->owner.request->tbsRequest->requestExtensions = exts;
break;
case OCSPSingleRequestExtensions:
handle->owner.singleRequest->singleRequestExtensions = exts;
break;
case OCSPResponseSingleExtensions:
handle->owner.singleResponse->singleExtensions = exts;
break;
}
#endif
handle->setExts(handle->object, exts);
/* update the version number */
/* copy each extension pointer */
node = handle->head;
while (node) {
*exts = node->ext;
node = node->next;
exts++;
}
/* terminate the array of extensions */
*exts = 0;
rv = SECSuccess;
loser:
/* free working arena */
PORT_FreeArena(handle->arena, PR_FALSE);
return rv;
}
SECStatus
CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
{
CERTCertExtension *ext;
SECStatus rv = SECSuccess;
SECOidTag tag;
extNode *node;
extRec *handle = exthandle;
if (!exthandle || !extensions) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
while ((ext = *extensions++) != NULL) {
tag = SECOID_FindOIDTag(&ext->id);
for (node = handle->head; node != NULL; node = node->next) {
if (tag == 0) {
if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
break;
} else {
if (SECOID_FindOIDTag(&node->ext->id) == tag) {
break;
}
}
}
if (node == NULL) {
PRBool critical = (ext->critical.len != 0 &&
ext->critical.data[ext->critical.len - 1] != 0);
if (critical && tag == SEC_OID_UNKNOWN) {
PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
rv = SECFailure;
break;
}
/* add to list */
rv = CERT_AddExtensionByOID(exthandle, &ext->id, &ext->value,
critical, PR_TRUE);
if (rv != SECSuccess)
break;
}
}
return rv;
}
/*
* get the value of the Netscape Certificate Type Extension
*/
SECStatus
CERT_FindBitStringExtension(CERTCertExtension **extensions, int tag,
SECItem *retItem)
{
SECItem wrapperItem, tmpItem = { siBuffer, 0 };
SECStatus rv;
PORTCheapArenaPool tmpArena;
wrapperItem.data = NULL;
tmpItem.data = NULL;
PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
rv = cert_FindExtension(extensions, tag, &wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &tmpItem,
SEC_ASN1_GET(SEC_BitStringTemplate),
&wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
retItem->data = (unsigned char *)PORT_Alloc((tmpItem.len + 7) >> 3);
if (retItem->data == NULL) {
goto loser;
}
PORT_Memcpy(retItem->data, tmpItem.data, (tmpItem.len + 7) >> 3);
retItem->len = tmpItem.len;
rv = SECSuccess;
goto done;
loser:
rv = SECFailure;
done:
PORT_DestroyCheapArena(&tmpArena);
if (wrapperItem.data) {
PORT_Free(wrapperItem.data);
}
return (rv);
}
PRBool
cert_HasCriticalExtension(CERTCertExtension **extensions)
{
CERTCertExtension **exts;
CERTCertExtension *ext = NULL;
PRBool hasCriticalExten = PR_FALSE;
exts = extensions;
if (exts) {
while (*exts) {
ext = *exts;
/* If the criticality is omitted, it's non-critical */
if (ext->critical.data && ext->critical.data[0] == 0xff) {
hasCriticalExten = PR_TRUE;
break;
}
exts++;
}
}
return (hasCriticalExten);
}
PRBool
cert_HasUnknownCriticalExten(CERTCertExtension **extensions)
{
CERTCertExtension **exts;
CERTCertExtension *ext = NULL;
PRBool hasUnknownCriticalExten = PR_FALSE;
exts = extensions;
if (exts) {
while (*exts) {
ext = *exts;
/* If the criticality is omitted, it's non-critical.
If an extension is critical, make sure that we know
how to process the extension.
*/
if (ext->critical.data && ext->critical.data[0] == 0xff) {
if (SECOID_KnownCertExtenOID(&ext->id) == PR_FALSE) {
hasUnknownCriticalExten = PR_TRUE;
break;
}
}
exts++;
}
}
return (hasUnknownCriticalExten);
}

View file

@ -0,0 +1,44 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* x.509 v3 certificate extension helper routines
*
*/
#ifndef _CERTXUTL_H_
#define _CERTXUTL_H_
#include "nspr.h"
#ifdef OLD
typedef enum {
CertificateExtensions,
CrlExtensions,
OCSPRequestExtensions,
OCSPSingleRequestExtensions,
OCSPResponseSingleExtensions
} ExtensionsType;
#endif
extern PRBool cert_HasCriticalExtension(CERTCertExtension **extensions);
extern SECStatus CERT_FindBitStringExtension(CERTCertExtension **extensions,
int tag, SECItem *retItem);
extern void *cert_StartExtensions(void *owner, PLArenaPool *arena,
void (*setExts)(void *object,
CERTCertExtension **exts));
extern SECStatus cert_FindExtension(CERTCertExtension **extensions, int tag,
SECItem *value);
extern SECStatus cert_FindExtensionByOID(CERTCertExtension **extensions,
SECItem *oid, SECItem *value);
extern SECStatus cert_GetExtenCriticality(CERTCertExtension **extensions,
int tag, PRBool *isCritical);
extern PRBool cert_HasUnknownCriticalExten(CERTCertExtension **extensions);
#endif

View file

@ -0,0 +1,15 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Override TARGETS variable so that only static libraries
# are specifed as dependencies within rules.mk.
#
TARGETS = $(LIBRARY)
SHARED_LIBRARY =
IMPORT_LIBRARY =
PROGRAM =

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
{
'includes': [
'../../coreconf/config.gypi'
],
'targets': [
{
'target_name': 'lib_certdb_exports',
'type': 'none',
'copies': [
{
'files': [
'cert.h',
'certdb.h',
'certt.h'
],
'destination': '<(nss_public_dist_dir)/<(module)'
},
{
'files': [
'certi.h',
'certxutl.h',
'genname.h',
'xconst.h'
],
'destination': '<(nss_private_dist_dir)/<(module)'
}
]
}
],
'variables': {
'module': 'nss'
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,93 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _GENAME_H_
#define _GENAME_H_
#include "plarena.h"
#include "seccomon.h"
#include "secoidt.h"
#include "secasn1.h"
#include "secder.h"
#include "certt.h"
/************************************************************************/
SEC_BEGIN_PROTOS
extern const SEC_ASN1Template CERT_GeneralNamesTemplate[];
extern SECItem **cert_EncodeGeneralNames(PLArenaPool *arena,
CERTGeneralName *names);
extern CERTGeneralName *cert_DecodeGeneralNames(PLArenaPool *arena,
SECItem **encodedGenName);
extern SECStatus cert_DestroyGeneralNames(CERTGeneralName *name);
extern SECStatus cert_EncodeNameConstraints(CERTNameConstraints *constraints,
PLArenaPool *arena, SECItem *dest);
extern CERTNameConstraints *cert_DecodeNameConstraints(
PLArenaPool *arena, const SECItem *encodedConstraints);
extern CERTGeneralName *cert_CombineNamesLists(CERTGeneralName *list1,
CERTGeneralName *list2);
extern CERTNameConstraint *cert_CombineConstraintsLists(
CERTNameConstraint *list1, CERTNameConstraint *list2);
/*********************************************************************/
/* A thread safe implementation of General Names */
/*********************************************************************/
/* Destroy a Single CERTGeneralName */
void CERT_DestroyGeneralName(CERTGeneralName *name);
SECStatus CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b);
SECStatus CERT_CopyGeneralName(PLArenaPool *arena, CERTGeneralName *dest,
CERTGeneralName *src);
/* General Name Lists are a thread safe, reference counting layer to
* general names */
/* Destroys a CERTGeneralNameList */
void CERT_DestroyGeneralNameList(CERTGeneralNameList *list);
/* Creates a CERTGeneralNameList */
CERTGeneralNameList *CERT_CreateGeneralNameList(CERTGeneralName *name);
/* Compares two CERTGeneralNameList */
SECStatus CERT_CompareGeneralNameLists(CERTGeneralNameList *a,
CERTGeneralNameList *b);
/* returns a copy of the first name of the type requested */
void *CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
CERTGeneralNameType type,
PLArenaPool *arena);
/* Adds a name to the tail of the list */
void CERT_AddGeneralNameToList(CERTGeneralNameList *list,
CERTGeneralNameType type, void *data,
SECItem *oid);
/* returns a duplicate of the CERTGeneralNameList */
CERTGeneralNameList *CERT_DupGeneralNameList(CERTGeneralNameList *list);
/* returns the number of CERTGeneralName objects in the doubly linked
** list of which *names is a member.
*/
extern int CERT_GetNamesLength(CERTGeneralName *names);
/************************************************************************/
SECStatus CERT_CompareNameSpace(CERTCertificate *cert,
CERTGeneralName *namesList,
CERTCertificate **certsList,
PLArenaPool *reqArena,
CERTCertificate **pBadCert);
SEC_END_PROTOS
#endif

View file

@ -0,0 +1,40 @@
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
CORE_DEPTH = ../..
EXPORTS = \
cert.h \
certt.h \
certdb.h \
$(NULL)
PRIVATE_EXPORTS = \
genname.h \
xconst.h \
certxutl.h \
certi.h \
$(NULL)
MODULE = nss
CSRCS = \
alg1485.c \
certdb.c \
certv3.c \
certxutl.c \
crl.c \
genname.c \
stanpcertdb.c \
polcyxtn.c \
secname.c \
xauthkid.c \
xbsconst.c \
xconst.c \
$(NULL)
LIBRARY_NAME = certdb
# This part of the code, including all sub-dirs, can be optimized for size
export ALLOW_OPT_CODE_SIZE = 1

View file

@ -0,0 +1,806 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Support for various policy related extensions
*/
#include "seccomon.h"
#include "secport.h"
#include "secder.h"
#include "cert.h"
#include "secoid.h"
#include "secasn1.h"
#include "secerr.h"
#include "nspr.h"
SEC_ASN1_MKSUB(SEC_IntegerTemplate)
SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
const SEC_ASN1Template CERT_DisplayTextTypeTemplate[] = {
{ SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
{ SEC_ASN1_IA5_STRING, 0, 0, siAsciiString },
{ SEC_ASN1_VISIBLE_STRING, 0, 0, siVisibleString },
{ SEC_ASN1_BMP_STRING, 0, 0, siBMPString },
{ SEC_ASN1_UTF8_STRING, 0, 0, siUTF8String },
{ 0 }
};
const SEC_ASN1Template CERT_NoticeReferenceTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNoticeReference) },
{ SEC_ASN1_INLINE, offsetof(CERTNoticeReference, organization),
CERT_DisplayTextTypeTemplate, 0 },
{ SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN,
offsetof(CERTNoticeReference, noticeNumbers),
SEC_ASN1_SUB(SEC_IntegerTemplate) },
{ 0 }
};
const SEC_ASN1Template CERT_UserNoticeTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTUserNotice) },
{ SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
offsetof(CERTUserNotice, noticeReference), CERT_NoticeReferenceTemplate,
0 },
{ SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
offsetof(CERTUserNotice, displayText), CERT_DisplayTextTypeTemplate, 0 },
{ 0 }
};
const SEC_ASN1Template CERT_PolicyQualifierTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPolicyQualifier) },
{ SEC_ASN1_OBJECT_ID, offsetof(CERTPolicyQualifier, qualifierID) },
{ SEC_ASN1_ANY, offsetof(CERTPolicyQualifier, qualifierValue) },
{ 0 }
};
const SEC_ASN1Template CERT_PolicyInfoTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPolicyInfo) },
{ SEC_ASN1_OBJECT_ID, offsetof(CERTPolicyInfo, policyID) },
{ SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL,
offsetof(CERTPolicyInfo, policyQualifiers),
CERT_PolicyQualifierTemplate },
{ 0 }
};
const SEC_ASN1Template CERT_CertificatePoliciesTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, offsetof(CERTCertificatePolicies, policyInfos),
CERT_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) }
};
const SEC_ASN1Template CERT_PolicyMapTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPolicyMap) },
{ SEC_ASN1_OBJECT_ID, offsetof(CERTPolicyMap, issuerDomainPolicy) },
{ SEC_ASN1_OBJECT_ID, offsetof(CERTPolicyMap, subjectDomainPolicy) },
{ 0 }
};
const SEC_ASN1Template CERT_PolicyMappingsTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, offsetof(CERTCertificatePolicyMappings, policyMaps),
CERT_PolicyMapTemplate, sizeof(CERTPolicyMap) }
};
const SEC_ASN1Template CERT_PolicyConstraintsTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificatePolicyConstraints) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
offsetof(CERTCertificatePolicyConstraints, explicitPolicySkipCerts),
SEC_ASN1_SUB(SEC_IntegerTemplate) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
offsetof(CERTCertificatePolicyConstraints, inhibitMappingSkipCerts),
SEC_ASN1_SUB(SEC_IntegerTemplate) },
{ 0 }
};
const SEC_ASN1Template CERT_InhibitAnyTemplate[] = {
{ SEC_ASN1_INTEGER,
offsetof(CERTCertificateInhibitAny, inhibitAnySkipCerts), NULL,
sizeof(CERTCertificateInhibitAny) }
};
static void
breakLines(char *string)
{
char *tmpstr;
char *lastspace = NULL;
int curlen = 0;
int c;
tmpstr = string;
while ((c = *tmpstr) != '\0') {
switch (c) {
case ' ':
lastspace = tmpstr;
break;
case '\n':
lastspace = NULL;
curlen = 0;
break;
}
if ((curlen >= 55) && (lastspace != NULL)) {
*lastspace = '\n';
curlen = (tmpstr - lastspace);
lastspace = NULL;
}
curlen++;
tmpstr++;
}
return;
}
CERTCertificatePolicies *
CERT_DecodeCertificatePoliciesExtension(const SECItem *extnValue)
{
PLArenaPool *arena = NULL;
SECStatus rv;
CERTCertificatePolicies *policies;
CERTPolicyInfo **policyInfos, *policyInfo;
CERTPolicyQualifier **policyQualifiers, *policyQualifier;
SECItem newExtnValue;
/* make a new arena */
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
goto loser;
}
/* allocate the certificate policies structure */
policies = (CERTCertificatePolicies *)PORT_ArenaZAlloc(
arena, sizeof(CERTCertificatePolicies));
if (policies == NULL) {
goto loser;
}
policies->arena = arena;
/* copy the DER into the arena, since Quick DER returns data that points
into the DER input, which may get freed by the caller */
rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
if (rv != SECSuccess) {
goto loser;
}
/* decode the policy info */
rv = SEC_QuickDERDecodeItem(
arena, policies, CERT_CertificatePoliciesTemplate, &newExtnValue);
if (rv != SECSuccess) {
goto loser;
}
/* initialize the oid tags */
policyInfos = policies->policyInfos;
while (*policyInfos != NULL) {
policyInfo = *policyInfos;
policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID);
policyQualifiers = policyInfo->policyQualifiers;
while (policyQualifiers != NULL && *policyQualifiers != NULL) {
policyQualifier = *policyQualifiers;
policyQualifier->oid =
SECOID_FindOIDTag(&policyQualifier->qualifierID);
policyQualifiers++;
}
policyInfos++;
}
return (policies);
loser:
if (arena != NULL) {
PORT_FreeArena(arena, PR_FALSE);
}
return (NULL);
}
void
CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies)
{
if (policies != NULL) {
PORT_FreeArena(policies->arena, PR_FALSE);
}
return;
}
CERTCertificatePolicyMappings *
CERT_DecodePolicyMappingsExtension(SECItem *extnValue)
{
PLArenaPool *arena = NULL;
SECStatus rv;
CERTCertificatePolicyMappings *mappings;
SECItem newExtnValue;
/* make a new arena */
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
goto loser;
}
/* allocate the policy mappings structure */
mappings = (CERTCertificatePolicyMappings *)PORT_ArenaZAlloc(
arena, sizeof(CERTCertificatePolicyMappings));
if (mappings == NULL) {
goto loser;
}
mappings->arena = arena;
/* copy the DER into the arena, since Quick DER returns data that points
into the DER input, which may get freed by the caller */
rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
if (rv != SECSuccess) {
goto loser;
}
/* decode the policy mappings */
rv = SEC_QuickDERDecodeItem(arena, mappings, CERT_PolicyMappingsTemplate,
&newExtnValue);
if (rv != SECSuccess) {
goto loser;
}
return (mappings);
loser:
if (arena != NULL) {
PORT_FreeArena(arena, PR_FALSE);
}
return (NULL);
}
SECStatus
CERT_DestroyPolicyMappingsExtension(CERTCertificatePolicyMappings *mappings)
{
if (mappings != NULL) {
PORT_FreeArena(mappings->arena, PR_FALSE);
}
return SECSuccess;
}
SECStatus
CERT_DecodePolicyConstraintsExtension(
CERTCertificatePolicyConstraints *decodedValue, const SECItem *encodedValue)
{
CERTCertificatePolicyConstraints decodeContext;
PLArenaPool *arena = NULL;
SECStatus rv = SECSuccess;
/* initialize so we can tell when an optional component is omitted */
PORT_Memset(&decodeContext, 0, sizeof(decodeContext));
/* make a new arena */
arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
if (!arena) {
return SECFailure;
}
do {
/* decode the policy constraints */
rv = SEC_QuickDERDecodeItem(arena, &decodeContext,
CERT_PolicyConstraintsTemplate,
encodedValue);
if (rv != SECSuccess) {
break;
}
if (decodeContext.explicitPolicySkipCerts.len == 0) {
*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data = -1;
} else {
*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data =
DER_GetInteger(&decodeContext.explicitPolicySkipCerts);
}
if (decodeContext.inhibitMappingSkipCerts.len == 0) {
*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data = -1;
} else {
*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data =
DER_GetInteger(&decodeContext.inhibitMappingSkipCerts);
}
if ((*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
PR_INT32_MIN) ||
(*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
PR_INT32_MAX) ||
(*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
PR_INT32_MIN) ||
(*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
PR_INT32_MAX)) {
rv = SECFailure;
}
} while (0);
PORT_FreeArena(arena, PR_FALSE);
return (rv);
}
SECStatus
CERT_DecodeInhibitAnyExtension(CERTCertificateInhibitAny *decodedValue,
SECItem *encodedValue)
{
CERTCertificateInhibitAny decodeContext;
PLArenaPool *arena = NULL;
SECStatus rv = SECSuccess;
/* make a new arena */
arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
if (!arena) {
return SECFailure;
}
do {
/* decode the policy mappings */
decodeContext.inhibitAnySkipCerts.type = siUnsignedInteger;
rv = SEC_QuickDERDecodeItem(arena, &decodeContext,
CERT_InhibitAnyTemplate, encodedValue);
if (rv != SECSuccess) {
break;
}
*(PRInt32 *)decodedValue->inhibitAnySkipCerts.data =
DER_GetInteger(&decodeContext.inhibitAnySkipCerts);
} while (0);
PORT_FreeArena(arena, PR_FALSE);
return (rv);
}
CERTUserNotice *
CERT_DecodeUserNotice(SECItem *noticeItem)
{
PLArenaPool *arena = NULL;
SECStatus rv;
CERTUserNotice *userNotice;
SECItem newNoticeItem;
/* make a new arena */
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
goto loser;
}
/* allocate the userNotice structure */
userNotice =
(CERTUserNotice *)PORT_ArenaZAlloc(arena, sizeof(CERTUserNotice));
if (userNotice == NULL) {
goto loser;
}
userNotice->arena = arena;
/* copy the DER into the arena, since Quick DER returns data that points
into the DER input, which may get freed by the caller */
rv = SECITEM_CopyItem(arena, &newNoticeItem, noticeItem);
if (rv != SECSuccess) {
goto loser;
}
/* decode the user notice */
rv = SEC_QuickDERDecodeItem(arena, userNotice, CERT_UserNoticeTemplate,
&newNoticeItem);
if (rv != SECSuccess) {
goto loser;
}
if (userNotice->derNoticeReference.data != NULL) {
rv = SEC_QuickDERDecodeItem(arena, &userNotice->noticeReference,
CERT_NoticeReferenceTemplate,
&userNotice->derNoticeReference);
if (rv == SECFailure) {
goto loser;
}
}
return (userNotice);
loser:
if (arena != NULL) {
PORT_FreeArena(arena, PR_FALSE);
}
return (NULL);
}
void
CERT_DestroyUserNotice(CERTUserNotice *userNotice)
{
if (userNotice != NULL) {
PORT_FreeArena(userNotice->arena, PR_FALSE);
}
return;
}
static CERTPolicyStringCallback policyStringCB = NULL;
static void *policyStringCBArg = NULL;
void
CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg)
{
policyStringCB = cb;
policyStringCBArg = cbarg;
return;
}
char *
stringFromUserNotice(SECItem *noticeItem)
{
SECItem *org;
unsigned int len, headerlen;
char *stringbuf;
CERTUserNotice *userNotice;
char *policystr;
char *retstr = NULL;
SECItem *displayText;
SECItem **noticeNumbers;
unsigned int strnum;
/* decode the user notice */
userNotice = CERT_DecodeUserNotice(noticeItem);
if (userNotice == NULL) {
return (NULL);
}
org = &userNotice->noticeReference.organization;
if ((org->len != 0) && (policyStringCB != NULL)) {
/* has a noticeReference */
/* extract the org string */
len = org->len;
stringbuf = (char *)PORT_Alloc(len + 1);
if (stringbuf != NULL) {
PORT_Memcpy(stringbuf, org->data, len);
stringbuf[len] = '\0';
noticeNumbers = userNotice->noticeReference.noticeNumbers;
while (*noticeNumbers != NULL) {
/* XXX - only one byte integers right now*/
strnum = (*noticeNumbers)->data[0];
policystr =
(*policyStringCB)(stringbuf, strnum, policyStringCBArg);
if (policystr != NULL) {
if (retstr != NULL) {
retstr = PR_sprintf_append(retstr, "\n%s", policystr);
} else {
retstr = PR_sprintf_append(retstr, "%s", policystr);
}
PORT_Free(policystr);
}
noticeNumbers++;
}
PORT_Free(stringbuf);
}
}
if (retstr == NULL) {
if (userNotice->displayText.len != 0) {
displayText = &userNotice->displayText;
if (displayText->len > 2) {
if (displayText->data[0] == SEC_ASN1_VISIBLE_STRING) {
headerlen = 2;
if (displayText->data[1] & 0x80) {
/* multibyte length */
headerlen += (displayText->data[1] & 0x7f);
}
len = displayText->len - headerlen;
retstr = (char *)PORT_Alloc(len + 1);
if (retstr != NULL) {
PORT_Memcpy(retstr, &displayText->data[headerlen], len);
retstr[len] = '\0';
}
}
}
}
}
CERT_DestroyUserNotice(userNotice);
return (retstr);
}
char *
CERT_GetCertCommentString(CERTCertificate *cert)
{
char *retstring = NULL;
SECStatus rv;
SECItem policyItem;
CERTCertificatePolicies *policies = NULL;
CERTPolicyInfo **policyInfos;
CERTPolicyQualifier **policyQualifiers, *qualifier;
policyItem.data = NULL;
rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
&policyItem);
if (rv != SECSuccess) {
goto nopolicy;
}
policies = CERT_DecodeCertificatePoliciesExtension(&policyItem);
if (policies == NULL) {
goto nopolicy;
}
policyInfos = policies->policyInfos;
/* search through policyInfos looking for the verisign policy */
while (*policyInfos != NULL) {
if ((*policyInfos)->oid == SEC_OID_VERISIGN_USER_NOTICES) {
policyQualifiers = (*policyInfos)->policyQualifiers;
/* search through the policy qualifiers looking for user notice */
while (policyQualifiers != NULL && *policyQualifiers != NULL) {
qualifier = *policyQualifiers;
if (qualifier->oid == SEC_OID_PKIX_USER_NOTICE_QUALIFIER) {
retstring =
stringFromUserNotice(&qualifier->qualifierValue);
break;
}
policyQualifiers++;
}
break;
}
policyInfos++;
}
nopolicy:
if (policyItem.data != NULL) {
PORT_Free(policyItem.data);
}
if (policies != NULL) {
CERT_DestroyCertificatePoliciesExtension(policies);
}
if (retstring == NULL) {
retstring =
CERT_FindNSStringExtension(cert, SEC_OID_NS_CERT_EXT_COMMENT);
}
if (retstring != NULL) {
breakLines(retstring);
}
return (retstring);
}
const SEC_ASN1Template CERT_OidSeqTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, offsetof(CERTOidSequence, oids),
SEC_ASN1_SUB(SEC_ObjectIDTemplate) }
};
CERTOidSequence *
CERT_DecodeOidSequence(const SECItem *seqItem)
{
PLArenaPool *arena = NULL;
SECStatus rv;
CERTOidSequence *oidSeq;
SECItem newSeqItem;
/* make a new arena */
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
goto loser;
}
/* allocate the userNotice structure */
oidSeq =
(CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
if (oidSeq == NULL) {
goto loser;
}
oidSeq->arena = arena;
/* copy the DER into the arena, since Quick DER returns data that points
into the DER input, which may get freed by the caller */
rv = SECITEM_CopyItem(arena, &newSeqItem, seqItem);
if (rv != SECSuccess) {
goto loser;
}
/* decode the user notice */
rv =
SEC_QuickDERDecodeItem(arena, oidSeq, CERT_OidSeqTemplate, &newSeqItem);
if (rv != SECSuccess) {
goto loser;
}
return (oidSeq);
loser:
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
return (NULL);
}
void
CERT_DestroyOidSequence(CERTOidSequence *oidSeq)
{
if (oidSeq != NULL) {
PORT_FreeArena(oidSeq->arena, PR_FALSE);
}
return;
}
PRBool
CERT_GovtApprovedBitSet(CERTCertificate *cert)
{
SECStatus rv;
SECItem extItem;
CERTOidSequence *oidSeq = NULL;
PRBool ret;
SECItem **oids;
SECItem *oid;
SECOidTag oidTag;
extItem.data = NULL;
rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
if (rv != SECSuccess) {
goto loser;
}
oidSeq = CERT_DecodeOidSequence(&extItem);
if (oidSeq == NULL) {
goto loser;
}
oids = oidSeq->oids;
while (oids != NULL && *oids != NULL) {
oid = *oids;
oidTag = SECOID_FindOIDTag(oid);
if (oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) {
goto success;
}
oids++;
}
loser:
ret = PR_FALSE;
goto done;
success:
ret = PR_TRUE;
done:
if (oidSeq != NULL) {
CERT_DestroyOidSequence(oidSeq);
}
if (extItem.data != NULL) {
PORT_Free(extItem.data);
}
return (ret);
}
SECStatus
CERT_EncodePolicyConstraintsExtension(PLArenaPool *arena,
CERTCertificatePolicyConstraints *constr,
SECItem *dest)
{
SECStatus rv = SECSuccess;
PORT_Assert(constr != NULL && dest != NULL);
if (constr == NULL || dest == NULL) {
return SECFailure;
}
if (SEC_ASN1EncodeItem(arena, dest, constr,
CERT_PolicyConstraintsTemplate) == NULL) {
rv = SECFailure;
}
return (rv);
}
SECStatus
CERT_EncodePolicyMappingExtension(PLArenaPool *arena,
CERTCertificatePolicyMappings *mapping,
SECItem *dest)
{
SECStatus rv = SECSuccess;
PORT_Assert(mapping != NULL && dest != NULL);
if (mapping == NULL || dest == NULL) {
return SECFailure;
}
if (SEC_ASN1EncodeItem(arena, dest, mapping, CERT_PolicyMappingsTemplate) ==
NULL) {
rv = SECFailure;
}
return (rv);
}
SECStatus
CERT_EncodeCertPoliciesExtension(PLArenaPool *arena, CERTPolicyInfo **info,
SECItem *dest)
{
SECStatus rv = SECSuccess;
PORT_Assert(info != NULL && dest != NULL);
if (info == NULL || dest == NULL) {
return SECFailure;
}
if (SEC_ASN1EncodeItem(arena, dest, info,
CERT_CertificatePoliciesTemplate) == NULL) {
rv = SECFailure;
}
return (rv);
}
SECStatus
CERT_EncodeUserNotice(PLArenaPool *arena, CERTUserNotice *notice, SECItem *dest)
{
SECStatus rv = SECSuccess;
PORT_Assert(notice != NULL && dest != NULL);
if (notice == NULL || dest == NULL) {
return SECFailure;
}
if (SEC_ASN1EncodeItem(arena, dest, notice, CERT_UserNoticeTemplate) ==
NULL) {
rv = SECFailure;
}
return (rv);
}
SECStatus
CERT_EncodeNoticeReference(PLArenaPool *arena, CERTNoticeReference *reference,
SECItem *dest)
{
SECStatus rv = SECSuccess;
PORT_Assert(reference != NULL && dest != NULL);
if (reference == NULL || dest == NULL) {
return SECFailure;
}
if (SEC_ASN1EncodeItem(arena, dest, reference,
CERT_NoticeReferenceTemplate) == NULL) {
rv = SECFailure;
}
return (rv);
}
SECStatus
CERT_EncodeInhibitAnyExtension(PLArenaPool *arena,
CERTCertificateInhibitAny *certInhibitAny,
SECItem *dest)
{
SECStatus rv = SECSuccess;
PORT_Assert(certInhibitAny != NULL && dest != NULL);
if (certInhibitAny == NULL || dest == NULL) {
return SECFailure;
}
if (SEC_ASN1EncodeItem(arena, dest, certInhibitAny,
CERT_InhibitAnyTemplate) == NULL) {
rv = SECFailure;
}
return (rv);
}

View file

@ -0,0 +1,711 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cert.h"
#include "secoid.h"
#include "secder.h" /* XXX remove this when remove the DERTemplates */
#include "secasn1.h"
#include "secitem.h"
#include <stdarg.h>
#include "secerr.h"
#include "certi.h"
static const SEC_ASN1Template cert_AVATemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAVA) },
{ SEC_ASN1_OBJECT_ID, offsetof(CERTAVA, type) },
{ SEC_ASN1_ANY, offsetof(CERTAVA, value) },
{ 0 }
};
const SEC_ASN1Template CERT_RDNTemplate[] = {
{ SEC_ASN1_SET_OF, offsetof(CERTRDN, avas), cert_AVATemplate,
sizeof(CERTRDN) }
};
static int
CountArray(void **array)
{
int count = 0;
if (array) {
while (*array++) {
count++;
}
}
return count;
}
static void **
AddToArray(PLArenaPool *arena, void **array, void *element)
{
unsigned count;
void **ap;
/* Count up number of slots already in use in the array */
count = 0;
ap = array;
if (ap) {
while (*ap++) {
count++;
}
}
if (array) {
array =
(void **)PORT_ArenaGrow(arena, array, (count + 1) * sizeof(void *),
(count + 2) * sizeof(void *));
} else {
array = (void **)PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *));
}
if (array) {
array[count] = element;
array[count + 1] = 0;
}
return array;
}
SECOidTag
CERT_GetAVATag(CERTAVA *ava)
{
SECOidData *oid;
if (!ava->type.data)
return (SECOidTag)-1;
oid = SECOID_FindOID(&ava->type);
if (oid) {
return (oid->offset);
}
return (SECOidTag)-1;
}
static SECStatus
SetupAVAType(PLArenaPool *arena, SECOidTag type, SECItem *it, unsigned *maxLenp)
{
unsigned char *oid;
unsigned oidLen;
unsigned char *cp;
int maxLen;
SECOidData *oidrec;
oidrec = SECOID_FindOIDByTag(type);
if (oidrec == NULL)
return SECFailure;
oid = oidrec->oid.data;
oidLen = oidrec->oid.len;
maxLen = cert_AVAOidTagToMaxLen(type);
if (maxLen < 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
it->data = cp = (unsigned char *)PORT_ArenaAlloc(arena, oidLen);
if (cp == NULL) {
return SECFailure;
}
it->len = oidLen;
PORT_Memcpy(cp, oid, oidLen);
*maxLenp = (unsigned)maxLen;
return SECSuccess;
}
static SECStatus
SetupAVAValue(PLArenaPool *arena, int valueType, const SECItem *in,
SECItem *out, unsigned maxLen)
{
PRUint8 *value, *cp, *ucs4Val;
unsigned valueLen, valueLenLen, total;
unsigned ucs4Len = 0, ucs4MaxLen;
value = in->data;
valueLen = in->len;
switch (valueType) {
case SEC_ASN1_PRINTABLE_STRING:
case SEC_ASN1_IA5_STRING:
case SEC_ASN1_T61_STRING:
case SEC_ASN1_UTF8_STRING: /* no conversion required */
break;
case SEC_ASN1_UNIVERSAL_STRING:
ucs4MaxLen = valueLen * 6;
ucs4Val = (PRUint8 *)PORT_ArenaZAlloc(arena, ucs4MaxLen);
if (!ucs4Val ||
!PORT_UCS4_UTF8Conversion(PR_TRUE, value, valueLen, ucs4Val,
ucs4MaxLen, &ucs4Len)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
value = ucs4Val;
valueLen = ucs4Len;
maxLen *= 4;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (valueLen > maxLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
valueLenLen = DER_LengthLength(valueLen);
total = 1 + valueLenLen + valueLen;
cp = (PRUint8 *)PORT_ArenaAlloc(arena, total);
if (!cp) {
return SECFailure;
}
out->data = cp;
out->len = total;
cp = (PRUint8 *)DER_StoreHeader(cp, valueType, valueLen);
PORT_Memcpy(cp, value, valueLen);
return SECSuccess;
}
CERTAVA *
CERT_CreateAVAFromRaw(PLArenaPool *pool, const SECItem *OID,
const SECItem *value)
{
CERTAVA *ava;
int rv;
ava = PORT_ArenaZNew(pool, CERTAVA);
if (ava) {
rv = SECITEM_CopyItem(pool, &ava->type, OID);
if (rv)
return NULL;
rv = SECITEM_CopyItem(pool, &ava->value, value);
if (rv)
return NULL;
}
return ava;
}
CERTAVA *
CERT_CreateAVAFromSECItem(PLArenaPool *arena, SECOidTag kind, int valueType,
SECItem *value)
{
CERTAVA *ava;
int rv;
unsigned maxLen;
ava = (CERTAVA *)PORT_ArenaZAlloc(arena, sizeof(CERTAVA));
if (ava) {
rv = SetupAVAType(arena, kind, &ava->type, &maxLen);
if (rv) {
/* Illegal AVA type */
return NULL;
}
rv = SetupAVAValue(arena, valueType, value, &ava->value, maxLen);
if (rv) {
/* Illegal value type */
return NULL;
}
}
return ava;
}
CERTAVA *
CERT_CreateAVA(PLArenaPool *arena, SECOidTag kind, int valueType, char *value)
{
SECItem item = { siBuffer, NULL, 0 };
item.data = (PRUint8 *)value;
item.len = PORT_Strlen(value);
return CERT_CreateAVAFromSECItem(arena, kind, valueType, &item);
}
CERTAVA *
CERT_CopyAVA(PLArenaPool *arena, CERTAVA *from)
{
CERTAVA *ava;
int rv;
ava = (CERTAVA *)PORT_ArenaZAlloc(arena, sizeof(CERTAVA));
if (ava) {
rv = SECITEM_CopyItem(arena, &ava->type, &from->type);
if (rv)
goto loser;
rv = SECITEM_CopyItem(arena, &ava->value, &from->value);
if (rv)
goto loser;
}
return ava;
loser:
return 0;
}
CERTRDN *
CERT_CreateRDN(PLArenaPool *arena, CERTAVA *ava0, ...)
{
CERTAVA *ava;
CERTRDN *rdn;
va_list ap;
unsigned count;
CERTAVA **avap;
rdn = (CERTRDN *)PORT_ArenaAlloc(arena, sizeof(CERTRDN));
if (rdn) {
/* Count number of avas going into the rdn */
count = 0;
if (ava0) {
count++;
va_start(ap, ava0);
while ((ava = va_arg(ap, CERTAVA *)) != 0) {
count++;
}
va_end(ap);
}
/* Now fill in the pointers */
rdn->avas = avap =
(CERTAVA **)PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTAVA *));
if (!avap) {
return 0;
}
if (ava0) {
*avap++ = ava0;
va_start(ap, ava0);
while ((ava = va_arg(ap, CERTAVA *)) != 0) {
*avap++ = ava;
}
va_end(ap);
}
*avap++ = 0;
}
return rdn;
}
SECStatus
CERT_AddAVA(PLArenaPool *arena, CERTRDN *rdn, CERTAVA *ava)
{
rdn->avas = (CERTAVA **)AddToArray(arena, (void **)rdn->avas, ava);
return rdn->avas ? SECSuccess : SECFailure;
}
SECStatus
CERT_CopyRDN(PLArenaPool *arena, CERTRDN *to, CERTRDN *from)
{
CERTAVA **avas, *fava, *tava;
SECStatus rv = SECSuccess;
/* Copy each ava from from */
avas = from->avas;
if (avas) {
if (avas[0] == NULL) {
rv = CERT_AddAVA(arena, to, NULL);
return rv;
}
while ((fava = *avas++) != 0) {
tava = CERT_CopyAVA(arena, fava);
if (!tava) {
rv = SECFailure;
break;
}
rv = CERT_AddAVA(arena, to, tava);
if (rv != SECSuccess)
break;
}
}
return rv;
}
/************************************************************************/
const SEC_ASN1Template CERT_NameTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, offsetof(CERTName, rdns), CERT_RDNTemplate,
sizeof(CERTName) }
};
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_NameTemplate)
CERTName *
CERT_CreateName(CERTRDN *rdn0, ...)
{
CERTRDN *rdn;
CERTName *name;
va_list ap;
unsigned count;
CERTRDN **rdnp;
PLArenaPool *arena;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
return (0);
}
name = (CERTName *)PORT_ArenaAlloc(arena, sizeof(CERTName));
if (name) {
name->arena = arena;
/* Count number of RDNs going into the Name */
if (!rdn0) {
count = 0;
} else {
count = 1;
va_start(ap, rdn0);
while ((rdn = va_arg(ap, CERTRDN *)) != 0) {
count++;
}
va_end(ap);
}
/* Allocate space (including space for terminal null ptr) */
name->rdns = rdnp =
(CERTRDN **)PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTRDN *));
if (!name->rdns) {
goto loser;
}
/* Now fill in the pointers */
if (count > 0) {
*rdnp++ = rdn0;
va_start(ap, rdn0);
while ((rdn = va_arg(ap, CERTRDN *)) != 0) {
*rdnp++ = rdn;
}
va_end(ap);
}
/* null terminate the list */
*rdnp++ = 0;
}
return name;
loser:
PORT_FreeArena(arena, PR_FALSE);
return (0);
}
void
CERT_DestroyName(CERTName *name)
{
if (name) {
PLArenaPool *arena = name->arena;
name->rdns = NULL;
name->arena = NULL;
if (arena)
PORT_FreeArena(arena, PR_FALSE);
}
}
SECStatus
CERT_AddRDN(CERTName *name, CERTRDN *rdn)
{
name->rdns = (CERTRDN **)AddToArray(name->arena, (void **)name->rdns, rdn);
return name->rdns ? SECSuccess : SECFailure;
}
SECStatus
CERT_CopyName(PLArenaPool *arena, CERTName *to, const CERTName *from)
{
CERTRDN **rdns, *frdn, *trdn;
SECStatus rv = SECSuccess;
if (!to || !from) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
CERT_DestroyName(to);
to->arena = arena;
/* Copy each rdn from from */
rdns = from->rdns;
if (rdns) {
if (rdns[0] == NULL) {
rv = CERT_AddRDN(to, NULL);
return rv;
}
while ((frdn = *rdns++) != NULL) {
trdn = CERT_CreateRDN(arena, NULL);
if (!trdn) {
rv = SECFailure;
break;
}
rv = CERT_CopyRDN(arena, trdn, frdn);
if (rv != SECSuccess)
break;
rv = CERT_AddRDN(to, trdn);
if (rv != SECSuccess)
break;
}
}
return rv;
}
/************************************************************************/
static void
canonicalize(SECItem *foo)
{
int ch, lastch, len, src, dest;
/* strip trailing whitespace. */
len = foo->len;
while (len > 0 && ((ch = foo->data[len - 1]) == ' ' || ch == '\t' ||
ch == '\r' || ch == '\n')) {
len--;
}
src = 0;
/* strip leading whitespace. */
while (src < len && ((ch = foo->data[src]) == ' ' || ch == '\t' ||
ch == '\r' || ch == '\n')) {
src++;
}
dest = 0;
lastch = ' ';
while (src < len) {
ch = foo->data[src++];
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
ch = ' ';
if (ch == lastch)
continue;
} else if (ch >= 'A' && ch <= 'Z') {
ch |= 0x20; /* downshift */
}
foo->data[dest++] = lastch = ch;
}
foo->len = dest;
}
/* SECItems a and b contain DER-encoded printable strings. */
SECComparison
CERT_CompareDERPrintableStrings(const SECItem *a, const SECItem *b)
{
SECComparison rv = SECLessThan;
SECItem *aVal = CERT_DecodeAVAValue(a);
SECItem *bVal = CERT_DecodeAVAValue(b);
if (aVal && aVal->len && aVal->data && bVal && bVal->len && bVal->data) {
canonicalize(aVal);
canonicalize(bVal);
rv = SECITEM_CompareItem(aVal, bVal);
}
SECITEM_FreeItem(aVal, PR_TRUE);
SECITEM_FreeItem(bVal, PR_TRUE);
return rv;
}
SECComparison
CERT_CompareAVA(const CERTAVA *a, const CERTAVA *b)
{
SECComparison rv;
rv = SECITEM_CompareItem(&a->type, &b->type);
if (SECEqual != rv)
return rv; /* Attribute types don't match. */
/* Let's be optimistic. Maybe the values will just compare equal. */
rv = SECITEM_CompareItem(&a->value, &b->value);
if (SECEqual == rv)
return rv; /* values compared exactly. */
if (a->value.len && a->value.data && b->value.len && b->value.data) {
/* Here, the values did not match.
** If the values had different encodings, convert them to the same
** encoding and compare that way.
*/
if (a->value.data[0] != b->value.data[0]) {
/* encodings differ. Convert both to UTF-8 and compare. */
SECItem *aVal = CERT_DecodeAVAValue(&a->value);
SECItem *bVal = CERT_DecodeAVAValue(&b->value);
if (aVal && aVal->len && aVal->data && bVal && bVal->len &&
bVal->data) {
rv = SECITEM_CompareItem(aVal, bVal);
}
SECITEM_FreeItem(aVal, PR_TRUE);
SECITEM_FreeItem(bVal, PR_TRUE);
} else if (a->value.data[0] == 0x13) { /* both are printable strings. */
/* printable strings */
rv = CERT_CompareDERPrintableStrings(&a->value, &b->value);
}
}
return rv;
}
SECComparison
CERT_CompareRDN(const CERTRDN *a, const CERTRDN *b)
{
CERTAVA **aavas, *aava;
CERTAVA **bavas, *bava;
int ac, bc;
SECComparison rv = SECEqual;
aavas = a->avas;
bavas = b->avas;
/*
** Make sure array of ava's are the same length. If not, then we are
** not equal
*/
ac = CountArray((void **)aavas);
bc = CountArray((void **)bavas);
if (ac < bc)
return SECLessThan;
if (ac > bc)
return SECGreaterThan;
while (NULL != (aava = *aavas++)) {
for (bavas = b->avas; NULL != (bava = *bavas++);) {
rv = SECITEM_CompareItem(&aava->type, &bava->type);
if (SECEqual == rv) {
rv = CERT_CompareAVA(aava, bava);
if (SECEqual != rv)
return rv;
break;
}
}
if (!bava) /* didn't find a match */
return SECGreaterThan;
}
return rv;
}
SECComparison
CERT_CompareName(const CERTName *a, const CERTName *b)
{
CERTRDN **ardns, *ardn;
CERTRDN **brdns, *brdn;
int ac, bc;
SECComparison rv = SECEqual;
ardns = a->rdns;
brdns = b->rdns;
/*
** Make sure array of rdn's are the same length. If not, then we are
** not equal
*/
ac = CountArray((void **)ardns);
bc = CountArray((void **)brdns);
if (ac < bc)
return SECLessThan;
if (ac > bc)
return SECGreaterThan;
for (;;) {
if (!ardns++ || !brdns++) {
break;
}
ardn = *ardns;
brdn = *brdns;
if (!ardn) {
break;
}
rv = CERT_CompareRDN(ardn, brdn);
if (rv)
return rv;
}
return rv;
}
/* Moved from certhtml.c */
SECItem *
CERT_DecodeAVAValue(const SECItem *derAVAValue)
{
SECItem *retItem;
const SEC_ASN1Template *theTemplate = NULL;
enum { conv_none,
conv_ucs4,
conv_ucs2,
conv_iso88591 } convert = conv_none;
SECItem avaValue = { siBuffer, 0 };
PORTCheapArenaPool tmpArena;
if (!derAVAValue || !derAVAValue->len || !derAVAValue->data) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
switch (derAVAValue->data[0]) {
case SEC_ASN1_UNIVERSAL_STRING:
convert = conv_ucs4;
theTemplate = SEC_ASN1_GET(SEC_UniversalStringTemplate);
break;
case SEC_ASN1_IA5_STRING:
theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
break;
case SEC_ASN1_PRINTABLE_STRING:
theTemplate = SEC_ASN1_GET(SEC_PrintableStringTemplate);
break;
case SEC_ASN1_T61_STRING:
/*
* Per common practice, we're not decoding actual T.61, but instead
* treating T61-labeled strings as containing ISO-8859-1.
*/
convert = conv_iso88591;
theTemplate = SEC_ASN1_GET(SEC_T61StringTemplate);
break;
case SEC_ASN1_BMP_STRING:
convert = conv_ucs2;
theTemplate = SEC_ASN1_GET(SEC_BMPStringTemplate);
break;
case SEC_ASN1_UTF8_STRING:
/* No conversion needed ! */
theTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
break;
default:
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
PORT_Memset(&avaValue, 0, sizeof(SECItem));
PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
if (SEC_QuickDERDecodeItem(&tmpArena.arena, &avaValue, theTemplate,
derAVAValue) != SECSuccess) {
PORT_DestroyCheapArena(&tmpArena);
return NULL;
}
if (convert != conv_none) {
unsigned int utf8ValLen = avaValue.len * 3;
unsigned char *utf8Val =
(unsigned char *)PORT_ArenaZAlloc(&tmpArena.arena, utf8ValLen);
switch (convert) {
case conv_ucs4:
if (avaValue.len % 4 != 0 ||
!PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data,
avaValue.len, utf8Val, utf8ValLen,
&utf8ValLen)) {
PORT_DestroyCheapArena(&tmpArena);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
break;
case conv_ucs2:
if (avaValue.len % 2 != 0 ||
!PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data,
avaValue.len, utf8Val, utf8ValLen,
&utf8ValLen)) {
PORT_DestroyCheapArena(&tmpArena);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
break;
case conv_iso88591:
if (!PORT_ISO88591_UTF8Conversion(avaValue.data, avaValue.len,
utf8Val, utf8ValLen,
&utf8ValLen)) {
PORT_DestroyCheapArena(&tmpArena);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
break;
case conv_none:
PORT_Assert(0); /* not reached */
break;
}
avaValue.data = utf8Val;
avaValue.len = utf8ValLen;
}
retItem = SECITEM_DupItem(&avaValue);
PORT_DestroyCheapArena(&tmpArena);
return retItem;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,128 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* X.509 v3 Subject Key Usage Extension
*
*/
#include "prtypes.h"
#include "seccomon.h"
#include "secdert.h"
#include "secoidt.h"
#include "secasn1t.h"
#include "secasn1.h"
#include "secport.h"
#include "certt.h"
#include "genname.h"
#include "secerr.h"
SEC_ASN1_MKSUB(SEC_IntegerTemplate)
SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
const SEC_ASN1Template CERTAuthKeyIDTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAuthKeyID) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
offsetof(CERTAuthKeyID, keyID), SEC_ASN1_SUB(SEC_OctetStringTemplate) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
offsetof(CERTAuthKeyID, DERAuthCertIssuer), CERT_GeneralNamesTemplate },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
offsetof(CERTAuthKeyID, authCertSerialNumber),
SEC_ASN1_SUB(SEC_IntegerTemplate) },
{ 0 }
};
SECStatus
CERT_EncodeAuthKeyID(PLArenaPool *arena, CERTAuthKeyID *value,
SECItem *encodedValue)
{
SECStatus rv = SECFailure;
PORT_Assert(value);
PORT_Assert(arena);
PORT_Assert(value->DERAuthCertIssuer == NULL);
PORT_Assert(encodedValue);
do {
/* If both of the authCertIssuer and the serial number exist, encode
the name first. Otherwise, it is an error if one exist and the other
is not.
*/
if (value->authCertIssuer) {
if (!value->authCertSerialNumber.data) {
PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
break;
}
value->DERAuthCertIssuer =
cert_EncodeGeneralNames(arena, value->authCertIssuer);
if (!value->DERAuthCertIssuer) {
PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
break;
}
} else if (value->authCertSerialNumber.data) {
PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
break;
}
if (SEC_ASN1EncodeItem(arena, encodedValue, value,
CERTAuthKeyIDTemplate) == NULL)
break;
rv = SECSuccess;
} while (0);
return (rv);
}
CERTAuthKeyID *
CERT_DecodeAuthKeyID(PLArenaPool *arena, const SECItem *encodedValue)
{
CERTAuthKeyID *value = NULL;
SECStatus rv = SECFailure;
void *mark;
SECItem newEncodedValue;
PORT_Assert(arena);
do {
mark = PORT_ArenaMark(arena);
value = (CERTAuthKeyID *)PORT_ArenaZAlloc(arena, sizeof(*value));
if (value == NULL)
break;
value->DERAuthCertIssuer = NULL;
/* copy the DER into the arena, since Quick DER returns data that points
into the DER input, which may get freed by the caller */
rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue);
if (rv != SECSuccess) {
break;
}
rv = SEC_QuickDERDecodeItem(arena, value, CERTAuthKeyIDTemplate,
&newEncodedValue);
if (rv != SECSuccess)
break;
value->authCertIssuer =
cert_DecodeGeneralNames(arena, value->DERAuthCertIssuer);
if (value->authCertIssuer == NULL)
break;
/* what if the general name contains other format but not URI ?
hl
*/
if ((value->authCertSerialNumber.data && !value->authCertIssuer) ||
(!value->authCertSerialNumber.data && value->authCertIssuer)) {
PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
break;
}
} while (0);
if (rv != SECSuccess) {
PORT_ArenaRelease(arena, mark);
return ((CERTAuthKeyID *)NULL);
}
PORT_ArenaUnmark(arena, mark);
return (value);
}

View file

@ -0,0 +1,143 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* X.509 v3 Basic Constraints Extension
*/
#include "prtypes.h"
#include <limits.h> /* for LONG_MAX */
#include "seccomon.h"
#include "secdert.h"
#include "secoidt.h"
#include "secasn1t.h"
#include "secasn1.h"
#include "certt.h"
#include "secder.h"
#include "prprf.h"
#include "secerr.h"
typedef struct EncodedContext {
SECItem isCA;
SECItem pathLenConstraint;
SECItem encodedValue;
PLArenaPool *arena;
} EncodedContext;
static const SEC_ASN1Template CERTBasicConstraintsTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(EncodedContext) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
offsetof(EncodedContext, isCA) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
offsetof(EncodedContext, pathLenConstraint) },
{ 0 }
};
static unsigned char hexTrue = 0xff;
static unsigned char hexFalse = 0x00;
#define GEN_BREAK(status) \
rv = status; \
break;
SECStatus
CERT_EncodeBasicConstraintValue(PLArenaPool *arena, CERTBasicConstraints *value,
SECItem *encodedValue)
{
EncodedContext encodeContext;
PLArenaPool *our_pool = NULL;
SECStatus rv = SECSuccess;
do {
PORT_Memset(&encodeContext, 0, sizeof(encodeContext));
if (!value->isCA && value->pathLenConstraint >= 0) {
PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
GEN_BREAK(SECFailure);
}
encodeContext.arena = arena;
if (value->isCA == PR_TRUE) {
encodeContext.isCA.data = &hexTrue;
encodeContext.isCA.len = 1;
}
/* If the pathLenConstraint is less than 0, then it should be
* omitted from the encoding.
*/
if (value->isCA && value->pathLenConstraint >= 0) {
our_pool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
if (our_pool == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
GEN_BREAK(SECFailure);
}
if (SEC_ASN1EncodeUnsignedInteger(
our_pool, &encodeContext.pathLenConstraint,
(unsigned long)value->pathLenConstraint) == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
GEN_BREAK(SECFailure);
}
}
if (SEC_ASN1EncodeItem(arena, encodedValue, &encodeContext,
CERTBasicConstraintsTemplate) == NULL) {
GEN_BREAK(SECFailure);
}
} while (0);
if (our_pool)
PORT_FreeArena(our_pool, PR_FALSE);
return (rv);
}
SECStatus
CERT_DecodeBasicConstraintValue(CERTBasicConstraints *value,
const SECItem *encodedValue)
{
EncodedContext decodeContext;
PORTCheapArenaPool tmpArena;
SECStatus rv = SECSuccess;
do {
PORT_Memset(&decodeContext, 0, sizeof(decodeContext));
/* initialize the value just in case we got "0x30 00", or when the
pathLenConstraint is omitted.
*/
decodeContext.isCA.data = &hexFalse;
decodeContext.isCA.len = 1;
PORT_InitCheapArena(&tmpArena, SEC_ASN1_DEFAULT_ARENA_SIZE);
rv = SEC_QuickDERDecodeItem(&tmpArena.arena, &decodeContext,
CERTBasicConstraintsTemplate, encodedValue);
if (rv == SECFailure)
break;
value->isCA = decodeContext.isCA.data
? (PRBool)(decodeContext.isCA.data[0] != 0)
: PR_FALSE;
if (decodeContext.pathLenConstraint.data == NULL) {
/* if the pathLenConstraint is not encoded, and the current setting
is CA, then the pathLenConstraint should be set to a negative
number
for unlimited certificate path.
*/
if (value->isCA)
value->pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
} else if (value->isCA) {
long len = DER_GetInteger(&decodeContext.pathLenConstraint);
if (len < 0 || len == LONG_MAX) {
PORT_SetError(SEC_ERROR_BAD_DER);
GEN_BREAK(SECFailure);
}
value->pathLenConstraint = len;
} else {
/* here we get an error where the subject is not a CA, but
the pathLenConstraint is set */
PORT_SetError(SEC_ERROR_BAD_DER);
GEN_BREAK(SECFailure);
break;
}
} while (0);
PORT_DestroyCheapArena(&tmpArena);
return (rv);
}

View file

@ -0,0 +1,269 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* X.509 Extension Encoding
*/
#include "prtypes.h"
#include "seccomon.h"
#include "secdert.h"
#include "secoidt.h"
#include "secasn1t.h"
#include "secasn1.h"
#include "cert.h"
#include "secder.h"
#include "prprf.h"
#include "xconst.h"
#include "genname.h"
#include "secasn1.h"
#include "secerr.h"
static const SEC_ASN1Template CERTSubjectKeyIDTemplate[] = {
{ SEC_ASN1_OCTET_STRING }
};
static const SEC_ASN1Template CERTIA5TypeTemplate[] = {
{ SEC_ASN1_IA5_STRING }
};
SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate)
static const SEC_ASN1Template CERTPrivateKeyUsagePeriodTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPrivKeyUsagePeriod) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
offsetof(CERTPrivKeyUsagePeriod, notBefore),
SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
offsetof(CERTPrivKeyUsagePeriod, notAfter),
SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
{ 0 }
};
const SEC_ASN1Template CERTAltNameTemplate[] = {
{ SEC_ASN1_CONSTRUCTED, offsetof(CERTAltNameEncodedContext, encodedGenName),
CERT_GeneralNamesTemplate }
};
const SEC_ASN1Template CERTAuthInfoAccessItemTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAuthInfoAccess) },
{ SEC_ASN1_OBJECT_ID, offsetof(CERTAuthInfoAccess, method) },
{ SEC_ASN1_ANY, offsetof(CERTAuthInfoAccess, derLocation) },
{ 0 }
};
const SEC_ASN1Template CERTAuthInfoAccessTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, 0, CERTAuthInfoAccessItemTemplate }
};
SECStatus
CERT_EncodeSubjectKeyID(PLArenaPool *arena, const SECItem *srcString,
SECItem *encodedValue)
{
SECStatus rv = SECSuccess;
if (!srcString) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (SEC_ASN1EncodeItem(arena, encodedValue, srcString,
CERTSubjectKeyIDTemplate) == NULL) {
rv = SECFailure;
}
return (rv);
}
SECStatus
CERT_EncodePrivateKeyUsagePeriod(PLArenaPool *arena,
CERTPrivKeyUsagePeriod *pkup,
SECItem *encodedValue)
{
SECStatus rv = SECSuccess;
if (SEC_ASN1EncodeItem(arena, encodedValue, pkup,
CERTPrivateKeyUsagePeriodTemplate) == NULL) {
rv = SECFailure;
}
return (rv);
}
CERTPrivKeyUsagePeriod *
CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue)
{
SECStatus rv;
CERTPrivKeyUsagePeriod *pPeriod;
SECItem newExtnValue;
/* allocate the certificate policies structure */
pPeriod = PORT_ArenaZNew(arena, CERTPrivKeyUsagePeriod);
if (pPeriod == NULL) {
goto loser;
}
pPeriod->arena = arena;
/* copy the DER into the arena, since Quick DER returns data that points
into the DER input, which may get freed by the caller */
rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
if (rv != SECSuccess) {
goto loser;
}
rv = SEC_QuickDERDecodeItem(
arena, pPeriod, CERTPrivateKeyUsagePeriodTemplate, &newExtnValue);
if (rv != SECSuccess) {
goto loser;
}
return pPeriod;
loser:
return NULL;
}
SECStatus
CERT_EncodeIA5TypeExtension(PLArenaPool *arena, char *value,
SECItem *encodedValue)
{
SECItem encodeContext;
SECStatus rv = SECSuccess;
PORT_Memset(&encodeContext, 0, sizeof(encodeContext));
if (value != NULL) {
encodeContext.data = (unsigned char *)value;
encodeContext.len = strlen(value);
}
if (SEC_ASN1EncodeItem(arena, encodedValue, &encodeContext,
CERTIA5TypeTemplate) == NULL) {
rv = SECFailure;
}
return (rv);
}
SECStatus
CERT_EncodeAltNameExtension(PLArenaPool *arena, CERTGeneralName *value,
SECItem *encodedValue)
{
SECItem **encodedGenName;
SECStatus rv = SECSuccess;
encodedGenName = cert_EncodeGeneralNames(arena, value);
if (SEC_ASN1EncodeItem(arena, encodedValue, &encodedGenName,
CERT_GeneralNamesTemplate) == NULL) {
rv = SECFailure;
}
return rv;
}
CERTGeneralName *
CERT_DecodeAltNameExtension(PLArenaPool *reqArena, SECItem *EncodedAltName)
{
SECStatus rv = SECSuccess;
CERTAltNameEncodedContext encodedContext;
SECItem *newEncodedAltName;
if (!reqArena) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
newEncodedAltName = SECITEM_ArenaDupItem(reqArena, EncodedAltName);
if (!newEncodedAltName) {
return NULL;
}
encodedContext.encodedGenName = NULL;
PORT_Memset(&encodedContext, 0, sizeof(CERTAltNameEncodedContext));
rv = SEC_QuickDERDecodeItem(reqArena, &encodedContext,
CERT_GeneralNamesTemplate, newEncodedAltName);
if (rv == SECFailure) {
goto loser;
}
if (encodedContext.encodedGenName && encodedContext.encodedGenName[0])
return cert_DecodeGeneralNames(reqArena, encodedContext.encodedGenName);
/* Extension contained an empty GeneralNames sequence */
/* Treat as extension not found */
PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
loser:
return NULL;
}
SECStatus
CERT_EncodeNameConstraintsExtension(PLArenaPool *arena,
CERTNameConstraints *value,
SECItem *encodedValue)
{
SECStatus rv = SECSuccess;
rv = cert_EncodeNameConstraints(value, arena, encodedValue);
return rv;
}
CERTNameConstraints *
CERT_DecodeNameConstraintsExtension(PLArenaPool *arena,
const SECItem *encodedConstraints)
{
return cert_DecodeNameConstraints(arena, encodedConstraints);
}
CERTAuthInfoAccess **
CERT_DecodeAuthInfoAccessExtension(PLArenaPool *reqArena,
const SECItem *encodedExtension)
{
CERTAuthInfoAccess **info = NULL;
SECStatus rv;
int i;
SECItem *newEncodedExtension;
if (!reqArena) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
newEncodedExtension = SECITEM_ArenaDupItem(reqArena, encodedExtension);
if (!newEncodedExtension) {
return NULL;
}
rv = SEC_QuickDERDecodeItem(reqArena, &info, CERTAuthInfoAccessTemplate,
newEncodedExtension);
if (rv != SECSuccess || info == NULL) {
return NULL;
}
for (i = 0; info[i] != NULL; i++) {
info[i]->location =
CERT_DecodeGeneralName(reqArena, &(info[i]->derLocation), NULL);
}
return info;
}
SECStatus
CERT_EncodeInfoAccessExtension(PLArenaPool *arena, CERTAuthInfoAccess **info,
SECItem *dest)
{
SECItem *dummy;
int i;
PORT_Assert(info != NULL);
PORT_Assert(dest != NULL);
if (info == NULL || dest == NULL) {
return SECFailure;
}
for (i = 0; info[i] != NULL; i++) {
if (CERT_EncodeGeneralName(info[i]->location, &(info[i]->derLocation),
arena) == NULL)
/* Note that this may leave some of the locations filled in. */
return SECFailure;
}
dummy = SEC_ASN1EncodeItem(arena, dest, &info, CERTAuthInfoAccessTemplate);
if (dummy == NULL) {
return SECFailure;
}
return SECSuccess;
}

View file

@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _XCONST_H_
#define _XCONST_H_
#include "certt.h"
typedef struct CERTAltNameEncodedContextStr {
SECItem **encodedGenName;
} CERTAltNameEncodedContext;
SEC_BEGIN_PROTOS
extern SECStatus CERT_EncodePrivateKeyUsagePeriod(PLArenaPool *arena,
CERTPrivKeyUsagePeriod *pkup,
SECItem *encodedValue);
extern SECStatus CERT_EncodeNameConstraintsExtension(PLArenaPool *arena,
CERTNameConstraints *value,
SECItem *encodedValue);
extern SECStatus CERT_EncodeIA5TypeExtension(PLArenaPool *arena, char *value,
SECItem *encodedValue);
SECStatus cert_EncodeAuthInfoAccessExtension(PLArenaPool *arena,
CERTAuthInfoAccess **info,
SECItem *dest);
SEC_END_PROTOS
#endif