diff options
Diffstat (limited to 'security/nss/lib/certhigh')
-rw-r--r-- | security/nss/lib/certhigh/certhigh.c | 19 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certvfy.c | 53 | ||||
-rw-r--r-- | security/nss/lib/certhigh/manifest.mn | 1 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocsp.c | 279 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocsp.h | 12 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocspi.h | 47 | ||||
-rw-r--r-- | security/nss/lib/certhigh/ocspt.h | 231 |
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, + ®isteredHttpClient->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_ */ |