mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 03:30:17 +01:00
44b7f056d9
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
1172 lines
28 KiB
C
1172 lines
28 KiB
C
/* 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 NSSPKI_H
|
|
#include "nsspki.h"
|
|
#endif /* NSSPKI_H */
|
|
|
|
#ifndef PKIT_H
|
|
#include "pkit.h"
|
|
#endif /* PKIT_H */
|
|
|
|
#ifndef PKIM_H
|
|
#include "pkim.h"
|
|
#endif /* PKIM_H */
|
|
|
|
#ifndef DEV_H
|
|
#include "dev.h"
|
|
#endif /* DEV_H */
|
|
|
|
#include "pkistore.h"
|
|
|
|
#include "pki3hack.h"
|
|
#include "pk11func.h"
|
|
#include "hasht.h"
|
|
|
|
#ifndef BASE_H
|
|
#include "base.h"
|
|
#endif /* BASE_H */
|
|
|
|
extern const NSSError NSS_ERROR_NOT_FOUND;
|
|
|
|
/* Creates a certificate from a base object */
|
|
NSS_IMPLEMENT NSSCertificate *
|
|
nssCertificate_Create (
|
|
nssPKIObject *object
|
|
)
|
|
{
|
|
PRStatus status;
|
|
NSSCertificate *rvCert;
|
|
nssArenaMark * mark;
|
|
NSSArena *arena = object->arena;
|
|
PR_ASSERT(object->instances != NULL && object->numInstances > 0);
|
|
PR_ASSERT(object->lockType == nssPKIMonitor);
|
|
mark = nssArena_Mark(arena);
|
|
rvCert = nss_ZNEW(arena, NSSCertificate);
|
|
if (!rvCert) {
|
|
return (NSSCertificate *)NULL;
|
|
}
|
|
rvCert->object = *object;
|
|
/* XXX should choose instance based on some criteria */
|
|
status = nssCryptokiCertificate_GetAttributes(object->instances[0],
|
|
NULL, /* XXX sessionOpt */
|
|
arena,
|
|
&rvCert->type,
|
|
&rvCert->id,
|
|
&rvCert->encoding,
|
|
&rvCert->issuer,
|
|
&rvCert->serial,
|
|
&rvCert->subject);
|
|
if (status != PR_SUCCESS ||
|
|
!rvCert->encoding.data ||
|
|
!rvCert->encoding.size ||
|
|
!rvCert->issuer.data ||
|
|
!rvCert->issuer.size ||
|
|
!rvCert->serial.data ||
|
|
!rvCert->serial.size) {
|
|
if (mark)
|
|
nssArena_Release(arena, mark);
|
|
return (NSSCertificate *)NULL;
|
|
}
|
|
if (mark)
|
|
nssArena_Unmark(arena, mark);
|
|
return rvCert;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSCertificate *
|
|
nssCertificate_AddRef (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
if (c) {
|
|
nssPKIObject_AddRef(&c->object);
|
|
}
|
|
return c;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssCertificate_Destroy (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
|
|
nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE};
|
|
|
|
if (c) {
|
|
PRUint32 i;
|
|
nssDecodedCert *dc = c->decoding;
|
|
NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
|
|
NSSCryptoContext *cc = c->object.cryptoContext;
|
|
|
|
PR_ASSERT(c->object.refCount > 0);
|
|
|
|
/* --- LOCK storage --- */
|
|
if (cc) {
|
|
nssCertificateStore_Lock(cc->certStore, &lockTrace);
|
|
} else {
|
|
nssTrustDomain_LockCertCache(td);
|
|
}
|
|
if (PR_ATOMIC_DECREMENT(&c->object.refCount) == 0) {
|
|
/* --- remove cert and UNLOCK storage --- */
|
|
if (cc) {
|
|
nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
|
|
nssCertificateStore_Unlock(cc->certStore, &lockTrace,
|
|
&unlockTrace);
|
|
} else {
|
|
nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
|
|
nssTrustDomain_UnlockCertCache(td);
|
|
}
|
|
/* free cert data */
|
|
for (i=0; i<c->object.numInstances; i++) {
|
|
nssCryptokiObject_Destroy(c->object.instances[i]);
|
|
}
|
|
nssPKIObject_DestroyLock(&c->object);
|
|
nssArena_Destroy(c->object.arena);
|
|
nssDecodedCert_Destroy(dc);
|
|
} else {
|
|
/* --- UNLOCK storage --- */
|
|
if (cc) {
|
|
nssCertificateStore_Unlock(cc->certStore,
|
|
&lockTrace,
|
|
&unlockTrace);
|
|
} else {
|
|
nssTrustDomain_UnlockCertCache(td);
|
|
}
|
|
}
|
|
}
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
NSSCertificate_Destroy (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
return nssCertificate_Destroy(c);
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSDER *
|
|
nssCertificate_GetEncoding (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
if (c->encoding.size > 0 && c->encoding.data) {
|
|
return &c->encoding;
|
|
} else {
|
|
return (NSSDER *)NULL;
|
|
}
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSDER *
|
|
nssCertificate_GetIssuer (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
if (c->issuer.size > 0 && c->issuer.data) {
|
|
return &c->issuer;
|
|
} else {
|
|
return (NSSDER *)NULL;
|
|
}
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSDER *
|
|
nssCertificate_GetSerialNumber (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
if (c->serial.size > 0 && c->serial.data) {
|
|
return &c->serial;
|
|
} else {
|
|
return (NSSDER *)NULL;
|
|
}
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSDER *
|
|
nssCertificate_GetSubject (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
if (c->subject.size > 0 && c->subject.data) {
|
|
return &c->subject;
|
|
} else {
|
|
return (NSSDER *)NULL;
|
|
}
|
|
}
|
|
|
|
/* Returns a copy, Caller must free using nss_ZFreeIf */
|
|
NSS_IMPLEMENT NSSUTF8 *
|
|
nssCertificate_GetNickname (
|
|
NSSCertificate *c,
|
|
NSSToken *tokenOpt
|
|
)
|
|
{
|
|
return nssPKIObject_GetNicknameForToken(&c->object, tokenOpt);
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSASCII7 *
|
|
nssCertificate_GetEmailAddress (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
return c->email;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
NSSCertificate_DeleteStoredObject (
|
|
NSSCertificate *c,
|
|
NSSCallback *uhh
|
|
)
|
|
{
|
|
return nssPKIObject_DeleteStoredObject(&c->object, uhh, PR_TRUE);
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
NSSCertificate_Validate (
|
|
NSSCertificate *c,
|
|
NSSTime *timeOpt, /* NULL for "now" */
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt /* NULL for none */
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT void ** /* void *[] */
|
|
NSSCertificate_ValidateCompletely (
|
|
NSSCertificate *c,
|
|
NSSTime *timeOpt, /* NULL for "now" */
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt, /* NULL for none */
|
|
void **rvOpt, /* NULL for allocate */
|
|
PRUint32 rvLimit, /* zero for no limit */
|
|
NSSArena *arenaOpt /* NULL for heap */
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
NSSCertificate_ValidateAndDiscoverUsagesAndPolicies (
|
|
NSSCertificate *c,
|
|
NSSTime **notBeforeOutOpt,
|
|
NSSTime **notAfterOutOpt,
|
|
void *allowedUsages,
|
|
void *disallowedUsages,
|
|
void *allowedPolicies,
|
|
void *disallowedPolicies,
|
|
/* more args.. work on this fgmr */
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSDER *
|
|
NSSCertificate_Encode (
|
|
NSSCertificate *c,
|
|
NSSDER *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
/* Item, DER, BER are all typedefs now... */
|
|
return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt);
|
|
}
|
|
|
|
NSS_IMPLEMENT nssDecodedCert *
|
|
nssCertificate_GetDecoding (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
nssDecodedCert* deco = NULL;
|
|
if (c->type == NSSCertificateType_PKIX) {
|
|
(void)STAN_GetCERTCertificate(c);
|
|
}
|
|
nssPKIObject_Lock(&c->object);
|
|
if (!c->decoding) {
|
|
deco = nssDecodedCert_Create(NULL, &c->encoding, c->type);
|
|
PORT_Assert(!c->decoding);
|
|
c->decoding = deco;
|
|
} else {
|
|
deco = c->decoding;
|
|
}
|
|
nssPKIObject_Unlock(&c->object);
|
|
return deco;
|
|
}
|
|
|
|
static NSSCertificate **
|
|
filter_subject_certs_for_id (
|
|
NSSCertificate **subjectCerts,
|
|
void *id
|
|
)
|
|
{
|
|
NSSCertificate **si;
|
|
nssDecodedCert *dcp;
|
|
int nextOpenSlot = 0;
|
|
int i;
|
|
nssCertIDMatch matchLevel = nssCertIDMatch_Unknown;
|
|
nssCertIDMatch match;
|
|
|
|
/* walk the subject certs */
|
|
for (si = subjectCerts; *si; si++) {
|
|
dcp = nssCertificate_GetDecoding(*si);
|
|
if (!dcp) {
|
|
NSSCertificate_Destroy(*si);
|
|
continue;
|
|
}
|
|
match = dcp->matchIdentifier(dcp, id);
|
|
switch (match) {
|
|
case nssCertIDMatch_Yes:
|
|
if (matchLevel == nssCertIDMatch_Unknown) {
|
|
/* we have non-definitive matches, forget them */
|
|
for (i = 0; i < nextOpenSlot; i++) {
|
|
NSSCertificate_Destroy(subjectCerts[i]);
|
|
subjectCerts[i] = NULL;
|
|
}
|
|
nextOpenSlot = 0;
|
|
/* only keep definitive matches from now on */
|
|
matchLevel = nssCertIDMatch_Yes;
|
|
}
|
|
/* keep the cert */
|
|
subjectCerts[nextOpenSlot++] = *si;
|
|
break;
|
|
case nssCertIDMatch_Unknown:
|
|
if (matchLevel == nssCertIDMatch_Unknown) {
|
|
/* only have non-definitive matches so far, keep it */
|
|
subjectCerts[nextOpenSlot++] = *si;
|
|
break;
|
|
}
|
|
/* else fall through, we have a definitive match already */
|
|
case nssCertIDMatch_No:
|
|
default:
|
|
NSSCertificate_Destroy(*si);
|
|
*si = NULL;
|
|
}
|
|
}
|
|
subjectCerts[nextOpenSlot] = NULL;
|
|
return subjectCerts;
|
|
}
|
|
|
|
static NSSCertificate **
|
|
filter_certs_for_valid_issuers (
|
|
NSSCertificate **certs
|
|
)
|
|
{
|
|
NSSCertificate **cp;
|
|
nssDecodedCert *dcp;
|
|
int nextOpenSlot = 0;
|
|
|
|
for (cp = certs; *cp; cp++) {
|
|
dcp = nssCertificate_GetDecoding(*cp);
|
|
if (dcp && dcp->isValidIssuer(dcp)) {
|
|
certs[nextOpenSlot++] = *cp;
|
|
} else {
|
|
NSSCertificate_Destroy(*cp);
|
|
}
|
|
}
|
|
certs[nextOpenSlot] = NULL;
|
|
return certs;
|
|
}
|
|
|
|
static NSSCertificate *
|
|
find_cert_issuer (
|
|
NSSCertificate *c,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSTrustDomain *td,
|
|
NSSCryptoContext *cc
|
|
)
|
|
{
|
|
NSSArena *arena;
|
|
NSSCertificate **certs = NULL;
|
|
NSSCertificate **ccIssuers = NULL;
|
|
NSSCertificate **tdIssuers = NULL;
|
|
NSSCertificate *issuer = NULL;
|
|
|
|
if (!cc)
|
|
cc = c->object.cryptoContext;
|
|
if (!td)
|
|
td = NSSCertificate_GetTrustDomain(c);
|
|
arena = nssArena_Create();
|
|
if (!arena) {
|
|
return (NSSCertificate *)NULL;
|
|
}
|
|
if (cc) {
|
|
ccIssuers = nssCryptoContext_FindCertificatesBySubject(cc,
|
|
&c->issuer,
|
|
NULL,
|
|
0,
|
|
arena);
|
|
}
|
|
if (td)
|
|
tdIssuers = nssTrustDomain_FindCertificatesBySubject(td,
|
|
&c->issuer,
|
|
NULL,
|
|
0,
|
|
arena);
|
|
certs = nssCertificateArray_Join(ccIssuers, tdIssuers);
|
|
if (certs) {
|
|
nssDecodedCert *dc = NULL;
|
|
void *issuerID = NULL;
|
|
dc = nssCertificate_GetDecoding(c);
|
|
if (dc) {
|
|
issuerID = dc->getIssuerIdentifier(dc);
|
|
}
|
|
/* XXX review based on CERT_FindCertIssuer
|
|
* this function is not using the authCertIssuer field as a fallback
|
|
* if authority key id does not exist
|
|
*/
|
|
if (issuerID) {
|
|
certs = filter_subject_certs_for_id(certs, issuerID);
|
|
}
|
|
certs = filter_certs_for_valid_issuers(certs);
|
|
issuer = nssCertificateArray_FindBestCertificate(certs,
|
|
timeOpt,
|
|
usage,
|
|
policiesOpt);
|
|
nssCertificateArray_Destroy(certs);
|
|
}
|
|
nssArena_Destroy(arena);
|
|
return issuer;
|
|
}
|
|
|
|
/* This function returns the built chain, as far as it gets,
|
|
** even if/when it fails to find an issuer, and returns PR_FAILURE
|
|
*/
|
|
NSS_IMPLEMENT NSSCertificate **
|
|
nssCertificate_BuildChain (
|
|
NSSCertificate *c,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCertificate **rvOpt,
|
|
PRUint32 rvLimit,
|
|
NSSArena *arenaOpt,
|
|
PRStatus *statusOpt,
|
|
NSSTrustDomain *td,
|
|
NSSCryptoContext *cc
|
|
)
|
|
{
|
|
NSSCertificate **rvChain = NULL;
|
|
NSSUsage issuerUsage = *usage;
|
|
nssPKIObjectCollection *collection = NULL;
|
|
PRUint32 rvCount = 0;
|
|
PRStatus st;
|
|
PRStatus ret = PR_SUCCESS;
|
|
|
|
if (!c || !cc ||
|
|
(!td && (td = NSSCertificate_GetTrustDomain(c)) == NULL)) {
|
|
goto loser;
|
|
}
|
|
/* bump the usage up to CA level */
|
|
issuerUsage.nss3lookingForCA = PR_TRUE;
|
|
collection = nssCertificateCollection_Create(td, NULL);
|
|
if (!collection)
|
|
goto loser;
|
|
st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
|
|
if (st != PR_SUCCESS)
|
|
goto loser;
|
|
for (rvCount = 1; (!rvLimit || rvCount < rvLimit); ++rvCount) {
|
|
CERTCertificate *cCert = STAN_GetCERTCertificate(c);
|
|
if (cCert->isRoot) {
|
|
/* not including the issuer of the self-signed cert, which is,
|
|
* of course, itself
|
|
*/
|
|
break;
|
|
}
|
|
c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt, td, cc);
|
|
if (!c) {
|
|
ret = PR_FAILURE;
|
|
break;
|
|
}
|
|
st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
|
|
nssCertificate_Destroy(c); /* collection has it */
|
|
if (st != PR_SUCCESS)
|
|
goto loser;
|
|
}
|
|
rvChain = nssPKIObjectCollection_GetCertificates(collection,
|
|
rvOpt,
|
|
rvLimit,
|
|
arenaOpt);
|
|
if (rvChain) {
|
|
nssPKIObjectCollection_Destroy(collection);
|
|
if (statusOpt)
|
|
*statusOpt = ret;
|
|
if (ret != PR_SUCCESS)
|
|
nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
|
|
return rvChain;
|
|
}
|
|
|
|
loser:
|
|
if (collection)
|
|
nssPKIObjectCollection_Destroy(collection);
|
|
if (statusOpt)
|
|
*statusOpt = PR_FAILURE;
|
|
nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
|
|
return rvChain;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSCertificate **
|
|
NSSCertificate_BuildChain (
|
|
NSSCertificate *c,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCertificate **rvOpt,
|
|
PRUint32 rvLimit, /* zero for no limit */
|
|
NSSArena *arenaOpt,
|
|
PRStatus *statusOpt,
|
|
NSSTrustDomain *td,
|
|
NSSCryptoContext *cc
|
|
)
|
|
{
|
|
return nssCertificate_BuildChain(c, timeOpt, usage, policiesOpt,
|
|
rvOpt, rvLimit, arenaOpt, statusOpt,
|
|
td, cc);
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSCryptoContext *
|
|
nssCertificate_GetCryptoContext (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
return c->object.cryptoContext;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSTrustDomain *
|
|
nssCertificate_GetTrustDomain (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
return c->object.trustDomain;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSTrustDomain *
|
|
NSSCertificate_GetTrustDomain (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
return nssCertificate_GetTrustDomain(c);
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSToken *
|
|
NSSCertificate_GetToken (
|
|
NSSCertificate *c,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
return (NSSToken *)NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSSlot *
|
|
NSSCertificate_GetSlot (
|
|
NSSCertificate *c,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
return (NSSSlot *)NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSModule *
|
|
NSSCertificate_GetModule (
|
|
NSSCertificate *c,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
return (NSSModule *)NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
NSSCertificate_Encrypt (
|
|
NSSCertificate *c,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSItem *data,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
NSSCertificate_Verify (
|
|
NSSCertificate *c,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSItem *data,
|
|
NSSItem *signature,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return PR_FAILURE;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
NSSCertificate_VerifyRecover (
|
|
NSSCertificate *c,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSItem *signature,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
NSSCertificate_WrapSymmetricKey (
|
|
NSSCertificate *c,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSSymmetricKey *keyToWrap,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSCryptoContext *
|
|
NSSCertificate_CreateCryptoContext (
|
|
NSSCertificate *c,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSPublicKey *
|
|
NSSCertificate_GetPublicKey (
|
|
NSSCertificate *c
|
|
)
|
|
{
|
|
#if 0
|
|
CK_ATTRIBUTE pubktemplate[] = {
|
|
{ CKA_CLASS, NULL, 0 },
|
|
{ CKA_ID, NULL, 0 },
|
|
{ CKA_SUBJECT, NULL, 0 }
|
|
};
|
|
PRStatus nssrv;
|
|
CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]);
|
|
NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey);
|
|
if (c->id.size > 0) {
|
|
/* CKA_ID */
|
|
NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]);
|
|
} else {
|
|
/* failure, yes? */
|
|
return (NSSPublicKey *)NULL;
|
|
}
|
|
if (c->subject.size > 0) {
|
|
/* CKA_SUBJECT */
|
|
NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]);
|
|
} else {
|
|
/* failure, yes? */
|
|
return (NSSPublicKey *)NULL;
|
|
}
|
|
/* Try the cert's token first */
|
|
if (c->token) {
|
|
nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count);
|
|
}
|
|
#endif
|
|
/* Try all other key tokens */
|
|
return (NSSPublicKey *)NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSPrivateKey *
|
|
NSSCertificate_FindPrivateKey (
|
|
NSSCertificate *c,
|
|
NSSCallback *uhh
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
NSSCertificate_IsPrivateKeyAvailable (
|
|
NSSCertificate *c,
|
|
NSSCallback *uhh,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
PRBool isUser = PR_FALSE;
|
|
nssCryptokiObject **ip;
|
|
nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
|
|
if (!instances) {
|
|
return PR_FALSE;
|
|
}
|
|
for (ip = instances; *ip; ip++) {
|
|
nssCryptokiObject *instance = *ip;
|
|
if (nssToken_IsPrivateKeyAvailable(instance->token, c, instance)) {
|
|
isUser = PR_TRUE;
|
|
}
|
|
}
|
|
nssCryptokiObjectArray_Destroy(instances);
|
|
return isUser;
|
|
}
|
|
|
|
/* sort the subject cert list from newest to oldest */
|
|
PRIntn
|
|
nssCertificate_SubjectListSort (
|
|
void *v1,
|
|
void *v2
|
|
)
|
|
{
|
|
NSSCertificate *c1 = (NSSCertificate *)v1;
|
|
NSSCertificate *c2 = (NSSCertificate *)v2;
|
|
nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1);
|
|
nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2);
|
|
if (!dc1) {
|
|
return dc2 ? 1 : 0;
|
|
} else if (!dc2) {
|
|
return -1;
|
|
} else {
|
|
return dc1->isNewerThan(dc1, dc2) ? -1 : 1;
|
|
}
|
|
}
|
|
|
|
NSS_IMPLEMENT PRBool
|
|
NSSUserCertificate_IsStillPresent (
|
|
NSSUserCertificate *uc,
|
|
PRStatus *statusOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return PR_FALSE;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
NSSUserCertificate_Decrypt (
|
|
NSSUserCertificate *uc,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSItem *data,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
NSSUserCertificate_Sign (
|
|
NSSUserCertificate *uc,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSItem *data,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSItem *
|
|
NSSUserCertificate_SignRecover (
|
|
NSSUserCertificate *uc,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSItem *data,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSSymmetricKey *
|
|
NSSUserCertificate_UnwrapSymmetricKey (
|
|
NSSUserCertificate *uc,
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSItem *wrappedKey,
|
|
NSSTime *timeOpt,
|
|
NSSUsage *usage,
|
|
NSSPolicies *policiesOpt,
|
|
NSSCallback *uhh,
|
|
NSSItem *rvOpt,
|
|
NSSArena *arenaOpt
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSSymmetricKey *
|
|
NSSUserCertificate_DeriveSymmetricKey (
|
|
NSSUserCertificate *uc, /* provides private key */
|
|
NSSCertificate *c, /* provides public key */
|
|
NSSAlgorithmAndParameters *apOpt,
|
|
NSSOID *target,
|
|
PRUint32 keySizeOpt, /* zero for best allowed */
|
|
NSSOperations operations,
|
|
NSSCallback *uhh
|
|
)
|
|
{
|
|
nss_SetError(NSS_ERROR_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssSMIMEProfile *
|
|
nssSMIMEProfile_Create (
|
|
NSSCertificate *cert,
|
|
NSSItem *profileTime,
|
|
NSSItem *profileData
|
|
)
|
|
{
|
|
NSSArena *arena;
|
|
nssSMIMEProfile *rvProfile;
|
|
nssPKIObject *object;
|
|
NSSTrustDomain *td = nssCertificate_GetTrustDomain(cert);
|
|
NSSCryptoContext *cc = nssCertificate_GetCryptoContext(cert);
|
|
arena = nssArena_Create();
|
|
if (!arena) {
|
|
return NULL;
|
|
}
|
|
object = nssPKIObject_Create(arena, NULL, td, cc, nssPKILock);
|
|
if (!object) {
|
|
goto loser;
|
|
}
|
|
rvProfile = nss_ZNEW(arena, nssSMIMEProfile);
|
|
if (!rvProfile) {
|
|
goto loser;
|
|
}
|
|
rvProfile->object = *object;
|
|
rvProfile->certificate = cert;
|
|
rvProfile->email = nssUTF8_Duplicate(cert->email, arena);
|
|
rvProfile->subject = nssItem_Duplicate(&cert->subject, arena, NULL);
|
|
if (profileTime) {
|
|
rvProfile->profileTime = nssItem_Duplicate(profileTime, arena, NULL);
|
|
}
|
|
if (profileData) {
|
|
rvProfile->profileData = nssItem_Duplicate(profileData, arena, NULL);
|
|
}
|
|
return rvProfile;
|
|
loser:
|
|
if (object) nssPKIObject_Destroy(object);
|
|
else if (arena) nssArena_Destroy(arena);
|
|
return (nssSMIMEProfile *)NULL;
|
|
}
|
|
|
|
/* execute a callback function on all members of a cert list */
|
|
NSS_EXTERN PRStatus
|
|
nssCertificateList_DoCallback (
|
|
nssList *certList,
|
|
PRStatus (* callback)(NSSCertificate *c, void *arg),
|
|
void *arg
|
|
)
|
|
{
|
|
nssListIterator *certs;
|
|
NSSCertificate *cert;
|
|
certs = nssList_CreateIterator(certList);
|
|
if (!certs) {
|
|
return PR_FAILURE;
|
|
}
|
|
for (cert = (NSSCertificate *)nssListIterator_Start(certs);
|
|
cert != (NSSCertificate *)NULL;
|
|
cert = (NSSCertificate *)nssListIterator_Next(certs))
|
|
{
|
|
(void)(*callback)(cert, arg);
|
|
}
|
|
nssListIterator_Finish(certs);
|
|
nssListIterator_Destroy(certs);
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
static PRStatus add_ref_callback(NSSCertificate *c, void *a)
|
|
{
|
|
nssCertificate_AddRef(c);
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT void
|
|
nssCertificateList_AddReferences (
|
|
nssList *certList
|
|
)
|
|
{
|
|
(void)nssCertificateList_DoCallback(certList, add_ref_callback, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* Is this trust record safe to apply to all certs of the same issuer/SN
|
|
* independent of the cert matching the hash. This is only true is the trust
|
|
* is unknown or distrusted. In general this feature is only useful to
|
|
* explicitly distrusting certs. It is not safe to use to trust certs, so
|
|
* only allow unknown and untrusted trust types.
|
|
*/
|
|
PRBool
|
|
nssTrust_IsSafeToIgnoreCertHash(nssTrustLevel serverAuth,
|
|
nssTrustLevel clientAuth, nssTrustLevel codeSigning,
|
|
nssTrustLevel email, PRBool stepup)
|
|
{
|
|
/* step up is a trust type, if it's on, we must have a hash for the cert */
|
|
if (stepup) {
|
|
return PR_FALSE;
|
|
}
|
|
if ((serverAuth != nssTrustLevel_Unknown) &&
|
|
(serverAuth != nssTrustLevel_NotTrusted)) {
|
|
return PR_FALSE;
|
|
}
|
|
if ((clientAuth != nssTrustLevel_Unknown) &&
|
|
(clientAuth != nssTrustLevel_NotTrusted)) {
|
|
return PR_FALSE;
|
|
}
|
|
if ((codeSigning != nssTrustLevel_Unknown) &&
|
|
(codeSigning != nssTrustLevel_NotTrusted)) {
|
|
return PR_FALSE;
|
|
}
|
|
if ((email != nssTrustLevel_Unknown) &&
|
|
(email != nssTrustLevel_NotTrusted)) {
|
|
return PR_FALSE;
|
|
}
|
|
/* record only has Unknown and Untrusted entries, ok to accept without a
|
|
* hash */
|
|
return PR_TRUE;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSTrust *
|
|
nssTrust_Create (
|
|
nssPKIObject *object,
|
|
NSSItem *certData
|
|
)
|
|
{
|
|
PRStatus status;
|
|
PRUint32 i;
|
|
PRUint32 lastTrustOrder, myTrustOrder;
|
|
unsigned char sha1_hashcmp[SHA1_LENGTH];
|
|
unsigned char sha1_hashin[SHA1_LENGTH];
|
|
NSSItem sha1_hash;
|
|
NSSTrust *rvt;
|
|
nssCryptokiObject *instance;
|
|
nssTrustLevel serverAuth, clientAuth, codeSigning, emailProtection;
|
|
SECStatus rv; /* Should be stan flavor */
|
|
PRBool stepUp;
|
|
|
|
lastTrustOrder = 1<<16; /* just make it big */
|
|
PR_ASSERT(object->instances != NULL && object->numInstances > 0);
|
|
rvt = nss_ZNEW(object->arena, NSSTrust);
|
|
if (!rvt) {
|
|
return (NSSTrust *)NULL;
|
|
}
|
|
rvt->object = *object;
|
|
|
|
/* should be stan flavor of Hashbuf */
|
|
rv = PK11_HashBuf(SEC_OID_SHA1,sha1_hashcmp,certData->data,certData->size);
|
|
if (rv != SECSuccess) {
|
|
return (NSSTrust *)NULL;
|
|
}
|
|
sha1_hash.data = sha1_hashin;
|
|
sha1_hash.size = sizeof (sha1_hashin);
|
|
/* trust has to peek into the base object members */
|
|
nssPKIObject_Lock(object);
|
|
for (i=0; i<object->numInstances; i++) {
|
|
instance = object->instances[i];
|
|
myTrustOrder = nssToken_GetTrustOrder(instance->token);
|
|
status = nssCryptokiTrust_GetAttributes(instance, NULL,
|
|
&sha1_hash,
|
|
&serverAuth,
|
|
&clientAuth,
|
|
&codeSigning,
|
|
&emailProtection,
|
|
&stepUp);
|
|
if (status != PR_SUCCESS) {
|
|
nssPKIObject_Unlock(object);
|
|
return (NSSTrust *)NULL;
|
|
}
|
|
/* if no hash is specified, then trust applies to all certs with
|
|
* this issuer/SN. NOTE: This is only true for entries that
|
|
* have distrust and unknown record */
|
|
if (!(
|
|
/* we continue if there is no hash, and the trust type is
|
|
* safe to accept without a hash ... or ... */
|
|
((sha1_hash.size == 0) &&
|
|
nssTrust_IsSafeToIgnoreCertHash(serverAuth,clientAuth,
|
|
codeSigning, emailProtection,stepUp))
|
|
||
|
|
/* we have a hash of the correct size, and it matches */
|
|
((sha1_hash.size == SHA1_LENGTH) && (PORT_Memcmp(sha1_hashin,
|
|
sha1_hashcmp,SHA1_LENGTH) == 0)) )) {
|
|
nssPKIObject_Unlock(object);
|
|
return (NSSTrust *)NULL;
|
|
}
|
|
if (rvt->serverAuth == nssTrustLevel_Unknown ||
|
|
myTrustOrder < lastTrustOrder)
|
|
{
|
|
rvt->serverAuth = serverAuth;
|
|
}
|
|
if (rvt->clientAuth == nssTrustLevel_Unknown ||
|
|
myTrustOrder < lastTrustOrder)
|
|
{
|
|
rvt->clientAuth = clientAuth;
|
|
}
|
|
if (rvt->emailProtection == nssTrustLevel_Unknown ||
|
|
myTrustOrder < lastTrustOrder)
|
|
{
|
|
rvt->emailProtection = emailProtection;
|
|
}
|
|
if (rvt->codeSigning == nssTrustLevel_Unknown ||
|
|
myTrustOrder < lastTrustOrder)
|
|
{
|
|
rvt->codeSigning = codeSigning;
|
|
}
|
|
rvt->stepUpApproved = stepUp;
|
|
lastTrustOrder = myTrustOrder;
|
|
}
|
|
nssPKIObject_Unlock(object);
|
|
return rvt;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSTrust *
|
|
nssTrust_AddRef (
|
|
NSSTrust *trust
|
|
)
|
|
{
|
|
if (trust) {
|
|
nssPKIObject_AddRef(&trust->object);
|
|
}
|
|
return trust;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssTrust_Destroy (
|
|
NSSTrust *trust
|
|
)
|
|
{
|
|
if (trust) {
|
|
(void)nssPKIObject_Destroy(&trust->object);
|
|
}
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT nssSMIMEProfile *
|
|
nssSMIMEProfile_AddRef (
|
|
nssSMIMEProfile *profile
|
|
)
|
|
{
|
|
if (profile) {
|
|
nssPKIObject_AddRef(&profile->object);
|
|
}
|
|
return profile;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssSMIMEProfile_Destroy (
|
|
nssSMIMEProfile *profile
|
|
)
|
|
{
|
|
if (profile) {
|
|
(void)nssPKIObject_Destroy(&profile->object);
|
|
}
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSCRL *
|
|
nssCRL_Create (
|
|
nssPKIObject *object
|
|
)
|
|
{
|
|
PRStatus status;
|
|
NSSCRL *rvCRL;
|
|
NSSArena *arena = object->arena;
|
|
PR_ASSERT(object->instances != NULL && object->numInstances > 0);
|
|
rvCRL = nss_ZNEW(arena, NSSCRL);
|
|
if (!rvCRL) {
|
|
return (NSSCRL *)NULL;
|
|
}
|
|
rvCRL->object = *object;
|
|
/* XXX should choose instance based on some criteria */
|
|
status = nssCryptokiCRL_GetAttributes(object->instances[0],
|
|
NULL, /* XXX sessionOpt */
|
|
arena,
|
|
&rvCRL->encoding,
|
|
NULL, /* subject */
|
|
NULL, /* class */
|
|
&rvCRL->url,
|
|
&rvCRL->isKRL);
|
|
if (status != PR_SUCCESS) {
|
|
return (NSSCRL *)NULL;
|
|
}
|
|
return rvCRL;
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSCRL *
|
|
nssCRL_AddRef (
|
|
NSSCRL *crl
|
|
)
|
|
{
|
|
if (crl) {
|
|
nssPKIObject_AddRef(&crl->object);
|
|
}
|
|
return crl;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssCRL_Destroy (
|
|
NSSCRL *crl
|
|
)
|
|
{
|
|
if (crl) {
|
|
(void)nssPKIObject_Destroy(&crl->object);
|
|
}
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
NSS_IMPLEMENT PRStatus
|
|
nssCRL_DeleteStoredObject (
|
|
NSSCRL *crl,
|
|
NSSCallback *uhh
|
|
)
|
|
{
|
|
return nssPKIObject_DeleteStoredObject(&crl->object, uhh, PR_TRUE);
|
|
}
|
|
|
|
NSS_IMPLEMENT NSSDER *
|
|
nssCRL_GetEncoding (
|
|
NSSCRL *crl
|
|
)
|
|
{
|
|
if (crl && crl->encoding.data != NULL && crl->encoding.size > 0) {
|
|
return &crl->encoding;
|
|
} else {
|
|
return (NSSDER *)NULL;
|
|
}
|
|
}
|