1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * OcspChecker Object Functions
11 #include "pkix_ocspchecker.h"
12 #include "pkix_pl_ocspcertid.h"
13 #include "pkix_error.h"
16 /* --Private-Data-and-Types--------------------------------------- */
18 typedef struct pkix_OcspCheckerStruct {
19 /* RevocationMethod is the super class of OcspChecker. */
20 pkix_RevocationMethod method;
21 PKIX_PL_VerifyCallback certVerifyFcn;
24 /* --Private-Functions-------------------------------------------- */
27 * FUNCTION: pkix_OcspChecker_Destroy
28 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
31 pkix_OcspChecker_Destroy(
32 PKIX_PL_Object *object,
39 * FUNCTION: pkix_OcspChecker_RegisterSelf
41 * Registers PKIX_OCSPCHECKER_TYPE and its related functions with
44 * Not Thread Safe - for performance and complexity reasons
46 * Since this function is only called by PKIX_PL_Initialize, which should
47 * only be called once, it is acceptable that this function is not
51 pkix_OcspChecker_RegisterSelf(void *plContext)
53 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
54 pkix_ClassTable_Entry* entry = &systemClasses[PKIX_OCSPCHECKER_TYPE];
56 PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_RegisterSelf");
58 entry->description = "OcspChecker";
59 entry->typeObjectSize = sizeof(pkix_OcspChecker);
60 entry->destructor = pkix_OcspChecker_Destroy;
62 PKIX_RETURN(OCSPCHECKER);
67 * FUNCTION: pkix_OcspChecker_Create
70 pkix_OcspChecker_Create(PKIX_RevocationMethodType methodType,
73 pkix_LocalRevocationCheckFn localRevChecker,
74 pkix_ExternalRevocationCheckFn externalRevChecker,
75 PKIX_PL_VerifyCallback verifyFn,
76 pkix_RevocationMethod **pChecker,
79 pkix_OcspChecker *method = NULL;
81 PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_Create");
82 PKIX_NULLCHECK_ONE(pChecker);
84 PKIX_CHECK(PKIX_PL_Object_Alloc
85 (PKIX_OCSPCHECKER_TYPE,
86 sizeof (pkix_OcspChecker),
87 (PKIX_PL_Object **)&method,
89 PKIX_COULDNOTCREATECERTCHAINCHECKEROBJECT);
91 pkixErrorResult = pkix_RevocationMethod_Init(
92 (pkix_RevocationMethod*)method, methodType, flags, priority,
93 localRevChecker, externalRevChecker, plContext);
94 if (pkixErrorResult) {
97 method->certVerifyFcn = (PKIX_PL_VerifyCallback)verifyFn;
99 *pChecker = (pkix_RevocationMethod*)method;
105 PKIX_RETURN(OCSPCHECKER);
109 * FUNCTION: pkix_OcspChecker_MapResultCodeToRevStatus
111 PKIX_RevocationStatus
112 pkix_OcspChecker_MapResultCodeToRevStatus(SECErrorCodes resultCode)
114 switch (resultCode) {
115 case SEC_ERROR_REVOKED_CERTIFICATE:
116 return PKIX_RevStatus_Revoked;
118 return PKIX_RevStatus_NoInfo;
122 /* --Public-Functions--------------------------------------------- */
125 * FUNCTION: pkix_OcspChecker_Check (see comments in pkix_checker.h)
129 * The OCSPChecker is created in an idle state, and remains in this state until
130 * either (a) the default Responder has been set and enabled, and a Check
131 * request is received with no responder specified, or (b) a Check request is
132 * received with a specified responder. A request message is constructed and
133 * given to the HttpClient. If non-blocking I/O is used the client may return
134 * with WOULDBLOCK, in which case the OCSPChecker returns the WOULDBLOCK
135 * condition to its caller in turn. On a subsequent call the I/O is resumed.
136 * When a response is received it is decoded and the results provided to the
141 pkix_OcspChecker_CheckLocal(
143 PKIX_PL_Cert *issuer,
145 pkix_RevocationMethod *checkerObject,
146 PKIX_ProcessingParams *procParams,
147 PKIX_UInt32 methodFlags,
148 PKIX_Boolean chainVerificationState,
149 PKIX_RevocationStatus *pRevStatus,
150 PKIX_UInt32 *pReasonCode,
153 PKIX_PL_OcspCertID *cid = NULL;
154 PKIX_Boolean hasFreshStatus = PKIX_FALSE;
155 PKIX_Boolean statusIsGood = PKIX_FALSE;
156 SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP;
157 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
159 PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckLocal");
162 PKIX_PL_OcspCertID_Create(cert, NULL, &cid,
164 PKIX_OCSPCERTIDCREATEFAILED);
170 PKIX_PL_OcspCertID_GetFreshCacheStatus(cid, date,
175 PKIX_OCSPCERTIDGETFRESHCACHESTATUSFAILED);
176 if (hasFreshStatus) {
178 revStatus = PKIX_RevStatus_Success;
181 revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode);
186 *pRevStatus = revStatus;
188 /* ocsp carries only tree statuses: good, bad, and unknown.
189 * revStatus is used to pass them. reasonCode is always set
191 *pReasonCode = crlEntryReasonUnspecified;
194 PKIX_RETURN(OCSPCHECKER);
199 * The OCSPChecker is created in an idle state, and remains in this state until
200 * either (a) the default Responder has been set and enabled, and a Check
201 * request is received with no responder specified, or (b) a Check request is
202 * received with a specified responder. A request message is constructed and
203 * given to the HttpClient. If non-blocking I/O is used the client may return
204 * with WOULDBLOCK, in which case the OCSPChecker returns the WOULDBLOCK
205 * condition to its caller in turn. On a subsequent call the I/O is resumed.
206 * When a response is received it is decoded and the results provided to the
211 pkix_OcspChecker_CheckExternal(
213 PKIX_PL_Cert *issuer,
215 pkix_RevocationMethod *checkerObject,
216 PKIX_ProcessingParams *procParams,
217 PKIX_UInt32 methodFlags,
218 PKIX_RevocationStatus *pRevStatus,
219 PKIX_UInt32 *pReasonCode,
223 SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP;
224 PKIX_Boolean uriFound = PKIX_FALSE;
225 PKIX_Boolean passed = PKIX_TRUE;
226 pkix_OcspChecker *checker = NULL;
227 PKIX_PL_OcspCertID *cid = NULL;
228 PKIX_PL_OcspRequest *request = NULL;
229 PKIX_PL_OcspResponse *response = NULL;
230 PKIX_PL_Date *validity = NULL;
231 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
232 void *nbioContext = NULL;
234 PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckExternal");
237 pkix_CheckType((PKIX_PL_Object*)checkerObject,
238 PKIX_OCSPCHECKER_TYPE, plContext),
239 PKIX_OBJECTNOTOCSPCHECKER);
241 checker = (pkix_OcspChecker *)checkerObject;
244 PKIX_PL_OcspCertID_Create(cert, NULL, &cid,
246 PKIX_OCSPCERTIDCREATEFAILED);
250 pkix_pl_OcspRequest_Create(cert, cid, validity, NULL,
251 methodFlags, &uriFound, &request,
253 PKIX_OCSPREQUESTCREATEFAILED);
255 if (uriFound == PKIX_FALSE) {
256 /* no caching for certs lacking URI */
261 /* send request and create a response object */
263 pkix_pl_OcspResponse_Create(request, NULL,
264 checker->certVerifyFcn,
268 PKIX_OCSPRESPONSECREATEFAILED);
269 if (nbioContext != 0) {
270 *pNBIOContext = nbioContext;
275 pkix_pl_OcspResponse_Decode(response, &passed,
276 &resultCode, plContext),
277 PKIX_OCSPRESPONSEDECODEFAILED);
278 if (passed == PKIX_FALSE) {
283 pkix_pl_OcspResponse_GetStatus(response, &passed,
284 &resultCode, plContext),
285 PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR);
286 if (passed == PKIX_FALSE) {
291 pkix_pl_OcspResponse_VerifySignature(response, cert,
293 &nbioContext, plContext),
294 PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED);
295 if (nbioContext != 0) {
296 *pNBIOContext = nbioContext;
299 if (passed == PKIX_FALSE) {
304 pkix_pl_OcspResponse_GetStatusForCert(cid, response, date,
305 &passed, &resultCode,
307 PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED);
308 if (passed == PKIX_FALSE) {
309 revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode);
311 revStatus = PKIX_RevStatus_Success;
315 if (revStatus == PKIX_RevStatus_NoInfo && (uriFound ||
316 methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) &&
317 methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) {
318 revStatus = PKIX_RevStatus_Revoked;
320 *pRevStatus = revStatus;
322 /* ocsp carries only tree statuses: good, bad, and unknown.
323 * revStatus is used to pass them. reasonCode is always set
325 *pReasonCode = crlEntryReasonUnspecified;
327 if (!passed && cid && cid->certID) {
328 /* We still own the certID object, which means that
329 * it did not get consumed to create a cache entry.
330 * Let's make sure there is one.
333 err = PKIX_PL_OcspCertID_RememberOCSPProcessingFailure(
336 PKIX_PL_Object_DecRef((PKIX_PL_Object*)err, plContext);
340 PKIX_DECREF(request);
341 PKIX_DECREF(response);
343 PKIX_RETURN(OCSPCHECKER);