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 | |
23 extern const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[]; | |
24 extern const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[]; | |
25 extern const SEC_ASN1Template ocsp_OCSPResponseTemplate[]; | |
26 | |
27 ocspCertStatus* | |
28 ocsp_CreateCertStatus(PLArenaPool *arena, | |
29 ocspCertStatusType status, | |
30 PRTime revocationTime) | |
31 { | |
32 ocspCertStatus *cs; | |
33 | |
34 if (!arena) { | |
35 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
36 return NULL; | |
37 } | |
38 | |
39 switch (status) { | |
40 case ocspCertStatus_good: | |
41 case ocspCertStatus_unknown: | |
42 case ocspCertStatus_revoked: | |
43 break; | |
44 default: | |
45 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
46 return NULL; | |
47 } | |
48 | |
49 cs = PORT_ArenaZNew(arena, ocspCertStatus); | |
50 if (!cs) | |
51 return NULL; | |
52 cs->certStatusType = status; | |
53 switch (status) { | |
54 case ocspCertStatus_good: | |
55 cs->certStatusInfo.goodInfo = SECITEM_AllocItem(arena, NULL, 0); | |
56 if (!cs->certStatusInfo.goodInfo) | |
57 return NULL; | |
58 break; | |
59 case ocspCertStatus_unknown: | |
60 cs->certStatusInfo.unknownInfo = SECITEM_AllocItem(arena, NULL, 0); | |
61 if (!cs->certStatusInfo.unknownInfo) | |
62 return NULL; | |
63 break; | |
64 case ocspCertStatus_revoked: | |
65 cs->certStatusInfo.revokedInfo = | |
66 PORT_ArenaZNew(arena, ocspRevokedInfo); | |
67 if (!cs->certStatusInfo.revokedInfo) | |
68 return NULL; | |
69 cs->certStatusInfo.revokedInfo->revocationReason = | |
70 SECITEM_AllocItem(arena, NULL, 0); | |
71 if (!cs->certStatusInfo.revokedInfo->revocationReason) | |
72 return NULL; | |
73 if (DER_TimeToGeneralizedTimeArena(arena, | |
74 &cs->certStatusInfo.revokedInfo->revocationTime, | |
75 revocationTime) != 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 | |
241 static const SEC_ASN1Template ocsp_EncodeBasicOCSPResponseTemplate[] = { | |
242 { SEC_ASN1_SEQUENCE, | |
243 0, NULL, sizeof(ocspBasicOCSPResponse) }, | |
244 { SEC_ASN1_POINTER, | |
245 offsetof(ocspBasicOCSPResponse, tbsResponseData), | |
246 ocsp_myResponseDataTemplate }, | |
247 { SEC_ASN1_INLINE, | |
248 offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm), | |
249 mySECOID_AlgorithmIDTemplate }, | |
250 { SEC_ASN1_BIT_STRING, | |
251 offsetof(ocspBasicOCSPResponse, responseSignature.signature) }, | |
252 { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | | |
253 SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, | |
254 offsetof(ocspBasicOCSPResponse, responseSignature.derCerts), | |
255 mySEC_PointerToSequenceOfAnyTemplate }, | |
256 { 0 } | |
257 }; | |
258 | |
259 static CERTOCSPSingleResponse* | |
260 ocsp_CreateSingleResponse(PLArenaPool *arena, | |
261 CERTOCSPCertID *id, ocspCertStatus *status, | |
262 PRTime thisUpdate, const PRTime *nextUpdate) | |
263 { | |
264 CERTOCSPSingleResponse *sr; | |
265 | |
266 if (!arena || !id || !status) { | |
267 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
268 return NULL; | |
269 } | |
270 | |
271 sr = PORT_ArenaZNew(arena, CERTOCSPSingleResponse); | |
272 if (!sr) | |
273 return NULL; | |
274 sr->arena = arena; | |
275 sr->certID = id; | |
276 sr->certStatus = status; | |
277 if (DER_TimeToGeneralizedTimeArena(arena, &sr->thisUpdate, thisUpdate) | |
278 != SECSuccess) | |
279 return NULL; | |
280 sr->nextUpdate = NULL; | |
281 if (nextUpdate) { | |
282 sr->nextUpdate = SECITEM_AllocItem(arena, NULL, 0); | |
283 if (!sr->nextUpdate) | |
284 return NULL; | |
285 if (DER_TimeToGeneralizedTimeArena(arena, sr->nextUpdate, *nextUpdate) | |
286 != SECSuccess) | |
287 return NULL; | |
288 } | |
289 | |
290 sr->singleExtensions = PORT_ArenaNewArray(arena, CERTCertExtension*, 1); | |
291 if (!sr->singleExtensions) | |
292 return NULL; | |
293 | |
294 sr->singleExtensions[0] = NULL; | |
295 | |
296 if (!SEC_ASN1EncodeItem(arena, &sr->derCertStatus, | |
297 status, ocsp_CertStatusTemplate)) | |
298 return NULL; | |
299 | |
300 return sr; | |
301 } | |
302 | |
303 CERTOCSPSingleResponse* | |
304 CERT_CreateOCSPSingleResponseGood(PLArenaPool *arena, | |
305 CERTOCSPCertID *id, | |
306 PRTime thisUpdate, | |
307 const PRTime *nextUpdate) | |
308 { | |
309 ocspCertStatus * cs; | |
310 if (!arena) { | |
311 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
312 return NULL; | |
313 } | |
314 cs = ocsp_CreateCertStatus(arena, ocspCertStatus_good, 0); | |
315 if (!cs) | |
316 return NULL; | |
317 return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); | |
318 } | |
319 | |
320 CERTOCSPSingleResponse* | |
321 CERT_CreateOCSPSingleResponseUnknown(PLArenaPool *arena, | |
322 CERTOCSPCertID *id, | |
323 PRTime thisUpdate, | |
324 const PRTime *nextUpdate) | |
325 { | |
326 ocspCertStatus * cs; | |
327 if (!arena) { | |
328 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
329 return NULL; | |
330 } | |
331 cs = ocsp_CreateCertStatus(arena, ocspCertStatus_unknown, 0); | |
332 if (!cs) | |
333 return NULL; | |
334 return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); | |
335 } | |
336 | |
337 CERTOCSPSingleResponse* | |
338 CERT_CreateOCSPSingleResponseRevoked( | |
339 PLArenaPool *arena, | |
340 CERTOCSPCertID *id, | |
341 PRTime thisUpdate, | |
342 const PRTime *nextUpdate, | |
343 PRTime revocationTime, | |
344 const CERTCRLEntryReasonCode* revocationReason) | |
345 { | |
346 ocspCertStatus * cs; | |
347 /* revocationReason is not yet supported, so it must be NULL. */ | |
348 if (!arena || revocationReason) { | |
349 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
350 return NULL; | |
351 } | |
352 cs = ocsp_CreateCertStatus(arena, ocspCertStatus_revoked, revocationTime); | |
353 if (!cs) | |
354 return NULL; | |
355 return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); | |
356 } | |
357 | |
358 SECItem* | |
359 CERT_CreateEncodedOCSPSuccessResponse( | |
360 PLArenaPool *arena, | |
361 CERTCertificate *responderCert, | |
362 CERTOCSPResponderIDType responderIDType, | |
363 PRTime producedAt, | |
364 CERTOCSPSingleResponse **responses, | |
365 void *wincx) | |
366 { | |
367 PLArenaPool *tmpArena; | |
368 ocspResponseData *rd = NULL; | |
369 ocspResponderID *rid = NULL; | |
370 const SEC_ASN1Template *responderIDTemplate = NULL; | |
371 ocspBasicOCSPResponse *br = NULL; | |
372 ocspResponseBytes *rb = NULL; | |
373 CERTOCSPResponse *response = NULL; | |
374 | |
375 SECOidTag algID; | |
376 SECOidData *od = NULL; | |
377 SECKEYPrivateKey *privKey = NULL; | |
378 SECItem *result = NULL; | |
379 | |
380 if (!arena || !responderCert || !responses) { | |
381 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
382 return NULL; | |
383 } | |
384 if (responderIDType != ocspResponderID_byName && | |
385 responderIDType != ocspResponderID_byKey) { | |
386 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
387 return NULL; | |
388 } | |
389 | |
390 tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
391 if (!tmpArena) | |
392 return NULL; | |
393 | |
394 rd = PORT_ArenaZNew(tmpArena, ocspResponseData); | |
395 if (!rd) | |
396 goto done; | |
397 rid = PORT_ArenaZNew(tmpArena, ocspResponderID); | |
398 if (!rid) | |
399 goto done; | |
400 br = PORT_ArenaZNew(tmpArena, ocspBasicOCSPResponse); | |
401 if (!br) | |
402 goto done; | |
403 rb = PORT_ArenaZNew(tmpArena, ocspResponseBytes); | |
404 if (!rb) | |
405 goto done; | |
406 response = PORT_ArenaZNew(tmpArena, CERTOCSPResponse); | |
407 if (!response) | |
408 goto done; | |
409 | |
410 rd->version.data=NULL; | |
411 rd->version.len=0; | |
412 rd->responseExtensions = NULL; | |
413 rd->responses = responses; | |
414 if (DER_TimeToGeneralizedTimeArena(tmpArena, &rd->producedAt, producedAt) | |
415 != SECSuccess) | |
416 goto done; | |
417 rid->responderIDType = responderIDType; | |
418 if (responderIDType == ocspResponderID_byName) { | |
419 responderIDTemplate = ocsp_ResponderIDByNameTemplate; | |
420 if (CERT_CopyName(tmpArena, &rid->responderIDValue.name, | |
421 &responderCert->subject) != SECSuccess) | |
422 goto done; | |
423 } | |
424 else { | |
425 responderIDTemplate = ocsp_ResponderIDByKeyTemplate; | |
426 if (!CERT_GetSPKIDigest(tmpArena, responderCert, SEC_OID_SHA1, | |
427 &rid->responderIDValue.keyHash)) | |
428 goto done; | |
429 } | |
430 | |
431 if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, | |
432 responderIDTemplate)) | |
433 goto done; | |
434 | |
435 br->tbsResponseData = rd; | |
436 | |
437 if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseDa
ta, | |
438 ocsp_myResponseDataTemplate)) | |
439 goto done; | |
440 | |
441 br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem*, 1); | |
442 if (!br->responseSignature.derCerts) | |
443 goto done; | |
444 br->responseSignature.derCerts[0] = NULL; | |
445 | |
446 privKey = PK11_FindKeyByAnyCert(responderCert, wincx); | |
447 if (!privKey) | |
448 goto done; | |
449 | |
450 algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1); | |
451 if (algID == SEC_OID_UNKNOWN) | |
452 goto done; | |
453 | |
454 if (SEC_SignData(&br->responseSignature.signature, | |
455 br->tbsResponseDataDER.data, br->tbsResponseDataDER.len, | |
456 privKey, algID) | |
457 != SECSuccess) | |
458 goto done; | |
459 | |
460 /* convert len-in-bytes to len-in-bits */ | |
461 br->responseSignature.signature.len = br->responseSignature.signature.len <<
3; | |
462 | |
463 /* br->responseSignature.signature wasn't allocated from arena, | |
464 * we must free it when done. */ | |
465 | |
466 if (SECOID_SetAlgorithmID(tmpArena, &br->responseSignature.signatureAlgorith
m, algID, 0) | |
467 != SECSuccess) | |
468 goto done; | |
469 | |
470 if (!SEC_ASN1EncodeItem(tmpArena, &rb->response, br, | |
471 ocsp_EncodeBasicOCSPResponseTemplate)) | |
472 goto done; | |
473 | |
474 rb->responseTypeTag = SEC_OID_PKIX_OCSP_BASIC_RESPONSE; | |
475 | |
476 od = SECOID_FindOIDByTag(rb->responseTypeTag); | |
477 if (!od) | |
478 goto done; | |
479 | |
480 rb->responseType = od->oid; | |
481 rb->decodedResponse.basic = br; | |
482 | |
483 response->arena = tmpArena; | |
484 response->responseBytes = rb; | |
485 response->statusValue = ocspResponse_successful; | |
486 | |
487 if (!SEC_ASN1EncodeInteger(tmpArena, &response->responseStatus, | |
488 response->statusValue)) | |
489 goto done; | |
490 | |
491 result = SEC_ASN1EncodeItem(arena, NULL, response, ocsp_OCSPResponseTemplate
); | |
492 | |
493 done: | |
494 if (privKey) | |
495 SECKEY_DestroyPrivateKey(privKey); | |
496 if (br->responseSignature.signature.data) | |
497 SECITEM_FreeItem(&br->responseSignature.signature, PR_FALSE); | |
498 PORT_FreeArena(tmpArena, PR_FALSE); | |
499 | |
500 return result; | |
501 } | |
502 | |
503 static const SEC_ASN1Template ocsp_OCSPErrorResponseTemplate[] = { | |
504 { SEC_ASN1_SEQUENCE, | |
505 0, NULL, sizeof(CERTOCSPResponse) }, | |
506 { SEC_ASN1_ENUMERATED, | |
507 offsetof(CERTOCSPResponse, responseStatus) }, | |
508 { 0, 0, | |
509 mySEC_NullTemplate }, | |
510 { 0 } | |
511 }; | |
512 | |
513 SECItem* | |
514 CERT_CreateEncodedOCSPErrorResponse(PLArenaPool *arena, int error) | |
515 { | |
516 CERTOCSPResponse response; | |
517 SECItem *result = NULL; | |
518 | |
519 switch (error) { | |
520 case SEC_ERROR_OCSP_MALFORMED_REQUEST: | |
521 response.statusValue = ocspResponse_malformedRequest; | |
522 break; | |
523 case SEC_ERROR_OCSP_SERVER_ERROR: | |
524 response.statusValue = ocspResponse_internalError; | |
525 break; | |
526 case SEC_ERROR_OCSP_TRY_SERVER_LATER: | |
527 response.statusValue = ocspResponse_tryLater; | |
528 break; | |
529 case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG: | |
530 response.statusValue = ocspResponse_sigRequired; | |
531 break; | |
532 case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST: | |
533 response.statusValue = ocspResponse_unauthorized; | |
534 break; | |
535 default: | |
536 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
537 return NULL; | |
538 } | |
539 | |
540 if (!SEC_ASN1EncodeInteger(NULL, &response.responseStatus, | |
541 response.statusValue)) | |
542 return NULL; | |
543 | |
544 result = SEC_ASN1EncodeItem(arena, NULL, &response, | |
545 ocsp_OCSPErrorResponseTemplate); | |
546 | |
547 SECITEM_FreeItem(&response.responseStatus, PR_FALSE); | |
548 | |
549 return result; | |
550 } | |
OLD | NEW |