Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | #include "plarena.h" |
michael@0 | 6 | |
michael@0 | 7 | #include "seccomon.h" |
michael@0 | 8 | #include "secitem.h" |
michael@0 | 9 | #include "secasn1.h" |
michael@0 | 10 | #include "secder.h" |
michael@0 | 11 | #include "cert.h" |
michael@0 | 12 | #include "secerr.h" |
michael@0 | 13 | #include "secoid.h" |
michael@0 | 14 | #include "sechash.h" |
michael@0 | 15 | #include "keyhi.h" |
michael@0 | 16 | #include "cryptohi.h" |
michael@0 | 17 | #include "ocsp.h" |
michael@0 | 18 | #include "ocspti.h" |
michael@0 | 19 | #include "ocspi.h" |
michael@0 | 20 | #include "pk11pub.h" |
michael@0 | 21 | |
michael@0 | 22 | |
michael@0 | 23 | extern const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[]; |
michael@0 | 24 | extern const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[]; |
michael@0 | 25 | extern const SEC_ASN1Template ocsp_OCSPResponseTemplate[]; |
michael@0 | 26 | |
michael@0 | 27 | ocspCertStatus* |
michael@0 | 28 | ocsp_CreateCertStatus(PLArenaPool *arena, |
michael@0 | 29 | ocspCertStatusType status, |
michael@0 | 30 | PRTime revocationTime) |
michael@0 | 31 | { |
michael@0 | 32 | ocspCertStatus *cs; |
michael@0 | 33 | |
michael@0 | 34 | if (!arena) { |
michael@0 | 35 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 36 | return NULL; |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | switch (status) { |
michael@0 | 40 | case ocspCertStatus_good: |
michael@0 | 41 | case ocspCertStatus_unknown: |
michael@0 | 42 | case ocspCertStatus_revoked: |
michael@0 | 43 | break; |
michael@0 | 44 | default: |
michael@0 | 45 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 46 | return NULL; |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | cs = PORT_ArenaZNew(arena, ocspCertStatus); |
michael@0 | 50 | if (!cs) |
michael@0 | 51 | return NULL; |
michael@0 | 52 | cs->certStatusType = status; |
michael@0 | 53 | switch (status) { |
michael@0 | 54 | case ocspCertStatus_good: |
michael@0 | 55 | cs->certStatusInfo.goodInfo = SECITEM_AllocItem(arena, NULL, 0); |
michael@0 | 56 | if (!cs->certStatusInfo.goodInfo) |
michael@0 | 57 | return NULL; |
michael@0 | 58 | break; |
michael@0 | 59 | case ocspCertStatus_unknown: |
michael@0 | 60 | cs->certStatusInfo.unknownInfo = SECITEM_AllocItem(arena, NULL, 0); |
michael@0 | 61 | if (!cs->certStatusInfo.unknownInfo) |
michael@0 | 62 | return NULL; |
michael@0 | 63 | break; |
michael@0 | 64 | case ocspCertStatus_revoked: |
michael@0 | 65 | cs->certStatusInfo.revokedInfo = |
michael@0 | 66 | PORT_ArenaZNew(arena, ocspRevokedInfo); |
michael@0 | 67 | if (!cs->certStatusInfo.revokedInfo) |
michael@0 | 68 | return NULL; |
michael@0 | 69 | cs->certStatusInfo.revokedInfo->revocationReason = |
michael@0 | 70 | SECITEM_AllocItem(arena, NULL, 0); |
michael@0 | 71 | if (!cs->certStatusInfo.revokedInfo->revocationReason) |
michael@0 | 72 | return NULL; |
michael@0 | 73 | if (DER_TimeToGeneralizedTimeArena(arena, |
michael@0 | 74 | &cs->certStatusInfo.revokedInfo->revocationTime, |
michael@0 | 75 | revocationTime) != SECSuccess) |
michael@0 | 76 | return NULL; |
michael@0 | 77 | break; |
michael@0 | 78 | default: |
michael@0 | 79 | PORT_Assert(PR_FALSE); |
michael@0 | 80 | } |
michael@0 | 81 | return cs; |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | static const SEC_ASN1Template mySEC_EnumeratedTemplate[] = { |
michael@0 | 85 | { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) } |
michael@0 | 86 | }; |
michael@0 | 87 | |
michael@0 | 88 | static const SEC_ASN1Template mySEC_PointerToEnumeratedTemplate[] = { |
michael@0 | 89 | { SEC_ASN1_POINTER, 0, mySEC_EnumeratedTemplate } |
michael@0 | 90 | }; |
michael@0 | 91 | |
michael@0 | 92 | static const SEC_ASN1Template ocsp_EncodeRevokedInfoTemplate[] = { |
michael@0 | 93 | { SEC_ASN1_GENERALIZED_TIME, |
michael@0 | 94 | offsetof(ocspRevokedInfo, revocationTime) }, |
michael@0 | 95 | { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | |
michael@0 | 96 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC| 0, |
michael@0 | 97 | offsetof(ocspRevokedInfo, revocationReason), |
michael@0 | 98 | mySEC_PointerToEnumeratedTemplate }, |
michael@0 | 99 | { 0 } |
michael@0 | 100 | }; |
michael@0 | 101 | |
michael@0 | 102 | static const SEC_ASN1Template ocsp_PointerToEncodeRevokedInfoTemplate[] = { |
michael@0 | 103 | { SEC_ASN1_POINTER, 0, |
michael@0 | 104 | ocsp_EncodeRevokedInfoTemplate } |
michael@0 | 105 | }; |
michael@0 | 106 | |
michael@0 | 107 | static const SEC_ASN1Template mySEC_NullTemplate[] = { |
michael@0 | 108 | { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) } |
michael@0 | 109 | }; |
michael@0 | 110 | |
michael@0 | 111 | static const SEC_ASN1Template ocsp_CertStatusTemplate[] = { |
michael@0 | 112 | { SEC_ASN1_CHOICE, offsetof(ocspCertStatus, certStatusType), |
michael@0 | 113 | 0, sizeof(ocspCertStatus) }, |
michael@0 | 114 | { SEC_ASN1_CONTEXT_SPECIFIC | 0, |
michael@0 | 115 | 0, mySEC_NullTemplate, ocspCertStatus_good }, |
michael@0 | 116 | { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | |
michael@0 | 117 | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
michael@0 | 118 | offsetof(ocspCertStatus, certStatusInfo.revokedInfo), |
michael@0 | 119 | ocsp_PointerToEncodeRevokedInfoTemplate, ocspCertStatus_revoked }, |
michael@0 | 120 | { SEC_ASN1_CONTEXT_SPECIFIC | 2, |
michael@0 | 121 | 0, mySEC_NullTemplate, ocspCertStatus_unknown }, |
michael@0 | 122 | { 0 } |
michael@0 | 123 | }; |
michael@0 | 124 | |
michael@0 | 125 | static const SEC_ASN1Template mySECOID_AlgorithmIDTemplate[] = { |
michael@0 | 126 | { SEC_ASN1_SEQUENCE, |
michael@0 | 127 | 0, NULL, sizeof(SECAlgorithmID) }, |
michael@0 | 128 | { SEC_ASN1_OBJECT_ID, |
michael@0 | 129 | offsetof(SECAlgorithmID,algorithm), }, |
michael@0 | 130 | { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, |
michael@0 | 131 | offsetof(SECAlgorithmID,parameters), }, |
michael@0 | 132 | { 0, } |
michael@0 | 133 | }; |
michael@0 | 134 | |
michael@0 | 135 | static const SEC_ASN1Template mySEC_AnyTemplate[] = { |
michael@0 | 136 | { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } |
michael@0 | 137 | }; |
michael@0 | 138 | |
michael@0 | 139 | static const SEC_ASN1Template mySEC_SequenceOfAnyTemplate[] = { |
michael@0 | 140 | { SEC_ASN1_SEQUENCE_OF, 0, mySEC_AnyTemplate } |
michael@0 | 141 | }; |
michael@0 | 142 | |
michael@0 | 143 | static const SEC_ASN1Template mySEC_PointerToSequenceOfAnyTemplate[] = { |
michael@0 | 144 | { SEC_ASN1_POINTER, 0, mySEC_SequenceOfAnyTemplate } |
michael@0 | 145 | }; |
michael@0 | 146 | |
michael@0 | 147 | static const SEC_ASN1Template mySEC_IntegerTemplate[] = { |
michael@0 | 148 | { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) } |
michael@0 | 149 | }; |
michael@0 | 150 | |
michael@0 | 151 | static const SEC_ASN1Template mySEC_PointerToIntegerTemplate[] = { |
michael@0 | 152 | { SEC_ASN1_POINTER, 0, mySEC_IntegerTemplate } |
michael@0 | 153 | }; |
michael@0 | 154 | |
michael@0 | 155 | static const SEC_ASN1Template mySEC_GeneralizedTimeTemplate[] = { |
michael@0 | 156 | { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)} |
michael@0 | 157 | }; |
michael@0 | 158 | |
michael@0 | 159 | static const SEC_ASN1Template mySEC_PointerToGeneralizedTimeTemplate[] = { |
michael@0 | 160 | { SEC_ASN1_POINTER, 0, mySEC_GeneralizedTimeTemplate } |
michael@0 | 161 | }; |
michael@0 | 162 | |
michael@0 | 163 | static const SEC_ASN1Template ocsp_myCertIDTemplate[] = { |
michael@0 | 164 | { SEC_ASN1_SEQUENCE, |
michael@0 | 165 | 0, NULL, sizeof(CERTOCSPCertID) }, |
michael@0 | 166 | { SEC_ASN1_INLINE, |
michael@0 | 167 | offsetof(CERTOCSPCertID, hashAlgorithm), |
michael@0 | 168 | mySECOID_AlgorithmIDTemplate }, |
michael@0 | 169 | { SEC_ASN1_OCTET_STRING, |
michael@0 | 170 | offsetof(CERTOCSPCertID, issuerNameHash) }, |
michael@0 | 171 | { SEC_ASN1_OCTET_STRING, |
michael@0 | 172 | offsetof(CERTOCSPCertID, issuerKeyHash) }, |
michael@0 | 173 | { SEC_ASN1_INTEGER, |
michael@0 | 174 | offsetof(CERTOCSPCertID, serialNumber) }, |
michael@0 | 175 | { 0 } |
michael@0 | 176 | }; |
michael@0 | 177 | |
michael@0 | 178 | static const SEC_ASN1Template myCERT_CertExtensionTemplate[] = { |
michael@0 | 179 | { SEC_ASN1_SEQUENCE, |
michael@0 | 180 | 0, NULL, sizeof(CERTCertExtension) }, |
michael@0 | 181 | { SEC_ASN1_OBJECT_ID, |
michael@0 | 182 | offsetof(CERTCertExtension,id) }, |
michael@0 | 183 | { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ |
michael@0 | 184 | offsetof(CERTCertExtension,critical) }, |
michael@0 | 185 | { SEC_ASN1_OCTET_STRING, |
michael@0 | 186 | offsetof(CERTCertExtension,value) }, |
michael@0 | 187 | { 0, } |
michael@0 | 188 | }; |
michael@0 | 189 | |
michael@0 | 190 | static const SEC_ASN1Template myCERT_SequenceOfCertExtensionTemplate[] = { |
michael@0 | 191 | { SEC_ASN1_SEQUENCE_OF, 0, myCERT_CertExtensionTemplate } |
michael@0 | 192 | }; |
michael@0 | 193 | |
michael@0 | 194 | static const SEC_ASN1Template myCERT_PointerToSequenceOfCertExtensionTemplate[] = { |
michael@0 | 195 | { SEC_ASN1_POINTER, 0, myCERT_SequenceOfCertExtensionTemplate } |
michael@0 | 196 | }; |
michael@0 | 197 | |
michael@0 | 198 | static const SEC_ASN1Template ocsp_mySingleResponseTemplate[] = { |
michael@0 | 199 | { SEC_ASN1_SEQUENCE, |
michael@0 | 200 | 0, NULL, sizeof(CERTOCSPSingleResponse) }, |
michael@0 | 201 | { SEC_ASN1_POINTER, |
michael@0 | 202 | offsetof(CERTOCSPSingleResponse, certID), |
michael@0 | 203 | ocsp_myCertIDTemplate }, |
michael@0 | 204 | { SEC_ASN1_ANY, |
michael@0 | 205 | offsetof(CERTOCSPSingleResponse, derCertStatus) }, |
michael@0 | 206 | { SEC_ASN1_GENERALIZED_TIME, |
michael@0 | 207 | offsetof(CERTOCSPSingleResponse, thisUpdate) }, |
michael@0 | 208 | { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | |
michael@0 | 209 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
michael@0 | 210 | offsetof(CERTOCSPSingleResponse, nextUpdate), |
michael@0 | 211 | mySEC_PointerToGeneralizedTimeTemplate }, |
michael@0 | 212 | { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | |
michael@0 | 213 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
michael@0 | 214 | offsetof(CERTOCSPSingleResponse, singleExtensions), |
michael@0 | 215 | myCERT_PointerToSequenceOfCertExtensionTemplate }, |
michael@0 | 216 | { 0 } |
michael@0 | 217 | }; |
michael@0 | 218 | |
michael@0 | 219 | static const SEC_ASN1Template ocsp_myResponseDataTemplate[] = { |
michael@0 | 220 | { SEC_ASN1_SEQUENCE, |
michael@0 | 221 | 0, NULL, sizeof(ocspResponseData) }, |
michael@0 | 222 | { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */ |
michael@0 | 223 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
michael@0 | 224 | offsetof(ocspResponseData, version), |
michael@0 | 225 | mySEC_PointerToIntegerTemplate }, |
michael@0 | 226 | { SEC_ASN1_ANY, |
michael@0 | 227 | offsetof(ocspResponseData, derResponderID) }, |
michael@0 | 228 | { SEC_ASN1_GENERALIZED_TIME, |
michael@0 | 229 | offsetof(ocspResponseData, producedAt) }, |
michael@0 | 230 | { SEC_ASN1_SEQUENCE_OF, |
michael@0 | 231 | offsetof(ocspResponseData, responses), |
michael@0 | 232 | ocsp_mySingleResponseTemplate }, |
michael@0 | 233 | { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | |
michael@0 | 234 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
michael@0 | 235 | offsetof(ocspResponseData, responseExtensions), |
michael@0 | 236 | myCERT_PointerToSequenceOfCertExtensionTemplate }, |
michael@0 | 237 | { 0 } |
michael@0 | 238 | }; |
michael@0 | 239 | |
michael@0 | 240 | |
michael@0 | 241 | static const SEC_ASN1Template ocsp_EncodeBasicOCSPResponseTemplate[] = { |
michael@0 | 242 | { SEC_ASN1_SEQUENCE, |
michael@0 | 243 | 0, NULL, sizeof(ocspBasicOCSPResponse) }, |
michael@0 | 244 | { SEC_ASN1_POINTER, |
michael@0 | 245 | offsetof(ocspBasicOCSPResponse, tbsResponseData), |
michael@0 | 246 | ocsp_myResponseDataTemplate }, |
michael@0 | 247 | { SEC_ASN1_INLINE, |
michael@0 | 248 | offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm), |
michael@0 | 249 | mySECOID_AlgorithmIDTemplate }, |
michael@0 | 250 | { SEC_ASN1_BIT_STRING, |
michael@0 | 251 | offsetof(ocspBasicOCSPResponse, responseSignature.signature) }, |
michael@0 | 252 | { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | |
michael@0 | 253 | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
michael@0 | 254 | offsetof(ocspBasicOCSPResponse, responseSignature.derCerts), |
michael@0 | 255 | mySEC_PointerToSequenceOfAnyTemplate }, |
michael@0 | 256 | { 0 } |
michael@0 | 257 | }; |
michael@0 | 258 | |
michael@0 | 259 | static CERTOCSPSingleResponse* |
michael@0 | 260 | ocsp_CreateSingleResponse(PLArenaPool *arena, |
michael@0 | 261 | CERTOCSPCertID *id, ocspCertStatus *status, |
michael@0 | 262 | PRTime thisUpdate, const PRTime *nextUpdate) |
michael@0 | 263 | { |
michael@0 | 264 | CERTOCSPSingleResponse *sr; |
michael@0 | 265 | |
michael@0 | 266 | if (!arena || !id || !status) { |
michael@0 | 267 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 268 | return NULL; |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | sr = PORT_ArenaZNew(arena, CERTOCSPSingleResponse); |
michael@0 | 272 | if (!sr) |
michael@0 | 273 | return NULL; |
michael@0 | 274 | sr->arena = arena; |
michael@0 | 275 | sr->certID = id; |
michael@0 | 276 | sr->certStatus = status; |
michael@0 | 277 | if (DER_TimeToGeneralizedTimeArena(arena, &sr->thisUpdate, thisUpdate) |
michael@0 | 278 | != SECSuccess) |
michael@0 | 279 | return NULL; |
michael@0 | 280 | sr->nextUpdate = NULL; |
michael@0 | 281 | if (nextUpdate) { |
michael@0 | 282 | sr->nextUpdate = SECITEM_AllocItem(arena, NULL, 0); |
michael@0 | 283 | if (!sr->nextUpdate) |
michael@0 | 284 | return NULL; |
michael@0 | 285 | if (DER_TimeToGeneralizedTimeArena(arena, sr->nextUpdate, *nextUpdate) |
michael@0 | 286 | != SECSuccess) |
michael@0 | 287 | return NULL; |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | sr->singleExtensions = PORT_ArenaNewArray(arena, CERTCertExtension*, 1); |
michael@0 | 291 | if (!sr->singleExtensions) |
michael@0 | 292 | return NULL; |
michael@0 | 293 | |
michael@0 | 294 | sr->singleExtensions[0] = NULL; |
michael@0 | 295 | |
michael@0 | 296 | if (!SEC_ASN1EncodeItem(arena, &sr->derCertStatus, |
michael@0 | 297 | status, ocsp_CertStatusTemplate)) |
michael@0 | 298 | return NULL; |
michael@0 | 299 | |
michael@0 | 300 | return sr; |
michael@0 | 301 | } |
michael@0 | 302 | |
michael@0 | 303 | CERTOCSPSingleResponse* |
michael@0 | 304 | CERT_CreateOCSPSingleResponseGood(PLArenaPool *arena, |
michael@0 | 305 | CERTOCSPCertID *id, |
michael@0 | 306 | PRTime thisUpdate, |
michael@0 | 307 | const PRTime *nextUpdate) |
michael@0 | 308 | { |
michael@0 | 309 | ocspCertStatus * cs; |
michael@0 | 310 | if (!arena) { |
michael@0 | 311 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 312 | return NULL; |
michael@0 | 313 | } |
michael@0 | 314 | cs = ocsp_CreateCertStatus(arena, ocspCertStatus_good, 0); |
michael@0 | 315 | if (!cs) |
michael@0 | 316 | return NULL; |
michael@0 | 317 | return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); |
michael@0 | 318 | } |
michael@0 | 319 | |
michael@0 | 320 | CERTOCSPSingleResponse* |
michael@0 | 321 | CERT_CreateOCSPSingleResponseUnknown(PLArenaPool *arena, |
michael@0 | 322 | CERTOCSPCertID *id, |
michael@0 | 323 | PRTime thisUpdate, |
michael@0 | 324 | const PRTime *nextUpdate) |
michael@0 | 325 | { |
michael@0 | 326 | ocspCertStatus * cs; |
michael@0 | 327 | if (!arena) { |
michael@0 | 328 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 329 | return NULL; |
michael@0 | 330 | } |
michael@0 | 331 | cs = ocsp_CreateCertStatus(arena, ocspCertStatus_unknown, 0); |
michael@0 | 332 | if (!cs) |
michael@0 | 333 | return NULL; |
michael@0 | 334 | return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); |
michael@0 | 335 | } |
michael@0 | 336 | |
michael@0 | 337 | CERTOCSPSingleResponse* |
michael@0 | 338 | CERT_CreateOCSPSingleResponseRevoked( |
michael@0 | 339 | PLArenaPool *arena, |
michael@0 | 340 | CERTOCSPCertID *id, |
michael@0 | 341 | PRTime thisUpdate, |
michael@0 | 342 | const PRTime *nextUpdate, |
michael@0 | 343 | PRTime revocationTime, |
michael@0 | 344 | const CERTCRLEntryReasonCode* revocationReason) |
michael@0 | 345 | { |
michael@0 | 346 | ocspCertStatus * cs; |
michael@0 | 347 | /* revocationReason is not yet supported, so it must be NULL. */ |
michael@0 | 348 | if (!arena || revocationReason) { |
michael@0 | 349 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 350 | return NULL; |
michael@0 | 351 | } |
michael@0 | 352 | cs = ocsp_CreateCertStatus(arena, ocspCertStatus_revoked, revocationTime); |
michael@0 | 353 | if (!cs) |
michael@0 | 354 | return NULL; |
michael@0 | 355 | return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); |
michael@0 | 356 | } |
michael@0 | 357 | |
michael@0 | 358 | /* responderCert == 0 means: |
michael@0 | 359 | * create a response with an invalid signature (for testing purposes) */ |
michael@0 | 360 | SECItem* |
michael@0 | 361 | CERT_CreateEncodedOCSPSuccessResponse( |
michael@0 | 362 | PLArenaPool *arena, |
michael@0 | 363 | CERTCertificate *responderCert, |
michael@0 | 364 | CERTOCSPResponderIDType responderIDType, |
michael@0 | 365 | PRTime producedAt, |
michael@0 | 366 | CERTOCSPSingleResponse **responses, |
michael@0 | 367 | void *wincx) |
michael@0 | 368 | { |
michael@0 | 369 | PLArenaPool *tmpArena; |
michael@0 | 370 | ocspResponseData *rd = NULL; |
michael@0 | 371 | ocspResponderID *rid = NULL; |
michael@0 | 372 | const SEC_ASN1Template *responderIDTemplate = NULL; |
michael@0 | 373 | ocspBasicOCSPResponse *br = NULL; |
michael@0 | 374 | ocspResponseBytes *rb = NULL; |
michael@0 | 375 | CERTOCSPResponse *response = NULL; |
michael@0 | 376 | |
michael@0 | 377 | SECOidTag algID; |
michael@0 | 378 | SECOidData *od = NULL; |
michael@0 | 379 | SECKEYPrivateKey *privKey = NULL; |
michael@0 | 380 | SECItem *result = NULL; |
michael@0 | 381 | |
michael@0 | 382 | if (!arena || !responses) { |
michael@0 | 383 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 384 | return NULL; |
michael@0 | 385 | } |
michael@0 | 386 | if (responderIDType != ocspResponderID_byName && |
michael@0 | 387 | responderIDType != ocspResponderID_byKey) { |
michael@0 | 388 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 389 | return NULL; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
michael@0 | 393 | if (!tmpArena) |
michael@0 | 394 | return NULL; |
michael@0 | 395 | |
michael@0 | 396 | rd = PORT_ArenaZNew(tmpArena, ocspResponseData); |
michael@0 | 397 | if (!rd) |
michael@0 | 398 | goto done; |
michael@0 | 399 | rid = PORT_ArenaZNew(tmpArena, ocspResponderID); |
michael@0 | 400 | if (!rid) |
michael@0 | 401 | goto done; |
michael@0 | 402 | br = PORT_ArenaZNew(tmpArena, ocspBasicOCSPResponse); |
michael@0 | 403 | if (!br) |
michael@0 | 404 | goto done; |
michael@0 | 405 | rb = PORT_ArenaZNew(tmpArena, ocspResponseBytes); |
michael@0 | 406 | if (!rb) |
michael@0 | 407 | goto done; |
michael@0 | 408 | response = PORT_ArenaZNew(tmpArena, CERTOCSPResponse); |
michael@0 | 409 | if (!response) |
michael@0 | 410 | goto done; |
michael@0 | 411 | |
michael@0 | 412 | rd->version.data=NULL; |
michael@0 | 413 | rd->version.len=0; |
michael@0 | 414 | rd->responseExtensions = NULL; |
michael@0 | 415 | rd->responses = responses; |
michael@0 | 416 | if (DER_TimeToGeneralizedTimeArena(tmpArena, &rd->producedAt, producedAt) |
michael@0 | 417 | != SECSuccess) |
michael@0 | 418 | goto done; |
michael@0 | 419 | |
michael@0 | 420 | if (!responderCert) { |
michael@0 | 421 | /* use invalid signature for testing purposes */ |
michael@0 | 422 | unsigned char dummyChar = 'd'; |
michael@0 | 423 | SECItem dummy; |
michael@0 | 424 | |
michael@0 | 425 | dummy.len = 1; |
michael@0 | 426 | dummy.data = &dummyChar; |
michael@0 | 427 | |
michael@0 | 428 | /* it's easier to produdce a keyHash out of nowhere, |
michael@0 | 429 | * than to produce an encoded subject, |
michael@0 | 430 | * so for our dummy response we always use byKey |
michael@0 | 431 | */ |
michael@0 | 432 | |
michael@0 | 433 | rid->responderIDType = ocspResponderID_byKey; |
michael@0 | 434 | if (!ocsp_DigestValue(tmpArena, SEC_OID_SHA1, &rid->responderIDValue.keyHash, |
michael@0 | 435 | &dummy)) |
michael@0 | 436 | goto done; |
michael@0 | 437 | |
michael@0 | 438 | if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, |
michael@0 | 439 | ocsp_ResponderIDByKeyTemplate)) |
michael@0 | 440 | goto done; |
michael@0 | 441 | |
michael@0 | 442 | br->tbsResponseData = rd; |
michael@0 | 443 | |
michael@0 | 444 | if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, |
michael@0 | 445 | ocsp_myResponseDataTemplate)) |
michael@0 | 446 | goto done; |
michael@0 | 447 | |
michael@0 | 448 | br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem*, 1); |
michael@0 | 449 | if (!br->responseSignature.derCerts) |
michael@0 | 450 | goto done; |
michael@0 | 451 | br->responseSignature.derCerts[0] = NULL; |
michael@0 | 452 | |
michael@0 | 453 | algID = SEC_GetSignatureAlgorithmOidTag(rsaKey, SEC_OID_SHA1); |
michael@0 | 454 | if (algID == SEC_OID_UNKNOWN) |
michael@0 | 455 | goto done; |
michael@0 | 456 | |
michael@0 | 457 | /* match the regular signature code, which doesn't use the arena */ |
michael@0 | 458 | if (!SECITEM_AllocItem(NULL, &br->responseSignature.signature, 1)) |
michael@0 | 459 | goto done; |
michael@0 | 460 | PORT_Memcpy(br->responseSignature.signature.data, &dummyChar, 1); |
michael@0 | 461 | |
michael@0 | 462 | /* convert len-in-bytes to len-in-bits */ |
michael@0 | 463 | br->responseSignature.signature.len = br->responseSignature.signature.len << 3; |
michael@0 | 464 | } |
michael@0 | 465 | else { |
michael@0 | 466 | rid->responderIDType = responderIDType; |
michael@0 | 467 | if (responderIDType == ocspResponderID_byName) { |
michael@0 | 468 | responderIDTemplate = ocsp_ResponderIDByNameTemplate; |
michael@0 | 469 | if (CERT_CopyName(tmpArena, &rid->responderIDValue.name, |
michael@0 | 470 | &responderCert->subject) != SECSuccess) |
michael@0 | 471 | goto done; |
michael@0 | 472 | } |
michael@0 | 473 | else { |
michael@0 | 474 | responderIDTemplate = ocsp_ResponderIDByKeyTemplate; |
michael@0 | 475 | if (!CERT_GetSubjectPublicKeyDigest(tmpArena, responderCert, |
michael@0 | 476 | SEC_OID_SHA1, &rid->responderIDValue.keyHash)) |
michael@0 | 477 | goto done; |
michael@0 | 478 | } |
michael@0 | 479 | |
michael@0 | 480 | if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, |
michael@0 | 481 | responderIDTemplate)) |
michael@0 | 482 | goto done; |
michael@0 | 483 | |
michael@0 | 484 | br->tbsResponseData = rd; |
michael@0 | 485 | |
michael@0 | 486 | if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, |
michael@0 | 487 | ocsp_myResponseDataTemplate)) |
michael@0 | 488 | goto done; |
michael@0 | 489 | |
michael@0 | 490 | br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem*, 1); |
michael@0 | 491 | if (!br->responseSignature.derCerts) |
michael@0 | 492 | goto done; |
michael@0 | 493 | br->responseSignature.derCerts[0] = NULL; |
michael@0 | 494 | |
michael@0 | 495 | privKey = PK11_FindKeyByAnyCert(responderCert, wincx); |
michael@0 | 496 | if (!privKey) |
michael@0 | 497 | goto done; |
michael@0 | 498 | |
michael@0 | 499 | algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1); |
michael@0 | 500 | if (algID == SEC_OID_UNKNOWN) |
michael@0 | 501 | goto done; |
michael@0 | 502 | |
michael@0 | 503 | if (SEC_SignData(&br->responseSignature.signature, |
michael@0 | 504 | br->tbsResponseDataDER.data, br->tbsResponseDataDER.len, |
michael@0 | 505 | privKey, algID) |
michael@0 | 506 | != SECSuccess) |
michael@0 | 507 | goto done; |
michael@0 | 508 | |
michael@0 | 509 | /* convert len-in-bytes to len-in-bits */ |
michael@0 | 510 | br->responseSignature.signature.len = br->responseSignature.signature.len << 3; |
michael@0 | 511 | |
michael@0 | 512 | /* br->responseSignature.signature wasn't allocated from arena, |
michael@0 | 513 | * we must free it when done. */ |
michael@0 | 514 | } |
michael@0 | 515 | |
michael@0 | 516 | if (SECOID_SetAlgorithmID(tmpArena, &br->responseSignature.signatureAlgorithm, algID, 0) |
michael@0 | 517 | != SECSuccess) |
michael@0 | 518 | goto done; |
michael@0 | 519 | |
michael@0 | 520 | if (!SEC_ASN1EncodeItem(tmpArena, &rb->response, br, |
michael@0 | 521 | ocsp_EncodeBasicOCSPResponseTemplate)) |
michael@0 | 522 | goto done; |
michael@0 | 523 | |
michael@0 | 524 | rb->responseTypeTag = SEC_OID_PKIX_OCSP_BASIC_RESPONSE; |
michael@0 | 525 | |
michael@0 | 526 | od = SECOID_FindOIDByTag(rb->responseTypeTag); |
michael@0 | 527 | if (!od) |
michael@0 | 528 | goto done; |
michael@0 | 529 | |
michael@0 | 530 | rb->responseType = od->oid; |
michael@0 | 531 | rb->decodedResponse.basic = br; |
michael@0 | 532 | |
michael@0 | 533 | response->arena = tmpArena; |
michael@0 | 534 | response->responseBytes = rb; |
michael@0 | 535 | response->statusValue = ocspResponse_successful; |
michael@0 | 536 | |
michael@0 | 537 | if (!SEC_ASN1EncodeInteger(tmpArena, &response->responseStatus, |
michael@0 | 538 | response->statusValue)) |
michael@0 | 539 | goto done; |
michael@0 | 540 | |
michael@0 | 541 | result = SEC_ASN1EncodeItem(arena, NULL, response, ocsp_OCSPResponseTemplate); |
michael@0 | 542 | |
michael@0 | 543 | done: |
michael@0 | 544 | if (privKey) |
michael@0 | 545 | SECKEY_DestroyPrivateKey(privKey); |
michael@0 | 546 | if (br->responseSignature.signature.data) |
michael@0 | 547 | SECITEM_FreeItem(&br->responseSignature.signature, PR_FALSE); |
michael@0 | 548 | PORT_FreeArena(tmpArena, PR_FALSE); |
michael@0 | 549 | |
michael@0 | 550 | return result; |
michael@0 | 551 | } |
michael@0 | 552 | |
michael@0 | 553 | static const SEC_ASN1Template ocsp_OCSPErrorResponseTemplate[] = { |
michael@0 | 554 | { SEC_ASN1_SEQUENCE, |
michael@0 | 555 | 0, NULL, sizeof(CERTOCSPResponse) }, |
michael@0 | 556 | { SEC_ASN1_ENUMERATED, |
michael@0 | 557 | offsetof(CERTOCSPResponse, responseStatus) }, |
michael@0 | 558 | { 0, 0, |
michael@0 | 559 | mySEC_NullTemplate }, |
michael@0 | 560 | { 0 } |
michael@0 | 561 | }; |
michael@0 | 562 | |
michael@0 | 563 | SECItem* |
michael@0 | 564 | CERT_CreateEncodedOCSPErrorResponse(PLArenaPool *arena, int error) |
michael@0 | 565 | { |
michael@0 | 566 | CERTOCSPResponse response; |
michael@0 | 567 | SECItem *result = NULL; |
michael@0 | 568 | |
michael@0 | 569 | switch (error) { |
michael@0 | 570 | case SEC_ERROR_OCSP_MALFORMED_REQUEST: |
michael@0 | 571 | response.statusValue = ocspResponse_malformedRequest; |
michael@0 | 572 | break; |
michael@0 | 573 | case SEC_ERROR_OCSP_SERVER_ERROR: |
michael@0 | 574 | response.statusValue = ocspResponse_internalError; |
michael@0 | 575 | break; |
michael@0 | 576 | case SEC_ERROR_OCSP_TRY_SERVER_LATER: |
michael@0 | 577 | response.statusValue = ocspResponse_tryLater; |
michael@0 | 578 | break; |
michael@0 | 579 | case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG: |
michael@0 | 580 | response.statusValue = ocspResponse_sigRequired; |
michael@0 | 581 | break; |
michael@0 | 582 | case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST: |
michael@0 | 583 | response.statusValue = ocspResponse_unauthorized; |
michael@0 | 584 | break; |
michael@0 | 585 | default: |
michael@0 | 586 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
michael@0 | 587 | return NULL; |
michael@0 | 588 | } |
michael@0 | 589 | |
michael@0 | 590 | if (!SEC_ASN1EncodeInteger(NULL, &response.responseStatus, |
michael@0 | 591 | response.statusValue)) |
michael@0 | 592 | return NULL; |
michael@0 | 593 | |
michael@0 | 594 | result = SEC_ASN1EncodeItem(arena, NULL, &response, |
michael@0 | 595 | ocsp_OCSPErrorResponseTemplate); |
michael@0 | 596 | |
michael@0 | 597 | SECITEM_FreeItem(&response.responseStatus, PR_FALSE); |
michael@0 | 598 | |
michael@0 | 599 | return result; |
michael@0 | 600 | } |