/src/mozilla-central/security/nss/lib/certhigh/ocspsig.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | { |
31 | 0 | ocspCertStatus *cs; |
32 | 0 |
|
33 | 0 | if (!arena) { |
34 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
35 | 0 | return NULL; |
36 | 0 | } |
37 | 0 |
|
38 | 0 | switch (status) { |
39 | 0 | case ocspCertStatus_good: |
40 | 0 | case ocspCertStatus_unknown: |
41 | 0 | case ocspCertStatus_revoked: |
42 | 0 | break; |
43 | 0 | default: |
44 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
45 | 0 | return NULL; |
46 | 0 | } |
47 | 0 |
|
48 | 0 | cs = PORT_ArenaZNew(arena, ocspCertStatus); |
49 | 0 | if (!cs) |
50 | 0 | return NULL; |
51 | 0 | cs->certStatusType = status; |
52 | 0 | switch (status) { |
53 | 0 | case ocspCertStatus_good: |
54 | 0 | cs->certStatusInfo.goodInfo = SECITEM_AllocItem(arena, NULL, 0); |
55 | 0 | if (!cs->certStatusInfo.goodInfo) |
56 | 0 | return NULL; |
57 | 0 | break; |
58 | 0 | case ocspCertStatus_unknown: |
59 | 0 | cs->certStatusInfo.unknownInfo = SECITEM_AllocItem(arena, NULL, 0); |
60 | 0 | if (!cs->certStatusInfo.unknownInfo) |
61 | 0 | return NULL; |
62 | 0 | break; |
63 | 0 | case ocspCertStatus_revoked: |
64 | 0 | cs->certStatusInfo.revokedInfo = |
65 | 0 | PORT_ArenaZNew(arena, ocspRevokedInfo); |
66 | 0 | if (!cs->certStatusInfo.revokedInfo) |
67 | 0 | return NULL; |
68 | 0 | cs->certStatusInfo.revokedInfo->revocationReason = |
69 | 0 | SECITEM_AllocItem(arena, NULL, 0); |
70 | 0 | if (!cs->certStatusInfo.revokedInfo->revocationReason) |
71 | 0 | return NULL; |
72 | 0 | if (DER_TimeToGeneralizedTimeArena(arena, |
73 | 0 | &cs->certStatusInfo.revokedInfo->revocationTime, |
74 | 0 | revocationTime) != |
75 | 0 | SECSuccess) |
76 | 0 | return NULL; |
77 | 0 | break; |
78 | 0 | default: |
79 | 0 | PORT_Assert(PR_FALSE); |
80 | 0 | } |
81 | 0 | return cs; |
82 | 0 | } |
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 | 0 | { |
263 | 0 | CERTOCSPSingleResponse *sr; |
264 | 0 |
|
265 | 0 | if (!arena || !id || !status) { |
266 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
267 | 0 | return NULL; |
268 | 0 | } |
269 | 0 |
|
270 | 0 | sr = PORT_ArenaZNew(arena, CERTOCSPSingleResponse); |
271 | 0 | if (!sr) |
272 | 0 | return NULL; |
273 | 0 | sr->arena = arena; |
274 | 0 | sr->certID = id; |
275 | 0 | sr->certStatus = status; |
276 | 0 | if (DER_TimeToGeneralizedTimeArena(arena, &sr->thisUpdate, thisUpdate) != |
277 | 0 | SECSuccess) |
278 | 0 | return NULL; |
279 | 0 | sr->nextUpdate = NULL; |
280 | 0 | if (nextUpdate) { |
281 | 0 | sr->nextUpdate = SECITEM_AllocItem(arena, NULL, 0); |
282 | 0 | if (!sr->nextUpdate) |
283 | 0 | return NULL; |
284 | 0 | if (DER_TimeToGeneralizedTimeArena(arena, sr->nextUpdate, *nextUpdate) != |
285 | 0 | SECSuccess) |
286 | 0 | return NULL; |
287 | 0 | } |
288 | 0 | |
289 | 0 | sr->singleExtensions = PORT_ArenaNewArray(arena, CERTCertExtension *, 1); |
290 | 0 | if (!sr->singleExtensions) |
291 | 0 | return NULL; |
292 | 0 | |
293 | 0 | sr->singleExtensions[0] = NULL; |
294 | 0 |
|
295 | 0 | if (!SEC_ASN1EncodeItem(arena, &sr->derCertStatus, |
296 | 0 | status, ocsp_CertStatusTemplate)) |
297 | 0 | return NULL; |
298 | 0 | |
299 | 0 | return sr; |
300 | 0 | } |
301 | | |
302 | | CERTOCSPSingleResponse * |
303 | | CERT_CreateOCSPSingleResponseGood(PLArenaPool *arena, |
304 | | CERTOCSPCertID *id, |
305 | | PRTime thisUpdate, |
306 | | const PRTime *nextUpdate) |
307 | 0 | { |
308 | 0 | ocspCertStatus *cs; |
309 | 0 | if (!arena) { |
310 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
311 | 0 | return NULL; |
312 | 0 | } |
313 | 0 | cs = ocsp_CreateCertStatus(arena, ocspCertStatus_good, 0); |
314 | 0 | if (!cs) |
315 | 0 | return NULL; |
316 | 0 | return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); |
317 | 0 | } |
318 | | |
319 | | CERTOCSPSingleResponse * |
320 | | CERT_CreateOCSPSingleResponseUnknown(PLArenaPool *arena, |
321 | | CERTOCSPCertID *id, |
322 | | PRTime thisUpdate, |
323 | | const PRTime *nextUpdate) |
324 | 0 | { |
325 | 0 | ocspCertStatus *cs; |
326 | 0 | if (!arena) { |
327 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
328 | 0 | return NULL; |
329 | 0 | } |
330 | 0 | cs = ocsp_CreateCertStatus(arena, ocspCertStatus_unknown, 0); |
331 | 0 | if (!cs) |
332 | 0 | return NULL; |
333 | 0 | return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); |
334 | 0 | } |
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 | 0 | { |
345 | 0 | ocspCertStatus *cs; |
346 | 0 | /* revocationReason is not yet supported, so it must be NULL. */ |
347 | 0 | if (!arena || revocationReason) { |
348 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
349 | 0 | return NULL; |
350 | 0 | } |
351 | 0 | cs = ocsp_CreateCertStatus(arena, ocspCertStatus_revoked, revocationTime); |
352 | 0 | if (!cs) |
353 | 0 | return NULL; |
354 | 0 | return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); |
355 | 0 | } |
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 | 0 | { |
368 | 0 | PLArenaPool *tmpArena; |
369 | 0 | ocspResponseData *rd = NULL; |
370 | 0 | ocspResponderID *rid = NULL; |
371 | 0 | const SEC_ASN1Template *responderIDTemplate = NULL; |
372 | 0 | ocspBasicOCSPResponse *br = NULL; |
373 | 0 | ocspResponseBytes *rb = NULL; |
374 | 0 | CERTOCSPResponse *response = NULL; |
375 | 0 |
|
376 | 0 | SECOidTag algID; |
377 | 0 | SECOidData *od = NULL; |
378 | 0 | SECKEYPrivateKey *privKey = NULL; |
379 | 0 | SECItem *result = NULL; |
380 | 0 |
|
381 | 0 | if (!arena || !responses) { |
382 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
383 | 0 | return NULL; |
384 | 0 | } |
385 | 0 | if (responderIDType != ocspResponderID_byName && |
386 | 0 | responderIDType != ocspResponderID_byKey) { |
387 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
388 | 0 | return NULL; |
389 | 0 | } |
390 | 0 |
|
391 | 0 | tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
392 | 0 | if (!tmpArena) |
393 | 0 | return NULL; |
394 | 0 | |
395 | 0 | rd = PORT_ArenaZNew(tmpArena, ocspResponseData); |
396 | 0 | if (!rd) |
397 | 0 | goto done; |
398 | 0 | rid = PORT_ArenaZNew(tmpArena, ocspResponderID); |
399 | 0 | if (!rid) |
400 | 0 | goto done; |
401 | 0 | br = PORT_ArenaZNew(tmpArena, ocspBasicOCSPResponse); |
402 | 0 | if (!br) |
403 | 0 | goto done; |
404 | 0 | rb = PORT_ArenaZNew(tmpArena, ocspResponseBytes); |
405 | 0 | if (!rb) |
406 | 0 | goto done; |
407 | 0 | response = PORT_ArenaZNew(tmpArena, CERTOCSPResponse); |
408 | 0 | if (!response) |
409 | 0 | goto done; |
410 | 0 | |
411 | 0 | rd->version.data = NULL; |
412 | 0 | rd->version.len = 0; |
413 | 0 | rd->responseExtensions = NULL; |
414 | 0 | rd->responses = responses; |
415 | 0 | if (DER_TimeToGeneralizedTimeArena(tmpArena, &rd->producedAt, producedAt) != |
416 | 0 | SECSuccess) |
417 | 0 | goto done; |
418 | 0 | |
419 | 0 | if (!responderCert) { |
420 | 0 | /* use invalid signature for testing purposes */ |
421 | 0 | unsigned char dummyChar = 'd'; |
422 | 0 | SECItem dummy; |
423 | 0 |
|
424 | 0 | dummy.len = 1; |
425 | 0 | dummy.data = &dummyChar; |
426 | 0 |
|
427 | 0 | /* it's easier to produdce a keyHash out of nowhere, |
428 | 0 | * than to produce an encoded subject, |
429 | 0 | * so for our dummy response we always use byKey |
430 | 0 | */ |
431 | 0 |
|
432 | 0 | rid->responderIDType = ocspResponderID_byKey; |
433 | 0 | if (!ocsp_DigestValue(tmpArena, SEC_OID_SHA1, &rid->responderIDValue.keyHash, |
434 | 0 | &dummy)) |
435 | 0 | goto done; |
436 | 0 | |
437 | 0 | if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, |
438 | 0 | ocsp_ResponderIDByKeyTemplate)) |
439 | 0 | goto done; |
440 | 0 | |
441 | 0 | br->tbsResponseData = rd; |
442 | 0 |
|
443 | 0 | if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, |
444 | 0 | ocsp_myResponseDataTemplate)) |
445 | 0 | goto done; |
446 | 0 | |
447 | 0 | br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem *, 1); |
448 | 0 | if (!br->responseSignature.derCerts) |
449 | 0 | goto done; |
450 | 0 | br->responseSignature.derCerts[0] = NULL; |
451 | 0 |
|
452 | 0 | algID = SEC_GetSignatureAlgorithmOidTag(rsaKey, SEC_OID_SHA1); |
453 | 0 | if (algID == SEC_OID_UNKNOWN) |
454 | 0 | goto done; |
455 | 0 | |
456 | 0 | /* match the regular signature code, which doesn't use the arena */ |
457 | 0 | if (!SECITEM_AllocItem(NULL, &br->responseSignature.signature, 1)) |
458 | 0 | goto done; |
459 | 0 | PORT_Memcpy(br->responseSignature.signature.data, &dummyChar, 1); |
460 | 0 |
|
461 | 0 | /* convert len-in-bytes to len-in-bits */ |
462 | 0 | br->responseSignature.signature.len = br->responseSignature.signature.len << 3; |
463 | 0 | } else { |
464 | 0 | rid->responderIDType = responderIDType; |
465 | 0 | if (responderIDType == ocspResponderID_byName) { |
466 | 0 | responderIDTemplate = ocsp_ResponderIDByNameTemplate; |
467 | 0 | if (CERT_CopyName(tmpArena, &rid->responderIDValue.name, |
468 | 0 | &responderCert->subject) != SECSuccess) |
469 | 0 | goto done; |
470 | 0 | } else { |
471 | 0 | responderIDTemplate = ocsp_ResponderIDByKeyTemplate; |
472 | 0 | if (!CERT_GetSubjectPublicKeyDigest(tmpArena, responderCert, |
473 | 0 | SEC_OID_SHA1, &rid->responderIDValue.keyHash)) |
474 | 0 | goto done; |
475 | 0 | } |
476 | 0 | |
477 | 0 | if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, |
478 | 0 | responderIDTemplate)) |
479 | 0 | goto done; |
480 | 0 | |
481 | 0 | br->tbsResponseData = rd; |
482 | 0 |
|
483 | 0 | if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, |
484 | 0 | ocsp_myResponseDataTemplate)) |
485 | 0 | goto done; |
486 | 0 | |
487 | 0 | br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem *, 1); |
488 | 0 | if (!br->responseSignature.derCerts) |
489 | 0 | goto done; |
490 | 0 | br->responseSignature.derCerts[0] = NULL; |
491 | 0 |
|
492 | 0 | privKey = PK11_FindKeyByAnyCert(responderCert, wincx); |
493 | 0 | if (!privKey) |
494 | 0 | goto done; |
495 | 0 | |
496 | 0 | algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1); |
497 | 0 | if (algID == SEC_OID_UNKNOWN) |
498 | 0 | goto done; |
499 | 0 | |
500 | 0 | if (SEC_SignData(&br->responseSignature.signature, |
501 | 0 | br->tbsResponseDataDER.data, br->tbsResponseDataDER.len, |
502 | 0 | privKey, algID) != |
503 | 0 | SECSuccess) |
504 | 0 | goto done; |
505 | 0 | |
506 | 0 | /* convert len-in-bytes to len-in-bits */ |
507 | 0 | br->responseSignature.signature.len = br->responseSignature.signature.len << 3; |
508 | 0 |
|
509 | 0 | /* br->responseSignature.signature wasn't allocated from arena, |
510 | 0 | * we must free it when done. */ |
511 | 0 | } |
512 | 0 |
|
513 | 0 | if (SECOID_SetAlgorithmID(tmpArena, &br->responseSignature.signatureAlgorithm, algID, 0) != |
514 | 0 | SECSuccess) |
515 | 0 | goto done; |
516 | 0 | |
517 | 0 | if (!SEC_ASN1EncodeItem(tmpArena, &rb->response, br, |
518 | 0 | ocsp_EncodeBasicOCSPResponseTemplate)) |
519 | 0 | goto done; |
520 | 0 | |
521 | 0 | rb->responseTypeTag = SEC_OID_PKIX_OCSP_BASIC_RESPONSE; |
522 | 0 |
|
523 | 0 | od = SECOID_FindOIDByTag(rb->responseTypeTag); |
524 | 0 | if (!od) |
525 | 0 | goto done; |
526 | 0 | |
527 | 0 | rb->responseType = od->oid; |
528 | 0 | rb->decodedResponse.basic = br; |
529 | 0 |
|
530 | 0 | response->arena = tmpArena; |
531 | 0 | response->responseBytes = rb; |
532 | 0 | response->statusValue = ocspResponse_successful; |
533 | 0 |
|
534 | 0 | if (!SEC_ASN1EncodeInteger(tmpArena, &response->responseStatus, |
535 | 0 | response->statusValue)) |
536 | 0 | goto done; |
537 | 0 | |
538 | 0 | result = SEC_ASN1EncodeItem(arena, NULL, response, ocsp_OCSPResponseTemplate); |
539 | 0 |
|
540 | 0 | done: |
541 | 0 | if (privKey) |
542 | 0 | SECKEY_DestroyPrivateKey(privKey); |
543 | 0 | if (br && br->responseSignature.signature.data) |
544 | 0 | SECITEM_FreeItem(&br->responseSignature.signature, PR_FALSE); |
545 | 0 | PORT_FreeArena(tmpArena, PR_FALSE); |
546 | 0 |
|
547 | 0 | return result; |
548 | 0 | } |
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 | 0 | { |
563 | 0 | CERTOCSPResponse response; |
564 | 0 | SECItem *result = NULL; |
565 | 0 |
|
566 | 0 | switch (error) { |
567 | 0 | case SEC_ERROR_OCSP_MALFORMED_REQUEST: |
568 | 0 | response.statusValue = ocspResponse_malformedRequest; |
569 | 0 | break; |
570 | 0 | case SEC_ERROR_OCSP_SERVER_ERROR: |
571 | 0 | response.statusValue = ocspResponse_internalError; |
572 | 0 | break; |
573 | 0 | case SEC_ERROR_OCSP_TRY_SERVER_LATER: |
574 | 0 | response.statusValue = ocspResponse_tryLater; |
575 | 0 | break; |
576 | 0 | case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG: |
577 | 0 | response.statusValue = ocspResponse_sigRequired; |
578 | 0 | break; |
579 | 0 | case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST: |
580 | 0 | response.statusValue = ocspResponse_unauthorized; |
581 | 0 | break; |
582 | 0 | default: |
583 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
584 | 0 | return NULL; |
585 | 0 | } |
586 | 0 |
|
587 | 0 | if (!SEC_ASN1EncodeInteger(NULL, &response.responseStatus, |
588 | 0 | response.statusValue)) |
589 | 0 | return NULL; |
590 | 0 | |
591 | 0 | result = SEC_ASN1EncodeItem(arena, NULL, &response, |
592 | 0 | ocsp_OCSPErrorResponseTemplate); |
593 | 0 |
|
594 | 0 | SECITEM_FreeItem(&response.responseStatus, PR_FALSE); |
595 | 0 |
|
596 | 0 | return result; |
597 | 0 | } |