gecko/security/nss/lib/libpkix/pkix/checker/pkix_ocspchecker.c
2008-06-06 08:40:11 -04:00

449 lines
14 KiB
C

/* ***** 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 PKIX-C library.
*
* The Initial Developer of the Original Code is
* Sun Microsystems, Inc.
* Portions created by the Initial Developer are
* Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
*
* Contributor(s):
* Sun Microsystems, Inc.
* Red Hat, Inc.
*
* 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 ***** */
/*
* pkix_ocspchecker.c
*
* OcspChecker Object Functions
*
*/
#include "pkix_ocspchecker.h"
#include "pkix_pl_ocspcertid.h"
#include "pkix_error.h"
/* --Private-Functions-------------------------------------------- */
/*
* FUNCTION: pkix_OcspChecker_Destroy
* (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_OcspChecker_Destroy(
PKIX_PL_Object *object,
void *plContext)
{
PKIX_OcspChecker *checker = NULL;
PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_Destroy");
PKIX_NULLCHECK_ONE(object);
/* Check that this object is a ocsp checker */
PKIX_CHECK(pkix_CheckType
(object, PKIX_OCSPCHECKER_TYPE, plContext),
PKIX_OBJECTNOTOCSPCHECKER);
checker = (PKIX_OcspChecker *)object;
PKIX_DECREF(checker->response);
PKIX_DECREF(checker->validityTime);
PKIX_DECREF(checker->cert);
/* These are not yet ref-counted objects */
/* PKIX_DECREF(checker->passwordInfo); */
/* PKIX_DECREF(checker->responder); */
/* PKIX_DECREF(checker->nbioContext); */
cleanup:
PKIX_RETURN(OCSPCHECKER);
}
/*
* FUNCTION: pkix_OcspChecker_RegisterSelf
* DESCRIPTION:
* Registers PKIX_OCSPCHECKER_TYPE and its related functions with
* systemClasses[]
* THREAD SAFETY:
* Not Thread Safe - for performance and complexity reasons
*
* Since this function is only called by PKIX_PL_Initialize, which should
* only be called once, it is acceptable that this function is not
* thread-safe.
*/
PKIX_Error *
pkix_OcspChecker_RegisterSelf(void *plContext)
{
extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
pkix_ClassTable_Entry entry;
PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_RegisterSelf");
entry.description = "OcspChecker";
entry.objCounter = 0;
entry.typeObjectSize = sizeof(PKIX_OcspChecker);
entry.destructor = pkix_OcspChecker_Destroy;
entry.equalsFunction = NULL;
entry.hashcodeFunction = NULL;
entry.toStringFunction = NULL;
entry.comparator = NULL;
entry.duplicateFunction = NULL;
systemClasses[PKIX_OCSPCHECKER_TYPE] = entry;
PKIX_RETURN(OCSPCHECKER);
}
/* --Public-Functions--------------------------------------------- */
/*
* FUNCTION: pkix_OcspChecker_Check (see comments in pkix_checker.h)
*/
/*
* The OCSPChecker is created in an idle state, and remains in this state until
* either (a) the default Responder has been set and enabled, and a Check
* request is received with no responder specified, or (b) a Check request is
* received with a specified responder. A request message is constructed and
* given to the HttpClient. If non-blocking I/O is used the client may return
* with WOULDBLOCK, in which case the OCSPChecker returns the WOULDBLOCK
* condition to its caller in turn. On a subsequent call the I/O is resumed.
* When a response is received it is decoded and the results provided to the
* caller.
*
*/
static PKIX_Error *
pkix_OcspChecker_Check(
PKIX_PL_Object *checkerObject,
PKIX_PL_Cert *cert,
PKIX_ProcessingParams *procParams,
void **pNBIOContext,
PKIX_UInt32 *pResultCode,
void *plContext)
{
SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP;
PKIX_Boolean uriFound = PKIX_FALSE;
PKIX_Boolean passed = PKIX_FALSE;
PKIX_OcspChecker *checker = NULL;
PKIX_PL_OcspCertID *cid = NULL;
PKIX_PL_OcspRequest *request = NULL;
PKIX_PL_Date *validity = NULL;
void *nbioContext = NULL;
PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_Check");
PKIX_NULLCHECK_FOUR(checkerObject, cert, pNBIOContext, pResultCode);
PKIX_CHECK(pkix_CheckType
(checkerObject, PKIX_OCSPCHECKER_TYPE, plContext),
PKIX_OBJECTNOTOCSPCHECKER);
checker = (PKIX_OcspChecker *)checkerObject;
nbioContext = *pNBIOContext;
*pNBIOContext = 0;
/* assert(checker->nbioContext == nbioContext) */
if (nbioContext == 0) {
/* We are initiating a check, not resuming previous I/O. */
PKIX_Boolean hasFreshStatus = PKIX_FALSE;
PKIX_Boolean statusIsGood = PKIX_FALSE;
PKIX_CHECK(PKIX_PL_OcspCertID_Create
(cert,
validity,
&cid,
plContext),
PKIX_OCSPCERTIDCREATEFAILED);
if (!cid) {
goto cleanup;
}
PKIX_CHECK(PKIX_PL_OcspCertID_GetFreshCacheStatus
(cid,
validity,
&hasFreshStatus,
&statusIsGood,
&resultCode,
plContext),
PKIX_OCSPCERTIDGETFRESHCACHESTATUSFAILED);
if (hasFreshStatus) {
/* avoid updating the cache with a cached result... */
passed = PKIX_TRUE;
if (statusIsGood) {
resultCode = 0;
}
goto cleanup;
}
PKIX_INCREF(cert);
PKIX_DECREF(checker->cert);
checker->cert = cert;
/* create request */
PKIX_CHECK(pkix_pl_OcspRequest_Create
(cert,
cid,
validity,
PKIX_FALSE, /* PKIX_Boolean addServiceLocator */
NULL, /* PKIX_PL_Cert *signerCert */
&uriFound,
&request,
plContext),
PKIX_OCSPREQUESTCREATEFAILED);
/* No uri to check is considered passing! */
if (uriFound == PKIX_FALSE) {
/* no caching for certs lacking URI */
passed = PKIX_TRUE;
resultCode = 0;
goto cleanup;
}
}
/* Do we already have a response object? */
if ((checker->response) == NULL) {
/* send request and create a response object */
PKIX_CHECK(pkix_pl_OcspResponse_Create
(request,
checker->responder,
checker->verifyFcn,
&nbioContext,
&(checker->response),
plContext),
PKIX_OCSPRESPONSECREATEFAILED);
if (nbioContext != 0) {
*pNBIOContext = nbioContext;
goto cleanup;
}
PKIX_CHECK(pkix_pl_OcspResponse_Decode
((checker->response), &passed, &resultCode, plContext),
PKIX_OCSPRESPONSEDECODEFAILED);
if (passed == PKIX_FALSE) {
goto cleanup;
}
PKIX_CHECK(pkix_pl_OcspResponse_GetStatus
((checker->response), &passed, &resultCode, plContext),
PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR);
if (passed == PKIX_FALSE) {
goto cleanup;
}
}
PKIX_CHECK(pkix_pl_OcspResponse_VerifySignature
((checker->response),
cert,
procParams,
&passed,
&nbioContext,
plContext),
PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED);
if (nbioContext != 0) {
*pNBIOContext = nbioContext;
goto cleanup;
}
if (passed == PKIX_FALSE) {
resultCode = PORT_GetError();
goto cleanup;
}
PKIX_CHECK(pkix_pl_OcspResponse_GetStatusForCert
(cid, (checker->response), &passed, &resultCode, plContext),
PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED);
cleanup:
if (!passed && cid && cid->certID && !cid->certIDWasConsumed) {
/* We still own the certID object, which means that
* it did not get consumed to create a cache entry.
* Let's make sure we create one.
*/
PKIX_Error *err;
err = PKIX_PL_OcspCertID_RememberOCSPProcessingFailure(
cid, plContext);
if (err) {
PKIX_PL_Object_DecRef((PKIX_PL_Object*)err, plContext);
}
}
*pResultCode = (PKIX_UInt32)resultCode;
PKIX_DECREF(cid);
PKIX_DECREF(request);
if (checker) {
PKIX_DECREF(checker->response);
}
PKIX_RETURN(OCSPCHECKER);
}
/*
* FUNCTION: pkix_OcspChecker_Create
*/
PKIX_Error *
pkix_OcspChecker_Create(
PKIX_PL_Date *validityTime,
void *passwordInfo,
void *responder,
PKIX_OcspChecker **pChecker,
void *plContext)
{
PKIX_OcspChecker *checkerObject = NULL;
PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_Create");
PKIX_NULLCHECK_ONE(pChecker);
PKIX_CHECK(PKIX_PL_Object_Alloc
(PKIX_OCSPCHECKER_TYPE,
sizeof (PKIX_OcspChecker),
(PKIX_PL_Object **)&checkerObject,
plContext),
PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT);
/* initialize fields */
checkerObject->response = NULL;
PKIX_INCREF(validityTime);
checkerObject->validityTime = validityTime;
checkerObject->clientIsDefault = PKIX_FALSE;
checkerObject->verifyFcn = NULL;
checkerObject->cert = NULL;
/* These void*'s will need INCREFs if they become PKIX_PL_Objects */
checkerObject->passwordInfo = passwordInfo;
checkerObject->responder = responder;
checkerObject->nbioContext = NULL;
*pChecker = checkerObject;
checkerObject = NULL;
cleanup:
PKIX_DECREF(checkerObject);
PKIX_RETURN(OCSPCHECKER);
}
/*
* FUNCTION: PKIX_OcspChecker_SetPasswordInfo
* (see comments in pkix_checker.h)
*/
PKIX_Error *
PKIX_OcspChecker_SetPasswordInfo(
PKIX_OcspChecker *checker,
void *passwordInfo,
void *plContext)
{
PKIX_ENTER(OCSPCHECKER, "PKIX_OcspChecker_SetPasswordInfo");
PKIX_NULLCHECK_ONE(checker);
checker->passwordInfo = passwordInfo;
PKIX_RETURN(OCSPCHECKER);
}
/*
* FUNCTION: PKIX_OcspChecker_SetOCSPResponder
* (see comments in pkix_checker.h)
*/
PKIX_Error *
PKIX_OcspChecker_SetOCSPResponder(
PKIX_OcspChecker *checker,
void *ocspResponder,
void *plContext)
{
PKIX_ENTER(OCSPCHECKER, "PKIX_OcspChecker_SetOCSPResponder");
PKIX_NULLCHECK_ONE(checker);
checker->responder = ocspResponder;
PKIX_RETURN(OCSPCHECKER);
}
/*
* FUNCTION: PKIX_OcspChecker_SetVerifyFcn
* (see comments in pkix_checker.h)
*/
PKIX_Error *
PKIX_OcspChecker_SetVerifyFcn(
PKIX_OcspChecker *checker,
PKIX_PL_OcspResponse_VerifyCallback verifyFcn,
void *plContext)
{
PKIX_ENTER(OCSPCHECKER, "PKIX_OcspChecker_SetVerifyFcn");
PKIX_NULLCHECK_ONE(checker);
checker->verifyFcn = verifyFcn;
PKIX_RETURN(OCSPCHECKER);
}
PKIX_Error *
PKIX_OcspChecker_Initialize(
PKIX_PL_Date *validityTime,
void *passwordInfo,
void *responder,
PKIX_RevocationChecker **pChecker,
void *plContext)
{
PKIX_OcspChecker *oChecker = NULL;
PKIX_ENTER(OCSPCHECKER, "PKIX_OcspChecker_Initialize");
PKIX_NULLCHECK_ONE(pChecker);
PKIX_CHECK(pkix_OcspChecker_Create
(validityTime, passwordInfo, responder, &oChecker, plContext),
PKIX_OCSPCHECKERCREATEFAILED);
PKIX_CHECK(PKIX_RevocationChecker_Create
(pkix_OcspChecker_Check,
(PKIX_PL_Object *)oChecker,
pChecker,
plContext),
PKIX_REVOCATIONCHECKERCREATEFAILED);
cleanup:
PKIX_DECREF(oChecker);
PKIX_RETURN(OCSPCHECKER);
}