andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: /* andre@0: * Private header defining OCSP types. andre@0: */ andre@0: andre@0: #ifndef _OCSPTI_H_ andre@0: #define _OCSPTI_H_ andre@0: andre@0: #include "ocspt.h" andre@0: andre@0: #include "certt.h" andre@0: #include "plarena.h" andre@0: #include "seccomon.h" andre@0: #include "secoidt.h" andre@0: andre@0: andre@0: /* andre@0: * Some notes about naming conventions... andre@0: * andre@0: * The public data types all start with "CERTOCSP" (e.g. CERTOCSPRequest). andre@0: * (Even the public types are opaque, however. Only their names are andre@0: * "exported".) andre@0: * andre@0: * Internal-only data types drop the "CERT" prefix and use only the andre@0: * lower-case "ocsp" (e.g. ocspTBSRequest), for brevity sake. andre@0: * andre@0: * In either case, the base/suffix of the type name usually matches the andre@0: * name as defined in the OCSP specification. The exceptions to this are: andre@0: * - When there is overlap between the "OCSP" or "ocsp" prefix and andre@0: * the name used in the standard. That is, you cannot strip off the andre@0: * "CERTOCSP" or "ocsp" prefix and necessarily get the name of the andre@0: * type as it is defined in the standard; the "real" name will be andre@0: * *either* "OCSPSuffix" or just "Suffix". andre@0: * - When the name in the standard was a little too generic. (e.g. The andre@0: * standard defines "Request" but we call it a "SingleRequest".) andre@0: * In this case a comment above the type definition calls attention andre@0: * to the difference. andre@0: * andre@0: * The definitions laid out in this header file are intended to follow andre@0: * the same order as the definitions in the OCSP specification itself. andre@0: * With the OCSP standard in hand, you should be able to move through andre@0: * this file and follow along. To future modifiers of this file: please andre@0: * try to keep it that way. The only exceptions are the few cases where andre@0: * we need to define a type before it is referenced (e.g. enumerations), andre@0: * whereas in the OCSP specification these are usually defined the other andre@0: * way around (reference before definition). andre@0: */ andre@0: andre@0: andre@0: /* andre@0: * Forward-declarations of internal-only data structures. andre@0: * andre@0: * These are in alphabetical order (case-insensitive); please keep it that way! andre@0: */ andre@0: typedef struct ocspBasicOCSPResponseStr ocspBasicOCSPResponse; andre@0: typedef struct ocspCertStatusStr ocspCertStatus; andre@0: typedef struct ocspResponderIDStr ocspResponderID; andre@0: typedef struct ocspResponseBytesStr ocspResponseBytes; andre@0: typedef struct ocspResponseDataStr ocspResponseData; andre@0: typedef struct ocspRevokedInfoStr ocspRevokedInfo; andre@0: typedef struct ocspServiceLocatorStr ocspServiceLocator; andre@0: typedef struct ocspSignatureStr ocspSignature; andre@0: typedef struct ocspSingleRequestStr ocspSingleRequest; andre@0: typedef struct ocspSingleResponseStr ocspSingleResponse; andre@0: typedef struct ocspTBSRequestStr ocspTBSRequest; andre@0: andre@0: andre@0: /* andre@0: * An OCSPRequest; this is what is sent (encoded) to an OCSP responder. andre@0: */ andre@0: struct CERTOCSPRequestStr { andre@0: PLArenaPool *arena; /* local; not part of encoding */ andre@0: ocspTBSRequest *tbsRequest; andre@0: ocspSignature *optionalSignature; andre@0: }; andre@0: andre@0: /* andre@0: * A TBSRequest; when an OCSPRequest is signed, the encoding of this andre@0: * is what the signature is actually applied to. ("TBS" == To Be Signed) andre@0: * Whether signed or not, however, this structure will be present, and andre@0: * is the "meat" of the OCSPRequest. andre@0: * andre@0: * Note that the "requestorName" field cannot be encoded/decoded in the andre@0: * same pass as the entire request -- it needs to be handled with a special andre@0: * call to convert to/from our internal form of a GeneralName. Thus the andre@0: * "derRequestorName" field, which is the actual DER-encoded bytes. andre@0: * andre@0: * The "extensionHandle" field is used on creation only; it holds andre@0: * in-progress extensions as they are optionally added to the request. andre@0: */ andre@0: struct ocspTBSRequestStr { andre@0: SECItem version; /* an INTEGER */ andre@0: SECItem *derRequestorName; /* encoded GeneralName; see above */ andre@0: CERTGeneralNameList *requestorName; /* local; not part of encoding */ andre@0: ocspSingleRequest **requestList; andre@0: CERTCertExtension **requestExtensions; andre@0: void *extensionHandle; /* local; not part of encoding */ andre@0: }; andre@0: andre@0: /* andre@0: * This is the actual signature information for an OCSPRequest (applied to andre@0: * the TBSRequest structure) or for a BasicOCSPResponse (applied to a andre@0: * ResponseData structure). andre@0: * andre@0: * Note that the "signature" field itself is a BIT STRING; operations on andre@0: * it need to keep that in mind, converting the length to bytes as needed andre@0: * and back again afterward (so that the length is usually expressing bits). andre@0: * andre@0: * The "cert" field is the signer's certificate. In the case of a received andre@0: * signature, it will be filled in when the signature is verified. In the andre@0: * case of a created signature, it is filled in on creation and will be the andre@0: * cert used to create the signature when the signing-and-encoding occurs, andre@0: * as well as the cert (and its chain) to fill in derCerts if requested. andre@0: * andre@0: * The extra fields cache information about the signature after we have andre@0: * attempted a verification. "wasChecked", if true, means the signature andre@0: * has been checked against the appropriate data and thus that "status" andre@0: * contains the result of that verification. If "status" is not SECSuccess, andre@0: * "failureReason" is a copy of the error code that was set at the time; andre@0: * presumably it tells why the signature verification failed. andre@0: */ andre@0: struct ocspSignatureStr { andre@0: SECAlgorithmID signatureAlgorithm; andre@0: SECItem signature; /* a BIT STRING */ andre@0: SECItem **derCerts; /* a SEQUENCE OF Certificate */ andre@0: CERTCertificate *cert; /* local; not part of encoding */ andre@0: PRBool wasChecked; /* local; not part of encoding */ andre@0: SECStatus status; /* local; not part of encoding */ andre@0: int failureReason; /* local; not part of encoding */ andre@0: }; andre@0: andre@0: /* andre@0: * An OCSPRequest contains a SEQUENCE OF these, one for each certificate andre@0: * whose status is being checked. andre@0: * andre@0: * Note that in the OCSP specification this is just called "Request", andre@0: * but since that seemed confusing (vs. an OCSPRequest) and to be more andre@0: * consistent with the parallel type "SingleResponse", I called it a andre@0: * "SingleRequest". andre@0: * andre@0: * XXX figure out how to get rid of that arena -- there must be a way andre@0: */ andre@0: struct ocspSingleRequestStr { andre@0: PLArenaPool *arena; /* just a copy of the response arena, andre@0: * needed here for extension handling andre@0: * routines, on creation only */ andre@0: CERTOCSPCertID *reqCert; andre@0: CERTCertExtension **singleRequestExtensions; andre@0: }; andre@0: andre@0: /* andre@0: * A CertID is the means of identifying a certificate, used both in requests andre@0: * and in responses. andre@0: * andre@0: * When in a SingleRequest it specifies the certificate to be checked. andre@0: * When in a SingleResponse it is the cert whose status is being given. andre@0: */ andre@0: struct CERTOCSPCertIDStr { andre@0: SECAlgorithmID hashAlgorithm; andre@0: SECItem issuerNameHash; /* an OCTET STRING */ andre@0: SECItem issuerKeyHash; /* an OCTET STRING */ andre@0: SECItem serialNumber; /* an INTEGER */ andre@0: SECItem issuerSHA1NameHash; /* keep other hashes around when */ andre@0: SECItem issuerMD5NameHash; /* we have them */ andre@0: SECItem issuerMD2NameHash; andre@0: SECItem issuerSHA1KeyHash; /* keep other hashes around when */ andre@0: SECItem issuerMD5KeyHash; /* we have them */ andre@0: SECItem issuerMD2KeyHash; andre@0: PLArenaPool *poolp; andre@0: }; andre@0: andre@0: /* andre@0: * This describes the value of the responseStatus field in an OCSPResponse. andre@0: * The corresponding ASN.1 definition is: andre@0: * andre@0: * OCSPResponseStatus ::= ENUMERATED { andre@0: * successful (0), --Response has valid confirmations andre@0: * malformedRequest (1), --Illegal confirmation request andre@0: * internalError (2), --Internal error in issuer andre@0: * tryLater (3), --Try again later andre@0: * --(4) is not used andre@0: * sigRequired (5), --Must sign the request andre@0: * unauthorized (6), --Request unauthorized andre@0: * } andre@0: */ andre@0: typedef enum { andre@0: ocspResponse_min = 0, andre@0: ocspResponse_successful = 0, andre@0: ocspResponse_malformedRequest = 1, andre@0: ocspResponse_internalError = 2, andre@0: ocspResponse_tryLater = 3, andre@0: ocspResponse_unused = 4, andre@0: ocspResponse_sigRequired = 5, andre@0: ocspResponse_unauthorized = 6, andre@0: ocspResponse_max = 6 /* Please update max when adding values. andre@0: * Remember to also update arrays, e.g. andre@0: * "responseStatusNames" in ocspclnt.c andre@0: * and potentially other places. */ andre@0: } ocspResponseStatus; andre@0: andre@0: /* andre@0: * An OCSPResponse is what is sent (encoded) by an OCSP responder. andre@0: * andre@0: * The field "responseStatus" is the ASN.1 encoded value; the field andre@0: * "statusValue" is simply that same value translated into our local andre@0: * type ocspResponseStatus. andre@0: */ andre@0: struct CERTOCSPResponseStr { andre@0: PLArenaPool *arena; /* local; not part of encoding */ andre@0: SECItem responseStatus; /* an ENUMERATED, see above */ andre@0: ocspResponseStatus statusValue; /* local; not part of encoding */ andre@0: ocspResponseBytes *responseBytes; /* only when status is successful */ andre@0: }; andre@0: andre@0: /* andre@0: * A ResponseBytes (despite appearances) is what contains the meat andre@0: * of a successful response -- but still in encoded form. The type andre@0: * given as "responseType" tells you how to decode the string. andre@0: * andre@0: * We look at the OID and translate it into our local OID representation andre@0: * "responseTypeTag", and use that value to tell us how to decode the andre@0: * actual response itself. For now the only kind of OCSP response we andre@0: * know about is a BasicOCSPResponse. However, the intention in the andre@0: * OCSP specification is to allow for other response types, so we are andre@0: * building in that flexibility from the start and thus put a pointer andre@0: * to that data structure inside of a union. Whenever OCSP adds more andre@0: * response types, just add them to the union. andre@0: */ andre@0: struct ocspResponseBytesStr { andre@0: SECItem responseType; /* an OBJECT IDENTIFIER */ andre@0: SECOidTag responseTypeTag; /* local; not part of encoding */ andre@0: SECItem response; /* an OCTET STRING */ andre@0: union { andre@0: ocspBasicOCSPResponse *basic; /* when type is id-pkix-ocsp-basic */ andre@0: } decodedResponse; /* local; not part of encoding */ andre@0: }; andre@0: andre@0: /* andre@0: * A BasicOCSPResponse -- when the responseType in a ResponseBytes is andre@0: * id-pkix-ocsp-basic, the "response" OCTET STRING above is the DER andre@0: * encoding of one of these. andre@0: * andre@0: * Note that in the OCSP specification, the signature fields are not andre@0: * part of a separate sub-structure. But since they are the same fields andre@0: * as we define for the signature in a request, it made sense to share andre@0: * the C data structure here and in some shared code to operate on them. andre@0: */ andre@0: struct ocspBasicOCSPResponseStr { andre@0: SECItem tbsResponseDataDER; andre@0: ocspResponseData *tbsResponseData; /* "tbs" == To Be Signed */ andre@0: ocspSignature responseSignature; andre@0: }; andre@0: andre@0: /* andre@0: * A ResponseData is the part of a BasicOCSPResponse that is signed andre@0: * (after it is DER encoded). It contains the real details of the response andre@0: * (a per-certificate status). andre@0: */ andre@0: struct ocspResponseDataStr { andre@0: SECItem version; /* an INTEGER */ andre@0: SECItem derResponderID; andre@0: ocspResponderID *responderID; /* local; not part of encoding */ andre@0: SECItem producedAt; /* a GeneralizedTime */ andre@0: CERTOCSPSingleResponse **responses; andre@0: CERTCertExtension **responseExtensions; andre@0: }; andre@0: andre@0: struct ocspResponderIDStr { andre@0: CERTOCSPResponderIDType responderIDType;/* local; not part of encoding */ andre@0: union { andre@0: CERTName name; /* when ocspResponderID_byName */ andre@0: SECItem keyHash; /* when ocspResponderID_byKey */ andre@0: SECItem other; /* when ocspResponderID_other */ andre@0: } responderIDValue; andre@0: }; andre@0: andre@0: /* andre@0: * The ResponseData in a BasicOCSPResponse contains a SEQUENCE OF andre@0: * SingleResponse -- one for each certificate whose status is being supplied. andre@0: * andre@0: * XXX figure out how to get rid of that arena -- there must be a way andre@0: */ andre@0: struct CERTOCSPSingleResponseStr { andre@0: PLArenaPool *arena; /* just a copy of the response arena, andre@0: * needed here for extension handling andre@0: * routines, on creation only */ andre@0: CERTOCSPCertID *certID; andre@0: SECItem derCertStatus; andre@0: ocspCertStatus *certStatus; /* local; not part of encoding */ andre@0: SECItem thisUpdate; /* a GeneralizedTime */ andre@0: SECItem *nextUpdate; /* a GeneralizedTime */ andre@0: CERTCertExtension **singleExtensions; andre@0: }; andre@0: andre@0: /* andre@0: * A CertStatus is the actual per-certificate status. Its ASN.1 definition: andre@0: * andre@0: * CertStatus ::= CHOICE { andre@0: * good [0] IMPLICIT NULL, andre@0: * revoked [1] IMPLICIT RevokedInfo, andre@0: * unknown [2] IMPLICIT UnknownInfo } andre@0: * andre@0: * (where for now UnknownInfo is defined to be NULL but in the andre@0: * future may be replaced with an enumeration). andre@0: * andre@0: * Because it is CHOICE, the status value and its associated information andre@0: * (if any) are actually encoded together. To represent this same andre@0: * information internally, we explicitly define a type and save it, andre@0: * along with the value, into a data structure. andre@0: */ andre@0: andre@0: typedef enum { andre@0: ocspCertStatus_good, /* cert is not revoked */ andre@0: ocspCertStatus_revoked, /* cert is revoked */ andre@0: ocspCertStatus_unknown, /* cert was unknown to the responder */ andre@0: ocspCertStatus_other /* status was not an expected value */ andre@0: } ocspCertStatusType; andre@0: andre@0: /* andre@0: * This is the actual per-certificate status. andre@0: * andre@0: * The "goodInfo" and "unknownInfo" items are only place-holders for a NULL. andre@0: * (Though someday OCSP may replace UnknownInfo with an enumeration that andre@0: * gives more detailed information.) andre@0: */ andre@0: struct ocspCertStatusStr { andre@0: ocspCertStatusType certStatusType; /* local; not part of encoding */ andre@0: union { andre@0: SECItem *goodInfo; /* when ocspCertStatus_good */ andre@0: ocspRevokedInfo *revokedInfo; /* when ocspCertStatus_revoked */ andre@0: SECItem *unknownInfo; /* when ocspCertStatus_unknown */ andre@0: SECItem *otherInfo; /* when ocspCertStatus_other */ andre@0: } certStatusInfo; andre@0: }; andre@0: andre@0: /* andre@0: * A RevokedInfo gives information about a revoked certificate -- when it andre@0: * was revoked and why. andre@0: */ andre@0: struct ocspRevokedInfoStr { andre@0: SECItem revocationTime; /* a GeneralizedTime */ andre@0: SECItem *revocationReason; /* a CRLReason; ignored for now */ andre@0: }; andre@0: andre@0: /* andre@0: * ServiceLocator can be included as one of the singleRequestExtensions. andre@0: * When added, it specifies the (name of the) issuer of the cert being andre@0: * checked, and optionally the value of the AuthorityInfoAccess extension andre@0: * if the cert has one. andre@0: */ andre@0: struct ocspServiceLocatorStr { andre@0: CERTName *issuer; andre@0: SECItem locator; /* DER encoded authInfoAccess extension from cert */ andre@0: }; andre@0: andre@0: #endif /* _OCSPTI_H_ */