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 |