nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / lib / libpkix / pkix_pl_nss / pki / pkix_pl_ocspresponse.c
blobd09ad867ef37e29a3c012ce800972454040610b9
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the PKIX-C library.
16 * The Initial Developer of the Original Code is
17 * Sun Microsystems, Inc.
18 * Portions created by the Initial Developer are
19 * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
21 * Contributor(s):
22 * Sun Microsystems, Inc.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 * pkix_pl_ocspresponse.c
42 #include "pkix_pl_ocspresponse.h"
44 /* ----Public functions------------------------------------- */
46 * This is the libpkix replacement for CERT_VerifyOCSPResponseSignature.
47 * It is used if it has been set as the verifyFcn member of ocspChecker.
49 PKIX_Error *
50 PKIX_PL_OcspResponse_UseBuildChain(
51 PKIX_PL_Cert *signerCert,
52 PKIX_PL_Date *producedAt,
53 PKIX_ProcessingParams *procParams,
54 void **pNBIOContext,
55 void **pState,
56 PKIX_BuildResult **pBuildResult,
57 PKIX_VerifyNode **pVerifyTree,
58 void *plContext)
60 PKIX_ProcessingParams *caProcParams = NULL;
61 PKIX_PL_Date *date = NULL;
62 PKIX_ComCertSelParams *certSelParams = NULL;
63 PKIX_CertSelector *certSelector = NULL;
64 void *nbioContext = NULL;
65 PKIX_Error *buildError = NULL;
67 PKIX_ENTER(OCSPRESPONSE, "pkix_OcspResponse_UseBuildChain");
68 PKIX_NULLCHECK_THREE(signerCert, producedAt, procParams);
69 PKIX_NULLCHECK_THREE(pNBIOContext, pState, pBuildResult);
71 nbioContext = *pNBIOContext;
72 *pNBIOContext = NULL;
74 /* Are we resuming after a WOULDBLOCK return, or starting anew ? */
75 if (nbioContext == NULL) {
76 /* Starting anew */
77 PKIX_CHECK(PKIX_PL_Object_Duplicate
78 ((PKIX_PL_Object *)procParams,
79 (PKIX_PL_Object **)&caProcParams,
80 plContext),
81 PKIX_OBJECTDUPLICATEFAILED);
83 PKIX_CHECK(PKIX_ProcessingParams_SetDate(procParams, date, plContext),
84 PKIX_PROCESSINGPARAMSSETDATEFAILED);
86 /* create CertSelector with target certificate in params */
88 PKIX_CHECK(PKIX_CertSelector_Create
89 (NULL, NULL, &certSelector, plContext),
90 PKIX_CERTSELECTORCREATEFAILED);
92 PKIX_CHECK(PKIX_ComCertSelParams_Create
93 (&certSelParams, plContext),
94 PKIX_COMCERTSELPARAMSCREATEFAILED);
96 PKIX_CHECK(PKIX_ComCertSelParams_SetCertificate
97 (certSelParams, signerCert, plContext),
98 PKIX_COMCERTSELPARAMSSETCERTIFICATEFAILED);
100 PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
101 (certSelector, certSelParams, plContext),
102 PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
104 PKIX_CHECK(PKIX_ProcessingParams_SetTargetCertConstraints
105 (caProcParams, certSelector, plContext),
106 PKIX_PROCESSINGPARAMSSETTARGETCERTCONSTRAINTSFAILED);
109 buildError = PKIX_BuildChain
110 (caProcParams,
111 &nbioContext,
112 pState,
113 pBuildResult,
114 pVerifyTree,
115 plContext);
117 /* non-null nbioContext means the build would block */
118 if (nbioContext != NULL) {
120 *pNBIOContext = nbioContext;
122 /* no buildResult means the build has failed */
123 } else if (buildError) {
124 pkixErrorResult = buildError;
125 buildError = NULL;
126 } else {
127 PKIX_DECREF(*pState);
130 cleanup:
132 PKIX_DECREF(caProcParams);
133 PKIX_DECREF(date);
134 PKIX_DECREF(certSelParams);
135 PKIX_DECREF(certSelector);
137 PKIX_RETURN(OCSPRESPONSE);
140 /* --Private-OcspResponse-Functions------------------------------------- */
143 * FUNCTION: pkix_pl_OcspResponse_Destroy
144 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
146 static PKIX_Error *
147 pkix_pl_OcspResponse_Destroy(
148 PKIX_PL_Object *object,
149 void *plContext)
151 PKIX_PL_OcspResponse *ocspRsp = NULL;
152 const SEC_HttpClientFcn *httpClient = NULL;
153 const SEC_HttpClientFcnV1 *hcv1 = NULL;
155 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Destroy");
156 PKIX_NULLCHECK_ONE(object);
158 PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
159 PKIX_OBJECTNOTANOCSPRESPONSE);
161 ocspRsp = (PKIX_PL_OcspResponse *)object;
163 if (ocspRsp->nssOCSPResponse != NULL) {
164 CERT_DestroyOCSPResponse(ocspRsp->nssOCSPResponse);
165 ocspRsp->nssOCSPResponse = NULL;
166 ocspRsp->signerCert = NULL;
169 if (ocspRsp->signerCert != NULL) {
170 CERT_DestroyCertificate(ocspRsp->signerCert);
171 ocspRsp->signerCert = NULL;
174 httpClient = (const SEC_HttpClientFcn *)(ocspRsp->httpClient);
176 if (httpClient && (httpClient->version == 1)) {
178 hcv1 = &(httpClient->fcnTable.ftable1);
180 if (ocspRsp->requestSession != NULL) {
181 hcv1->freeFcn(ocspRsp->requestSession);
182 ocspRsp->requestSession = NULL;
185 if (ocspRsp->serverSession != NULL) {
186 hcv1->freeSessionFcn(ocspRsp->serverSession);
187 ocspRsp->serverSession = NULL;
191 if (ocspRsp->arena != NULL) {
192 PORT_FreeArena(ocspRsp->arena, PR_FALSE);
193 ocspRsp->arena = NULL;
196 PKIX_DECREF(ocspRsp->producedAtDate);
197 PKIX_DECREF(ocspRsp->pkixSignerCert);
198 PKIX_DECREF(ocspRsp->request);
200 cleanup:
202 PKIX_RETURN(OCSPRESPONSE);
206 * FUNCTION: pkix_pl_OcspResponse_Hashcode
207 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
209 static PKIX_Error *
210 pkix_pl_OcspResponse_Hashcode(
211 PKIX_PL_Object *object,
212 PKIX_UInt32 *pHashcode,
213 void *plContext)
215 PKIX_PL_OcspResponse *ocspRsp = NULL;
217 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Hashcode");
218 PKIX_NULLCHECK_TWO(object, pHashcode);
220 PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
221 PKIX_OBJECTNOTANOCSPRESPONSE);
223 ocspRsp = (PKIX_PL_OcspResponse *)object;
225 if (ocspRsp->encodedResponse->data == NULL) {
226 *pHashcode = 0;
227 } else {
228 PKIX_CHECK(pkix_hash
229 (ocspRsp->encodedResponse->data,
230 ocspRsp->encodedResponse->len,
231 pHashcode,
232 plContext),
233 PKIX_HASHFAILED);
236 cleanup:
238 PKIX_RETURN(OCSPRESPONSE);
242 * FUNCTION: pkix_pl_OcspResponse_Equals
243 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
245 static PKIX_Error *
246 pkix_pl_OcspResponse_Equals(
247 PKIX_PL_Object *firstObj,
248 PKIX_PL_Object *secondObj,
249 PKIX_Boolean *pResult,
250 void *plContext)
252 PKIX_UInt32 secondType = 0;
253 PKIX_UInt32 firstLen = 0;
254 PKIX_UInt32 i = 0;
255 PKIX_PL_OcspResponse *rsp1 = NULL;
256 PKIX_PL_OcspResponse *rsp2 = NULL;
257 const unsigned char *firstData = NULL;
258 const unsigned char *secondData = NULL;
260 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Equals");
261 PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
263 /* test that firstObj is a OcspResponse */
264 PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPRESPONSE_TYPE, plContext),
265 PKIX_FIRSTOBJARGUMENTNOTANOCSPRESPONSE);
268 * Since we know firstObj is a OcspResponse, if both references are
269 * identical, they must be equal
271 if (firstObj == secondObj){
272 *pResult = PKIX_TRUE;
273 goto cleanup;
277 * If secondObj isn't a OcspResponse, we don't throw an error.
278 * We simply return a Boolean result of FALSE
280 *pResult = PKIX_FALSE;
281 PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext),
282 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
283 if (secondType != PKIX_OCSPRESPONSE_TYPE) {
284 goto cleanup;
287 rsp1 = (PKIX_PL_OcspResponse *)firstObj;
288 rsp2 = (PKIX_PL_OcspResponse *)secondObj;
290 /* If either lacks an encoded string, they cannot be compared */
291 firstData = (const unsigned char *)rsp1->encodedResponse->data;
292 secondData = (const unsigned char *)rsp2->encodedResponse->data;
293 if ((firstData == NULL) || (secondData == NULL)) {
294 goto cleanup;
297 firstLen = rsp1->encodedResponse->len;
299 if (firstLen != rsp2->encodedResponse->len) {
300 goto cleanup;
303 for (i = 0; i < firstLen; i++) {
304 if (*firstData++ != *secondData++) {
305 goto cleanup;
309 *pResult = PKIX_TRUE;
311 cleanup:
313 PKIX_RETURN(OCSPRESPONSE);
317 * FUNCTION: pkix_pl_OcspResponse_RegisterSelf
318 * DESCRIPTION:
319 * Registers PKIX_OCSPRESPONSE_TYPE and its related functions with
320 * systemClasses[]
321 * PARAMETERS:
322 * "plContext"
323 * Platform-specific context pointer.
324 * THREAD SAFETY:
325 * Not Thread Safe - for performance and complexity reasons
327 * Since this function is only called by PKIX_PL_Initialize, which should
328 * only be called once, it is acceptable that this function is not
329 * thread-safe.
331 PKIX_Error *
332 pkix_pl_OcspResponse_RegisterSelf(void *plContext)
334 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
335 pkix_ClassTable_Entry entry;
337 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_RegisterSelf");
339 entry.description = "OcspResponse";
340 entry.objCounter = 0;
341 entry.typeObjectSize = sizeof(PKIX_PL_OcspResponse);
342 entry.destructor = pkix_pl_OcspResponse_Destroy;
343 entry.equalsFunction = pkix_pl_OcspResponse_Equals;
344 entry.hashcodeFunction = pkix_pl_OcspResponse_Hashcode;
345 entry.toStringFunction = NULL;
346 entry.comparator = NULL;
347 entry.duplicateFunction = pkix_duplicateImmutable;
349 systemClasses[PKIX_OCSPRESPONSE_TYPE] = entry;
351 PKIX_RETURN(OCSPRESPONSE);
354 /* --Public-Functions------------------------------------------------------- */
357 * FUNCTION: pkix_pl_OcspResponse_Create
358 * DESCRIPTION:
360 * This function transmits the OcspRequest pointed to by "request" and obtains
361 * an OcspResponse, which it stores at "pOcspResponse". If the HTTPClient
362 * supports non-blocking I/O this function may store a non-NULL value at
363 * "pNBIOContext" (the WOULDBLOCK condition). In that case the caller should
364 * make a subsequent call with the same value in "pNBIOContext" and
365 * "pOcspResponse" to resume the operation. Additional WOULDBLOCK returns may
366 * occur; the caller should persist until a return occurs with NULL stored at
367 * "pNBIOContext".
369 * If a SEC_HttpClientFcn "responder" is supplied, it is used as the client
370 * to which the OCSP query is sent. If none is supplied, the default responder
371 * is used.
373 * If an OcspResponse_VerifyCallback "verifyFcn" is supplied, it is used to
374 * verify the Cert received from the responder as the signer. If none is
375 * supplied, the default verification function is used.
377 * The contents of "request" are ignored on calls subsequent to a WOULDBLOCK
378 * return, and the caller is permitted to supply NULL.
380 * PARAMETERS
381 * "request"
382 * Address of the OcspRequest for which a response is desired.
383 * "responder"
384 * Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP
385 * query.
386 * "verifyFcn"
387 * Address, if non-NULL, of the OcspResponse_VerifyCallback function to be
388 * used to verify the Cert of the OCSP responder.
389 * "pNBIOContext"
390 * Address at which platform-dependent information is stored for handling
391 * of non-blocking I/O. Must be non-NULL.
392 * "pOcspResponse"
393 * The address where the created OcspResponse is stored. Must be non-NULL.
394 * "plContext"
395 * Platform-specific context pointer.
396 * THREAD SAFETY:
397 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
398 * RETURNS:
399 * Returns NULL if the function succeeds.
400 * Returns an OcspResponse Error if the function fails in a non-fatal way.
401 * Returns a Fatal Error if the function fails in an unrecoverable way.
403 PKIX_Error *
404 pkix_pl_OcspResponse_Create(
405 PKIX_PL_OcspRequest *request,
406 void *responder,
407 PKIX_PL_OcspResponse_VerifyCallback verifyFcn,
408 void **pNBIOContext,
409 PKIX_PL_OcspResponse **pResponse,
410 void *plContext)
412 void *nbioContext = NULL;
413 PKIX_PL_OcspResponse *ocspResponse = NULL;
414 const SEC_HttpClientFcn *httpClient = NULL;
415 const SEC_HttpClientFcnV1 *hcv1 = NULL;
416 SECStatus rv = SECFailure;
417 char *location = NULL;
418 char *hostname = NULL;
419 char *path = NULL;
420 PRUint16 port = 0;
421 SEC_HTTP_SERVER_SESSION serverSession = NULL;
422 SEC_HTTP_REQUEST_SESSION requestSession = NULL;
423 SECItem *encodedRequest = NULL;
424 PRUint16 responseCode = 0;
425 char *responseData = NULL;
426 PRUint32 responseDataLen = 0;
428 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create");
429 PKIX_NULLCHECK_TWO(pNBIOContext, pResponse);
431 nbioContext = *pNBIOContext;
432 *pNBIOContext = NULL;
434 if (nbioContext != NULL) {
436 ocspResponse = *pResponse;
437 PKIX_NULLCHECK_ONE(ocspResponse);
439 httpClient = ocspResponse->httpClient;
440 serverSession = ocspResponse->serverSession;
441 requestSession = ocspResponse->requestSession;
442 PKIX_NULLCHECK_THREE(httpClient, serverSession, requestSession);
444 } else {
446 PKIX_NULLCHECK_ONE(request);
448 PKIX_CHECK(pkix_pl_OcspRequest_GetEncoded
449 (request, &encodedRequest, plContext),
450 PKIX_OCSPREQUESTGETENCODEDFAILED);
452 /* prepare initial message to HTTPClient */
454 /* Is there a default responder and is it enabled? */
455 if (!responder) {
456 PKIX_PL_NSSCALLRV
457 (OCSPRESPONSE,
458 responder,
459 (void *)SEC_GetRegisteredHttpClient,
460 ());
463 httpClient = (const SEC_HttpClientFcn *)responder;
465 if (httpClient && (httpClient->version == 1)) {
467 hcv1 = &(httpClient->fcnTable.ftable1);
469 PKIX_CHECK(pkix_pl_OcspRequest_GetLocation
470 (request, &location, plContext),
471 PKIX_OCSPREQUESTGETLOCATIONFAILED);
473 /* parse location -> hostname, port, path */
474 PKIX_PL_NSSCALLRV(OCSPRESPONSE, rv, CERT_ParseURL,
475 (location, &hostname, &port, &path));
477 if ((hostname == NULL) || (path == NULL)) {
478 PKIX_ERROR(PKIX_URLPARSINGFAILED);
481 PKIX_PL_NSSCALLRV
482 (OCSPRESPONSE,
484 hcv1->createSessionFcn,
485 (hostname, port, &serverSession));
487 if (rv != SECSuccess) {
488 PKIX_ERROR(PKIX_OCSPSERVERERROR);
491 PKIX_PL_NSSCALLRV
492 (OCSPRESPONSE, rv, hcv1->createFcn,
493 (serverSession,
494 "http",
495 path,
496 "POST",
497 PR_TicksPerSecond() * 60,
498 &requestSession));
500 if (rv != SECSuccess) {
501 PKIX_ERROR(PKIX_OCSPSERVERERROR);
504 PKIX_PL_NSSCALLRV
505 (OCSPRESPONSE, rv, hcv1->setPostDataFcn,
506 (requestSession,
507 (char *)encodedRequest->data,
508 encodedRequest->len,
509 "application/ocsp-request"));
511 if (rv != SECSuccess) {
512 PKIX_ERROR(PKIX_OCSPSERVERERROR);
515 /* create a PKIX_PL_OcspResponse object */
516 PKIX_CHECK(PKIX_PL_Object_Alloc
517 (PKIX_OCSPRESPONSE_TYPE,
518 sizeof (PKIX_PL_OcspResponse),
519 (PKIX_PL_Object **)&ocspResponse,
520 plContext),
521 PKIX_COULDNOTCREATEOBJECT);
523 PKIX_INCREF(request);
524 ocspResponse->request = request;
525 ocspResponse->httpClient = httpClient;
526 ocspResponse->serverSession = serverSession;
527 ocspResponse->requestSession = requestSession;
528 ocspResponse->verifyFcn = verifyFcn;
529 ocspResponse->handle = CERT_GetDefaultCertDB();
530 ocspResponse->encodedResponse = NULL;
531 ocspResponse->arena = NULL;
532 ocspResponse->producedAt = 0;
533 ocspResponse->producedAtDate = NULL;
534 ocspResponse->pkixSignerCert = NULL;
535 ocspResponse->nssOCSPResponse = NULL;
536 ocspResponse->signerCert = NULL;
540 /* begin or resume IO to HTTPClient */
541 if (httpClient && (httpClient->version == 1)) {
543 hcv1 = &(httpClient->fcnTable.ftable1);
545 responseDataLen = MAX_OCSP_RESPONSE_LEN;
547 PKIX_PL_NSSCALLRV(OCSPRESPONSE, rv, hcv1->trySendAndReceiveFcn,
548 (requestSession,
549 (PRPollDesc **)&nbioContext,
550 &responseCode,
551 NULL, /* responseContentType */
552 NULL, /* responseHeaders */
553 (const char **)&responseData,
554 &responseDataLen));
556 if (rv != SECSuccess) {
557 PKIX_ERROR(PKIX_OCSPSERVERERROR);
560 if (nbioContext != NULL) {
561 *pNBIOContext = nbioContext;
562 goto cleanup;
565 if (responseCode != 200) {
566 PKIX_ERROR(PKIX_OCSPBADHTTPRESPONSE);
570 PKIX_PL_NSSCALLRV
571 (OCSPRESPONSE, ocspResponse->arena, PORT_NewArena,
572 (DER_DEFAULT_CHUNKSIZE));
574 if (ocspResponse->arena == NULL) {
575 PKIX_ERROR(PKIX_OUTOFMEMORY);
578 PKIX_PL_NSSCALLRV
579 (OCSPRESPONSE,
580 ocspResponse->encodedResponse,
581 SECITEM_AllocItem,
582 (ocspResponse->arena, NULL, responseDataLen));
584 if (ocspResponse->encodedResponse == NULL) {
585 PKIX_ERROR(PKIX_OUTOFMEMORY);
588 PKIX_PL_NSSCALL(OCSPRESPONSE, PORT_Memcpy,
589 (ocspResponse->encodedResponse->data,
590 responseData,
591 responseDataLen));
595 *pResponse = ocspResponse;
597 cleanup:
599 if (path != NULL) {
600 PKIX_PL_NSSCALL(OCSPRESPONSE, PORT_Free, (path));
603 if (hostname != NULL) {
604 PKIX_PL_NSSCALL(OCSPRESPONSE, PORT_Free, (hostname));
607 if (PKIX_ERROR_RECEIVED){
608 PKIX_DECREF(ocspResponse);
611 PKIX_RETURN(OCSPRESPONSE);
615 * FUNCTION: pkix_pl_OcspResponse_Decode
616 * DESCRIPTION:
618 * This function decodes the DER data contained in the OcspResponse pointed to
619 * by "response", storing PKIX_TRUE at "pPassed" if the decoding was
620 * successful, and PKIX_FALSE otherwise.
622 * PARAMETERS
623 * "response"
624 * The address of the OcspResponse whose DER data is to be decoded. Must
625 * be non-NULL.
626 * "pPassed"
627 * Address at which the Boolean result is stored. Must be non-NULL.
628 * "pReturnCode"
629 * Address at which the SECErrorCodes result is stored. Must be non-NULL.
630 * "plContext"
631 * Platform-specific context pointer.
632 * THREAD SAFETY:
633 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
634 * RETURNS:
635 * Returns NULL if the function succeeds.
636 * Returns an OcspResponse Error if the function fails in a non-fatal way.
637 * Returns a Fatal Error if the function fails in an unrecoverable way.
640 PKIX_Error *
641 pkix_pl_OcspResponse_Decode(
642 PKIX_PL_OcspResponse *response,
643 PKIX_Boolean *pPassed,
644 SECErrorCodes *pReturnCode,
645 void *plContext)
648 PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_Decode");
649 PKIX_NULLCHECK_TWO(response, response->encodedResponse);
651 response->nssOCSPResponse =
652 CERT_DecodeOCSPResponse(response->encodedResponse);
654 if (response->nssOCSPResponse != NULL) {
655 *pPassed = PKIX_TRUE;
656 *pReturnCode = 0;
657 } else {
658 *pPassed = PKIX_FALSE;
659 *pReturnCode = PORT_GetError();
662 PKIX_RETURN(OCSPRESPONSE);
666 * FUNCTION: pkix_pl_OcspResponse_GetStatus
667 * DESCRIPTION:
669 * This function checks the response status of the OcspResponse pointed to
670 * by "response", storing PKIX_TRUE at "pPassed" if the responder understood
671 * the request and considered it valid, and PKIX_FALSE otherwise.
673 * PARAMETERS
674 * "response"
675 * The address of the OcspResponse whose status is to be retrieved. Must
676 * be non-NULL.
677 * "pPassed"
678 * Address at which the Boolean result is stored. Must be non-NULL.
679 * "plContext"
680 * Platform-specific context pointer.
681 * THREAD SAFETY:
682 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
683 * RETURNS:
684 * Returns NULL if the function succeeds.
685 * Returns an OcspResponse Error if the function fails in a non-fatal way.
686 * Returns a Fatal Error if the function fails in an unrecoverable way.
689 PKIX_Error *
690 pkix_pl_OcspResponse_GetStatus(
691 PKIX_PL_OcspResponse *response,
692 PKIX_Boolean *pPassed,
693 SECErrorCodes *pReturnCode,
694 void *plContext)
696 SECStatus rv = SECFailure;
698 PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_GetStatus");
699 PKIX_NULLCHECK_FOUR(response, response->nssOCSPResponse, pPassed, pReturnCode);
701 rv = CERT_GetOCSPResponseStatus(response->nssOCSPResponse);
703 if (rv == SECSuccess) {
704 *pPassed = PKIX_TRUE;
705 *pReturnCode = 0;
706 } else {
707 *pPassed = PKIX_FALSE;
708 *pReturnCode = PORT_GetError();
711 PKIX_RETURN(OCSPRESPONSE);
715 PKIX_Error*
716 pkix_pl_OcspResponse_CallCertVerify(
717 PKIX_PL_OcspResponse *response,
718 PKIX_ProcessingParams *procParams,
719 SECCertUsage certUsage,
720 void **state,
721 PKIX_BuildResult **buildResult,
722 void **pNBIOContext,
723 void *plContext)
725 SECStatus rv = SECSuccess;
727 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_CallCertVerify");
729 if (response->verifyFcn != NULL) {
730 void *lplContext = NULL;
732 PKIX_CHECK(
733 PKIX_PL_NssContext_Create(((SECCertificateUsage)1) << certUsage,
734 PKIX_FALSE, NULL, &lplContext),
735 PKIX_NSSCONTEXTCREATEFAILED);
737 PKIX_CHECK(
738 (response->verifyFcn)(response->pkixSignerCert,
739 response->producedAtDate,
740 procParams, pNBIOContext,
741 state, buildResult,
742 NULL, lplContext),
743 PKIX_CERTVERIFYKEYUSAGEFAILED);
744 } else {
745 rv = CERT_VerifyCert(response->handle, response->signerCert, PKIX_TRUE,
746 certUsage, response->producedAt, NULL, NULL);
747 if (rv != SECSuccess) {
748 PKIX_ERROR(PKIX_CERTVERIFYKEYUSAGEFAILED);
752 cleanup:
754 PKIX_RETURN(OCSPRESPONSE);
758 * FUNCTION: pkix_pl_OcspResponse_VerifySignature
759 * DESCRIPTION:
761 * This function verifies the ocspResponse signature field in the OcspResponse
762 * pointed to by "response", storing PKIX_TRUE at "pPassed" if verification
763 * is successful and PKIX_FALSE otherwise. If verification is unsuccessful an
764 * error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode.
766 * PARAMETERS
767 * "response"
768 * The address of the OcspResponse whose signature field is to be
769 * retrieved. Must be non-NULL.
770 * "cert"
771 * The address of the Cert for which the OCSP query was made. Must be
772 * non-NULL.
773 * "procParams"
774 * Address of ProcessingParams used to initialize the ExpirationChecker
775 * and TargetCertChecker. Must be non-NULL.
776 * "pPassed"
777 * Address at which the Boolean result is stored. Must be non-NULL.
778 * "pNBIOContext"
779 * Address at which the NBIOContext is stored indicating whether the
780 * checking is complete. Must be non-NULL.
781 * "plContext"
782 * Platform-specific context pointer.
783 * THREAD SAFETY:
784 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
785 * RETURNS:
786 * Returns NULL if the function succeeds.
787 * Returns an OcspResponse Error if the function fails in a non-fatal way.
788 * Returns a Fatal Error if the function fails in an unrecoverable way.
790 PKIX_Error *
791 pkix_pl_OcspResponse_VerifySignature(
792 PKIX_PL_OcspResponse *response,
793 PKIX_PL_Cert *cert,
794 PKIX_ProcessingParams *procParams,
795 PKIX_Boolean *pPassed,
796 void **pNBIOContext,
797 void *plContext)
799 SECStatus rv = SECFailure;
800 CERTOCSPResponse *nssOCSPResponse = NULL;
801 CERTCertificate *issuerCert = NULL;
802 PKIX_BuildResult *buildResult = NULL;
803 void *nbio = NULL;
804 void *state = NULL;
806 ocspSignature *signature = NULL;
807 ocspResponseData *tbsData = NULL;
808 SECItem *tbsResponseDataDER = NULL;
811 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature");
812 PKIX_NULLCHECK_FOUR(response, cert, pPassed, pNBIOContext);
814 nbio = *pNBIOContext;
815 *pNBIOContext = NULL;
817 nssOCSPResponse = response->nssOCSPResponse;
818 if (nssOCSPResponse == NULL) {
819 PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
820 goto cleanup;
823 tbsData =
824 ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER);
826 signature = ocsp_GetResponseSignature(nssOCSPResponse);
829 /* Are we resuming after a WOULDBLOCK response? */
830 if (nbio == NULL) {
831 /* No, this is a new query */
833 issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(),
834 certUsageAnyCA);
837 * If this signature has already gone through verification,
838 * just return the cached result.
840 if (signature->wasChecked) {
841 if (signature->status == SECSuccess) {
842 response->signerCert =
843 CERT_DupCertificate(signature->cert);
844 } else {
845 PORT_SetError(signature->failureReason);
846 goto cleanup;
850 response->signerCert =
851 ocsp_GetSignerCertificate(response->handle, tbsData,
852 signature, issuerCert);
854 if (response->signerCert == NULL) {
855 PORT_SetError(SEC_ERROR_UNKNOWN_SIGNER);
856 goto cleanup;
859 PKIX_CHECK(
860 PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert,
861 &(response->pkixSignerCert),
862 plContext),
863 PKIX_CERTCREATEWITHNSSCERTFAILED);
866 * We could mark this true at the top of this function, or
867 * always below at "finish", but if the problem was just that
868 * we could not find the signer's cert, leave that as if the
869 * signature hasn't been checked. Maybe a subsequent call will
870 * have better luck.
872 signature->wasChecked = PR_TRUE;
875 * We are about to verify the signer certificate; we need to
876 * specify *when* that certificate must be valid -- for our
877 * purposes we expect it to be valid when the response was
878 * signed. The value of "producedAt" is the signing time.
880 rv = DER_GeneralizedTimeToTime(&response->producedAt,
881 &tbsData->producedAt);
882 if (rv != SECSuccess) {
883 PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
884 goto cleanup;
888 * We need producedAtDate and pkixSignerCert if we are calling a
889 * user-supplied verification function. Let's put their
890 * creation before the code that gets repeated when
891 * non-blocking I/O is used.
894 PKIX_CHECK(
895 pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt,
896 &(response->producedAtDate),
897 plContext),
898 PKIX_DATECREATEFROMPRTIMEFAILED);
903 * Just because we have a cert does not mean it is any good; check
904 * it for validity, trust and usage. Use the caller-supplied
905 * verification function, if one was supplied.
907 if (ocsp_CertIsOCSPDefaultResponder(response->handle,
908 response->signerCert)) {
909 rv = SECSuccess;
910 } else {
911 SECCertUsage certUsage;
912 if (CERT_IsCACert(response->signerCert, NULL)) {
913 certUsage = certUsageVerifyCA;
914 } else {
915 certUsage = certUsageStatusResponder;
917 /* Set negative result before call. If fail to verify, will jump
918 * into cleanup with rv = SECFailure. Restore rv after the call. */
919 rv = SECFailure;
920 PKIX_CHECK(
921 pkix_pl_OcspResponse_CallCertVerify(response, procParams,
922 certUsage, &state,
923 &buildResult, &nbio,
924 plContext),
925 PKIX_CERTVERIFYKEYUSAGEFAILED);
927 rv = SECSuccess;
929 if (nbio != NULL) {
930 *pNBIOContext = nbio;
931 goto cleanup;
935 rv = ocsp_VerifyResponseSignature(response->signerCert, signature,
936 tbsResponseDataDER, NULL);
938 cleanup:
939 if (rv == SECSuccess) {
940 *pPassed = PKIX_TRUE;
941 } else {
942 *pPassed = PKIX_FALSE;
945 if (signature->wasChecked) {
946 signature->status = rv;
949 if (rv != SECSuccess) {
950 signature->failureReason = PORT_GetError();
951 if (response->signerCert != NULL) {
952 CERT_DestroyCertificate(response->signerCert);
953 response->signerCert = NULL;
955 } else {
956 /* Save signer's certificate in signature. */
957 signature->cert = CERT_DupCertificate(response->signerCert);
960 PKIX_RETURN(OCSPRESPONSE);
964 * FUNCTION: pkix_pl_OcspResponse_GetStatusForCert
965 * DESCRIPTION:
967 * This function checks the revocation status of the Cert for which the
968 * OcspResponse was obtained, storing PKIX_TRUE at "pPassed" if the Cert has
969 * not been revoked and PKIX_FALSE otherwise.
971 * PARAMETERS
972 * "response"
973 * The address of the OcspResponse whose certificate status is to be
974 * retrieved. Must be non-NULL.
975 * "pPassed"
976 * Address at which the Boolean result is stored. Must be non-NULL.
977 * "pReturnCode"
978 * Address at which the SECErrorCodes result is stored. Must be non-NULL.
979 * "plContext"
980 * Platform-specific context pointer.
981 * THREAD SAFETY:
982 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
983 * RETURNS:
984 * Returns NULL if the function succeeds.
985 * Returns an OcspResponse Error if the function fails in a non-fatal way.
986 * Returns a Fatal Error if the function fails in an unrecoverable way.
988 PKIX_Error *
989 pkix_pl_OcspResponse_GetStatusForCert(
990 PKIX_PL_OcspCertID *cid,
991 PKIX_PL_OcspResponse *response,
992 PKIX_Boolean *pPassed,
993 SECErrorCodes *pReturnCode,
994 void *plContext)
996 SECStatus rv = SECFailure;
997 SECStatus rvCache;
999 PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert");
1000 PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode);
1003 * It is an error to call this function except following a successful
1004 * return from pkix_pl_OcspResponse_VerifySignature, which would have
1005 * set response->signerCert.
1007 PKIX_NULLCHECK_TWO(response->signerCert, response->request);
1009 rv = cert_ProcessOCSPResponse(response->handle,
1010 response->nssOCSPResponse,
1011 cid->certID,
1012 response->signerCert,
1013 PR_Now(),
1014 &cid->certIDWasConsumed,
1015 &rvCache);
1016 if (rv == SECSuccess) {
1017 *pPassed = PKIX_TRUE;
1018 *pReturnCode = 0;
1019 } else {
1020 *pPassed = PKIX_FALSE;
1021 *pReturnCode = PORT_GetError();
1024 PKIX_RETURN(OCSPRESPONSE);