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