Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | /* |
michael@0 | 6 | * Private header defining OCSP types. |
michael@0 | 7 | */ |
michael@0 | 8 | |
michael@0 | 9 | #ifndef _OCSPTI_H_ |
michael@0 | 10 | #define _OCSPTI_H_ |
michael@0 | 11 | |
michael@0 | 12 | #include "ocspt.h" |
michael@0 | 13 | |
michael@0 | 14 | #include "certt.h" |
michael@0 | 15 | #include "plarena.h" |
michael@0 | 16 | #include "seccomon.h" |
michael@0 | 17 | #include "secoidt.h" |
michael@0 | 18 | |
michael@0 | 19 | |
michael@0 | 20 | /* |
michael@0 | 21 | * Some notes about naming conventions... |
michael@0 | 22 | * |
michael@0 | 23 | * The public data types all start with "CERTOCSP" (e.g. CERTOCSPRequest). |
michael@0 | 24 | * (Even the public types are opaque, however. Only their names are |
michael@0 | 25 | * "exported".) |
michael@0 | 26 | * |
michael@0 | 27 | * Internal-only data types drop the "CERT" prefix and use only the |
michael@0 | 28 | * lower-case "ocsp" (e.g. ocspTBSRequest), for brevity sake. |
michael@0 | 29 | * |
michael@0 | 30 | * In either case, the base/suffix of the type name usually matches the |
michael@0 | 31 | * name as defined in the OCSP specification. The exceptions to this are: |
michael@0 | 32 | * - When there is overlap between the "OCSP" or "ocsp" prefix and |
michael@0 | 33 | * the name used in the standard. That is, you cannot strip off the |
michael@0 | 34 | * "CERTOCSP" or "ocsp" prefix and necessarily get the name of the |
michael@0 | 35 | * type as it is defined in the standard; the "real" name will be |
michael@0 | 36 | * *either* "OCSPSuffix" or just "Suffix". |
michael@0 | 37 | * - When the name in the standard was a little too generic. (e.g. The |
michael@0 | 38 | * standard defines "Request" but we call it a "SingleRequest".) |
michael@0 | 39 | * In this case a comment above the type definition calls attention |
michael@0 | 40 | * to the difference. |
michael@0 | 41 | * |
michael@0 | 42 | * The definitions laid out in this header file are intended to follow |
michael@0 | 43 | * the same order as the definitions in the OCSP specification itself. |
michael@0 | 44 | * With the OCSP standard in hand, you should be able to move through |
michael@0 | 45 | * this file and follow along. To future modifiers of this file: please |
michael@0 | 46 | * try to keep it that way. The only exceptions are the few cases where |
michael@0 | 47 | * we need to define a type before it is referenced (e.g. enumerations), |
michael@0 | 48 | * whereas in the OCSP specification these are usually defined the other |
michael@0 | 49 | * way around (reference before definition). |
michael@0 | 50 | */ |
michael@0 | 51 | |
michael@0 | 52 | |
michael@0 | 53 | /* |
michael@0 | 54 | * Forward-declarations of internal-only data structures. |
michael@0 | 55 | * |
michael@0 | 56 | * These are in alphabetical order (case-insensitive); please keep it that way! |
michael@0 | 57 | */ |
michael@0 | 58 | typedef struct ocspBasicOCSPResponseStr ocspBasicOCSPResponse; |
michael@0 | 59 | typedef struct ocspCertStatusStr ocspCertStatus; |
michael@0 | 60 | typedef struct ocspResponderIDStr ocspResponderID; |
michael@0 | 61 | typedef struct ocspResponseBytesStr ocspResponseBytes; |
michael@0 | 62 | typedef struct ocspResponseDataStr ocspResponseData; |
michael@0 | 63 | typedef struct ocspRevokedInfoStr ocspRevokedInfo; |
michael@0 | 64 | typedef struct ocspServiceLocatorStr ocspServiceLocator; |
michael@0 | 65 | typedef struct ocspSignatureStr ocspSignature; |
michael@0 | 66 | typedef struct ocspSingleRequestStr ocspSingleRequest; |
michael@0 | 67 | typedef struct ocspSingleResponseStr ocspSingleResponse; |
michael@0 | 68 | typedef struct ocspTBSRequestStr ocspTBSRequest; |
michael@0 | 69 | |
michael@0 | 70 | |
michael@0 | 71 | /* |
michael@0 | 72 | * An OCSPRequest; this is what is sent (encoded) to an OCSP responder. |
michael@0 | 73 | */ |
michael@0 | 74 | struct CERTOCSPRequestStr { |
michael@0 | 75 | PLArenaPool *arena; /* local; not part of encoding */ |
michael@0 | 76 | ocspTBSRequest *tbsRequest; |
michael@0 | 77 | ocspSignature *optionalSignature; |
michael@0 | 78 | }; |
michael@0 | 79 | |
michael@0 | 80 | /* |
michael@0 | 81 | * A TBSRequest; when an OCSPRequest is signed, the encoding of this |
michael@0 | 82 | * is what the signature is actually applied to. ("TBS" == To Be Signed) |
michael@0 | 83 | * Whether signed or not, however, this structure will be present, and |
michael@0 | 84 | * is the "meat" of the OCSPRequest. |
michael@0 | 85 | * |
michael@0 | 86 | * Note that the "requestorName" field cannot be encoded/decoded in the |
michael@0 | 87 | * same pass as the entire request -- it needs to be handled with a special |
michael@0 | 88 | * call to convert to/from our internal form of a GeneralName. Thus the |
michael@0 | 89 | * "derRequestorName" field, which is the actual DER-encoded bytes. |
michael@0 | 90 | * |
michael@0 | 91 | * The "extensionHandle" field is used on creation only; it holds |
michael@0 | 92 | * in-progress extensions as they are optionally added to the request. |
michael@0 | 93 | */ |
michael@0 | 94 | struct ocspTBSRequestStr { |
michael@0 | 95 | SECItem version; /* an INTEGER */ |
michael@0 | 96 | SECItem *derRequestorName; /* encoded GeneralName; see above */ |
michael@0 | 97 | CERTGeneralNameList *requestorName; /* local; not part of encoding */ |
michael@0 | 98 | ocspSingleRequest **requestList; |
michael@0 | 99 | CERTCertExtension **requestExtensions; |
michael@0 | 100 | void *extensionHandle; /* local; not part of encoding */ |
michael@0 | 101 | }; |
michael@0 | 102 | |
michael@0 | 103 | /* |
michael@0 | 104 | * This is the actual signature information for an OCSPRequest (applied to |
michael@0 | 105 | * the TBSRequest structure) or for a BasicOCSPResponse (applied to a |
michael@0 | 106 | * ResponseData structure). |
michael@0 | 107 | * |
michael@0 | 108 | * Note that the "signature" field itself is a BIT STRING; operations on |
michael@0 | 109 | * it need to keep that in mind, converting the length to bytes as needed |
michael@0 | 110 | * and back again afterward (so that the length is usually expressing bits). |
michael@0 | 111 | * |
michael@0 | 112 | * The "cert" field is the signer's certificate. In the case of a received |
michael@0 | 113 | * signature, it will be filled in when the signature is verified. In the |
michael@0 | 114 | * case of a created signature, it is filled in on creation and will be the |
michael@0 | 115 | * cert used to create the signature when the signing-and-encoding occurs, |
michael@0 | 116 | * as well as the cert (and its chain) to fill in derCerts if requested. |
michael@0 | 117 | * |
michael@0 | 118 | * The extra fields cache information about the signature after we have |
michael@0 | 119 | * attempted a verification. "wasChecked", if true, means the signature |
michael@0 | 120 | * has been checked against the appropriate data and thus that "status" |
michael@0 | 121 | * contains the result of that verification. If "status" is not SECSuccess, |
michael@0 | 122 | * "failureReason" is a copy of the error code that was set at the time; |
michael@0 | 123 | * presumably it tells why the signature verification failed. |
michael@0 | 124 | */ |
michael@0 | 125 | struct ocspSignatureStr { |
michael@0 | 126 | SECAlgorithmID signatureAlgorithm; |
michael@0 | 127 | SECItem signature; /* a BIT STRING */ |
michael@0 | 128 | SECItem **derCerts; /* a SEQUENCE OF Certificate */ |
michael@0 | 129 | CERTCertificate *cert; /* local; not part of encoding */ |
michael@0 | 130 | PRBool wasChecked; /* local; not part of encoding */ |
michael@0 | 131 | SECStatus status; /* local; not part of encoding */ |
michael@0 | 132 | int failureReason; /* local; not part of encoding */ |
michael@0 | 133 | }; |
michael@0 | 134 | |
michael@0 | 135 | /* |
michael@0 | 136 | * An OCSPRequest contains a SEQUENCE OF these, one for each certificate |
michael@0 | 137 | * whose status is being checked. |
michael@0 | 138 | * |
michael@0 | 139 | * Note that in the OCSP specification this is just called "Request", |
michael@0 | 140 | * but since that seemed confusing (vs. an OCSPRequest) and to be more |
michael@0 | 141 | * consistent with the parallel type "SingleResponse", I called it a |
michael@0 | 142 | * "SingleRequest". |
michael@0 | 143 | * |
michael@0 | 144 | * XXX figure out how to get rid of that arena -- there must be a way |
michael@0 | 145 | */ |
michael@0 | 146 | struct ocspSingleRequestStr { |
michael@0 | 147 | PLArenaPool *arena; /* just a copy of the response arena, |
michael@0 | 148 | * needed here for extension handling |
michael@0 | 149 | * routines, on creation only */ |
michael@0 | 150 | CERTOCSPCertID *reqCert; |
michael@0 | 151 | CERTCertExtension **singleRequestExtensions; |
michael@0 | 152 | }; |
michael@0 | 153 | |
michael@0 | 154 | /* |
michael@0 | 155 | * A CertID is the means of identifying a certificate, used both in requests |
michael@0 | 156 | * and in responses. |
michael@0 | 157 | * |
michael@0 | 158 | * When in a SingleRequest it specifies the certificate to be checked. |
michael@0 | 159 | * When in a SingleResponse it is the cert whose status is being given. |
michael@0 | 160 | */ |
michael@0 | 161 | struct CERTOCSPCertIDStr { |
michael@0 | 162 | SECAlgorithmID hashAlgorithm; |
michael@0 | 163 | SECItem issuerNameHash; /* an OCTET STRING */ |
michael@0 | 164 | SECItem issuerKeyHash; /* an OCTET STRING */ |
michael@0 | 165 | SECItem serialNumber; /* an INTEGER */ |
michael@0 | 166 | SECItem issuerSHA1NameHash; /* keep other hashes around when */ |
michael@0 | 167 | SECItem issuerMD5NameHash; /* we have them */ |
michael@0 | 168 | SECItem issuerMD2NameHash; |
michael@0 | 169 | SECItem issuerSHA1KeyHash; /* keep other hashes around when */ |
michael@0 | 170 | SECItem issuerMD5KeyHash; /* we have them */ |
michael@0 | 171 | SECItem issuerMD2KeyHash; |
michael@0 | 172 | PLArenaPool *poolp; |
michael@0 | 173 | }; |
michael@0 | 174 | |
michael@0 | 175 | /* |
michael@0 | 176 | * This describes the value of the responseStatus field in an OCSPResponse. |
michael@0 | 177 | * The corresponding ASN.1 definition is: |
michael@0 | 178 | * |
michael@0 | 179 | * OCSPResponseStatus ::= ENUMERATED { |
michael@0 | 180 | * successful (0), --Response has valid confirmations |
michael@0 | 181 | * malformedRequest (1), --Illegal confirmation request |
michael@0 | 182 | * internalError (2), --Internal error in issuer |
michael@0 | 183 | * tryLater (3), --Try again later |
michael@0 | 184 | * --(4) is not used |
michael@0 | 185 | * sigRequired (5), --Must sign the request |
michael@0 | 186 | * unauthorized (6), --Request unauthorized |
michael@0 | 187 | * } |
michael@0 | 188 | */ |
michael@0 | 189 | typedef enum { |
michael@0 | 190 | ocspResponse_min = 0, |
michael@0 | 191 | ocspResponse_successful = 0, |
michael@0 | 192 | ocspResponse_malformedRequest = 1, |
michael@0 | 193 | ocspResponse_internalError = 2, |
michael@0 | 194 | ocspResponse_tryLater = 3, |
michael@0 | 195 | ocspResponse_unused = 4, |
michael@0 | 196 | ocspResponse_sigRequired = 5, |
michael@0 | 197 | ocspResponse_unauthorized = 6, |
michael@0 | 198 | ocspResponse_max = 6 /* Please update max when adding values. |
michael@0 | 199 | * Remember to also update arrays, e.g. |
michael@0 | 200 | * "responseStatusNames" in ocspclnt.c |
michael@0 | 201 | * and potentially other places. */ |
michael@0 | 202 | } ocspResponseStatus; |
michael@0 | 203 | |
michael@0 | 204 | /* |
michael@0 | 205 | * An OCSPResponse is what is sent (encoded) by an OCSP responder. |
michael@0 | 206 | * |
michael@0 | 207 | * The field "responseStatus" is the ASN.1 encoded value; the field |
michael@0 | 208 | * "statusValue" is simply that same value translated into our local |
michael@0 | 209 | * type ocspResponseStatus. |
michael@0 | 210 | */ |
michael@0 | 211 | struct CERTOCSPResponseStr { |
michael@0 | 212 | PLArenaPool *arena; /* local; not part of encoding */ |
michael@0 | 213 | SECItem responseStatus; /* an ENUMERATED, see above */ |
michael@0 | 214 | ocspResponseStatus statusValue; /* local; not part of encoding */ |
michael@0 | 215 | ocspResponseBytes *responseBytes; /* only when status is successful */ |
michael@0 | 216 | }; |
michael@0 | 217 | |
michael@0 | 218 | /* |
michael@0 | 219 | * A ResponseBytes (despite appearances) is what contains the meat |
michael@0 | 220 | * of a successful response -- but still in encoded form. The type |
michael@0 | 221 | * given as "responseType" tells you how to decode the string. |
michael@0 | 222 | * |
michael@0 | 223 | * We look at the OID and translate it into our local OID representation |
michael@0 | 224 | * "responseTypeTag", and use that value to tell us how to decode the |
michael@0 | 225 | * actual response itself. For now the only kind of OCSP response we |
michael@0 | 226 | * know about is a BasicOCSPResponse. However, the intention in the |
michael@0 | 227 | * OCSP specification is to allow for other response types, so we are |
michael@0 | 228 | * building in that flexibility from the start and thus put a pointer |
michael@0 | 229 | * to that data structure inside of a union. Whenever OCSP adds more |
michael@0 | 230 | * response types, just add them to the union. |
michael@0 | 231 | */ |
michael@0 | 232 | struct ocspResponseBytesStr { |
michael@0 | 233 | SECItem responseType; /* an OBJECT IDENTIFIER */ |
michael@0 | 234 | SECOidTag responseTypeTag; /* local; not part of encoding */ |
michael@0 | 235 | SECItem response; /* an OCTET STRING */ |
michael@0 | 236 | union { |
michael@0 | 237 | ocspBasicOCSPResponse *basic; /* when type is id-pkix-ocsp-basic */ |
michael@0 | 238 | } decodedResponse; /* local; not part of encoding */ |
michael@0 | 239 | }; |
michael@0 | 240 | |
michael@0 | 241 | /* |
michael@0 | 242 | * A BasicOCSPResponse -- when the responseType in a ResponseBytes is |
michael@0 | 243 | * id-pkix-ocsp-basic, the "response" OCTET STRING above is the DER |
michael@0 | 244 | * encoding of one of these. |
michael@0 | 245 | * |
michael@0 | 246 | * Note that in the OCSP specification, the signature fields are not |
michael@0 | 247 | * part of a separate sub-structure. But since they are the same fields |
michael@0 | 248 | * as we define for the signature in a request, it made sense to share |
michael@0 | 249 | * the C data structure here and in some shared code to operate on them. |
michael@0 | 250 | */ |
michael@0 | 251 | struct ocspBasicOCSPResponseStr { |
michael@0 | 252 | SECItem tbsResponseDataDER; |
michael@0 | 253 | ocspResponseData *tbsResponseData; /* "tbs" == To Be Signed */ |
michael@0 | 254 | ocspSignature responseSignature; |
michael@0 | 255 | }; |
michael@0 | 256 | |
michael@0 | 257 | /* |
michael@0 | 258 | * A ResponseData is the part of a BasicOCSPResponse that is signed |
michael@0 | 259 | * (after it is DER encoded). It contains the real details of the response |
michael@0 | 260 | * (a per-certificate status). |
michael@0 | 261 | */ |
michael@0 | 262 | struct ocspResponseDataStr { |
michael@0 | 263 | SECItem version; /* an INTEGER */ |
michael@0 | 264 | SECItem derResponderID; |
michael@0 | 265 | ocspResponderID *responderID; /* local; not part of encoding */ |
michael@0 | 266 | SECItem producedAt; /* a GeneralizedTime */ |
michael@0 | 267 | CERTOCSPSingleResponse **responses; |
michael@0 | 268 | CERTCertExtension **responseExtensions; |
michael@0 | 269 | }; |
michael@0 | 270 | |
michael@0 | 271 | struct ocspResponderIDStr { |
michael@0 | 272 | CERTOCSPResponderIDType responderIDType;/* local; not part of encoding */ |
michael@0 | 273 | union { |
michael@0 | 274 | CERTName name; /* when ocspResponderID_byName */ |
michael@0 | 275 | SECItem keyHash; /* when ocspResponderID_byKey */ |
michael@0 | 276 | SECItem other; /* when ocspResponderID_other */ |
michael@0 | 277 | } responderIDValue; |
michael@0 | 278 | }; |
michael@0 | 279 | |
michael@0 | 280 | /* |
michael@0 | 281 | * The ResponseData in a BasicOCSPResponse contains a SEQUENCE OF |
michael@0 | 282 | * SingleResponse -- one for each certificate whose status is being supplied. |
michael@0 | 283 | * |
michael@0 | 284 | * XXX figure out how to get rid of that arena -- there must be a way |
michael@0 | 285 | */ |
michael@0 | 286 | struct CERTOCSPSingleResponseStr { |
michael@0 | 287 | PLArenaPool *arena; /* just a copy of the response arena, |
michael@0 | 288 | * needed here for extension handling |
michael@0 | 289 | * routines, on creation only */ |
michael@0 | 290 | CERTOCSPCertID *certID; |
michael@0 | 291 | SECItem derCertStatus; |
michael@0 | 292 | ocspCertStatus *certStatus; /* local; not part of encoding */ |
michael@0 | 293 | SECItem thisUpdate; /* a GeneralizedTime */ |
michael@0 | 294 | SECItem *nextUpdate; /* a GeneralizedTime */ |
michael@0 | 295 | CERTCertExtension **singleExtensions; |
michael@0 | 296 | }; |
michael@0 | 297 | |
michael@0 | 298 | /* |
michael@0 | 299 | * A CertStatus is the actual per-certificate status. Its ASN.1 definition: |
michael@0 | 300 | * |
michael@0 | 301 | * CertStatus ::= CHOICE { |
michael@0 | 302 | * good [0] IMPLICIT NULL, |
michael@0 | 303 | * revoked [1] IMPLICIT RevokedInfo, |
michael@0 | 304 | * unknown [2] IMPLICIT UnknownInfo } |
michael@0 | 305 | * |
michael@0 | 306 | * (where for now UnknownInfo is defined to be NULL but in the |
michael@0 | 307 | * future may be replaced with an enumeration). |
michael@0 | 308 | * |
michael@0 | 309 | * Because it is CHOICE, the status value and its associated information |
michael@0 | 310 | * (if any) are actually encoded together. To represent this same |
michael@0 | 311 | * information internally, we explicitly define a type and save it, |
michael@0 | 312 | * along with the value, into a data structure. |
michael@0 | 313 | */ |
michael@0 | 314 | |
michael@0 | 315 | typedef enum { |
michael@0 | 316 | ocspCertStatus_good, /* cert is not revoked */ |
michael@0 | 317 | ocspCertStatus_revoked, /* cert is revoked */ |
michael@0 | 318 | ocspCertStatus_unknown, /* cert was unknown to the responder */ |
michael@0 | 319 | ocspCertStatus_other /* status was not an expected value */ |
michael@0 | 320 | } ocspCertStatusType; |
michael@0 | 321 | |
michael@0 | 322 | /* |
michael@0 | 323 | * This is the actual per-certificate status. |
michael@0 | 324 | * |
michael@0 | 325 | * The "goodInfo" and "unknownInfo" items are only place-holders for a NULL. |
michael@0 | 326 | * (Though someday OCSP may replace UnknownInfo with an enumeration that |
michael@0 | 327 | * gives more detailed information.) |
michael@0 | 328 | */ |
michael@0 | 329 | struct ocspCertStatusStr { |
michael@0 | 330 | ocspCertStatusType certStatusType; /* local; not part of encoding */ |
michael@0 | 331 | union { |
michael@0 | 332 | SECItem *goodInfo; /* when ocspCertStatus_good */ |
michael@0 | 333 | ocspRevokedInfo *revokedInfo; /* when ocspCertStatus_revoked */ |
michael@0 | 334 | SECItem *unknownInfo; /* when ocspCertStatus_unknown */ |
michael@0 | 335 | SECItem *otherInfo; /* when ocspCertStatus_other */ |
michael@0 | 336 | } certStatusInfo; |
michael@0 | 337 | }; |
michael@0 | 338 | |
michael@0 | 339 | /* |
michael@0 | 340 | * A RevokedInfo gives information about a revoked certificate -- when it |
michael@0 | 341 | * was revoked and why. |
michael@0 | 342 | */ |
michael@0 | 343 | struct ocspRevokedInfoStr { |
michael@0 | 344 | SECItem revocationTime; /* a GeneralizedTime */ |
michael@0 | 345 | SECItem *revocationReason; /* a CRLReason; ignored for now */ |
michael@0 | 346 | }; |
michael@0 | 347 | |
michael@0 | 348 | /* |
michael@0 | 349 | * ServiceLocator can be included as one of the singleRequestExtensions. |
michael@0 | 350 | * When added, it specifies the (name of the) issuer of the cert being |
michael@0 | 351 | * checked, and optionally the value of the AuthorityInfoAccess extension |
michael@0 | 352 | * if the cert has one. |
michael@0 | 353 | */ |
michael@0 | 354 | struct ocspServiceLocatorStr { |
michael@0 | 355 | CERTName *issuer; |
michael@0 | 356 | SECItem locator; /* DER encoded authInfoAccess extension from cert */ |
michael@0 | 357 | }; |
michael@0 | 358 | |
michael@0 | 359 | #endif /* _OCSPTI_H_ */ |