summaryrefslogtreecommitdiff
path: root/security/nss/lib/certhigh
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/certhigh')
-rw-r--r--security/nss/lib/certhigh/certhigh.c19
-rw-r--r--security/nss/lib/certhigh/certvfy.c53
-rw-r--r--security/nss/lib/certhigh/manifest.mn1
-rw-r--r--security/nss/lib/certhigh/ocsp.c279
-rw-r--r--security/nss/lib/certhigh/ocsp.h12
-rw-r--r--security/nss/lib/certhigh/ocspi.h47
-rw-r--r--security/nss/lib/certhigh/ocspt.h231
7 files changed, 555 insertions, 87 deletions
diff --git a/security/nss/lib/certhigh/certhigh.c b/security/nss/lib/certhigh/certhigh.c
index 2c0ffe7cb..ea7f50a0e 100644
--- a/security/nss/lib/certhigh/certhigh.c
+++ b/security/nss/lib/certhigh/certhigh.c
@@ -443,15 +443,16 @@ CollectNicknames( NSSCertificate *c, void *data)
/* allocate the node */
node = (stringNode*)PORT_ArenaAlloc(names->arena, sizeof(stringNode));
if ( node == NULL ) {
- return(PR_FAILURE);
+ PORT_Free(nickname);
+ return PR_FAILURE;
}
/* copy the string */
len = PORT_Strlen(nickname) + 1;
node->string = (char*)PORT_ArenaAlloc(names->arena, len);
if ( node->string == NULL ) {
- if (nickname) PORT_Free(nickname);
- return(PR_FAILURE);
+ PORT_Free(nickname);
+ return PR_FAILURE;
}
PORT_Memcpy(node->string, nickname, len);
@@ -494,7 +495,7 @@ CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx)
names->totallen = 0;
/* make sure we are logged in */
- (void) pk11_TraverseAllSlots(NULL, NULL, wincx);
+ (void) pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
NSSTrustDomain_TraverseCertificates(handle,
CollectNicknames, (void *)names);
@@ -672,12 +673,12 @@ CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) goto loser;
- dnames = (CERTDistNames*)PORT_Alloc(sizeof(CERTDistNames));
+ dnames = PORT_ArenaZNew(arena, CERTDistNames);
if (dnames == NULL) goto loser;
dnames->arena = arena;
dnames->nnames = nnames;
- dnames->names = names = (SECItem*)PORT_Alloc(nnames * sizeof(SECItem));
+ dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames);
if (names == NULL) goto loser;
for (i = 0; i < nnames; i++) {
@@ -720,11 +721,9 @@ CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
if ( name ) {
nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name,
CERT_NameTemplate);
- if ( nameItem == NULL ) {
- goto loser;
+ if ( nameItem != NULL ) {
+ cert = CERT_FindCertByName(handle, nameItem);
}
-
- cert = CERT_FindCertByName(handle, nameItem);
CERT_DestroyName(name);
}
diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c
index 25d0eaf42..b57720d68 100644
--- a/security/nss/lib/certhigh/certvfy.c
+++ b/security/nss/lib/certhigh/certvfy.c
@@ -101,7 +101,6 @@ CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd,
void *wincx)
{
SECStatus rv;
- SECOidTag algid;
SECItem sig;
if ( !pubKey || !sd ) {
@@ -114,9 +113,8 @@ CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd,
/* convert sig->len from bit counts to byte count. */
DER_ConvertBitString(&sig);
- algid = SECOID_GetAlgorithmTag(&sd->signatureAlgorithm);
- rv = VFY_VerifyData(sd->data.data, sd->data.len, pubKey, &sig,
- algid, wincx);
+ rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey,
+ &sig, &sd->signatureAlgorithm, NULL, wincx);
return rv ? SECFailure : SECSuccess;
}
@@ -362,20 +360,20 @@ loser:
chain, 2, NULL, &status, td, cc);
nss_ZFreeIf(nssTime);
if (status == PR_SUCCESS) {
+ PORT_Assert(me == chain[0]);
/* if it's a root, the chain will only have one cert */
if (!chain[1]) {
/* already has a reference from the call to BuildChain */
return cert;
- } else {
- CERT_DestroyCertificate(cert); /* the first cert in the chain */
- return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */
- }
- } else {
- if (chain[0]) {
- CERT_DestroyCertificate(cert);
- }
- PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
- }
+ }
+ NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
+ return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */
+ }
+ if (chain[0]) {
+ PORT_Assert(me == chain[0]);
+ NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */
+ }
+ PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER);
return NULL;
#endif
}
@@ -729,6 +727,13 @@ cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert,
namesCount += subjectNameListLen;
namesList = cert_CombineNamesLists(namesList, subjectNameList);
}
+
+ /* check if the cert has an unsupported critical extension */
+ if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) {
+ PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ LOG_ERROR_OR_EXIT(log,subjectCert,count,0);
+ }
+
/* find the certificate of the issuer */
issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage);
if ( ! issuerCert ) {
@@ -1207,30 +1212,21 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
}
valid = SECSuccess ; /* start off assuming cert is valid */
-#ifdef notdef
- /* check if this cert is in the Evil list */
- rv = CERT_CheckForEvilCert(cert);
- if ( rv != SECSuccess ) {
- PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
- LOG_ERROR(log,cert,0,0);
- return SECFailure;
- }
-#endif
-
/* make sure that the cert is valid at time t */
allowOverride = (PRBool)((requiredUsages & certificateUsageSSLServer) ||
(requiredUsages & certificateUsageSSLServerWithStepUp));
validity = CERT_CheckCertValidTimes(cert, t, allowOverride);
if ( validity != secCertTimeValid ) {
- LOG_ERROR(log,cert,0,validity);
- return SECFailure;
+ valid = SECFailure;
+ LOG_ERROR_OR_EXIT(log,cert,0,validity);
}
/* check key usage and netscape cert type */
cert_GetCertType(cert);
certType = cert->nsCertType;
- for (i=1;i<=certificateUsageHighest && !(SECFailure == valid && !returnedUsages) ;) {
+ for (i=1; i<=certificateUsageHighest &&
+ (SECSuccess == valid || returnedUsages || log) ; ) {
PRBool requiredUsage = (i & requiredUsages) ? PR_TRUE : PR_FALSE;
if (PR_FALSE == requiredUsage && PR_FALSE == checkAllUsages) {
NEXT_USAGE();
@@ -1394,7 +1390,7 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
if (PR_FALSE == checkedOCSP) {
checkedOCSP = PR_TRUE; /* only check OCSP once */
statusConfig = CERT_GetStatusConfig(handle);
- if ( (! (requiredUsages & certificateUsageStatusResponder)) &&
+ if ( (! (requiredUsages == certificateUsageStatusResponder)) &&
statusConfig != NULL) {
if (statusConfig->statusChecker != NULL) {
rv = (* statusConfig->statusChecker)(handle, cert,
@@ -1411,6 +1407,7 @@ CERT_VerifyCertificate(CERTCertDBHandle *handle, CERTCertificate *cert,
NEXT_USAGE();
}
+loser:
return(valid);
}
diff --git a/security/nss/lib/certhigh/manifest.mn b/security/nss/lib/certhigh/manifest.mn
index bd8de3771..98eb9876d 100644
--- a/security/nss/lib/certhigh/manifest.mn
+++ b/security/nss/lib/certhigh/manifest.mn
@@ -43,6 +43,7 @@ EXPORTS = \
PRIVATE_EXPORTS = \
ocspti.h \
+ ocspi.h \
$(NULL)
MODULE = nss
diff --git a/security/nss/lib/certhigh/ocsp.c b/security/nss/lib/certhigh/ocsp.c
index 9eda390b4..183f9b902 100644
--- a/security/nss/lib/certhigh/ocsp.c
+++ b/security/nss/lib/certhigh/ocsp.c
@@ -68,6 +68,59 @@
#include <stdarg.h>
+static struct OCSPGlobalStruct {
+ PRLock *lock;
+ const SEC_HttpClientFcn *defaultHttpClientFcn;
+} OCSP_Global = { NULL, NULL };
+
+SECStatus
+SEC_RegisterDefaultHttpClient(const SEC_HttpClientFcn *fcnTable)
+{
+ if (!OCSP_Global.lock) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ PR_Lock(OCSP_Global.lock);
+ OCSP_Global.defaultHttpClientFcn = fcnTable;
+ PR_Unlock(OCSP_Global.lock);
+
+ return SECSuccess;
+}
+
+/* this function is called at NSS initialization time */
+SECStatus InitOCSPGlobal(void)
+{
+ if (OCSP_Global.lock != NULL) {
+ /* already initialized */
+ return SECSuccess;
+ }
+
+ OCSP_Global.lock = PR_NewLock();
+
+ return (OCSP_Global.lock) ? SECSuccess : SECFailure;
+}
+
+/*
+ * A return value of NULL means:
+ * The application did not register it's own HTTP client.
+ */
+static const SEC_HttpClientFcn *GetRegisteredHttpClient()
+{
+ const SEC_HttpClientFcn *retval;
+
+ if (!OCSP_Global.lock) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return NULL;
+ }
+
+ PR_Lock(OCSP_Global.lock);
+ retval = OCSP_Global.defaultHttpClientFcn;
+ PR_Unlock(OCSP_Global.lock);
+
+ return retval;
+}
+
/*
* The following structure is only used internally. It is allocated when
* someone turns on OCSP checking, and hangs off of the status-configuration
@@ -801,6 +854,7 @@ ocsp_AddServiceLocatorExtension(ocspSingleRequest *singleRequest,
/* prepare for following loser gotos */
rv = SECFailure;
+ PORT_SetError(0);
extensionHandle = cert_StartExtensions(singleRequest,
singleRequest->arena, SetSingleReqExts);
@@ -1702,6 +1756,8 @@ ocsp_ParseURL(char *url, char **pHostname, PRUint16 *pPort, char **pPath)
path[len] = '\0';
} else {
path = PORT_Strdup("/");
+ if (path == NULL)
+ goto loser;
}
*pHostname = hostname;
@@ -1712,8 +1768,6 @@ ocsp_ParseURL(char *url, char **pHostname, PRUint16 *pPort, char **pPath)
loser:
if (hostname != NULL)
PORT_Free(hostname);
- if (path != NULL)
- PORT_Free(path);
PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
return SECFailure;
}
@@ -2133,6 +2187,110 @@ ocsp_GetEncodedResponse(PRArenaPool *arena, PRFileDesc *sock)
return result;
}
+/*
+ * Limit the size of http responses we are willing to accept.
+ */
+#define MAX_WANTED_OCSP_RESPONSE_LEN 64*1024
+
+static SECItem *
+fetchOcspHttpClientV1(PRArenaPool *arena,
+ const SEC_HttpClientFcnV1 *hcv1,
+ char *location,
+ SECItem *encodedRequest)
+{
+ char *hostname = NULL;
+ char *path = NULL;
+ PRUint16 port;
+ SECItem *encodedResponse = NULL;
+ SEC_HTTP_SERVER_SESSION pServerSession = NULL;
+ SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
+ PRUint16 myHttpResponseCode;
+ const char *myHttpResponseData;
+ PRUint32 myHttpResponseDataLen;
+
+ if (ocsp_ParseURL(location, &hostname, &port, &path) == SECFailure) {
+ PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
+ goto loser;
+ }
+
+ PORT_Assert(hostname != NULL);
+ PORT_Assert(path != NULL);
+
+ if ((*hcv1->createSessionFcn)(
+ hostname,
+ port,
+ &pServerSession) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+ goto loser;
+ }
+
+ /* We use a non-zero timeout, which means:
+ - the client will use blocking I/O
+ - TryFcn will not return WOULD_BLOCK nor a poll descriptor
+ - it's sufficient to call TryFcn once
+ */
+
+ if ((*hcv1->createFcn)(
+ pServerSession,
+ "http",
+ path,
+ "POST",
+ PR_TicksPerSecond() * 60,
+ &pRequestSession) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+ goto loser;
+ }
+
+ if ((*hcv1->setPostDataFcn)(
+ pRequestSession,
+ (char*)encodedRequest->data,
+ encodedRequest->len,
+ "application/ocsp-request") != SECSuccess) {
+ PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+ goto loser;
+ }
+
+ /* we don't want result objects larger than this: */
+ myHttpResponseDataLen = MAX_WANTED_OCSP_RESPONSE_LEN;
+
+ if ((*hcv1->trySendAndReceiveFcn)(
+ pRequestSession,
+ NULL,
+ &myHttpResponseCode,
+ NULL,
+ NULL,
+ &myHttpResponseData,
+ &myHttpResponseDataLen) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
+ goto loser;
+ }
+
+ if (myHttpResponseCode != 200) {
+ PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+ goto loser;
+ }
+
+ encodedResponse = SECITEM_AllocItem(arena, NULL, myHttpResponseDataLen);
+
+ if (!encodedResponse) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto loser;
+ }
+
+ PORT_Memcpy(encodedResponse->data, myHttpResponseData, myHttpResponseDataLen);
+
+loser:
+ if (pRequestSession != NULL)
+ (*hcv1->freeFcn)(pRequestSession);
+ if (pServerSession != NULL)
+ (*hcv1->freeSessionFcn)(pServerSession);
+ if (path != NULL)
+ PORT_Free(path);
+ if (hostname != NULL)
+ PORT_Free(hostname);
+
+ return encodedResponse;
+}
/*
* FUNCTION: CERT_GetEncodedOCSPResponse
@@ -2192,6 +2350,7 @@ CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList,
SECItem *encodedResponse = NULL;
PRFileDesc *sock = NULL;
SECStatus rv;
+ const SEC_HttpClientFcn *registeredHttpClient = NULL;
request = CERT_CreateOCSPRequest(certList, time, addServiceLocator,
signerCert);
@@ -2207,11 +2366,27 @@ CERT_GetEncodedOCSPResponse(PRArenaPool *arena, CERTCertList *certList,
if (encodedRequest == NULL)
goto loser;
- sock = ocsp_SendEncodedRequest(location, encodedRequest);
- if (sock == NULL)
- goto loser;
+ registeredHttpClient = GetRegisteredHttpClient();
+
+ if (registeredHttpClient
+ &&
+ registeredHttpClient->version == 1) {
+ encodedResponse = fetchOcspHttpClientV1(
+ arena,
+ &registeredHttpClient->fcnTable.ftable1,
+ location,
+ encodedRequest);
+ }
+ else {
+ /* use internal http client */
+
+ sock = ocsp_SendEncodedRequest(location, encodedRequest);
+ if (sock == NULL)
+ goto loser;
+
+ encodedResponse = ocsp_GetEncodedResponse(arena, sock);
+ }
- encodedResponse = ocsp_GetEncodedResponse(arena, sock);
if (encodedResponse != NULL && pRequest != NULL) {
*pRequest = request;
request = NULL; /* avoid destroying below */
@@ -2268,6 +2443,7 @@ ocsp_CertIsOCSPSigner(CERTCertificate *cert)
loser:
retval = PR_FALSE;
+ PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
goto done;
success:
retval = PR_TRUE;
@@ -2453,7 +2629,7 @@ ocsp_CheckSignature(ocspSignature *signature, void *tbs,
rv = SECFailure;
if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) {
/* Make the error a little more specific. */
- PORT_SetError(SEC_ERROR_UNKNOWN_SIGNER);
+ PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
}
goto finish;
}
@@ -2504,10 +2680,9 @@ ocsp_CheckSignature(ocspSignature *signature, void *tbs,
*/
DER_ConvertBitString(&rawSignature);
- rv = VFY_VerifyData(encodedTBS->data, encodedTBS->len, signerKey,
- &rawSignature,
- SECOID_GetAlgorithmTag(&signature->signatureAlgorithm),
- pwArg);
+ rv = VFY_VerifyDataWithAlgorithmID(encodedTBS->data, encodedTBS->len,
+ signerKey, &rawSignature,
+ &signature->signatureAlgorithm, NULL, pwArg);
finish:
if (signature->wasChecked)
@@ -2622,15 +2797,16 @@ CERT_VerifyOCSPResponseSignature(CERTOCSPResponse *response,
}
/*
- * See if two certIDs match. This can be easy or difficult, depending
- * on whether the same hash algorithm was used.
+ * See if the request's certID and the single response's certID match.
+ * This can be easy or difficult, depending on whether the same hash
+ * algorithm was used.
*/
static PRBool
ocsp_CertIDsMatch(CERTCertDBHandle *handle,
- CERTOCSPCertID *certID1, CERTOCSPCertID *certID2)
+ CERTOCSPCertID *requestCertID,
+ CERTOCSPCertID *responseCertID)
{
PRBool match = PR_FALSE;
- SECItem *foundHash = NULL;
SECOidTag hashAlg;
SECItem *keyHash = NULL;
SECItem *nameHash = NULL;
@@ -2641,52 +2817,54 @@ ocsp_CertIDsMatch(CERTCertDBHandle *handle,
*
* We just compare the easier things first.
*/
- if (SECITEM_CompareItem(&certID1->serialNumber,
- &certID2->serialNumber) != SECEqual) {
+ if (SECITEM_CompareItem(&requestCertID->serialNumber,
+ &responseCertID->serialNumber) != SECEqual) {
goto done;
}
- if (SECOID_CompareAlgorithmID(&certID1->hashAlgorithm,
- &certID2->hashAlgorithm) == SECEqual) {
+ /*
+ * Make sure the "parameters" are not too bogus. Since we encoded
+ * requestCertID->hashAlgorithm, we don't need to check it.
+ */
+ if (responseCertID->hashAlgorithm.parameters.len > 2) {
+ goto done;
+ }
+ if (SECITEM_CompareItem(&requestCertID->hashAlgorithm.algorithm,
+ &responseCertID->hashAlgorithm.algorithm) == SECEqual) {
/*
* If the hash algorithms match then we can do a simple compare
* of the hash values themselves.
*/
- if ((SECITEM_CompareItem(&certID1->issuerNameHash,
- &certID2->issuerNameHash) == SECEqual)
- && (SECITEM_CompareItem(&certID1->issuerKeyHash,
- &certID2->issuerKeyHash) == SECEqual)) {
+ if ((SECITEM_CompareItem(&requestCertID->issuerNameHash,
+ &responseCertID->issuerNameHash) == SECEqual)
+ && (SECITEM_CompareItem(&requestCertID->issuerKeyHash,
+ &responseCertID->issuerKeyHash) == SECEqual)) {
match = PR_TRUE;
}
goto done;
}
- hashAlg = SECOID_FindOIDTag(&certID2->hashAlgorithm.algorithm);
+ hashAlg = SECOID_FindOIDTag(&responseCertID->hashAlgorithm.algorithm);
switch (hashAlg) {
case SEC_OID_SHA1:
- keyHash = &certID1->issuerSHA1KeyHash;
- nameHash = &certID1->issuerSHA1NameHash;
+ keyHash = &requestCertID->issuerSHA1KeyHash;
+ nameHash = &requestCertID->issuerSHA1NameHash;
break;
case SEC_OID_MD5:
- keyHash = &certID1->issuerMD5KeyHash;
- nameHash = &certID1->issuerMD5NameHash;
+ keyHash = &requestCertID->issuerMD5KeyHash;
+ nameHash = &requestCertID->issuerMD5NameHash;
break;
case SEC_OID_MD2:
- keyHash = &certID1->issuerMD2KeyHash;
- nameHash = &certID1->issuerMD2NameHash;
- break;
- default:
- foundHash = NULL;
+ keyHash = &requestCertID->issuerMD2KeyHash;
+ nameHash = &requestCertID->issuerMD2NameHash;
break;
}
- if (foundHash == NULL) {
- goto done;
- }
- PORT_Assert(keyHash && nameHash);
-
- if ((SECITEM_CompareItem(nameHash, &certID2->issuerNameHash) == SECEqual)
- && (SECITEM_CompareItem(keyHash, &certID2->issuerKeyHash) == SECEqual)) {
+ if ((keyHash != NULL)
+ && (SECITEM_CompareItem(nameHash,
+ &responseCertID->issuerNameHash) == SECEqual)
+ && (SECITEM_CompareItem(keyHash,
+ &responseCertID->issuerKeyHash) == SECEqual)) {
match = PR_TRUE;
}
@@ -3025,7 +3203,7 @@ ocsp_VerifySingleResponse(CERTOCSPSingleResponse *single,
* 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.
+ * SEC_ERROR_CERT_BAD_ACCESS_LOCATION 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.
@@ -3053,8 +3231,10 @@ CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert)
rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS,
encodedAuthInfoAccess);
- if (rv == SECFailure)
+ if (rv == SECFailure) {
+ PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
goto loser;
+ }
/*
* The rest of the things allocated in the routine will come out of
@@ -3084,7 +3264,7 @@ CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert)
* not there at all.
*/
if (locname == NULL) {
- PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
+ PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
goto loser;
}
@@ -3101,7 +3281,7 @@ CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert)
* this should probably be something more like the extension was
* badly formed.
*/
- PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
+ PORT_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION);
goto loser;
}
@@ -3307,10 +3487,13 @@ CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
*/
location = ocsp_GetResponderLocation(handle, cert, &locationIsDefault);
if (location == NULL) {
- if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND)
+ int err = PORT_GetError();
+ if (err == SEC_ERROR_EXTENSION_NOT_FOUND ||
+ err == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) {
+ PORT_SetError(0);
return SECSuccess;
- else
- return SECFailure;
+ }
+ return SECFailure;
}
/*
@@ -3590,8 +3773,6 @@ ocsp_InitStatusChecking(CERTCertDBHandle *handle)
return SECSuccess;
loser:
- if (statusContext != NULL)
- PORT_Free(statusContext);
if (statusConfig != NULL)
PORT_Free(statusConfig);
return SECFailure;
diff --git a/security/nss/lib/certhigh/ocsp.h b/security/nss/lib/certhigh/ocsp.h
index c188f6780..810bc010c 100644
--- a/security/nss/lib/certhigh/ocsp.h
+++ b/security/nss/lib/certhigh/ocsp.h
@@ -56,6 +56,18 @@
SEC_BEGIN_PROTOS
/*
+ * This function registers the HttpClient with whose functions the
+ * HttpClientFcn structure have 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);
+
+/*
* FUNCTION: CERT_EnableOCSPChecking
* Turns on OCSP checking for the given certificate database.
* INPUTS:
diff --git a/security/nss/lib/certhigh/ocspi.h b/security/nss/lib/certhigh/ocspi.h
new file mode 100644
index 000000000..a1c1ccb78
--- /dev/null
+++ b/security/nss/lib/certhigh/ocspi.h
@@ -0,0 +1,47 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * ocspi.h - NSS internal interfaces to OCSP code
+ *
+ * $Id$
+ */
+
+#ifndef _OCSPI_H_
+#define _OCSPI_H_
+
+SECStatus InitOCSPGlobal(void);
+
+#endif /* _OCSPI_H_ */
diff --git a/security/nss/lib/certhigh/ocspt.h b/security/nss/lib/certhigh/ocspt.h
index 5171d9cdb..18ca8ecb6 100644
--- a/security/nss/lib/certhigh/ocspt.h
+++ b/security/nss/lib/certhigh/ocspt.h
@@ -59,4 +59,235 @@ typedef struct CERTOCSPCertIDStr CERTOCSPCertID;
typedef struct CERTOCSPCertStatusStr CERTOCSPCertStatus;
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;
+
#endif /* _OCSPT_H_ */