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

View file

@ -0,0 +1,31 @@
# 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': 'certhi',
'type': 'static_library',
'sources': [
'certhigh.c',
'certhtml.c',
'certreq.c',
'certvfy.c',
'certvfypkix.c',
'crlv2.c',
'ocsp.c',
'ocspsig.c',
'xcrldist.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
]
}
],
'variables': {
'module': 'nss'
}
}

View file

@ -0,0 +1,300 @@
/* 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/. */
/*
* certhtml.c --- convert a cert to html
*/
#include "seccomon.h"
#include "secitem.h"
#include "sechash.h"
#include "cert.h"
#include "keyhi.h"
#include "secder.h"
#include "prprf.h"
#include "secport.h"
#include "secasn1.h"
#include "pk11func.h"
static char *hex = "0123456789ABCDEF";
/*
** Convert a der-encoded integer to a hex printable string form
*/
char *
CERT_Hexify(SECItem *i, int do_colon)
{
unsigned char *cp, *end;
char *rv, *o;
if (!i->len) {
return PORT_Strdup("00");
}
rv = o = (char *)PORT_Alloc(i->len * 3);
if (!rv)
return rv;
cp = i->data;
end = cp + i->len;
while (cp < end) {
unsigned char ch = *cp++;
*o++ = hex[(ch >> 4) & 0xf];
*o++ = hex[ch & 0xf];
if (cp != end) {
if (do_colon) {
*o++ = ':';
}
}
}
*o = 0; /* Null terminate the string */
return rv;
}
#define BREAK "<br>"
#define BREAKLEN 4
#define COMMA ", "
#define COMMALEN 2
#define MAX_OUS 20
#define MAX_DC MAX_OUS
char *
CERT_FormatName(CERTName *name)
{
CERTRDN **rdns;
CERTRDN *rdn;
CERTAVA **avas;
CERTAVA *ava;
char *buf = 0;
char *tmpbuf = 0;
SECItem *cn = 0;
SECItem *email = 0;
SECItem *org = 0;
SECItem *loc = 0;
SECItem *state = 0;
SECItem *country = 0;
SECItem *dq = 0;
unsigned len = 0;
int tag;
int i;
int ou_count = 0;
int dc_count = 0;
PRBool first;
SECItem *orgunit[MAX_OUS];
SECItem *dc[MAX_DC];
/* Loop over name components and gather the interesting ones */
rdns = name->rdns;
while ((rdn = *rdns++) != 0) {
avas = rdn->avas;
while ((ava = *avas++) != 0) {
tag = CERT_GetAVATag(ava);
switch (tag) {
case SEC_OID_AVA_COMMON_NAME:
if (cn) {
break;
}
cn = CERT_DecodeAVAValue(&ava->value);
if (!cn) {
goto loser;
}
len += cn->len;
break;
case SEC_OID_AVA_COUNTRY_NAME:
if (country) {
break;
}
country = CERT_DecodeAVAValue(&ava->value);
if (!country) {
goto loser;
}
len += country->len;
break;
case SEC_OID_AVA_LOCALITY:
if (loc) {
break;
}
loc = CERT_DecodeAVAValue(&ava->value);
if (!loc) {
goto loser;
}
len += loc->len;
break;
case SEC_OID_AVA_STATE_OR_PROVINCE:
if (state) {
break;
}
state = CERT_DecodeAVAValue(&ava->value);
if (!state) {
goto loser;
}
len += state->len;
break;
case SEC_OID_AVA_ORGANIZATION_NAME:
if (org) {
break;
}
org = CERT_DecodeAVAValue(&ava->value);
if (!org) {
goto loser;
}
len += org->len;
break;
case SEC_OID_AVA_DN_QUALIFIER:
if (dq) {
break;
}
dq = CERT_DecodeAVAValue(&ava->value);
if (!dq) {
goto loser;
}
len += dq->len;
break;
case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
if (ou_count < MAX_OUS) {
orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value);
if (!orgunit[ou_count]) {
goto loser;
}
len += orgunit[ou_count++]->len;
}
break;
case SEC_OID_AVA_DC:
if (dc_count < MAX_DC) {
dc[dc_count] = CERT_DecodeAVAValue(&ava->value);
if (!dc[dc_count]) {
goto loser;
}
len += dc[dc_count++]->len;
}
break;
case SEC_OID_PKCS9_EMAIL_ADDRESS:
case SEC_OID_RFC1274_MAIL:
if (email) {
break;
}
email = CERT_DecodeAVAValue(&ava->value);
if (!email) {
goto loser;
}
len += email->len;
break;
default:
break;
}
}
}
/* XXX - add some for formatting */
len += 128;
/* allocate buffer */
buf = (char *)PORT_Alloc(len);
if (!buf) {
goto loser;
}
tmpbuf = buf;
if (cn) {
PORT_Memcpy(tmpbuf, cn->data, cn->len);
tmpbuf += cn->len;
PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
tmpbuf += BREAKLEN;
}
if (email) {
PORT_Memcpy(tmpbuf, email->data, email->len);
tmpbuf += (email->len);
PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
tmpbuf += BREAKLEN;
}
for (i = ou_count - 1; i >= 0; i--) {
PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len);
tmpbuf += (orgunit[i]->len);
PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
tmpbuf += BREAKLEN;
}
if (dq) {
PORT_Memcpy(tmpbuf, dq->data, dq->len);
tmpbuf += (dq->len);
PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
tmpbuf += BREAKLEN;
}
if (org) {
PORT_Memcpy(tmpbuf, org->data, org->len);
tmpbuf += (org->len);
PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
tmpbuf += BREAKLEN;
}
for (i = dc_count - 1; i >= 0; i--) {
PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len);
tmpbuf += (dc[i]->len);
PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
tmpbuf += BREAKLEN;
}
first = PR_TRUE;
if (loc) {
PORT_Memcpy(tmpbuf, loc->data, loc->len);
tmpbuf += (loc->len);
first = PR_FALSE;
}
if (state) {
if (!first) {
PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
tmpbuf += COMMALEN;
}
PORT_Memcpy(tmpbuf, state->data, state->len);
tmpbuf += (state->len);
first = PR_FALSE;
}
if (country) {
if (!first) {
PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
tmpbuf += COMMALEN;
}
PORT_Memcpy(tmpbuf, country->data, country->len);
tmpbuf += (country->len);
first = PR_FALSE;
}
if (!first) {
PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
tmpbuf += BREAKLEN;
}
*tmpbuf = 0;
/* fall through and clean */
loser:
if (cn) {
SECITEM_FreeItem(cn, PR_TRUE);
}
if (email) {
SECITEM_FreeItem(email, PR_TRUE);
}
for (i = ou_count - 1; i >= 0; i--) {
SECITEM_FreeItem(orgunit[i], PR_TRUE);
}
if (dq) {
SECITEM_FreeItem(dq, PR_TRUE);
}
if (org) {
SECITEM_FreeItem(org, PR_TRUE);
}
for (i = dc_count - 1; i >= 0; i--) {
SECITEM_FreeItem(dc[i], PR_TRUE);
}
if (loc) {
SECITEM_FreeItem(loc, PR_TRUE);
}
if (state) {
SECITEM_FreeItem(state, PR_TRUE);
}
if (country) {
SECITEM_FreeItem(country, PR_TRUE);
}
return (buf);
}

View file

@ -0,0 +1,331 @@
/* 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 "certt.h"
#include "secder.h"
#include "key.h"
#include "secitem.h"
#include "secasn1.h"
#include "secerr.h"
SEC_ASN1_MKSUB(SEC_AnyTemplate)
const SEC_ASN1Template CERT_AttributeTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CERTAttribute) },
{ SEC_ASN1_OBJECT_ID, offsetof(CERTAttribute, attrType) },
{ SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(CERTAttribute, attrValue),
SEC_ASN1_SUB(SEC_AnyTemplate) },
{ 0 }
};
const SEC_ASN1Template CERT_SetOfAttributeTemplate[] = {
{ SEC_ASN1_SET_OF, 0, CERT_AttributeTemplate },
};
const SEC_ASN1Template CERT_CertificateRequestTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CERTCertificateRequest) },
{ SEC_ASN1_INTEGER,
offsetof(CERTCertificateRequest, version) },
{ SEC_ASN1_INLINE,
offsetof(CERTCertificateRequest, subject),
CERT_NameTemplate },
{ SEC_ASN1_INLINE,
offsetof(CERTCertificateRequest, subjectPublicKeyInfo),
CERT_SubjectPublicKeyInfoTemplate },
{ SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
offsetof(CERTCertificateRequest, attributes),
CERT_SetOfAttributeTemplate },
{ 0 }
};
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CertificateRequestTemplate)
CERTCertificate *
CERT_CreateCertificate(unsigned long serialNumber,
CERTName *issuer,
CERTValidity *validity,
CERTCertificateRequest *req)
{
CERTCertificate *c;
int rv;
PLArenaPool *arena;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
return (0);
}
c = (CERTCertificate *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificate));
if (!c) {
PORT_FreeArena(arena, PR_FALSE);
return 0;
}
c->referenceCount = 1;
c->arena = arena;
/*
* Default is a plain version 1.
* If extensions are added, it will get changed as appropriate.
*/
rv = DER_SetUInteger(arena, &c->version, SEC_CERTIFICATE_VERSION_1);
if (rv)
goto loser;
rv = DER_SetUInteger(arena, &c->serialNumber, serialNumber);
if (rv)
goto loser;
rv = CERT_CopyName(arena, &c->issuer, issuer);
if (rv)
goto loser;
rv = CERT_CopyValidity(arena, &c->validity, validity);
if (rv)
goto loser;
rv = CERT_CopyName(arena, &c->subject, &req->subject);
if (rv)
goto loser;
rv = SECKEY_CopySubjectPublicKeyInfo(arena, &c->subjectPublicKeyInfo,
&req->subjectPublicKeyInfo);
if (rv)
goto loser;
return c;
loser:
CERT_DestroyCertificate(c);
return 0;
}
/************************************************************************/
/* It's clear from the comments that the original author of this
* function expected the template for certificate requests to treat
* the attributes as a SET OF ANY. This function expected to be
* passed an array of SECItems each of which contained an already encoded
* Attribute. But the cert request template does not treat the
* Attributes as a SET OF ANY, and AFAIK never has. Instead the template
* encodes attributes as a SET OF xxxxxxx. That is, it expects to encode
* each of the Attributes, not have them pre-encoded. Consequently an
* array of SECItems containing encoded Attributes is of no value to this
* function. But we cannot change the signature of this public function.
* It must continue to take SECItems.
*
* I have recoded this function so that each SECItem contains an
* encoded cert extension. The encoded cert extensions form the list for the
* single attribute of the cert request. In this implementation there is at most
* one attribute and it is always of type SEC_OID_PKCS9_EXTENSION_REQUEST.
*/
CERTCertificateRequest *
CERT_CreateCertificateRequest(CERTName *subject,
CERTSubjectPublicKeyInfo *spki,
SECItem **attributes)
{
CERTCertificateRequest *certreq;
PLArenaPool *arena;
CERTAttribute *attribute;
SECOidData *oidData;
SECStatus rv;
int i = 0;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
return NULL;
}
certreq = PORT_ArenaZNew(arena, CERTCertificateRequest);
if (!certreq) {
PORT_FreeArena(arena, PR_FALSE);
return NULL;
}
/* below here it is safe to goto loser */
certreq->arena = arena;
rv = DER_SetUInteger(arena, &certreq->version,
SEC_CERTIFICATE_REQUEST_VERSION);
if (rv != SECSuccess)
goto loser;
rv = CERT_CopyName(arena, &certreq->subject, subject);
if (rv != SECSuccess)
goto loser;
rv = SECKEY_CopySubjectPublicKeyInfo(arena,
&certreq->subjectPublicKeyInfo,
spki);
if (rv != SECSuccess)
goto loser;
certreq->attributes = PORT_ArenaZNewArray(arena, CERTAttribute *, 2);
if (!certreq->attributes)
goto loser;
/* Copy over attribute information */
if (!attributes || !attributes[0]) {
/*
** Invent empty attribute information. According to the
** pkcs#10 spec, attributes has this ASN.1 type:
**
** attributes [0] IMPLICIT Attributes
**
** Which means, we should create a NULL terminated list
** with the first entry being NULL;
*/
certreq->attributes[0] = NULL;
return certreq;
}
/* allocate space for attributes */
attribute = PORT_ArenaZNew(arena, CERTAttribute);
if (!attribute)
goto loser;
oidData = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
PORT_Assert(oidData);
if (!oidData)
goto loser;
rv = SECITEM_CopyItem(arena, &attribute->attrType, &oidData->oid);
if (rv != SECSuccess)
goto loser;
for (i = 0; attributes[i] != NULL; i++)
;
attribute->attrValue = PORT_ArenaZNewArray(arena, SECItem *, i + 1);
if (!attribute->attrValue)
goto loser;
/* copy attributes */
for (i = 0; attributes[i]; i++) {
/*
** Attributes are a SetOf Attribute which implies
** lexigraphical ordering. It is assumes that the
** attributes are passed in sorted. If we need to
** add functionality to sort them, there is an
** example in the PKCS 7 code.
*/
attribute->attrValue[i] = SECITEM_ArenaDupItem(arena, attributes[i]);
if (!attribute->attrValue[i])
goto loser;
}
certreq->attributes[0] = attribute;
return certreq;
loser:
CERT_DestroyCertificateRequest(certreq);
return NULL;
}
void
CERT_DestroyCertificateRequest(CERTCertificateRequest *req)
{
if (req && req->arena) {
PORT_FreeArena(req->arena, PR_FALSE);
}
return;
}
static void
setCRExt(void *o, CERTCertExtension **exts)
{
((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts;
}
/*
** Set up to start gathering cert extensions for a cert request.
** The list is created as CertExtensions and converted to an
** attribute list by CERT_FinishCRAttributes().
*/
extern void *cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
void (*setExts)(void *object, CERTCertExtension **exts));
void *
CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req)
{
return (cert_StartExtensions((void *)req, req->arena, setCRExt));
}
/*
** At entry req->attributes actually contains an list of cert extensions--
** req-attributes is overloaded until the list is DER encoded (the first
** ...EncodeItem() below).
** We turn this into an attribute list by encapsulating it
** in a PKCS 10 Attribute structure
*/
SECStatus
CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req)
{
SECItem *extlist;
SECOidData *oidrec;
CERTAttribute *attribute;
if (!req || !req->arena) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (req->attributes == NULL || req->attributes[0] == NULL)
return SECSuccess;
extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes,
SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate));
if (extlist == NULL)
return (SECFailure);
oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST);
if (oidrec == NULL)
return SECFailure;
/* now change the list of cert extensions into a list of attributes
*/
req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute *, 2);
attribute = PORT_ArenaZNew(req->arena, CERTAttribute);
if (req->attributes == NULL || attribute == NULL ||
SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem *, 2);
if (attribute->attrValue == NULL)
return SECFailure;
attribute->attrValue[0] = extlist;
attribute->attrValue[1] = NULL;
req->attributes[0] = attribute;
req->attributes[1] = NULL;
return SECSuccess;
}
SECStatus
CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req,
CERTCertExtension ***exts)
{
if (req == NULL || exts == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (req->attributes == NULL || *req->attributes == NULL)
return SECSuccess;
if ((*req->attributes)->attrValue == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
return (SEC_ASN1DecodeItem(req->arena, exts,
SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate),
(*req->attributes)->attrValue[0]));
}

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,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 =

View file

@ -0,0 +1,160 @@
/* 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 x.509 v3 crl and crl entries extensions.
*/
#include "cert.h"
#include "secitem.h"
#include "secoid.h"
#include "secoidt.h"
#include "secder.h"
#include "secasn1.h"
#include "certxutl.h"
SECStatus
CERT_FindCRLExtensionByOID(CERTCrl *crl, SECItem *oid, SECItem *value)
{
return (cert_FindExtensionByOID(crl->extensions, oid, value));
}
SECStatus
CERT_FindCRLExtension(CERTCrl *crl, int tag, SECItem *value)
{
return (cert_FindExtension(crl->extensions, tag, value));
}
/* Callback to set extensions and adjust verison */
static void
SetCrlExts(void *object, CERTCertExtension **exts)
{
CERTCrl *crl = (CERTCrl *)object;
crl->extensions = exts;
DER_SetUInteger(crl->arena, &crl->version, SEC_CRL_VERSION_2);
}
void *
CERT_StartCRLExtensions(CERTCrl *crl)
{
return (cert_StartExtensions((void *)crl, crl->arena, SetCrlExts));
}
static void
SetCrlEntryExts(void *object, CERTCertExtension **exts)
{
CERTCrlEntry *crlEntry = (CERTCrlEntry *)object;
crlEntry->extensions = exts;
}
void *
CERT_StartCRLEntryExtensions(CERTCrl *crl, CERTCrlEntry *entry)
{
return (cert_StartExtensions(entry, crl->arena, SetCrlEntryExts));
}
SECStatus
CERT_FindCRLNumberExten(PLArenaPool *arena, CERTCrl *crl,
SECItem *value)
{
SECItem encodedExtenValue;
SECItem *tmpItem = NULL;
SECStatus rv;
void *mark = NULL;
encodedExtenValue.data = NULL;
encodedExtenValue.len = 0;
rv = cert_FindExtension(crl->extensions, SEC_OID_X509_CRL_NUMBER,
&encodedExtenValue);
if (rv != SECSuccess)
return (rv);
mark = PORT_ArenaMark(arena);
tmpItem = SECITEM_ArenaDupItem(arena, &encodedExtenValue);
if (tmpItem) {
rv = SEC_QuickDERDecodeItem(arena, value,
SEC_ASN1_GET(SEC_IntegerTemplate),
tmpItem);
} else {
rv = SECFailure;
}
PORT_Free(encodedExtenValue.data);
if (rv == SECFailure) {
PORT_ArenaRelease(arena, mark);
} else {
PORT_ArenaUnmark(arena, mark);
}
return (rv);
}
SECStatus
CERT_FindCRLEntryReasonExten(CERTCrlEntry *crlEntry,
CERTCRLEntryReasonCode *value)
{
SECItem wrapperItem = { siBuffer, 0 };
SECItem tmpItem = { siBuffer, 0 };
SECStatus rv;
PLArenaPool *arena = NULL;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
return (SECFailure);
}
rv = cert_FindExtension(crlEntry->extensions, SEC_OID_X509_REASON_CODE,
&wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
rv = SEC_QuickDERDecodeItem(arena, &tmpItem,
SEC_ASN1_GET(SEC_EnumeratedTemplate),
&wrapperItem);
if (rv != SECSuccess) {
goto loser;
}
*value = (CERTCRLEntryReasonCode)DER_GetInteger(&tmpItem);
loser:
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
if (wrapperItem.data) {
PORT_Free(wrapperItem.data);
}
return (rv);
}
SECStatus
CERT_FindInvalidDateExten(CERTCrl *crl, PRTime *value)
{
SECItem encodedExtenValue;
SECItem decodedExtenValue = { siBuffer, 0 };
SECStatus rv;
encodedExtenValue.data = decodedExtenValue.data = NULL;
encodedExtenValue.len = decodedExtenValue.len = 0;
rv = cert_FindExtension(crl->extensions, SEC_OID_X509_INVALID_DATE, &encodedExtenValue);
if (rv != SECSuccess)
return (rv);
rv = SEC_ASN1DecodeItem(NULL, &decodedExtenValue,
SEC_ASN1_GET(SEC_GeneralizedTimeTemplate),
&encodedExtenValue);
if (rv == SECSuccess)
rv = DER_GeneralizedTimeToTime(value, &encodedExtenValue);
PORT_Free(decodedExtenValue.data);
PORT_Free(encodedExtenValue.data);
return (rv);
}

View file

@ -0,0 +1,33 @@
# 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_certhigh_exports',
'type': 'none',
'copies': [
{
'files': [
'ocsp.h',
'ocspt.h'
],
'destination': '<(nss_public_dist_dir)/<(module)'
},
{
'files': [
'ocspi.h',
'ocspti.h'
],
'destination': '<(nss_private_dist_dir)/<(module)'
}
]
}
],
'variables': {
'module': 'nss'
}
}

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/.
CORE_DEPTH = ../..
EXPORTS = \
ocsp.h \
ocspt.h \
$(NULL)
PRIVATE_EXPORTS = \
ocspti.h \
ocspi.h \
$(NULL)
MODULE = nss
CSRCS = \
certhtml.c \
certreq.c \
crlv2.c \
ocsp.c \
ocspsig.c \
certhigh.c \
certvfy.c \
certvfypkix.c \
xcrldist.c \
$(NULL)
LIBRARY_NAME = certhi
# This part of the code, including all sub-dirs, can be optimized for size
export ALLOW_OPT_CODE_SIZE = 1

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,723 @@
/* 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/. */
/*
* Interface to the OCSP implementation.
*/
#ifndef _OCSP_H_
#define _OCSP_H_
#include "plarena.h"
#include "seccomon.h"
#include "secoidt.h"
#include "keyt.h"
#include "certt.h"
#include "ocspt.h"
/************************************************************************/
SEC_BEGIN_PROTOS
/*
* This function registers the HttpClient with whose functions the
* HttpClientFcn structure has been populated as the default Http
* client.
*
* The function table must be a global object.
* The caller must ensure that NSS will be able to call
* the registered functions for the lifetime of the process.
*/
extern SECStatus
SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable);
/*
* This function obtains the HttpClient which has been registered
* by an earlier call to SEC_RegisterDefaultHttpClient.
*/
extern const SEC_HttpClientFcn *
SEC_GetRegisteredHttpClient(void);
/*
* Sets parameters that control NSS' internal OCSP cache.
* maxCacheEntries, special varlues are:
* -1 disable cache
* 0 unlimited cache entries
* minimumSecondsToNextFetchAttempt:
* whenever an OCSP request was attempted or completed over the network,
* wait at least this number of seconds before trying to fetch again.
* maximumSecondsToNextFetchAttempt:
* this is the maximum age of a cached response we allow, until we try
* to fetch an updated response, even if the OCSP responder expects
* that newer information update will not be available yet.
*/
extern SECStatus
CERT_OCSPCacheSettings(PRInt32 maxCacheEntries,
PRUint32 minimumSecondsToNextFetchAttempt,
PRUint32 maximumSecondsToNextFetchAttempt);
/*
* Set the desired behaviour on OCSP failures.
* See definition of ocspFailureMode for allowed choices.
*/
extern SECStatus
CERT_SetOCSPFailureMode(SEC_OcspFailureMode ocspFailureMode);
/*
* Configure the maximum time NSS will wait for an OCSP response.
*/
extern SECStatus
CERT_SetOCSPTimeout(PRUint32 seconds);
/*
* Removes all items currently stored in the OCSP cache.
*/
extern SECStatus
CERT_ClearOCSPCache(void);
/*
* FUNCTION: CERT_EnableOCSPChecking
* Turns on OCSP checking for the given certificate database.
* INPUTS:
* CERTCertDBHandle *handle
* Certificate database for which OCSP checking will be enabled.
* RETURN:
* Returns SECFailure if an error occurred (likely only problem
* allocating memory); SECSuccess otherwise.
*/
extern SECStatus
CERT_EnableOCSPChecking(CERTCertDBHandle *handle);
/*
* FUNCTION: CERT_DisableOCSPChecking
* Turns off OCSP checking for the given certificate database.
* This routine disables OCSP checking. Though it will return
* SECFailure if OCSP checking is not enabled, it is "safe" to
* call it that way and just ignore the return value, if it is
* easier to just call it than to "remember" whether it is enabled.
* INPUTS:
* CERTCertDBHandle *handle
* Certificate database for which OCSP checking will be disabled.
* RETURN:
* Returns SECFailure if an error occurred (usually means that OCSP
* checking was not enabled or status contexts were not initialized --
* error set will be SEC_ERROR_OCSP_NOT_ENABLED); SECSuccess otherwise.
*/
extern SECStatus
CERT_DisableOCSPChecking(CERTCertDBHandle *handle);
/*
* FUNCTION: CERT_SetOCSPDefaultResponder
* Specify the location and cert of the default responder.
* If OCSP checking is already enabled *and* use of a default responder
* is also already enabled, all OCSP checking from now on will go directly
* to the specified responder. If OCSP checking is not enabled, or if
* it is but use of a default responder is not enabled, the information
* will be recorded and take effect whenever both are enabled.
* INPUTS:
* CERTCertDBHandle *handle
* Cert database on which OCSP checking should use the default responder.
* const char *url
* The location of the default responder (e.g. "http://foo.com:80/ocsp")
* Note that the location will not be tested until the first attempt
* to send a request there.
* const char *name
* The nickname of the cert to trust (expected) to sign the OCSP responses.
* If the corresponding cert cannot be found, SECFailure is returned.
* RETURN:
* Returns SECFailure if an error occurred; SECSuccess otherwise.
* The most likely error is that the cert for "name" could not be found
* (probably SEC_ERROR_UNKNOWN_CERT). Other errors are low-level (no memory,
* bad database, etc.).
*/
extern SECStatus
CERT_SetOCSPDefaultResponder(CERTCertDBHandle *handle,
const char *url, const char *name);
/*
* FUNCTION: CERT_EnableOCSPDefaultResponder
* Turns on use of a default responder when OCSP checking.
* If OCSP checking is already enabled, this will make subsequent checks
* go directly to the default responder. (The location of the responder
* and the nickname of the responder cert must already be specified.)
* If OCSP checking is not enabled, this will be recorded and take effect
* whenever it is enabled.
* INPUTS:
* CERTCertDBHandle *handle
* Cert database on which OCSP checking should use the default responder.
* RETURN:
* Returns SECFailure if an error occurred; SECSuccess otherwise.
* No errors are especially likely unless the caller did not previously
* perform a successful call to SetOCSPDefaultResponder (in which case
* the error set will be SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER).
*/
extern SECStatus
CERT_EnableOCSPDefaultResponder(CERTCertDBHandle *handle);
/*
* FUNCTION: CERT_DisableOCSPDefaultResponder
* Turns off use of a default responder when OCSP checking.
* (Does nothing if use of a default responder is not enabled.)
* INPUTS:
* CERTCertDBHandle *handle
* Cert database on which OCSP checking should stop using a default
* responder.
* RETURN:
* Returns SECFailure if an error occurred; SECSuccess otherwise.
* Errors very unlikely (like random memory corruption...).
*/
extern SECStatus
CERT_DisableOCSPDefaultResponder(CERTCertDBHandle *handle);
/* If forcePost is set, OCSP requests will only be sent using the HTTP POST
* method. When forcePost is not set, OCSP requests will be sent using the
* HTTP GET method, with a fallback to POST when we fail to receive a response
* and/or when we receive an uncacheable response like "Unknown."
*
* The default is to use GET and fallback to POST.
*/
extern SECStatus CERT_ForcePostMethodForOCSP(PRBool forcePost);
/*
* -------------------------------------------------------
* The Functions above are those expected to be used by a client
* providing OCSP status checking along with every cert verification.
* The functions below are for OCSP testing, debugging, or clients
* or servers performing more specialized OCSP tasks.
* -------------------------------------------------------
*/
/*
* FUNCTION: CERT_CreateOCSPRequest
* Creates a CERTOCSPRequest, requesting the status of the certs in
* the given list.
* INPUTS:
* CERTCertList *certList
* A list of certs for which status will be requested.
* Note that all of these certificates should have the same issuer,
* or it's expected the response will be signed by a trusted responder.
* If the certs need to be broken up into multiple requests, that
* must be handled by the caller (and thus by having multiple calls
* to this routine), who knows about where the request(s) are being
* sent and whether there are any trusted responders in place.
* PRTime time
* Indicates the time for which the certificate status is to be
* determined -- this may be used in the search for the cert's issuer
* but has no effect on the request itself.
* PRBool addServiceLocator
* If true, the Service Locator extension should be added to the
* single request(s) for each cert.
* CERTCertificate *signerCert
* If non-NULL, means sign the request using this cert. Otherwise,
* do not sign.
* XXX note that request signing is not yet supported; see comment in code
* RETURN:
* A pointer to a CERTOCSPRequest structure containing an OCSP request
* for the cert list. On error, null is returned, with an error set
* indicating the reason. This is likely SEC_ERROR_UNKNOWN_ISSUER.
* (The issuer is needed to create a request for the certificate.)
* Other errors are low-level problems (no memory, bad database, etc.).
*/
extern CERTOCSPRequest *
CERT_CreateOCSPRequest(CERTCertList *certList, PRTime time,
PRBool addServiceLocator,
CERTCertificate *signerCert);
/*
* FUNCTION: CERT_AddOCSPAcceptableResponses
* Add the AcceptableResponses extension to an OCSP Request.
* INPUTS:
* CERTOCSPRequest *request
* The request to which the extension should be added.
* SECOidTag responseType0, ...
* A list (of one or more) of SECOidTag -- each of the response types
* to be added. The last OID *must* be SEC_OID_PKIX_OCSP_BASIC_RESPONSE.
* (This marks the end of the list, and it must be specified because a
* client conforming to the OCSP standard is required to handle the basic
* response type.) The OIDs are not checked in any way.
* RETURN:
* SECSuccess if the extension is added; SECFailure if anything goes wrong.
* All errors are internal or low-level problems (e.g. no memory).
*/
extern SECStatus
CERT_AddOCSPAcceptableResponses(CERTOCSPRequest *request,
SECOidTag responseType0, ...);
/*
* FUNCTION: CERT_EncodeOCSPRequest
* DER encodes an OCSP Request, possibly adding a signature as well.
* XXX Signing is not yet supported, however; see comments in code.
* INPUTS:
* PLArenaPool *arena
* The return value is allocated from here.
* If a NULL is passed in, allocation is done from the heap instead.
* CERTOCSPRequest *request
* The request to be encoded.
* void *pwArg
* Pointer to argument for password prompting, if needed. (Definitely
* not needed if not signing.)
* RETURN:
* Returns a NULL on error and a pointer to the SECItem with the
* encoded value otherwise. Any error is likely to be low-level
* (e.g. no memory).
*/
extern SECItem *
CERT_EncodeOCSPRequest(PLArenaPool *arena, CERTOCSPRequest *request,
void *pwArg);
/*
* FUNCTION: CERT_DecodeOCSPRequest
* Decode a DER encoded OCSP Request.
* INPUTS:
* SECItem *src
* Pointer to a SECItem holding DER encoded OCSP Request.
* RETURN:
* Returns a pointer to a CERTOCSPRequest containing the decoded request.
* On error, returns NULL. Most likely error is trouble decoding
* (SEC_ERROR_OCSP_MALFORMED_REQUEST), or low-level problem (no memory).
*/
extern CERTOCSPRequest *
CERT_DecodeOCSPRequest(const SECItem *src);
/*
* FUNCTION: CERT_DestroyOCSPRequest
* Frees an OCSP Request structure.
* INPUTS:
* CERTOCSPRequest *request
* Pointer to CERTOCSPRequest to be freed.
* RETURN:
* No return value; no errors.
*/
extern void
CERT_DestroyOCSPRequest(CERTOCSPRequest *request);
/*
* FUNCTION: CERT_DecodeOCSPResponse
* Decode a DER encoded OCSP Response.
* INPUTS:
* SECItem *src
* Pointer to a SECItem holding DER encoded OCSP Response.
* RETURN:
* Returns a pointer to a CERTOCSPResponse (the decoded OCSP Response);
* the caller is responsible for destroying it. Or NULL if error (either
* response could not be decoded (SEC_ERROR_OCSP_MALFORMED_RESPONSE),
* it was of an unexpected type (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE),
* or a low-level or internal error occurred).
*/
extern CERTOCSPResponse *
CERT_DecodeOCSPResponse(const SECItem *src);
/*
* FUNCTION: CERT_DestroyOCSPResponse
* Frees an OCSP Response structure.
* INPUTS:
* CERTOCSPResponse *request
* Pointer to CERTOCSPResponse to be freed.
* RETURN:
* No return value; no errors.
*/
extern void
CERT_DestroyOCSPResponse(CERTOCSPResponse *response);
/*
* FUNCTION: CERT_GetEncodedOCSPResponse
* Creates and sends a request to an OCSP responder, then reads and
* returns the (encoded) response.
* INPUTS:
* PLArenaPool *arena
* Pointer to arena from which return value will be allocated.
* If NULL, result will be allocated from the heap (and thus should
* be freed via SECITEM_FreeItem).
* CERTCertList *certList
* A list of certs for which status will be requested.
* Note that all of these certificates should have the same issuer,
* or it's expected the response will be signed by a trusted responder.
* If the certs need to be broken up into multiple requests, that
* must be handled by the caller (and thus by having multiple calls
* to this routine), who knows about where the request(s) are being
* sent and whether there are any trusted responders in place.
* const char *location
* The location of the OCSP responder (a URL).
* PRTime time
* Indicates the time for which the certificate status is to be
* determined -- this may be used in the search for the cert's issuer
* but has no other bearing on the operation.
* PRBool addServiceLocator
* If true, the Service Locator extension should be added to the
* single request(s) for each cert.
* CERTCertificate *signerCert
* If non-NULL, means sign the request using this cert. Otherwise,
* do not sign.
* void *pwArg
* Pointer to argument for password prompting, if needed. (Definitely
* not needed if not signing.)
* OUTPUTS:
* CERTOCSPRequest **pRequest
* Pointer in which to store the OCSP request created for the given
* list of certificates. It is only filled in if the entire operation
* is successful and the pointer is not null -- and in that case the
* caller is then reponsible for destroying it.
* RETURN:
* Returns a pointer to the SECItem holding the response.
* On error, returns null with error set describing the reason:
* SEC_ERROR_UNKNOWN_ISSUER
* SEC_ERROR_CERT_BAD_ACCESS_LOCATION
* SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
* Other errors are low-level problems (no memory, bad database, etc.).
*/
extern SECItem *
CERT_GetEncodedOCSPResponse(PLArenaPool *arena, CERTCertList *certList,
const char *location, PRTime time,
PRBool addServiceLocator,
CERTCertificate *signerCert, void *pwArg,
CERTOCSPRequest **pRequest);
/*
* FUNCTION: CERT_VerifyOCSPResponseSignature
* Check the signature on an OCSP Response. Will also perform a
* verification of the signer's certificate. Note, however, that a
* successful verification does not make any statement about the
* signer's *authority* to provide status for the certificate(s),
* that must be checked individually for each certificate.
* INPUTS:
* CERTOCSPResponse *response
* Pointer to response structure with signature to be checked.
* CERTCertDBHandle *handle
* Pointer to CERTCertDBHandle for certificate DB to use for verification.
* void *pwArg
* Pointer to argument for password prompting, if needed.
* CERTCertificate *issuerCert
* Issuer of the certificate that generated the OCSP request.
* OUTPUTS:
* CERTCertificate **pSignerCert
* Pointer in which to store signer's certificate; only filled-in if
* non-null.
* RETURN:
* Returns SECSuccess when signature is valid, anything else means invalid.
* Possible errors set:
* SEC_ERROR_OCSP_MALFORMED_RESPONSE - unknown type of ResponderID
* SEC_ERROR_INVALID_TIME - bad format of "ProducedAt" time
* SEC_ERROR_UNKNOWN_SIGNER - signer's cert could not be found
* SEC_ERROR_BAD_SIGNATURE - the signature did not verify
* Other errors are any of the many possible failures in cert verification
* (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
* verifying the signer's cert, or low-level problems (no memory, etc.)
*/
extern SECStatus
CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response,
CERTCertDBHandle *handle, void *pwArg,
CERTCertificate **pSignerCert,
CERTCertificate *issuerCert);
/*
* FUNCTION: CERT_GetOCSPAuthorityInfoAccessLocation
* Get the value of the URI of the OCSP responder for the given cert.
* This is found in the (optional) Authority Information Access extension
* in the cert.
* INPUTS:
* CERTCertificate *cert
* The certificate being examined.
* RETURN:
* char *
* A copy of the URI for the OCSP method, if found. If either the
* extension is not present or it does not contain an entry for OCSP,
* SEC_ERROR_EXTENSION_NOT_FOUND will be set and a NULL returned.
* Any other error will also result in a NULL being returned.
*
* This result should be freed (via PORT_Free) when no longer in use.
*/
extern char *
CERT_GetOCSPAuthorityInfoAccessLocation(const CERTCertificate *cert);
/*
* FUNCTION: CERT_RegisterAlternateOCSPAIAInfoCallBack
* This function serves two purposes.
* 1) It registers the address of a callback function that will be
* called for certs that have no OCSP AIA extension, to see if the
* callback wishes to supply an alternative URL for such an OCSP inquiry.
* 2) It outputs the previously registered function's address to the
* address supplied by the caller, unless that is NULL.
* The registered callback function returns NULL, or an allocated string
* that may be subsequently freed by calling PORT_Free().
* RETURN:
* SECSuccess or SECFailure (if the library is not yet intialized)
*/
extern SECStatus
CERT_RegisterAlternateOCSPAIAInfoCallBack(
CERT_StringFromCertFcn newCallback,
CERT_StringFromCertFcn *oldCallback);
/*
* FUNCTION: CERT_ParseURL
* Parse a URI into hostname, port, and path. The scheme in the URI must
* be "http".
* INPUTS:
* const char *url
* The URI to be parsed
* OUTPUTS:
* char **pHostname
* Pointer to store the hostname obtained from the URI.
* This result should be freed (via PORT_Free) when no longer in use.
* PRUint16 *pPort
* Pointer to store the port number obtained from the URI.
* char **pPath
* Pointer to store the path obtained from the URI.
* This result should be freed (via PORT_Free) when no longer in use.
* RETURN:
* Returns SECSuccess when parsing was successful. Returns SECFailure when
* problems were encountered.
*/
extern SECStatus
CERT_ParseURL(const char *url, char **pHostname, PRUint16 *pPort, char **pPath);
/*
* FUNCTION: CERT_CheckOCSPStatus
* Checks the status of a certificate via OCSP. Will only check status for
* a certificate that has an AIA (Authority Information Access) extension
* for OCSP *or* when a "default responder" is specified and enabled.
* (If no AIA extension for OCSP and no default responder in place, the
* cert is considered to have a good status and SECSuccess is returned.)
* INPUTS:
* CERTCertDBHandle *handle
* certificate DB of the cert that is being checked
* CERTCertificate *cert
* the certificate being checked
* XXX in the long term also need a boolean parameter that specifies
* whether to check the cert chain, as well; for now we check only
* the leaf (the specified certificate)
* PRTime time
* time for which status is to be determined
* void *pwArg
* argument for password prompting, if needed
* RETURN:
* Returns SECSuccess if an approved OCSP responder "knows" the cert
* *and* returns a non-revoked status for it; SECFailure otherwise,
* with an error set describing the reason:
*
* SEC_ERROR_OCSP_BAD_HTTP_RESPONSE
* SEC_ERROR_OCSP_FUTURE_RESPONSE
* SEC_ERROR_OCSP_MALFORMED_REQUEST
* SEC_ERROR_OCSP_MALFORMED_RESPONSE
* SEC_ERROR_OCSP_OLD_RESPONSE
* SEC_ERROR_OCSP_REQUEST_NEEDS_SIG
* SEC_ERROR_OCSP_SERVER_ERROR
* SEC_ERROR_OCSP_TRY_SERVER_LATER
* SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST
* SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE
* SEC_ERROR_OCSP_UNKNOWN_CERT
* SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
* SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE
*
* SEC_ERROR_BAD_SIGNATURE
* SEC_ERROR_CERT_BAD_ACCESS_LOCATION
* SEC_ERROR_INVALID_TIME
* SEC_ERROR_REVOKED_CERTIFICATE
* SEC_ERROR_UNKNOWN_ISSUER
* SEC_ERROR_UNKNOWN_SIGNER
*
* Other errors are any of the many possible failures in cert verification
* (e.g. SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_UNTRUSTED_ISSUER) when
* verifying the signer's cert, or low-level problems (error allocating
* memory, error performing ASN.1 decoding, etc.).
*/
extern SECStatus
CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
PRTime time, void *pwArg);
/*
* FUNCTION: CERT_CacheOCSPResponseFromSideChannel
* First, this function checks the OCSP cache to see if a good response
* for the given certificate already exists. If it does, then the function
* returns successfully.
*
* If not, then it validates that the given OCSP response is a valid,
* good response for the given certificate and inserts it into the
* cache.
*
* This function is intended for use when OCSP responses are provided via a
* side-channel, i.e. TLS OCSP stapling (a.k.a. the status_request extension).
*
* INPUTS:
* CERTCertDBHandle *handle
* certificate DB of the cert that is being checked
* CERTCertificate *cert
* the certificate being checked
* PRTime time
* time for which status is to be determined
* SECItem *encodedResponse
* the DER encoded bytes of the OCSP response
* void *pwArg
* argument for password prompting, if needed
* RETURN:
* SECSuccess if the cert was found in the cache, or if the OCSP response was
* found to be valid and inserted into the cache. SECFailure otherwise.
*/
extern SECStatus
CERT_CacheOCSPResponseFromSideChannel(CERTCertDBHandle *handle,
CERTCertificate *cert,
PRTime time,
const SECItem *encodedResponse,
void *pwArg);
/*
* FUNCTION: CERT_GetOCSPStatusForCertID
* Returns the OCSP status contained in the passed in parameter response
* that corresponds to the certID passed in.
* INPUTS:
* CERTCertDBHandle *handle
* certificate DB of the cert that is being checked
* CERTOCSPResponse *response
* the OCSP response we want to retrieve status from.
* CERTOCSPCertID *certID
* the ID we want to look for from the response.
* CERTCertificate *signerCert
* the certificate that was used to sign the OCSP response.
* must be obtained via a call to CERT_VerifyOCSPResponseSignature.
* PRTime time
* The time at which we're checking the status for.
* RETURN:
* Return values are the same as those for CERT_CheckOCSPStatus
*/
extern SECStatus
CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle,
CERTOCSPResponse *response,
CERTOCSPCertID *certID,
CERTCertificate *signerCert,
PRTime time);
/*
* FUNCTION CERT_GetOCSPResponseStatus
* Returns the response status for the response passed.
* INPUTS:
* CERTOCSPResponse *response
* The response to query for status
* RETURN:
* Returns SECSuccess if the response has a successful status value.
* Otherwise it returns SECFailure and sets one of the following error
* codes via PORT_SetError
* SEC_ERROR_OCSP_MALFORMED_REQUEST
* SEC_ERROR_OCSP_SERVER_ERROR
* SEC_ERROR_OCSP_TRY_SERVER_LATER
* SEC_ERROR_OCSP_REQUEST_NEEDS_SIG
* SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST
* SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
*/
extern SECStatus
CERT_GetOCSPResponseStatus(CERTOCSPResponse *response);
/*
* FUNCTION CERT_CreateOCSPCertID
* Returns the OCSP certID for the certificate passed in.
* INPUTS:
* CERTCertificate *cert
* The certificate for which to create the certID for.
* PRTime time
* The time at which the id is requested for. This is used
* to determine the appropriate issuer for the cert since
* the issuing CA may be an older expired certificate.
* RETURN:
* A new copy of a CERTOCSPCertID*. The memory for this certID
* should be freed by calling CERT_DestroyOCSPCertID when the
* certID is no longer necessary.
*/
extern CERTOCSPCertID *
CERT_CreateOCSPCertID(CERTCertificate *cert, PRTime time);
/*
* FUNCTION: CERT_DestroyOCSPCertID
* Frees the memory associated with the certID passed in.
* INPUTS:
* CERTOCSPCertID* certID
* The certID that the caller no longer needs and wants to
* free the associated memory.
* RETURN:
* SECSuccess if freeing the memory was successful. Returns
* SECFailure if the memory passed in was not allocated with
* a call to CERT_CreateOCSPCertID.
*/
extern SECStatus
CERT_DestroyOCSPCertID(CERTOCSPCertID *certID);
extern CERTOCSPSingleResponse *
CERT_CreateOCSPSingleResponseGood(PLArenaPool *arena,
CERTOCSPCertID *id,
PRTime thisUpdate,
const PRTime *nextUpdate);
extern CERTOCSPSingleResponse *
CERT_CreateOCSPSingleResponseUnknown(PLArenaPool *arena,
CERTOCSPCertID *id,
PRTime thisUpdate,
const PRTime *nextUpdate);
extern CERTOCSPSingleResponse *
CERT_CreateOCSPSingleResponseRevoked(
PLArenaPool *arena,
CERTOCSPCertID *id,
PRTime thisUpdate,
const PRTime *nextUpdate,
PRTime revocationTime,
const CERTCRLEntryReasonCode *revocationReason);
extern SECItem *
CERT_CreateEncodedOCSPSuccessResponse(
PLArenaPool *arena,
CERTCertificate *responderCert,
CERTOCSPResponderIDType responderIDType,
PRTime producedAt,
CERTOCSPSingleResponse **responses,
void *wincx);
/*
* FUNCTION: CERT_CreateEncodedOCSPErrorResponse
* Creates an encoded OCSP response with an error response status.
* INPUTS:
* PLArenaPool *arena
* The return value is allocated from here.
* If a NULL is passed in, allocation is done from the heap instead.
* int error
* An NSS error code indicating an error response status. The error
* code is mapped to an OCSP response status as follows:
* SEC_ERROR_OCSP_MALFORMED_REQUEST -> malformedRequest
* SEC_ERROR_OCSP_SERVER_ERROR -> internalError
* SEC_ERROR_OCSP_TRY_SERVER_LATER -> tryLater
* SEC_ERROR_OCSP_REQUEST_NEEDS_SIG -> sigRequired
* SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST -> unauthorized
* where the OCSP response status is an enumerated type defined in
* RFC 2560:
* OCSPResponseStatus ::= ENUMERATED {
* successful (0), --Response has valid confirmations
* malformedRequest (1), --Illegal confirmation request
* internalError (2), --Internal error in issuer
* tryLater (3), --Try again later
* --(4) is not used
* sigRequired (5), --Must sign the request
* unauthorized (6) --Request unauthorized
* }
* RETURN:
* Returns a pointer to the SECItem holding the response.
* On error, returns null with error set describing the reason:
* SEC_ERROR_INVALID_ARGS
* Other errors are low-level problems (no memory, bad database, etc.).
*/
extern SECItem *
CERT_CreateEncodedOCSPErrorResponse(PLArenaPool *arena, int error);
/* Sends an OCSP request using the HTTP POST method to the location addressed
* by the URL in |location| parameter. The request body will be
* |encodedRequest|, which must be a valid encoded OCSP request. On success,
* the server's response is returned and the caller must free it using
* SECITEM_FreeItem. On failure, NULL is returned. No parsing or validation of
* the HTTP response is done.
*
* If a default HTTP client has been registered with
* SEC_RegisterDefaultHttpClient then that client is used. Otherwise, an
* internal HTTP client is used.
*/
SECItem *CERT_PostOCSPRequest(PLArenaPool *arena, const char *location,
const SECItem *encodedRequest);
/************************************************************************/
SEC_END_PROTOS
#endif /* _OCSP_H_ */

View file

@ -0,0 +1,166 @@
/* 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/. */
/*
* ocspi.h - NSS internal interfaces to OCSP code
*/
#ifndef _OCSPI_H_
#define _OCSPI_H_
SECStatus OCSP_InitGlobal(void);
SECStatus OCSP_ShutdownGlobal(void);
ocspResponseData *
ocsp_GetResponseData(CERTOCSPResponse *response, SECItem **tbsResponseDataDER);
ocspSignature *
ocsp_GetResponseSignature(CERTOCSPResponse *response);
SECItem *
ocsp_DigestValue(PLArenaPool *arena, SECOidTag digestAlg,
SECItem *fill, const SECItem *src);
PRBool
ocsp_CertIsOCSPDefaultResponder(CERTCertDBHandle *handle, CERTCertificate *cert);
CERTCertificate *
ocsp_GetSignerCertificate(CERTCertDBHandle *handle, ocspResponseData *tbsData,
ocspSignature *signature, CERTCertificate *issuer);
SECStatus
ocsp_VerifyResponseSignature(CERTCertificate *signerCert,
ocspSignature *signature,
SECItem *tbsResponseDataDER,
void *pwArg);
CERTOCSPRequest *
cert_CreateSingleCertOCSPRequest(CERTOCSPCertID *certID,
CERTCertificate *singleCert,
PRTime time,
PRBool addServiceLocator,
CERTCertificate *signerCert);
typedef enum { ocspMissing,
ocspFresh,
ocspStale } OCSPFreshness;
SECStatus
ocsp_GetCachedOCSPResponseStatus(CERTOCSPCertID *certID,
PRTime time,
PRBool ignoreOcspFailureMode,
SECStatus *rvOcsp,
SECErrorCodes *missingResponseError,
OCSPFreshness *freshness);
/*
* FUNCTION: cert_ProcessOCSPResponse
* Same behavior and basic parameters as CERT_GetOCSPStatusForCertID.
* In addition it can update the OCSP cache (using information
* available internally to this function).
* INPUTS:
* CERTCertDBHandle *handle
* certificate DB of the cert that is being checked
* CERTOCSPResponse *response
* the OCSP response we want to retrieve status from.
* CERTOCSPCertID *certID
* the ID we want to look for from the response.
* CERTCertificate *signerCert
* the certificate that was used to sign the OCSP response.
* must be obtained via a call to CERT_VerifyOCSPResponseSignature.
* PRTime time
* The time at which we're checking the status for.
* PRBool *certIDWasConsumed
* In and Out parameter.
* If certIDWasConsumed is NULL on input,
* this function might produce a deep copy of cert ID
* for storing it in the cache.
* If out value is true, ownership of parameter certID was
* transferred to the OCSP cache.
* SECStatus *cacheUpdateStatus
* This optional out parameter will contain the result
* of the cache update operation (if requested).
* RETURN:
* The return value is not influenced by the cache operation,
* it matches the documentation for CERT_CheckOCSPStatus
*/
SECStatus
cert_ProcessOCSPResponse(CERTCertDBHandle *handle,
CERTOCSPResponse *response,
CERTOCSPCertID *certID,
CERTCertificate *signerCert,
PRTime time,
PRBool *certIDWasConsumed,
SECStatus *cacheUpdateStatus);
/*
* FUNCTION: cert_RememberOCSPProcessingFailure
* If an application notices a failure during OCSP processing,
* it should finally call this function. The failure will be recorded
* in the OCSP cache in order to avoid repetitive failures.
* INPUTS:
* CERTOCSPCertID *certID
* the ID that was used for the failed OCSP processing
* PRBool *certIDWasConsumed
* Out parameter, if set to true, ownership of parameter certID was
* transferred to the OCSP cache.
* RETURN:
* Status of the cache update operation.
*/
SECStatus
cert_RememberOCSPProcessingFailure(CERTOCSPCertID *certID,
PRBool *certIDWasConsumed);
/*
* FUNCTION: ocsp_GetResponderLocation
* Check ocspx context for user-designated responder URI first. If not
* found, checks cert AIA extension.
* INPUTS:
* CERTCertDBHandle *handle
* certificate DB of the cert that is being checked
* CERTCertificate *cert
* The certificate being examined.
* PRBool *certIDWasConsumed
* Out parameter, if set to true, URI of default responder is
* returned.
* RETURN:
* Responder URI.
*/
char *
ocsp_GetResponderLocation(CERTCertDBHandle *handle,
CERTCertificate *cert,
PRBool canUseDefaultLocation,
PRBool *isDefault);
/* FUNCTION: ocsp_FetchingFailureIsVerificationFailure
* The function checks the global ocsp settings and
* tells how to treat an ocsp response fetching failure.
* RETURNS:
* if PR_TRUE is returned, then treat fetching as a
* revoked cert status.
*/
PRBool
ocsp_FetchingFailureIsVerificationFailure(void);
size_t
ocsp_UrlEncodeBase64Buf(const char *base64Buf, char *outputBuf);
SECStatus
ocsp_GetVerifiedSingleResponseForCertID(CERTCertDBHandle *handle,
CERTOCSPResponse *response,
CERTOCSPCertID *certID,
CERTCertificate *signerCert,
PRTime time,
CERTOCSPSingleResponse **pSingleResponse);
SECStatus
ocsp_CertHasGoodStatus(ocspCertStatus *status, PRTime time);
void
ocsp_CacheSingleResponse(CERTOCSPCertID *certID,
CERTOCSPSingleResponse *single,
PRBool *certIDWasConsumed);
#endif /* _OCSPI_H_ */

View file

@ -0,0 +1,597 @@
/* 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 "plarena.h"
#include "seccomon.h"
#include "secitem.h"
#include "secasn1.h"
#include "secder.h"
#include "cert.h"
#include "secerr.h"
#include "secoid.h"
#include "sechash.h"
#include "keyhi.h"
#include "cryptohi.h"
#include "ocsp.h"
#include "ocspti.h"
#include "ocspi.h"
#include "pk11pub.h"
extern const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[];
extern const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[];
extern const SEC_ASN1Template ocsp_OCSPResponseTemplate[];
ocspCertStatus *
ocsp_CreateCertStatus(PLArenaPool *arena,
ocspCertStatusType status,
PRTime revocationTime)
{
ocspCertStatus *cs;
if (!arena) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
switch (status) {
case ocspCertStatus_good:
case ocspCertStatus_unknown:
case ocspCertStatus_revoked:
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
cs = PORT_ArenaZNew(arena, ocspCertStatus);
if (!cs)
return NULL;
cs->certStatusType = status;
switch (status) {
case ocspCertStatus_good:
cs->certStatusInfo.goodInfo = SECITEM_AllocItem(arena, NULL, 0);
if (!cs->certStatusInfo.goodInfo)
return NULL;
break;
case ocspCertStatus_unknown:
cs->certStatusInfo.unknownInfo = SECITEM_AllocItem(arena, NULL, 0);
if (!cs->certStatusInfo.unknownInfo)
return NULL;
break;
case ocspCertStatus_revoked:
cs->certStatusInfo.revokedInfo =
PORT_ArenaZNew(arena, ocspRevokedInfo);
if (!cs->certStatusInfo.revokedInfo)
return NULL;
cs->certStatusInfo.revokedInfo->revocationReason =
SECITEM_AllocItem(arena, NULL, 0);
if (!cs->certStatusInfo.revokedInfo->revocationReason)
return NULL;
if (DER_TimeToGeneralizedTimeArena(arena,
&cs->certStatusInfo.revokedInfo->revocationTime,
revocationTime) !=
SECSuccess)
return NULL;
break;
default:
PORT_Assert(PR_FALSE);
}
return cs;
}
static const SEC_ASN1Template mySEC_EnumeratedTemplate[] = {
{ SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) }
};
static const SEC_ASN1Template mySEC_PointerToEnumeratedTemplate[] = {
{ SEC_ASN1_POINTER, 0, mySEC_EnumeratedTemplate }
};
static const SEC_ASN1Template ocsp_EncodeRevokedInfoTemplate[] = {
{ SEC_ASN1_GENERALIZED_TIME,
offsetof(ocspRevokedInfo, revocationTime) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
offsetof(ocspRevokedInfo, revocationReason),
mySEC_PointerToEnumeratedTemplate },
{ 0 }
};
static const SEC_ASN1Template ocsp_PointerToEncodeRevokedInfoTemplate[] = {
{ SEC_ASN1_POINTER, 0,
ocsp_EncodeRevokedInfoTemplate }
};
static const SEC_ASN1Template mySEC_NullTemplate[] = {
{ SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) }
};
static const SEC_ASN1Template ocsp_CertStatusTemplate[] = {
{ SEC_ASN1_CHOICE, offsetof(ocspCertStatus, certStatusType),
0, sizeof(ocspCertStatus) },
{ SEC_ASN1_CONTEXT_SPECIFIC | 0,
0, mySEC_NullTemplate, ocspCertStatus_good },
{ SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
SEC_ASN1_CONTEXT_SPECIFIC | 1,
offsetof(ocspCertStatus, certStatusInfo.revokedInfo),
ocsp_PointerToEncodeRevokedInfoTemplate, ocspCertStatus_revoked },
{ SEC_ASN1_CONTEXT_SPECIFIC | 2,
0, mySEC_NullTemplate, ocspCertStatus_unknown },
{ 0 }
};
static const SEC_ASN1Template mySECOID_AlgorithmIDTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(SECAlgorithmID) },
{ SEC_ASN1_OBJECT_ID,
offsetof(SECAlgorithmID, algorithm) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
offsetof(SECAlgorithmID, parameters) },
{ 0 }
};
static const SEC_ASN1Template mySEC_AnyTemplate[] = {
{ SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
};
static const SEC_ASN1Template mySEC_SequenceOfAnyTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, 0, mySEC_AnyTemplate }
};
static const SEC_ASN1Template mySEC_PointerToSequenceOfAnyTemplate[] = {
{ SEC_ASN1_POINTER, 0, mySEC_SequenceOfAnyTemplate }
};
static const SEC_ASN1Template mySEC_IntegerTemplate[] = {
{ SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) }
};
static const SEC_ASN1Template mySEC_PointerToIntegerTemplate[] = {
{ SEC_ASN1_POINTER, 0, mySEC_IntegerTemplate }
};
static const SEC_ASN1Template mySEC_GeneralizedTimeTemplate[] = {
{ SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
};
static const SEC_ASN1Template mySEC_PointerToGeneralizedTimeTemplate[] = {
{ SEC_ASN1_POINTER, 0, mySEC_GeneralizedTimeTemplate }
};
static const SEC_ASN1Template ocsp_myCertIDTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CERTOCSPCertID) },
{ SEC_ASN1_INLINE,
offsetof(CERTOCSPCertID, hashAlgorithm),
mySECOID_AlgorithmIDTemplate },
{ SEC_ASN1_OCTET_STRING,
offsetof(CERTOCSPCertID, issuerNameHash) },
{ SEC_ASN1_OCTET_STRING,
offsetof(CERTOCSPCertID, issuerKeyHash) },
{ SEC_ASN1_INTEGER,
offsetof(CERTOCSPCertID, serialNumber) },
{ 0 }
};
static const SEC_ASN1Template myCERT_CertExtensionTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CERTCertExtension) },
{ SEC_ASN1_OBJECT_ID,
offsetof(CERTCertExtension, id) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
offsetof(CERTCertExtension, critical) },
{ SEC_ASN1_OCTET_STRING,
offsetof(CERTCertExtension, value) },
{ 0 }
};
static const SEC_ASN1Template myCERT_SequenceOfCertExtensionTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, 0, myCERT_CertExtensionTemplate }
};
static const SEC_ASN1Template myCERT_PointerToSequenceOfCertExtensionTemplate[] = {
{ SEC_ASN1_POINTER, 0, myCERT_SequenceOfCertExtensionTemplate }
};
static const SEC_ASN1Template ocsp_mySingleResponseTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CERTOCSPSingleResponse) },
{ SEC_ASN1_POINTER,
offsetof(CERTOCSPSingleResponse, certID),
ocsp_myCertIDTemplate },
{ SEC_ASN1_ANY,
offsetof(CERTOCSPSingleResponse, derCertStatus) },
{ SEC_ASN1_GENERALIZED_TIME,
offsetof(CERTOCSPSingleResponse, thisUpdate) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
offsetof(CERTOCSPSingleResponse, nextUpdate),
mySEC_PointerToGeneralizedTimeTemplate },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
offsetof(CERTOCSPSingleResponse, singleExtensions),
myCERT_PointerToSequenceOfCertExtensionTemplate },
{ 0 }
};
static const SEC_ASN1Template ocsp_myResponseDataTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(ocspResponseData) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */
SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
offsetof(ocspResponseData, version),
mySEC_PointerToIntegerTemplate },
{ SEC_ASN1_ANY,
offsetof(ocspResponseData, derResponderID) },
{ SEC_ASN1_GENERALIZED_TIME,
offsetof(ocspResponseData, producedAt) },
{ SEC_ASN1_SEQUENCE_OF,
offsetof(ocspResponseData, responses),
ocsp_mySingleResponseTemplate },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
offsetof(ocspResponseData, responseExtensions),
myCERT_PointerToSequenceOfCertExtensionTemplate },
{ 0 }
};
static const SEC_ASN1Template ocsp_EncodeBasicOCSPResponseTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(ocspBasicOCSPResponse) },
{ SEC_ASN1_POINTER,
offsetof(ocspBasicOCSPResponse, tbsResponseData),
ocsp_myResponseDataTemplate },
{ SEC_ASN1_INLINE,
offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
mySECOID_AlgorithmIDTemplate },
{ SEC_ASN1_BIT_STRING,
offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
offsetof(ocspBasicOCSPResponse, responseSignature.derCerts),
mySEC_PointerToSequenceOfAnyTemplate },
{ 0 }
};
static CERTOCSPSingleResponse *
ocsp_CreateSingleResponse(PLArenaPool *arena,
CERTOCSPCertID *id, ocspCertStatus *status,
PRTime thisUpdate, const PRTime *nextUpdate)
{
CERTOCSPSingleResponse *sr;
if (!arena || !id || !status) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
sr = PORT_ArenaZNew(arena, CERTOCSPSingleResponse);
if (!sr)
return NULL;
sr->arena = arena;
sr->certID = id;
sr->certStatus = status;
if (DER_TimeToGeneralizedTimeArena(arena, &sr->thisUpdate, thisUpdate) !=
SECSuccess)
return NULL;
sr->nextUpdate = NULL;
if (nextUpdate) {
sr->nextUpdate = SECITEM_AllocItem(arena, NULL, 0);
if (!sr->nextUpdate)
return NULL;
if (DER_TimeToGeneralizedTimeArena(arena, sr->nextUpdate, *nextUpdate) !=
SECSuccess)
return NULL;
}
sr->singleExtensions = PORT_ArenaNewArray(arena, CERTCertExtension *, 1);
if (!sr->singleExtensions)
return NULL;
sr->singleExtensions[0] = NULL;
if (!SEC_ASN1EncodeItem(arena, &sr->derCertStatus,
status, ocsp_CertStatusTemplate))
return NULL;
return sr;
}
CERTOCSPSingleResponse *
CERT_CreateOCSPSingleResponseGood(PLArenaPool *arena,
CERTOCSPCertID *id,
PRTime thisUpdate,
const PRTime *nextUpdate)
{
ocspCertStatus *cs;
if (!arena) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
cs = ocsp_CreateCertStatus(arena, ocspCertStatus_good, 0);
if (!cs)
return NULL;
return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate);
}
CERTOCSPSingleResponse *
CERT_CreateOCSPSingleResponseUnknown(PLArenaPool *arena,
CERTOCSPCertID *id,
PRTime thisUpdate,
const PRTime *nextUpdate)
{
ocspCertStatus *cs;
if (!arena) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
cs = ocsp_CreateCertStatus(arena, ocspCertStatus_unknown, 0);
if (!cs)
return NULL;
return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate);
}
CERTOCSPSingleResponse *
CERT_CreateOCSPSingleResponseRevoked(
PLArenaPool *arena,
CERTOCSPCertID *id,
PRTime thisUpdate,
const PRTime *nextUpdate,
PRTime revocationTime,
const CERTCRLEntryReasonCode *revocationReason)
{
ocspCertStatus *cs;
/* revocationReason is not yet supported, so it must be NULL. */
if (!arena || revocationReason) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
cs = ocsp_CreateCertStatus(arena, ocspCertStatus_revoked, revocationTime);
if (!cs)
return NULL;
return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate);
}
/* responderCert == 0 means:
* create a response with an invalid signature (for testing purposes) */
SECItem *
CERT_CreateEncodedOCSPSuccessResponse(
PLArenaPool *arena,
CERTCertificate *responderCert,
CERTOCSPResponderIDType responderIDType,
PRTime producedAt,
CERTOCSPSingleResponse **responses,
void *wincx)
{
PLArenaPool *tmpArena;
ocspResponseData *rd = NULL;
ocspResponderID *rid = NULL;
const SEC_ASN1Template *responderIDTemplate = NULL;
ocspBasicOCSPResponse *br = NULL;
ocspResponseBytes *rb = NULL;
CERTOCSPResponse *response = NULL;
SECOidTag algID;
SECOidData *od = NULL;
SECKEYPrivateKey *privKey = NULL;
SECItem *result = NULL;
if (!arena || !responses) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
if (responderIDType != ocspResponderID_byName &&
responderIDType != ocspResponderID_byKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!tmpArena)
return NULL;
rd = PORT_ArenaZNew(tmpArena, ocspResponseData);
if (!rd)
goto done;
rid = PORT_ArenaZNew(tmpArena, ocspResponderID);
if (!rid)
goto done;
br = PORT_ArenaZNew(tmpArena, ocspBasicOCSPResponse);
if (!br)
goto done;
rb = PORT_ArenaZNew(tmpArena, ocspResponseBytes);
if (!rb)
goto done;
response = PORT_ArenaZNew(tmpArena, CERTOCSPResponse);
if (!response)
goto done;
rd->version.data = NULL;
rd->version.len = 0;
rd->responseExtensions = NULL;
rd->responses = responses;
if (DER_TimeToGeneralizedTimeArena(tmpArena, &rd->producedAt, producedAt) !=
SECSuccess)
goto done;
if (!responderCert) {
/* use invalid signature for testing purposes */
unsigned char dummyChar = 'd';
SECItem dummy;
dummy.len = 1;
dummy.data = &dummyChar;
/* it's easier to produdce a keyHash out of nowhere,
* than to produce an encoded subject,
* so for our dummy response we always use byKey
*/
rid->responderIDType = ocspResponderID_byKey;
if (!ocsp_DigestValue(tmpArena, SEC_OID_SHA1, &rid->responderIDValue.keyHash,
&dummy))
goto done;
if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid,
ocsp_ResponderIDByKeyTemplate))
goto done;
br->tbsResponseData = rd;
if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData,
ocsp_myResponseDataTemplate))
goto done;
br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem *, 1);
if (!br->responseSignature.derCerts)
goto done;
br->responseSignature.derCerts[0] = NULL;
algID = SEC_GetSignatureAlgorithmOidTag(rsaKey, SEC_OID_SHA1);
if (algID == SEC_OID_UNKNOWN)
goto done;
/* match the regular signature code, which doesn't use the arena */
if (!SECITEM_AllocItem(NULL, &br->responseSignature.signature, 1))
goto done;
PORT_Memcpy(br->responseSignature.signature.data, &dummyChar, 1);
/* convert len-in-bytes to len-in-bits */
br->responseSignature.signature.len = br->responseSignature.signature.len << 3;
} else {
rid->responderIDType = responderIDType;
if (responderIDType == ocspResponderID_byName) {
responderIDTemplate = ocsp_ResponderIDByNameTemplate;
if (CERT_CopyName(tmpArena, &rid->responderIDValue.name,
&responderCert->subject) != SECSuccess)
goto done;
} else {
responderIDTemplate = ocsp_ResponderIDByKeyTemplate;
if (!CERT_GetSubjectPublicKeyDigest(tmpArena, responderCert,
SEC_OID_SHA1, &rid->responderIDValue.keyHash))
goto done;
}
if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid,
responderIDTemplate))
goto done;
br->tbsResponseData = rd;
if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData,
ocsp_myResponseDataTemplate))
goto done;
br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem *, 1);
if (!br->responseSignature.derCerts)
goto done;
br->responseSignature.derCerts[0] = NULL;
privKey = PK11_FindKeyByAnyCert(responderCert, wincx);
if (!privKey)
goto done;
algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1);
if (algID == SEC_OID_UNKNOWN)
goto done;
if (SEC_SignData(&br->responseSignature.signature,
br->tbsResponseDataDER.data, br->tbsResponseDataDER.len,
privKey, algID) !=
SECSuccess)
goto done;
/* convert len-in-bytes to len-in-bits */
br->responseSignature.signature.len = br->responseSignature.signature.len << 3;
/* br->responseSignature.signature wasn't allocated from arena,
* we must free it when done. */
}
if (SECOID_SetAlgorithmID(tmpArena, &br->responseSignature.signatureAlgorithm, algID, 0) !=
SECSuccess)
goto done;
if (!SEC_ASN1EncodeItem(tmpArena, &rb->response, br,
ocsp_EncodeBasicOCSPResponseTemplate))
goto done;
rb->responseTypeTag = SEC_OID_PKIX_OCSP_BASIC_RESPONSE;
od = SECOID_FindOIDByTag(rb->responseTypeTag);
if (!od)
goto done;
rb->responseType = od->oid;
rb->decodedResponse.basic = br;
response->arena = tmpArena;
response->responseBytes = rb;
response->statusValue = ocspResponse_successful;
if (!SEC_ASN1EncodeInteger(tmpArena, &response->responseStatus,
response->statusValue))
goto done;
result = SEC_ASN1EncodeItem(arena, NULL, response, ocsp_OCSPResponseTemplate);
done:
if (privKey)
SECKEY_DestroyPrivateKey(privKey);
if (br && br->responseSignature.signature.data)
SECITEM_FreeItem(&br->responseSignature.signature, PR_FALSE);
PORT_FreeArena(tmpArena, PR_FALSE);
return result;
}
static const SEC_ASN1Template ocsp_OCSPErrorResponseTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(CERTOCSPResponse) },
{ SEC_ASN1_ENUMERATED,
offsetof(CERTOCSPResponse, responseStatus) },
{ 0, 0,
mySEC_NullTemplate },
{ 0 }
};
SECItem *
CERT_CreateEncodedOCSPErrorResponse(PLArenaPool *arena, int error)
{
CERTOCSPResponse response;
SECItem *result = NULL;
switch (error) {
case SEC_ERROR_OCSP_MALFORMED_REQUEST:
response.statusValue = ocspResponse_malformedRequest;
break;
case SEC_ERROR_OCSP_SERVER_ERROR:
response.statusValue = ocspResponse_internalError;
break;
case SEC_ERROR_OCSP_TRY_SERVER_LATER:
response.statusValue = ocspResponse_tryLater;
break;
case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG:
response.statusValue = ocspResponse_sigRequired;
break;
case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST:
response.statusValue = ocspResponse_unauthorized;
break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
if (!SEC_ASN1EncodeInteger(NULL, &response.responseStatus,
response.statusValue))
return NULL;
result = SEC_ASN1EncodeItem(arena, NULL, &response,
ocsp_OCSPErrorResponseTemplate);
SECITEM_FreeItem(&response.responseStatus, PR_FALSE);
return result;
}

View file

@ -0,0 +1,301 @@
/* 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/. */
/*
* Public header for exported OCSP types.
*/
#ifndef _OCSPT_H_
#define _OCSPT_H_
/*
* The following are all opaque types. If someone needs to get at
* a field within, then we need to fix the API. Try very hard not
* make the type available to them.
*/
typedef struct CERTOCSPRequestStr CERTOCSPRequest;
typedef struct CERTOCSPResponseStr CERTOCSPResponse;
/*
* XXX I think only those first two above should need to be exported,
* but until I know for certain I am leaving the rest of these here, too.
*/
typedef struct CERTOCSPCertIDStr CERTOCSPCertID;
typedef struct CERTOCSPSingleResponseStr CERTOCSPSingleResponse;
/*
* This interface is described in terms of an HttpClient which
* supports at least a specified set of functions. (An implementer may
* provide HttpClients with additional functionality accessible only to
* users with a particular implementation in mind.) The basic behavior
* is provided by defining a set of functions, listed in an
* SEC_HttpServerFcnStruct. If the implementor of a SpecificHttpClient
* registers his SpecificHttpClient as the default HttpClient, then his
* functions will be called by the user of an HttpClient, such as an
* OCSPChecker.
*
* The implementer of a specific HttpClient (e.g., the NSS-provided
* DefaultHttpClient), populates an SEC_HttpClientFcnStruct, uses it to
* register his client, and waits for his functions to be called.
*
* For future expandability, the SEC_HttpClientFcnStruct is defined as a
* union, with the version field acting as a selector. The proposed
* initial version of the structure is given following the definition
* of the union. The HttpClientState structure is implementation-
* dependent, and should be opaque to the user.
*/
typedef void *SEC_HTTP_SERVER_SESSION;
typedef void *SEC_HTTP_REQUEST_SESSION;
/*
* This function creates a SEC_HTTP_SERVER_SESSION object. The implementer of a
* specific HttpClient will allocate the necessary space, when this
* function is called, and will free it when the corresponding FreeFcn
* is called. The SEC_HTTP_SERVER_SESSION object is passed, as an opaque object,
* to subsequent calls.
*
* If the function returns SECSuccess, the returned SEC_HTTP_SERVER_SESSION
* must be cleaned up with a call to SEC_HttpServer_FreeSession,
* after processing is finished.
*/
typedef SECStatus (*SEC_HttpServer_CreateSessionFcn)(
const char *host,
PRUint16 portnum,
SEC_HTTP_SERVER_SESSION *pSession);
/*
* This function is called to allow the implementation to attempt to keep
* the connection alive. Depending on the underlying platform, it might
* immediately return SECSuccess without having performed any operations.
* (If a connection has not been kept alive, a subsequent call to
* SEC_HttpRequest_TrySendAndReceiveFcn should reopen the connection
* automatically.)
*
* If the connection uses nonblocking I/O, this function may return
* SECWouldBlock and store a nonzero value at "pPollDesc". In that case
* the caller may wait on the poll descriptor, and should call this function
* again until SECSuccess (and a zero value at "pPollDesc") is obtained.
*/
typedef SECStatus (*SEC_HttpServer_KeepAliveSessionFcn)(
SEC_HTTP_SERVER_SESSION session,
PRPollDesc **pPollDesc);
/*
* This function frees the client SEC_HTTP_SERVER_SESSION object, closes all
* SEC_HTTP_REQUEST_SESSIONs created for that server, discards all partial results,
* frees any memory that was allocated by the client, and invalidates any
* response pointers that might have been returned by prior server or request
* functions.
*/
typedef SECStatus (*SEC_HttpServer_FreeSessionFcn)(
SEC_HTTP_SERVER_SESSION session);
/*
* This function creates a SEC_HTTP_REQUEST_SESSION object. The implementer of a
* specific HttpClient will allocate the necessary space, when this
* function is called, and will free it when the corresponding FreeFcn
* is called. The SEC_HTTP_REQUEST_SESSION object is passed, as an opaque object,
* to subsequent calls.
*
* An implementation that does not support the requested protocol variant
* (usually "http", but could eventually allow "https") or request method
* should return SECFailure.
*
* Timeout values may include the constants PR_INTERVAL_NO_TIMEOUT (wait
* forever) or PR_INTERVAL_NO_WAIT (nonblocking I/O).
*
* If the function returns SECSuccess, the returned SEC_HTTP_REQUEST_SESSION
* must be cleaned up with a call to SEC_HttpRequest_FreeSession,
* after processing is finished.
*/
typedef SECStatus (*SEC_HttpRequest_CreateFcn)(
SEC_HTTP_SERVER_SESSION session,
const char *http_protocol_variant, /* usually "http" */
const char *path_and_query_string,
const char *http_request_method,
const PRIntervalTime timeout,
SEC_HTTP_REQUEST_SESSION *pRequest);
/*
* This function sets data to be sent to the server for an HTTP request
* of http_request_method == POST. If a particular implementation
* supports it, the details for the POST request can be set by calling
* this function, prior to activating the request with TrySendAndReceiveFcn.
*
* An implementation that does not support the POST method should
* implement a SetPostDataFcn function that returns immediately.
*
* Setting http_content_type is optional, the parameter may
* by NULL or the empty string.
*/
typedef SECStatus (*SEC_HttpRequest_SetPostDataFcn)(
SEC_HTTP_REQUEST_SESSION request,
const char *http_data,
const PRUint32 http_data_len,
const char *http_content_type);
/*
* This function sets an additional HTTP protocol request header.
* If a particular implementation supports it, one or multiple headers
* can be added to the request by calling this function once or multiple
* times, prior to activating the request with TryFcn.
*
* An implementation that does not support setting additional headers
* should implement an AddRequestHeaderFcn function that returns immediately.
*/
typedef SECStatus (*SEC_HttpRequest_AddHeaderFcn)(
SEC_HTTP_REQUEST_SESSION request,
const char *http_header_name,
const char *http_header_value);
/*
* This function initiates or continues an HTTP request. After
* parameters have been set with the Create function and, optionally,
* modified or enhanced with the AddParams function, this call creates
* the socket connection and initiates the communication.
*
* If a timeout value of zero is specified, indicating non-blocking
* I/O, the client creates a non-blocking socket, and returns a status
* of SECWouldBlock and a non-NULL PRPollDesc if the operation is not
* complete. In that case all other return parameters are undefined.
* The caller is expected to repeat the call, possibly after using
* PRPoll to determine that a completion has occurred, until a return
* value of SECSuccess (and a NULL value for pPollDesc) or a return
* value of SECFailure (indicating failure on the network level)
* is obtained.
*
* http_response_data_len is both input and output parameter.
* If a pointer to a PRUint32 is supplied, the http client is
* expected to check the given integer value and always set an out
* value, even on failure.
* An input value of zero means, the caller will accept any response len.
* A different input value indicates the maximum response value acceptable
* to the caller.
* If data is successfully read and the size is acceptable to the caller,
* the function will return SECSuccess and set http_response_data_len to
* the size of the block returned in http_response_data.
* If the data read from the http server is larger than the acceptable
* size, the function will return SECFailure.
* http_response_data_len will be set to a value different from zero to
* indicate the reason of the failure.
* An out value of "0" means, the failure was unrelated to the
* acceptable size.
* An out value of "1" means, the result data is larger than the
* accpeptable size, but the real size is not yet known to the http client
* implementation and it stopped retrieving it,
* Any other out value combined with a return value of SECFailure
* will indicate the actual size of the server data.
*
* The caller is permitted to provide NULL values for any of the
* http_response arguments, indicating the caller is not interested in
* those values. If the caller does provide an address, the HttpClient
* stores at that address a pointer to the corresponding argument, at
* the completion of the operation.
*
* All returned pointers will be owned by the the HttpClient
* implementation and will remain valid until the call to
* SEC_HttpRequest_FreeFcn.
*/
typedef SECStatus (*SEC_HttpRequest_TrySendAndReceiveFcn)(
SEC_HTTP_REQUEST_SESSION request,
PRPollDesc **pPollDesc,
PRUint16 *http_response_code,
const char **http_response_content_type,
const char **http_response_headers,
const char **http_response_data,
PRUint32 *http_response_data_len);
/*
* Calling CancelFcn asks for premature termination of the request.
*
* Future calls to SEC_HttpRequest_TrySendAndReceive should
* by avoided, but in this case the HttpClient implementation
* is expected to return immediately with SECFailure.
*
* After calling CancelFcn, a separate call to SEC_HttpRequest_FreeFcn
* is still necessary to free resources.
*/
typedef SECStatus (*SEC_HttpRequest_CancelFcn)(
SEC_HTTP_REQUEST_SESSION request);
/*
* Before calling this function, it must be assured the request
* has been completed, i.e. either SEC_HttpRequest_TrySendAndReceiveFcn has
* returned SECSuccess, or the request has been canceled with
* a call to SEC_HttpRequest_CancelFcn.
*
* This function frees the client state object, closes all sockets,
* discards all partial results, frees any memory that was allocated
* by the client, and invalidates all response pointers that might
* have been returned by SEC_HttpRequest_TrySendAndReceiveFcn
*/
typedef SECStatus (*SEC_HttpRequest_FreeFcn)(
SEC_HTTP_REQUEST_SESSION request);
typedef struct SEC_HttpClientFcnV1Struct {
SEC_HttpServer_CreateSessionFcn createSessionFcn;
SEC_HttpServer_KeepAliveSessionFcn keepAliveSessionFcn;
SEC_HttpServer_FreeSessionFcn freeSessionFcn;
SEC_HttpRequest_CreateFcn createFcn;
SEC_HttpRequest_SetPostDataFcn setPostDataFcn;
SEC_HttpRequest_AddHeaderFcn addHeaderFcn;
SEC_HttpRequest_TrySendAndReceiveFcn trySendAndReceiveFcn;
SEC_HttpRequest_CancelFcn cancelFcn;
SEC_HttpRequest_FreeFcn freeFcn;
} SEC_HttpClientFcnV1;
typedef struct SEC_HttpClientFcnStruct {
PRInt16 version;
union {
SEC_HttpClientFcnV1 ftable1;
/* SEC_HttpClientFcnV2 ftable2; */
/* ... */
} fcnTable;
} SEC_HttpClientFcn;
/*
* ocspMode_FailureIsVerificationFailure:
* This is the classic behaviour of NSS.
* Any OCSP failure is a verification failure (classic mode, default).
* Without a good response, OCSP networking will be retried each time
* it is required for verifying a cert.
*
* ocspMode_FailureIsNotAVerificationFailure:
* If we fail to obtain a valid OCSP response, consider the
* cert as good.
* Failed OCSP attempts might get cached and not retried until
* minimumSecondsToNextFetchAttempt.
* If we are able to obtain a valid response, the cert
* will be considered good, if either status is "good"
* or the cert was not yet revoked at verification time.
*
* Additional failure modes might be added in the future.
*/
typedef enum {
ocspMode_FailureIsVerificationFailure = 0,
ocspMode_FailureIsNotAVerificationFailure = 1
} SEC_OcspFailureMode;
/*
* A ResponderID identifies the responder -- or more correctly, the
* signer of the response. The ASN.1 definition of a ResponderID is:
*
* ResponderID ::= CHOICE {
* byName [1] EXPLICIT Name,
* byKey [2] EXPLICIT KeyHash }
*
* Because it is CHOICE, the type of identification used and the
* identification itself are actually encoded together. To represent
* this same information internally, we explicitly define a type and
* save it, along with the value, into a data structure.
*/
typedef enum {
ocspResponderID_other = -1, /* unknown kind of responderID */
ocspResponderID_byName = 1,
ocspResponderID_byKey = 2
} CERTOCSPResponderIDType;
#endif /* _OCSPT_H_ */

View file

@ -0,0 +1,356 @@
/* 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/. */
/*
* Private header defining OCSP types.
*/
#ifndef _OCSPTI_H_
#define _OCSPTI_H_
#include "ocspt.h"
#include "certt.h"
#include "plarena.h"
#include "seccomon.h"
#include "secoidt.h"
/*
* Some notes about naming conventions...
*
* The public data types all start with "CERTOCSP" (e.g. CERTOCSPRequest).
* (Even the public types are opaque, however. Only their names are
* "exported".)
*
* Internal-only data types drop the "CERT" prefix and use only the
* lower-case "ocsp" (e.g. ocspTBSRequest), for brevity sake.
*
* In either case, the base/suffix of the type name usually matches the
* name as defined in the OCSP specification. The exceptions to this are:
* - When there is overlap between the "OCSP" or "ocsp" prefix and
* the name used in the standard. That is, you cannot strip off the
* "CERTOCSP" or "ocsp" prefix and necessarily get the name of the
* type as it is defined in the standard; the "real" name will be
* *either* "OCSPSuffix" or just "Suffix".
* - When the name in the standard was a little too generic. (e.g. The
* standard defines "Request" but we call it a "SingleRequest".)
* In this case a comment above the type definition calls attention
* to the difference.
*
* The definitions laid out in this header file are intended to follow
* the same order as the definitions in the OCSP specification itself.
* With the OCSP standard in hand, you should be able to move through
* this file and follow along. To future modifiers of this file: please
* try to keep it that way. The only exceptions are the few cases where
* we need to define a type before it is referenced (e.g. enumerations),
* whereas in the OCSP specification these are usually defined the other
* way around (reference before definition).
*/
/*
* Forward-declarations of internal-only data structures.
*
* These are in alphabetical order (case-insensitive); please keep it that way!
*/
typedef struct ocspBasicOCSPResponseStr ocspBasicOCSPResponse;
typedef struct ocspCertStatusStr ocspCertStatus;
typedef struct ocspResponderIDStr ocspResponderID;
typedef struct ocspResponseBytesStr ocspResponseBytes;
typedef struct ocspResponseDataStr ocspResponseData;
typedef struct ocspRevokedInfoStr ocspRevokedInfo;
typedef struct ocspServiceLocatorStr ocspServiceLocator;
typedef struct ocspSignatureStr ocspSignature;
typedef struct ocspSingleRequestStr ocspSingleRequest;
typedef struct ocspSingleResponseStr ocspSingleResponse;
typedef struct ocspTBSRequestStr ocspTBSRequest;
/*
* An OCSPRequest; this is what is sent (encoded) to an OCSP responder.
*/
struct CERTOCSPRequestStr {
PLArenaPool *arena; /* local; not part of encoding */
ocspTBSRequest *tbsRequest;
ocspSignature *optionalSignature;
};
/*
* A TBSRequest; when an OCSPRequest is signed, the encoding of this
* is what the signature is actually applied to. ("TBS" == To Be Signed)
* Whether signed or not, however, this structure will be present, and
* is the "meat" of the OCSPRequest.
*
* Note that the "requestorName" field cannot be encoded/decoded in the
* same pass as the entire request -- it needs to be handled with a special
* call to convert to/from our internal form of a GeneralName. Thus the
* "derRequestorName" field, which is the actual DER-encoded bytes.
*
* The "extensionHandle" field is used on creation only; it holds
* in-progress extensions as they are optionally added to the request.
*/
struct ocspTBSRequestStr {
SECItem version; /* an INTEGER */
SECItem *derRequestorName; /* encoded GeneralName; see above */
CERTGeneralNameList *requestorName; /* local; not part of encoding */
ocspSingleRequest **requestList;
CERTCertExtension **requestExtensions;
void *extensionHandle; /* local; not part of encoding */
};
/*
* This is the actual signature information for an OCSPRequest (applied to
* the TBSRequest structure) or for a BasicOCSPResponse (applied to a
* ResponseData structure).
*
* Note that the "signature" field itself is a BIT STRING; operations on
* it need to keep that in mind, converting the length to bytes as needed
* and back again afterward (so that the length is usually expressing bits).
*
* The "cert" field is the signer's certificate. In the case of a received
* signature, it will be filled in when the signature is verified. In the
* case of a created signature, it is filled in on creation and will be the
* cert used to create the signature when the signing-and-encoding occurs,
* as well as the cert (and its chain) to fill in derCerts if requested.
*
* The extra fields cache information about the signature after we have
* attempted a verification. "wasChecked", if true, means the signature
* has been checked against the appropriate data and thus that "status"
* contains the result of that verification. If "status" is not SECSuccess,
* "failureReason" is a copy of the error code that was set at the time;
* presumably it tells why the signature verification failed.
*/
struct ocspSignatureStr {
SECAlgorithmID signatureAlgorithm;
SECItem signature; /* a BIT STRING */
SECItem **derCerts; /* a SEQUENCE OF Certificate */
CERTCertificate *cert; /* local; not part of encoding */
PRBool wasChecked; /* local; not part of encoding */
SECStatus status; /* local; not part of encoding */
int failureReason; /* local; not part of encoding */
};
/*
* An OCSPRequest contains a SEQUENCE OF these, one for each certificate
* whose status is being checked.
*
* Note that in the OCSP specification this is just called "Request",
* but since that seemed confusing (vs. an OCSPRequest) and to be more
* consistent with the parallel type "SingleResponse", I called it a
* "SingleRequest".
*
* XXX figure out how to get rid of that arena -- there must be a way
*/
struct ocspSingleRequestStr {
PLArenaPool *arena; /* just a copy of the response arena,
* needed here for extension handling
* routines, on creation only */
CERTOCSPCertID *reqCert;
CERTCertExtension **singleRequestExtensions;
};
/*
* A CertID is the means of identifying a certificate, used both in requests
* and in responses.
*
* When in a SingleRequest it specifies the certificate to be checked.
* When in a SingleResponse it is the cert whose status is being given.
*/
struct CERTOCSPCertIDStr {
SECAlgorithmID hashAlgorithm;
SECItem issuerNameHash; /* an OCTET STRING */
SECItem issuerKeyHash; /* an OCTET STRING */
SECItem serialNumber; /* an INTEGER */
SECItem issuerSHA1NameHash; /* keep other hashes around when */
SECItem issuerMD5NameHash; /* we have them */
SECItem issuerMD2NameHash;
SECItem issuerSHA1KeyHash; /* keep other hashes around when */
SECItem issuerMD5KeyHash; /* we have them */
SECItem issuerMD2KeyHash;
PLArenaPool *poolp;
};
/*
* This describes the value of the responseStatus field in an OCSPResponse.
* The corresponding ASN.1 definition is:
*
* OCSPResponseStatus ::= ENUMERATED {
* successful (0), --Response has valid confirmations
* malformedRequest (1), --Illegal confirmation request
* internalError (2), --Internal error in issuer
* tryLater (3), --Try again later
* --(4) is not used
* sigRequired (5), --Must sign the request
* unauthorized (6), --Request unauthorized
* }
*/
typedef enum {
ocspResponse_min = 0,
ocspResponse_successful = 0,
ocspResponse_malformedRequest = 1,
ocspResponse_internalError = 2,
ocspResponse_tryLater = 3,
ocspResponse_unused = 4,
ocspResponse_sigRequired = 5,
ocspResponse_unauthorized = 6,
ocspResponse_max = 6 /* Please update max when adding values.
* Remember to also update arrays, e.g.
* "responseStatusNames" in ocspclnt.c
* and potentially other places. */
} ocspResponseStatus;
/*
* An OCSPResponse is what is sent (encoded) by an OCSP responder.
*
* The field "responseStatus" is the ASN.1 encoded value; the field
* "statusValue" is simply that same value translated into our local
* type ocspResponseStatus.
*/
struct CERTOCSPResponseStr {
PLArenaPool *arena; /* local; not part of encoding */
SECItem responseStatus; /* an ENUMERATED, see above */
ocspResponseStatus statusValue; /* local; not part of encoding */
ocspResponseBytes *responseBytes; /* only when status is successful */
};
/*
* A ResponseBytes (despite appearances) is what contains the meat
* of a successful response -- but still in encoded form. The type
* given as "responseType" tells you how to decode the string.
*
* We look at the OID and translate it into our local OID representation
* "responseTypeTag", and use that value to tell us how to decode the
* actual response itself. For now the only kind of OCSP response we
* know about is a BasicOCSPResponse. However, the intention in the
* OCSP specification is to allow for other response types, so we are
* building in that flexibility from the start and thus put a pointer
* to that data structure inside of a union. Whenever OCSP adds more
* response types, just add them to the union.
*/
struct ocspResponseBytesStr {
SECItem responseType; /* an OBJECT IDENTIFIER */
SECOidTag responseTypeTag; /* local; not part of encoding */
SECItem response; /* an OCTET STRING */
union {
ocspBasicOCSPResponse *basic; /* when type is id-pkix-ocsp-basic */
} decodedResponse; /* local; not part of encoding */
};
/*
* A BasicOCSPResponse -- when the responseType in a ResponseBytes is
* id-pkix-ocsp-basic, the "response" OCTET STRING above is the DER
* encoding of one of these.
*
* Note that in the OCSP specification, the signature fields are not
* part of a separate sub-structure. But since they are the same fields
* as we define for the signature in a request, it made sense to share
* the C data structure here and in some shared code to operate on them.
*/
struct ocspBasicOCSPResponseStr {
SECItem tbsResponseDataDER;
ocspResponseData *tbsResponseData; /* "tbs" == To Be Signed */
ocspSignature responseSignature;
};
/*
* A ResponseData is the part of a BasicOCSPResponse that is signed
* (after it is DER encoded). It contains the real details of the response
* (a per-certificate status).
*/
struct ocspResponseDataStr {
SECItem version; /* an INTEGER */
SECItem derResponderID;
ocspResponderID *responderID; /* local; not part of encoding */
SECItem producedAt; /* a GeneralizedTime */
CERTOCSPSingleResponse **responses;
CERTCertExtension **responseExtensions;
};
struct ocspResponderIDStr {
CERTOCSPResponderIDType responderIDType; /* local; not part of encoding */
union {
CERTName name; /* when ocspResponderID_byName */
SECItem keyHash; /* when ocspResponderID_byKey */
SECItem other; /* when ocspResponderID_other */
} responderIDValue;
};
/*
* The ResponseData in a BasicOCSPResponse contains a SEQUENCE OF
* SingleResponse -- one for each certificate whose status is being supplied.
*
* XXX figure out how to get rid of that arena -- there must be a way
*/
struct CERTOCSPSingleResponseStr {
PLArenaPool *arena; /* just a copy of the response arena,
* needed here for extension handling
* routines, on creation only */
CERTOCSPCertID *certID;
SECItem derCertStatus;
ocspCertStatus *certStatus; /* local; not part of encoding */
SECItem thisUpdate; /* a GeneralizedTime */
SECItem *nextUpdate; /* a GeneralizedTime */
CERTCertExtension **singleExtensions;
};
/*
* A CertStatus is the actual per-certificate status. Its ASN.1 definition:
*
* CertStatus ::= CHOICE {
* good [0] IMPLICIT NULL,
* revoked [1] IMPLICIT RevokedInfo,
* unknown [2] IMPLICIT UnknownInfo }
*
* (where for now UnknownInfo is defined to be NULL but in the
* future may be replaced with an enumeration).
*
* Because it is CHOICE, the status value and its associated information
* (if any) are actually encoded together. To represent this same
* information internally, we explicitly define a type and save it,
* along with the value, into a data structure.
*/
typedef enum {
ocspCertStatus_good, /* cert is not revoked */
ocspCertStatus_revoked, /* cert is revoked */
ocspCertStatus_unknown, /* cert was unknown to the responder */
ocspCertStatus_other /* status was not an expected value */
} ocspCertStatusType;
/*
* This is the actual per-certificate status.
*
* The "goodInfo" and "unknownInfo" items are only place-holders for a NULL.
* (Though someday OCSP may replace UnknownInfo with an enumeration that
* gives more detailed information.)
*/
struct ocspCertStatusStr {
ocspCertStatusType certStatusType; /* local; not part of encoding */
union {
SECItem *goodInfo; /* when ocspCertStatus_good */
ocspRevokedInfo *revokedInfo; /* when ocspCertStatus_revoked */
SECItem *unknownInfo; /* when ocspCertStatus_unknown */
SECItem *otherInfo; /* when ocspCertStatus_other */
} certStatusInfo;
};
/*
* A RevokedInfo gives information about a revoked certificate -- when it
* was revoked and why.
*/
struct ocspRevokedInfoStr {
SECItem revocationTime; /* a GeneralizedTime */
SECItem *revocationReason; /* a CRLReason; ignored for now */
};
/*
* ServiceLocator can be included as one of the singleRequestExtensions.
* When added, it specifies the (name of the) issuer of the cert being
* checked, and optionally the value of the AuthorityInfoAccess extension
* if the cert has one.
*/
struct ocspServiceLocatorStr {
CERTName *issuer;
SECItem locator; /* DER encoded authInfoAccess extension from cert */
};
#endif /* _OCSPTI_H_ */

View file

@ -0,0 +1,212 @@
/* 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 x.509 v3 CRL Distribution Point extension.
*/
#include "genname.h"
#include "certt.h"
#include "secerr.h"
SEC_ASN1_MKSUB(SEC_AnyTemplate)
SEC_ASN1_MKSUB(SEC_BitStringTemplate)
extern void PrepareBitStringForEncoding(SECItem *bitMap, SECItem *value);
static const SEC_ASN1Template FullNameTemplate[] = {
{ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0,
offsetof(CRLDistributionPoint, derFullName),
CERT_GeneralNamesTemplate }
};
static const SEC_ASN1Template RelativeNameTemplate[] = {
{ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1,
offsetof(CRLDistributionPoint, distPoint.relativeName),
CERT_RDNTemplate }
};
static const SEC_ASN1Template DistributionPointNameTemplate[] = {
{ SEC_ASN1_CHOICE,
offsetof(CRLDistributionPoint, distPointType), NULL,
sizeof(CRLDistributionPoint) },
{ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0,
offsetof(CRLDistributionPoint, derFullName),
CERT_GeneralNamesTemplate, generalName },
{ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1,
offsetof(CRLDistributionPoint, distPoint.relativeName),
CERT_RDNTemplate, relativeDistinguishedName },
{ 0 }
};
static const SEC_ASN1Template CRLDistributionPointTemplate[] = {
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRLDistributionPoint) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0,
offsetof(CRLDistributionPoint, derDistPoint),
SEC_ASN1_SUB(SEC_AnyTemplate) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
offsetof(CRLDistributionPoint, bitsmap),
SEC_ASN1_SUB(SEC_BitStringTemplate) },
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC |
SEC_ASN1_CONSTRUCTED | 2,
offsetof(CRLDistributionPoint, derCrlIssuer),
CERT_GeneralNamesTemplate },
{ 0 }
};
const SEC_ASN1Template CERTCRLDistributionPointsTemplate[] = {
{ SEC_ASN1_SEQUENCE_OF, 0, CRLDistributionPointTemplate }
};
SECStatus
CERT_EncodeCRLDistributionPoints(PLArenaPool *arena,
CERTCrlDistributionPoints *value,
SECItem *derValue)
{
CRLDistributionPoint **pointList, *point;
PLArenaPool *ourPool = NULL;
SECStatus rv = SECSuccess;
PORT_Assert(derValue);
PORT_Assert(value && value->distPoints);
do {
ourPool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
if (ourPool == NULL) {
rv = SECFailure;
break;
}
pointList = value->distPoints;
while (*pointList) {
point = *pointList;
point->derFullName = NULL;
point->derDistPoint.data = NULL;
switch (point->distPointType) {
case generalName:
point->derFullName = cert_EncodeGeneralNames(ourPool, point->distPoint.fullName);
if (!point->derFullName ||
!SEC_ASN1EncodeItem(ourPool, &point->derDistPoint,
point, FullNameTemplate))
rv = SECFailure;
break;
case relativeDistinguishedName:
if (!SEC_ASN1EncodeItem(ourPool, &point->derDistPoint,
point, RelativeNameTemplate))
rv = SECFailure;
break;
default:
PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
rv = SECFailure;
break;
}
if (rv != SECSuccess)
break;
if (point->reasons.data)
PrepareBitStringForEncoding(&point->bitsmap, &point->reasons);
if (point->crlIssuer) {
point->derCrlIssuer = cert_EncodeGeneralNames(ourPool, point->crlIssuer);
if (!point->derCrlIssuer) {
rv = SECFailure;
break;
}
}
++pointList;
}
if (rv != SECSuccess)
break;
if (!SEC_ASN1EncodeItem(arena, derValue, value,
CERTCRLDistributionPointsTemplate)) {
rv = SECFailure;
break;
}
} while (0);
PORT_FreeArena(ourPool, PR_FALSE);
return rv;
}
CERTCrlDistributionPoints *
CERT_DecodeCRLDistributionPoints(PLArenaPool *arena, SECItem *encodedValue)
{
CERTCrlDistributionPoints *value = NULL;
CRLDistributionPoint **pointList, *point;
SECStatus rv = SECSuccess;
SECItem newEncodedValue;
PORT_Assert(arena);
do {
value = PORT_ArenaZNew(arena, CERTCrlDistributionPoints);
if (value == NULL) {
rv = SECFailure;
break;
}
/* 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->distPoints,
CERTCRLDistributionPointsTemplate, &newEncodedValue);
if (rv != SECSuccess)
break;
pointList = value->distPoints;
while (NULL != (point = *pointList)) {
/* get the data if the distributionPointName is not omitted */
if (point->derDistPoint.data != NULL) {
rv = SEC_QuickDERDecodeItem(arena, point,
DistributionPointNameTemplate, &(point->derDistPoint));
if (rv != SECSuccess)
break;
switch (point->distPointType) {
case generalName:
point->distPoint.fullName =
cert_DecodeGeneralNames(arena, point->derFullName);
rv = point->distPoint.fullName ? SECSuccess : SECFailure;
break;
case relativeDistinguishedName:
break;
default:
PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID);
rv = SECFailure;
break;
} /* end switch */
if (rv != SECSuccess)
break;
} /* end if */
/* Get the reason code if it's not omitted in the encoding */
if (point->bitsmap.data != NULL) {
SECItem bitsmap = point->bitsmap;
DER_ConvertBitString(&bitsmap);
rv = SECITEM_CopyItem(arena, &point->reasons, &bitsmap);
if (rv != SECSuccess)
break;
}
/* Get the crl issuer name if it's not omitted in the encoding */
if (point->derCrlIssuer != NULL) {
point->crlIssuer = cert_DecodeGeneralNames(arena,
point->derCrlIssuer);
if (!point->crlIssuer)
break;
}
++pointList;
} /* end while points remain */
} while (0);
return (rv == SECSuccess ? value : NULL);
}