|
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 /* responderCert == 0 means: |
|
359 * create a response with an invalid signature (for testing purposes) */ |
|
360 SECItem* |
|
361 CERT_CreateEncodedOCSPSuccessResponse( |
|
362 PLArenaPool *arena, |
|
363 CERTCertificate *responderCert, |
|
364 CERTOCSPResponderIDType responderIDType, |
|
365 PRTime producedAt, |
|
366 CERTOCSPSingleResponse **responses, |
|
367 void *wincx) |
|
368 { |
|
369 PLArenaPool *tmpArena; |
|
370 ocspResponseData *rd = NULL; |
|
371 ocspResponderID *rid = NULL; |
|
372 const SEC_ASN1Template *responderIDTemplate = NULL; |
|
373 ocspBasicOCSPResponse *br = NULL; |
|
374 ocspResponseBytes *rb = NULL; |
|
375 CERTOCSPResponse *response = NULL; |
|
376 |
|
377 SECOidTag algID; |
|
378 SECOidData *od = NULL; |
|
379 SECKEYPrivateKey *privKey = NULL; |
|
380 SECItem *result = NULL; |
|
381 |
|
382 if (!arena || !responses) { |
|
383 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
384 return NULL; |
|
385 } |
|
386 if (responderIDType != ocspResponderID_byName && |
|
387 responderIDType != ocspResponderID_byKey) { |
|
388 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
389 return NULL; |
|
390 } |
|
391 |
|
392 tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
393 if (!tmpArena) |
|
394 return NULL; |
|
395 |
|
396 rd = PORT_ArenaZNew(tmpArena, ocspResponseData); |
|
397 if (!rd) |
|
398 goto done; |
|
399 rid = PORT_ArenaZNew(tmpArena, ocspResponderID); |
|
400 if (!rid) |
|
401 goto done; |
|
402 br = PORT_ArenaZNew(tmpArena, ocspBasicOCSPResponse); |
|
403 if (!br) |
|
404 goto done; |
|
405 rb = PORT_ArenaZNew(tmpArena, ocspResponseBytes); |
|
406 if (!rb) |
|
407 goto done; |
|
408 response = PORT_ArenaZNew(tmpArena, CERTOCSPResponse); |
|
409 if (!response) |
|
410 goto done; |
|
411 |
|
412 rd->version.data=NULL; |
|
413 rd->version.len=0; |
|
414 rd->responseExtensions = NULL; |
|
415 rd->responses = responses; |
|
416 if (DER_TimeToGeneralizedTimeArena(tmpArena, &rd->producedAt, producedAt) |
|
417 != SECSuccess) |
|
418 goto done; |
|
419 |
|
420 if (!responderCert) { |
|
421 /* use invalid signature for testing purposes */ |
|
422 unsigned char dummyChar = 'd'; |
|
423 SECItem dummy; |
|
424 |
|
425 dummy.len = 1; |
|
426 dummy.data = &dummyChar; |
|
427 |
|
428 /* it's easier to produdce a keyHash out of nowhere, |
|
429 * than to produce an encoded subject, |
|
430 * so for our dummy response we always use byKey |
|
431 */ |
|
432 |
|
433 rid->responderIDType = ocspResponderID_byKey; |
|
434 if (!ocsp_DigestValue(tmpArena, SEC_OID_SHA1, &rid->responderIDValue.keyHash, |
|
435 &dummy)) |
|
436 goto done; |
|
437 |
|
438 if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, |
|
439 ocsp_ResponderIDByKeyTemplate)) |
|
440 goto done; |
|
441 |
|
442 br->tbsResponseData = rd; |
|
443 |
|
444 if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, |
|
445 ocsp_myResponseDataTemplate)) |
|
446 goto done; |
|
447 |
|
448 br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem*, 1); |
|
449 if (!br->responseSignature.derCerts) |
|
450 goto done; |
|
451 br->responseSignature.derCerts[0] = NULL; |
|
452 |
|
453 algID = SEC_GetSignatureAlgorithmOidTag(rsaKey, SEC_OID_SHA1); |
|
454 if (algID == SEC_OID_UNKNOWN) |
|
455 goto done; |
|
456 |
|
457 /* match the regular signature code, which doesn't use the arena */ |
|
458 if (!SECITEM_AllocItem(NULL, &br->responseSignature.signature, 1)) |
|
459 goto done; |
|
460 PORT_Memcpy(br->responseSignature.signature.data, &dummyChar, 1); |
|
461 |
|
462 /* convert len-in-bytes to len-in-bits */ |
|
463 br->responseSignature.signature.len = br->responseSignature.signature.len << 3; |
|
464 } |
|
465 else { |
|
466 rid->responderIDType = responderIDType; |
|
467 if (responderIDType == ocspResponderID_byName) { |
|
468 responderIDTemplate = ocsp_ResponderIDByNameTemplate; |
|
469 if (CERT_CopyName(tmpArena, &rid->responderIDValue.name, |
|
470 &responderCert->subject) != SECSuccess) |
|
471 goto done; |
|
472 } |
|
473 else { |
|
474 responderIDTemplate = ocsp_ResponderIDByKeyTemplate; |
|
475 if (!CERT_GetSubjectPublicKeyDigest(tmpArena, responderCert, |
|
476 SEC_OID_SHA1, &rid->responderIDValue.keyHash)) |
|
477 goto done; |
|
478 } |
|
479 |
|
480 if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, |
|
481 responderIDTemplate)) |
|
482 goto done; |
|
483 |
|
484 br->tbsResponseData = rd; |
|
485 |
|
486 if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, |
|
487 ocsp_myResponseDataTemplate)) |
|
488 goto done; |
|
489 |
|
490 br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem*, 1); |
|
491 if (!br->responseSignature.derCerts) |
|
492 goto done; |
|
493 br->responseSignature.derCerts[0] = NULL; |
|
494 |
|
495 privKey = PK11_FindKeyByAnyCert(responderCert, wincx); |
|
496 if (!privKey) |
|
497 goto done; |
|
498 |
|
499 algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1); |
|
500 if (algID == SEC_OID_UNKNOWN) |
|
501 goto done; |
|
502 |
|
503 if (SEC_SignData(&br->responseSignature.signature, |
|
504 br->tbsResponseDataDER.data, br->tbsResponseDataDER.len, |
|
505 privKey, algID) |
|
506 != SECSuccess) |
|
507 goto done; |
|
508 |
|
509 /* convert len-in-bytes to len-in-bits */ |
|
510 br->responseSignature.signature.len = br->responseSignature.signature.len << 3; |
|
511 |
|
512 /* br->responseSignature.signature wasn't allocated from arena, |
|
513 * we must free it when done. */ |
|
514 } |
|
515 |
|
516 if (SECOID_SetAlgorithmID(tmpArena, &br->responseSignature.signatureAlgorithm, algID, 0) |
|
517 != SECSuccess) |
|
518 goto done; |
|
519 |
|
520 if (!SEC_ASN1EncodeItem(tmpArena, &rb->response, br, |
|
521 ocsp_EncodeBasicOCSPResponseTemplate)) |
|
522 goto done; |
|
523 |
|
524 rb->responseTypeTag = SEC_OID_PKIX_OCSP_BASIC_RESPONSE; |
|
525 |
|
526 od = SECOID_FindOIDByTag(rb->responseTypeTag); |
|
527 if (!od) |
|
528 goto done; |
|
529 |
|
530 rb->responseType = od->oid; |
|
531 rb->decodedResponse.basic = br; |
|
532 |
|
533 response->arena = tmpArena; |
|
534 response->responseBytes = rb; |
|
535 response->statusValue = ocspResponse_successful; |
|
536 |
|
537 if (!SEC_ASN1EncodeInteger(tmpArena, &response->responseStatus, |
|
538 response->statusValue)) |
|
539 goto done; |
|
540 |
|
541 result = SEC_ASN1EncodeItem(arena, NULL, response, ocsp_OCSPResponseTemplate); |
|
542 |
|
543 done: |
|
544 if (privKey) |
|
545 SECKEY_DestroyPrivateKey(privKey); |
|
546 if (br->responseSignature.signature.data) |
|
547 SECITEM_FreeItem(&br->responseSignature.signature, PR_FALSE); |
|
548 PORT_FreeArena(tmpArena, PR_FALSE); |
|
549 |
|
550 return result; |
|
551 } |
|
552 |
|
553 static const SEC_ASN1Template ocsp_OCSPErrorResponseTemplate[] = { |
|
554 { SEC_ASN1_SEQUENCE, |
|
555 0, NULL, sizeof(CERTOCSPResponse) }, |
|
556 { SEC_ASN1_ENUMERATED, |
|
557 offsetof(CERTOCSPResponse, responseStatus) }, |
|
558 { 0, 0, |
|
559 mySEC_NullTemplate }, |
|
560 { 0 } |
|
561 }; |
|
562 |
|
563 SECItem* |
|
564 CERT_CreateEncodedOCSPErrorResponse(PLArenaPool *arena, int error) |
|
565 { |
|
566 CERTOCSPResponse response; |
|
567 SECItem *result = NULL; |
|
568 |
|
569 switch (error) { |
|
570 case SEC_ERROR_OCSP_MALFORMED_REQUEST: |
|
571 response.statusValue = ocspResponse_malformedRequest; |
|
572 break; |
|
573 case SEC_ERROR_OCSP_SERVER_ERROR: |
|
574 response.statusValue = ocspResponse_internalError; |
|
575 break; |
|
576 case SEC_ERROR_OCSP_TRY_SERVER_LATER: |
|
577 response.statusValue = ocspResponse_tryLater; |
|
578 break; |
|
579 case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG: |
|
580 response.statusValue = ocspResponse_sigRequired; |
|
581 break; |
|
582 case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST: |
|
583 response.statusValue = ocspResponse_unauthorized; |
|
584 break; |
|
585 default: |
|
586 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
587 return NULL; |
|
588 } |
|
589 |
|
590 if (!SEC_ASN1EncodeInteger(NULL, &response.responseStatus, |
|
591 response.statusValue)) |
|
592 return NULL; |
|
593 |
|
594 result = SEC_ASN1EncodeItem(arena, NULL, &response, |
|
595 ocsp_OCSPErrorResponseTemplate); |
|
596 |
|
597 SECITEM_FreeItem(&response.responseStatus, PR_FALSE); |
|
598 |
|
599 return result; |
|
600 } |