OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 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 | 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/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 /* | 4 /* |
5 * pkix_ocspchecker.c | 5 * pkix_ocspchecker.c |
6 * | 6 * |
7 * OcspChecker Object Functions | 7 * OcspChecker Object Functions |
8 * | 8 * |
9 */ | 9 */ |
10 | 10 |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 | 193 |
194 PKIX_RETURN(OCSPCHECKER); | 194 PKIX_RETURN(OCSPCHECKER); |
195 } | 195 } |
196 | 196 |
197 | 197 |
198 /* | 198 /* |
199 * The OCSPChecker is created in an idle state, and remains in this state until | 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 | 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 | 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 | 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 | 203 * given to the HttpClient. When a response is received it is decoded and the |
204 * with WOULDBLOCK, in which case the OCSPChecker returns the WOULDBLOCK | 204 * results provided to the caller. |
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 | |
207 * caller. | |
208 * | 205 * |
| 206 * During the most recent enhancement of this function, it has been found that |
| 207 * it doesn't correctly implement non-blocking I/O. |
| 208 * |
| 209 * The nbioContext is used in two places, for "response-obtaining" and |
| 210 * for "response-verification". |
| 211 * |
| 212 * However, if this function gets called to resume, it always |
| 213 * repeats the "request creation" and "response fetching" steps! |
| 214 * As a result, the earlier operation is never resumed. |
209 */ | 215 */ |
210 PKIX_Error * | 216 PKIX_Error * |
211 pkix_OcspChecker_CheckExternal( | 217 pkix_OcspChecker_CheckExternal( |
212 PKIX_PL_Cert *cert, | 218 PKIX_PL_Cert *cert, |
213 PKIX_PL_Cert *issuer, | 219 PKIX_PL_Cert *issuer, |
214 PKIX_PL_Date *date, | 220 PKIX_PL_Date *date, |
215 pkix_RevocationMethod *checkerObject, | 221 pkix_RevocationMethod *checkerObject, |
216 PKIX_ProcessingParams *procParams, | 222 PKIX_ProcessingParams *procParams, |
217 PKIX_UInt32 methodFlags, | 223 PKIX_UInt32 methodFlags, |
218 PKIX_RevocationStatus *pRevStatus, | 224 PKIX_RevocationStatus *pRevStatus, |
219 PKIX_UInt32 *pReasonCode, | 225 PKIX_UInt32 *pReasonCode, |
220 void **pNBIOContext, | 226 void **pNBIOContext, |
221 void *plContext) | 227 void *plContext) |
222 { | 228 { |
223 SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP; | 229 SECErrorCodes resultCode = SEC_ERROR_REVOKED_CERTIFICATE_OCSP; |
224 PKIX_Boolean uriFound = PKIX_FALSE; | 230 PKIX_Boolean uriFound = PKIX_FALSE; |
225 PKIX_Boolean passed = PKIX_TRUE; | 231 PKIX_Boolean passed = PKIX_TRUE; |
226 pkix_OcspChecker *checker = NULL; | 232 pkix_OcspChecker *checker = NULL; |
227 PKIX_PL_OcspCertID *cid = NULL; | 233 PKIX_PL_OcspCertID *cid = NULL; |
228 PKIX_PL_OcspRequest *request = NULL; | 234 PKIX_PL_OcspRequest *request = NULL; |
229 PKIX_PL_OcspResponse *response = NULL; | 235 PKIX_PL_OcspResponse *response = NULL; |
230 PKIX_PL_Date *validity = NULL; | 236 PKIX_PL_Date *validity = NULL; |
231 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; | 237 PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo; |
232 void *nbioContext = NULL; | 238 void *nbioContext = NULL; |
| 239 enum { stageGET, stagePOST } currentStage; |
| 240 PRBool retry = PR_FALSE; |
233 | 241 |
234 PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckExternal"); | 242 PKIX_ENTER(OCSPCHECKER, "pkix_OcspChecker_CheckExternal"); |
235 | 243 |
236 PKIX_CHECK( | 244 PKIX_CHECK( |
237 pkix_CheckType((PKIX_PL_Object*)checkerObject, | 245 pkix_CheckType((PKIX_PL_Object*)checkerObject, |
238 PKIX_OCSPCHECKER_TYPE, plContext), | 246 PKIX_OCSPCHECKER_TYPE, plContext), |
239 PKIX_OBJECTNOTOCSPCHECKER); | 247 PKIX_OBJECTNOTOCSPCHECKER); |
240 | 248 |
241 checker = (pkix_OcspChecker *)checkerObject; | 249 checker = (pkix_OcspChecker *)checkerObject; |
242 | 250 |
243 PKIX_CHECK( | 251 PKIX_CHECK( |
244 PKIX_PL_OcspCertID_Create(cert, NULL, &cid, | 252 PKIX_PL_OcspCertID_Create(cert, NULL, &cid, |
245 plContext), | 253 plContext), |
246 PKIX_OCSPCERTIDCREATEFAILED); | 254 PKIX_OCSPCERTIDCREATEFAILED); |
247 | 255 |
248 /* create request */ | 256 /* create request */ |
249 PKIX_CHECK( | 257 PKIX_CHECK( |
250 pkix_pl_OcspRequest_Create(cert, cid, validity, NULL, | 258 pkix_pl_OcspRequest_Create(cert, cid, validity, NULL, |
251 methodFlags, &uriFound, &request, | 259 methodFlags, &uriFound, &request, |
252 plContext), | 260 plContext), |
253 PKIX_OCSPREQUESTCREATEFAILED); | 261 PKIX_OCSPREQUESTCREATEFAILED); |
254 | 262 |
255 if (uriFound == PKIX_FALSE) { | 263 if (uriFound == PKIX_FALSE) { |
256 /* no caching for certs lacking URI */ | 264 /* no caching for certs lacking URI */ |
257 resultCode = 0; | 265 resultCode = 0; |
258 goto cleanup; | 266 goto cleanup; |
259 } | 267 } |
260 | 268 |
261 /* send request and create a response object */ | 269 if (methodFlags & CERT_REV_M_FORCE_POST_METHOD_FOR_OCSP) { |
262 PKIX_CHECK( | 270 /* Do not try HTTP GET, only HTTP POST */ |
263 pkix_pl_OcspResponse_Create(request, NULL, | 271 currentStage = stagePOST; |
264 checker->certVerifyFcn, | 272 } else { |
265 &nbioContext, | 273 /* Try HTTP GET first, falling back to POST */ |
266 &response, | 274 currentStage = stageGET; |
267 plContext), | |
268 PKIX_OCSPRESPONSECREATEFAILED); | |
269 if (nbioContext != 0) { | |
270 *pNBIOContext = nbioContext; | |
271 goto cleanup; | |
272 } | |
273 | |
274 PKIX_CHECK( | |
275 pkix_pl_OcspResponse_Decode(response, &passed, | |
276 &resultCode, plContext), | |
277 PKIX_OCSPRESPONSEDECODEFAILED); | |
278 if (passed == PKIX_FALSE) { | |
279 goto cleanup; | |
280 } | |
281 | |
282 PKIX_CHECK( | |
283 pkix_pl_OcspResponse_GetStatus(response, &passed, | |
284 &resultCode, plContext), | |
285 PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR); | |
286 if (passed == PKIX_FALSE) { | |
287 goto cleanup; | |
288 } | 275 } |
289 | 276 |
290 PKIX_CHECK( | 277 do { |
291 pkix_pl_OcspResponse_VerifySignature(response, cert, | 278 const char *method; |
292 procParams, &passed, | 279 passed = PKIX_TRUE; |
293 &nbioContext, plContext), | |
294 PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED); | |
295 »if (nbioContext != 0) { | |
296 »*pNBIOContext = nbioContext; | |
297 goto cleanup; | |
298 } | |
299 if (passed == PKIX_FALSE) { | |
300 goto cleanup; | |
301 } | |
302 | 280 |
303 PKIX_CHECK( | 281 retry = PR_FALSE; |
304 pkix_pl_OcspResponse_GetStatusForCert(cid, response, date, | 282 if (currentStage == stageGET) { |
305 &passed, &resultCode, | 283 method = "GET"; |
306 plContext), | 284 } else { |
307 PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED); | 285 PORT_Assert(currentStage == stagePOST); |
308 if (passed == PKIX_FALSE) { | 286 method = "POST"; |
309 revStatus = pkix_OcspChecker_MapResultCodeToRevStatus(resultCode); | 287 } |
310 } else { | 288 |
311 revStatus = PKIX_RevStatus_Success; | 289 /* send request and create a response object */ |
312 } | 290 PKIX_CHECK_NO_GOTO( |
| 291 pkix_pl_OcspResponse_Create(request, method, NULL, |
| 292 checker->certVerifyFcn, |
| 293 &nbioContext, |
| 294 &response, |
| 295 plContext), |
| 296 PKIX_OCSPRESPONSECREATEFAILED); |
| 297 |
| 298 if (pkixErrorResult) { |
| 299 passed = PKIX_FALSE; |
| 300 } |
| 301 |
| 302 if (passed && nbioContext != 0) { |
| 303 *pNBIOContext = nbioContext; |
| 304 goto cleanup; |
| 305 } |
| 306 |
| 307 if (passed){ |
| 308 PKIX_CHECK_NO_GOTO( |
| 309 pkix_pl_OcspResponse_Decode(response, &passed, |
| 310 &resultCode, plContext), |
| 311 PKIX_OCSPRESPONSEDECODEFAILED); |
| 312 if (pkixErrorResult) { |
| 313 passed = PKIX_FALSE; |
| 314 } |
| 315 } |
| 316 |
| 317 if (passed){ |
| 318 PKIX_CHECK_NO_GOTO( |
| 319 pkix_pl_OcspResponse_GetStatus(response, &passed, |
| 320 &resultCode, plContex
t), |
| 321 PKIX_OCSPRESPONSEGETSTATUSRETURNEDANERROR); |
| 322 if (pkixErrorResult) { |
| 323 passed = PKIX_FALSE; |
| 324 } |
| 325 } |
| 326 |
| 327 if (passed){ |
| 328 PKIX_CHECK_NO_GOTO( |
| 329 pkix_pl_OcspResponse_VerifySignature(response, cert, |
| 330 procParams, &pa
ssed, |
| 331 &nbioContext, p
lContext), |
| 332 PKIX_OCSPRESPONSEVERIFYSIGNATUREFAILED); |
| 333 if (pkixErrorResult) { |
| 334 passed = PKIX_FALSE; |
| 335 } else { |
| 336 if (nbioContext != 0) { |
| 337 *pNBIOContext = nbioContext; |
| 338 goto cleanup; |
| 339 } |
| 340 } |
| 341 } |
| 342 |
| 343 if (!passed && currentStage == stagePOST) { |
| 344 /* We won't retry a POST failure, so it's final. |
| 345 * Because the following block with its call to |
| 346 * pkix_pl_OcspResponse_GetStatusForCert |
| 347 * will take care of caching good or bad state, |
| 348 * but we only execute that next block if there hasn't |
| 349 * been a failure yet, we must cache the POST |
| 350 * failure now. |
| 351 */ |
| 352 |
| 353 if (cid && cid->certID) { |
| 354 /* Caching MIGHT consume the cid. */ |
| 355 PKIX_Error *err; |
| 356 err = PKIX_PL_OcspCertID_RememberOCSPProcessingF
ailure( |
| 357 cid, plContext); |
| 358 if (err) { |
| 359 PKIX_PL_Object_DecRef((PKIX_PL_Object*)e
rr, plContext); |
| 360 } |
| 361 } |
| 362 } |
| 363 |
| 364 if (passed){ |
| 365 PKIX_Boolean allowCachingOfFailures = |
| 366 (currentStage == stagePOST) ? PKIX_TRUE : PKIX_F
ALSE; |
| 367 |
| 368 PKIX_CHECK_NO_GOTO( |
| 369 pkix_pl_OcspResponse_GetStatusForCert(cid, response, |
| 370 allowCachingOf
Failures, |
| 371 date, |
| 372 &passed, &resu
ltCode, |
| 373 plContext), |
| 374 PKIX_OCSPRESPONSEGETSTATUSFORCERTFAILED); |
| 375 if (pkixErrorResult) { |
| 376 passed = PKIX_FALSE; |
| 377 } else if (passed == PKIX_FALSE) { |
| 378 revStatus = pkix_OcspChecker_MapResultCodeToRevS
tatus(resultCode); |
| 379 } else { |
| 380 revStatus = PKIX_RevStatus_Success; |
| 381 } |
| 382 } |
| 383 |
| 384 if (currentStage == stageGET && revStatus != PKIX_RevStatus_Succ
ess && |
| 385 revStatus != PKIX_RevStatus_Revo
ked) { |
| 386 /* we'll retry */ |
| 387 PKIX_DECREF(response); |
| 388 retry = PR_TRUE; |
| 389 currentStage = stagePOST; |
| 390 revStatus = PKIX_RevStatus_NoInfo; |
| 391 if (pkixErrorResult) { |
| 392 PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixError
Result, |
| 393 plContext); |
| 394 pkixErrorResult = NULL; |
| 395 } |
| 396 } |
| 397 } while (retry); |
313 | 398 |
314 cleanup: | 399 cleanup: |
315 if (revStatus == PKIX_RevStatus_NoInfo && (uriFound || | 400 if (revStatus == PKIX_RevStatus_NoInfo && (uriFound || |
316 methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) && | 401 methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) && |
317 methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { | 402 methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) { |
318 revStatus = PKIX_RevStatus_Revoked; | 403 revStatus = PKIX_RevStatus_Revoked; |
319 } | 404 } |
320 *pRevStatus = revStatus; | 405 *pRevStatus = revStatus; |
321 | 406 |
322 /* ocsp carries only tree statuses: good, bad, and unknown. | 407 /* ocsp carries only three statuses: good, bad, and unknown. |
323 * revStatus is used to pass them. reasonCode is always set | 408 * revStatus is used to pass them. reasonCode is always set |
324 * to be unknown. */ | 409 * to be unknown. */ |
325 *pReasonCode = crlEntryReasonUnspecified; | 410 *pReasonCode = crlEntryReasonUnspecified; |
326 | 411 |
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. | |
331 */ | |
332 PKIX_Error *err; | |
333 err = PKIX_PL_OcspCertID_RememberOCSPProcessingFailure( | |
334 cid, plContext); | |
335 if (err) { | |
336 PKIX_PL_Object_DecRef((PKIX_PL_Object*)err, plContext); | |
337 } | |
338 } | |
339 PKIX_DECREF(cid); | 412 PKIX_DECREF(cid); |
340 PKIX_DECREF(request); | 413 PKIX_DECREF(request); |
341 PKIX_DECREF(response); | 414 PKIX_DECREF(response); |
342 | 415 |
343 PKIX_RETURN(OCSPCHECKER); | 416 PKIX_RETURN(OCSPCHECKER); |
344 } | 417 } |
345 | 418 |
346 | 419 |
OLD | NEW |