Break up OCSP so that 3rd party apps can send off an OCSP request and parse

it.
This commit is contained in:
javi%netscape.com 2002-07-03 00:02:39 +00:00
parent 3c19a51662
commit 1f078c5776
5 changed files with 185 additions and 79 deletions

View File

@ -35,7 +35,7 @@
* Implementation of OCSP services, for both client and server.
* (XXX, really, mostly just for client right now, but intended to do both.)
*
* $Id: ocsp.c,v 1.7 2002/06/06 01:05:40 jpierre%netscape.com Exp $
* $Id: ocsp.c,v 1.8 2002/07/03 00:02:34 javi%netscape.com Exp $
*/
#include "prerror.h"
@ -596,6 +596,14 @@ loser:
return NULL;
}
SECStatus
CERT_DestroyOCSPCertID(CERTOCSPCertID* certID)
{
if (certID->poolp)
PORT_FreeArena(certID->poolp, PR_FALSE);
return SECSuccess;
}
/*
* Create and fill-in a CertID. This function fills in the hash values
@ -718,6 +726,21 @@ loser:
return NULL;
}
CERTOCSPCertID*
CERT_CreateOCSPCertID(CERTCertificate *cert, int64 time)
{
PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
CERTOCSPCertID *certID;
PORT_Assert(arena != NULL);
if (!arena)
return NULL;
certID = ocsp_CreateCertID(arena, cert, time);
certID->poolp = arena;
return certID;
}
/*
* Callback to set Extensions in request object
@ -1391,7 +1414,7 @@ CERT_DecodeOCSPResponse(SECItem *src)
PRArenaPool *arena = NULL;
CERTOCSPResponse *response = NULL;
SECStatus rv = SECFailure;
ocspResponseStatus sv;
OCSPResponseStatus sv;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) {
@ -1411,9 +1434,9 @@ CERT_DecodeOCSPResponse(SECItem *src)
goto loser;
}
sv = (ocspResponseStatus) DER_GetInteger(&response->responseStatus);
sv = (OCSPResponseStatus) DER_GetInteger(&response->responseStatus);
response->statusValue = sv;
if (sv != ocspResponse_successful) {
if (sv != OCSPResponse_successful) {
/*
* If the response status is anything but successful, then we
* are all done with decoding; the status is all there is.
@ -3225,10 +3248,7 @@ CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
CERTOCSPResponse *response = NULL;
CERTCertificate *signerCert = NULL;
CERTCertificate *issuerCert = NULL;
ocspResponseData *responseData;
int64 producedAt;
CERTOCSPCertID *certID;
CERTOCSPSingleResponse *single;
SECStatus rv = SECFailure;
@ -3308,27 +3328,27 @@ CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
* Otherwise, we continue to find the actual per-cert status
* in the response.
*/
switch (response->statusValue) {
case ocspResponse_successful:
switch (CERT_GetStatusValue(response)) {
case OCSPResponse_successful:
break;
case ocspResponse_malformedRequest:
case OCSPResponse_malformedRequest:
PORT_SetError(SEC_ERROR_OCSP_MALFORMED_REQUEST);
goto loser;
case ocspResponse_internalError:
case OCSPResponse_internalError:
PORT_SetError(SEC_ERROR_OCSP_SERVER_ERROR);
goto loser;
case ocspResponse_tryLater:
case OCSPResponse_tryLater:
PORT_SetError(SEC_ERROR_OCSP_TRY_SERVER_LATER);
goto loser;
case ocspResponse_sigRequired:
case OCSPResponse_sigRequired:
/* XXX We *should* retry with a signature, if possible. */
PORT_SetError(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG);
goto loser;
case ocspResponse_unauthorized:
case OCSPResponse_unauthorized:
PORT_SetError(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST);
goto loser;
case ocspResponse_other:
case ocspResponse_unused:
case OCSPResponse_other:
case OCSPResponse_unused:
default:
PORT_SetError(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS);
goto loser;
@ -3347,6 +3367,57 @@ CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
PORT_Assert(signerCert != NULL); /* internal consistency check */
/* XXX probably should set error, return failure if signerCert is null */
/*
* Again, we are only doing one request for one cert.
* XXX When we handle cert chains, the following code will obviously
* have to be modified, in coordation with the code above that will
* have to determine how to make multiple requests, etc. It will need
* to loop, and for each certID in the request, find the matching
* single response and check the status specified by it.
*
* We are helped here in that we know that the requests are made with
* the request list in the same order as the order of the certs we hand
* to it. This is why I can directly access the first member of the
* single request array for the one cert I care about.
*/
certID = request->tbsRequest->requestList[0]->reqCert;
rv = CERT_GetOCSPStatusForCertID(handle, response, certID,
signerCert, time);
/*
* Add back the loser clause and corresponding free's...
*/
loser:
if (issuerCert != NULL)
CERT_DestroyCertificate(issuerCert);
if (signerCert != NULL)
CERT_DestroyCertificate(signerCert);
if (response != NULL)
CERT_DestroyOCSPResponse(response);
if (request != NULL)
CERT_DestroyOCSPRequest(request);
if (encodedResponse != NULL)
SECITEM_FreeItem(encodedResponse, PR_TRUE);
if (certList != NULL)
CERT_DestroyCertList(certList);
if (location != NULL)
PORT_Free(location);
return rv;
}
SECStatus
CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle,
CERTOCSPResponse *response,
CERTOCSPCertID *certID,
CERTCertificate *signerCert,
int64 time)
{
SECStatus rv;
ocspResponseData *responseData;
int64 producedAt;
CERTOCSPSingleResponse *single;
/*
* The ResponseData part is the real guts of the response.
*/
@ -3366,25 +3437,12 @@ CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
if (rv != SECSuccess)
goto loser;
/*
* Again, we are only doing one request for one cert.
* XXX When we handle cert chains, the following code will obviously
* have to be modified, in coordation with the code above that will
* have to determine how to make multiple requests, etc. It will need
* to loop, and for each certID in the request, find the matching
* single response and check the status specified by it.
*
* We are helped here in that we know that the requests are made with
* the request list in the same order as the order of the certs we hand
* to it. This is why I can directly access the first member of the
* single request array for the one cert I care about.
*/
certID = request->tbsRequest->requestList[0]->reqCert;
single = ocsp_GetSingleResponseForCertID(responseData->responses,
handle, certID);
if (single == NULL)
if (single == NULL) {
rv = SECFailure;
goto loser;
}
rv = ocsp_VerifySingleResponse(single, handle, signerCert, producedAt);
if (rv != SECSuccess)
@ -3396,23 +3454,7 @@ CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
*/
rv = ocsp_CertHasGoodStatus(single, time);
loser:
if (issuerCert != NULL)
CERT_DestroyCertificate(issuerCert);
if (signerCert != NULL)
CERT_DestroyCertificate(signerCert);
if (response != NULL)
CERT_DestroyOCSPResponse(response);
if (request != NULL)
CERT_DestroyOCSPRequest(request);
if (encodedResponse != NULL)
SECITEM_FreeItem(encodedResponse, PR_TRUE);
if (certList != NULL)
CERT_DestroyCertList(certList);
if (location != NULL)
PORT_Free(location);
return rv;
}
@ -3927,4 +3969,9 @@ loser:
return(NULL);
}
OCSPResponseStatus
CERT_GetStatusValue(CERTOCSPResponse *response)
{
PORT_Assert(response);
return response->statusValue;
}

View File

@ -34,7 +34,7 @@
/*
* Interface to the OCSP implementation.
*
* $Id: ocsp.h,v 1.2 2001/11/08 00:14:45 relyea%netscape.com Exp $
* $Id: ocsp.h,v 1.3 2002/07/03 00:02:34 javi%netscape.com Exp $
*/
#ifndef _OCSP_H_
@ -449,6 +449,50 @@ CERT_GetOCSPAuthorityInfoAccessLocation(CERTCertificate *cert);
extern SECStatus
CERT_CheckOCSPStatus(CERTCertDBHandle *handle, CERTCertificate *cert,
int64 time, void *pwArg);
/*
* FUNCTION: CERT_GetOCSPStatusForCertID
* Returns the OCSP status contained in the passed in paramter response
* that corresponds to the certID passed in.
* INPUTS:
* CERTCertDBHandle *handle
* certificate DB of the cert that is being checked
* CERTOCSPResponse *response
* the OCSP response we want to retrieve status from.
* CERTOCSPCertID *certID
* the ID we want to look for from the response.
* CERTCertificate *signerCert
* the certificate that was used to sign the OCSP response.
* must be obtained via a call to CERT_VerifyOCSPResponseSignature.
* int64 time
* The time at which we're checking the status for.
* RETURN:
* Return values are the same as those for CERT_CheckOCSPStatus
*/
extern SECStatus
CERT_GetOCSPStatusForCertID(CERTCertDBHandle *handle,
CERTOCSPResponse *response,
CERTOCSPCertID *certID,
CERTCertificate *signerCert,
int64 time);
/*
* FUNCTION CERT_GetStatusValue
* Returns the response status for the response passed.
* INPUTS:
* CERTOCSPResponse *response
* The response to query for status
* RETURN:
* OCSPResponseStatus an enumeration corresponding to the possible
* return values listed in the OCSP spec.
*/
extern OCSPResponseStatus
CERT_GetStatusValue(CERTOCSPResponse *response);
extern CERTOCSPCertID*
CERT_CreateOCSPCertID(CERTCertificate *cert, int64 time);
extern SECStatus
CERT_DestroyOCSPCertID(CERTOCSPCertID* certID);
/************************************************************************/
SEC_END_PROTOS

View File

@ -34,7 +34,7 @@
/*
* Public header for exported OCSP types.
*
* $Id: ocspt.h,v 1.1 2000/03/31 19:43:03 relyea%netscape.com Exp $
* $Id: ocspt.h,v 1.2 2002/07/03 00:02:34 javi%netscape.com Exp $
*/
#ifndef _OCSPT_H_
@ -56,4 +56,33 @@ typedef struct CERTOCSPCertIDStr CERTOCSPCertID;
typedef struct CERTOCSPCertStatusStr CERTOCSPCertStatus;
typedef struct CERTOCSPSingleResponseStr CERTOCSPSingleResponse;
/*
* Making these types public so that it is possible for 3rpd party
* apps to parse and look at the fields of an OCSP response.
*/
/*
* This describes the value of the responseStatus field in an OCSPResponse.
* The corresponding ASN.1 definition is:
*
* OCSPResponseStatus ::= ENUMERATED {
* successful (0), --Response has valid confirmations
* malformedRequest (1), --Illegal confirmation request
* internalError (2), --Internal error in issuer
* tryLater (3), --Try again later
* --(4) is not used
* sigRequired (5), --Must sign the request
* unauthorized (6), --Request unauthorized
* }
*/
typedef enum {
OCSPResponse_successful = 0,
OCSPResponse_malformedRequest = 1,
OCSPResponse_internalError = 2,
OCSPResponse_tryLater = 3,
OCSPResponse_unused = 4,
OCSPResponse_sigRequired = 5,
OCSPResponse_unauthorized = 6,
OCSPResponse_other /* unknown/unrecognized value */
} OCSPResponseStatus;
#endif /* _OCSPT_H_ */

View File

@ -34,7 +34,7 @@
/*
* Private header defining OCSP types.
*
* $Id: ocspti.h,v 1.2 2001/11/08 00:14:45 relyea%netscape.com Exp $
* $Id: ocspti.h,v 1.3 2002/07/03 00:02:35 javi%netscape.com Exp $
*/
#ifndef _OCSPTI_H_
@ -200,44 +200,20 @@ struct CERTOCSPCertIDStr {
SECItem issuerSHA1KeyHash; /* keep other hashes around when */
SECItem issuerMD5KeyHash; /* we have them */
SECItem issuerMD2KeyHash;
PRArenaPool *poolp;
};
/*
* This describes the value of the responseStatus field in an OCSPResponse.
* The corresponding ASN.1 definition is:
*
* OCSPResponseStatus ::= ENUMERATED {
* successful (0), --Response has valid confirmations
* malformedRequest (1), --Illegal confirmation request
* internalError (2), --Internal error in issuer
* tryLater (3), --Try again later
* --(4) is not used
* sigRequired (5), --Must sign the request
* unauthorized (6), --Request unauthorized
* }
*/
typedef enum {
ocspResponse_successful = 0,
ocspResponse_malformedRequest = 1,
ocspResponse_internalError = 2,
ocspResponse_tryLater = 3,
ocspResponse_unused = 4,
ocspResponse_sigRequired = 5,
ocspResponse_unauthorized = 6,
ocspResponse_other /* unknown/unrecognized value */
} ocspResponseStatus;
/*
* An OCSPResponse is what is sent (encoded) by an OCSP responder.
*
* The field "responseStatus" is the ASN.1 encoded value; the field
* "statusValue" is simply that same value translated into our local
* type ocspResponseStatus.
* type OCSPResponseStatus.
*/
struct CERTOCSPResponseStr {
PRArenaPool *arena; /* local; not part of encoding */
SECItem responseStatus; /* an ENUMERATED, see above */
ocspResponseStatus statusValue; /* local; not part of encoding */
OCSPResponseStatus statusValue; /* local; not part of encoding */
ocspResponseBytes *responseBytes; /* only when status is successful */
};

View File

@ -685,6 +685,16 @@ SECMOD_CanDeleteInternalModule;
PK11_GetPBEIV;
PK11_SaveContextAlloc;
CERT_VerifyCertChain;
CERT_DestroyOCSPRequest;
CERT_EncodeOCSPRequest;
CERT_AddOCSPAcceptableResponses;
CERT_CreateOCSPRequest;
CERT_GetOCSPStatusForCertID;
CERT_DecodeOCSPResponse;
CERT_VerifyOCSPResponseSignature;
CERT_GetStatusValue;
CERT_DestroyOCSPCertID;
CERT_CreateOCSPCertID;
;+ local:
;+ *;
;+};