|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 /* Copyright 2013 Mozilla Foundation |
|
4 * |
|
5 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 * you may not use this file except in compliance with the License. |
|
7 * You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 */ |
|
17 |
|
18 #include <limits> |
|
19 |
|
20 #include "pkix/bind.h" |
|
21 #include "pkix/pkix.h" |
|
22 #include "pkixcheck.h" |
|
23 #include "pkixder.h" |
|
24 |
|
25 #include "hasht.h" |
|
26 #include "pk11pub.h" |
|
27 #include "secder.h" |
|
28 |
|
29 #ifdef _MSC_VER |
|
30 // C4480: nonstandard extension used: specifying underlying type for enum |
|
31 #define ENUM_CLASS __pragma(warning(disable: 4480)) enum |
|
32 #else |
|
33 #define ENUM_CLASS enum class |
|
34 #endif |
|
35 |
|
36 // TODO: use typed/qualified typedefs everywhere? |
|
37 // TODO: When should we return SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE? |
|
38 |
|
39 namespace mozilla { namespace pkix { |
|
40 |
|
41 static const PRTime ONE_DAY |
|
42 = INT64_C(24) * INT64_C(60) * INT64_C(60) * PR_USEC_PER_SEC; |
|
43 static const PRTime SLOP = ONE_DAY; |
|
44 |
|
45 // These values correspond to the tag values in the ASN.1 CertStatus |
|
46 ENUM_CLASS CertStatus : uint8_t { |
|
47 Good = der::CONTEXT_SPECIFIC | 0, |
|
48 Revoked = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, |
|
49 Unknown = der::CONTEXT_SPECIFIC | 2 |
|
50 }; |
|
51 |
|
52 class Context |
|
53 { |
|
54 public: |
|
55 Context(TrustDomain& trustDomain, |
|
56 const CERTCertificate& cert, |
|
57 CERTCertificate& issuerCert, |
|
58 PRTime time, |
|
59 uint16_t maxLifetimeInDays, |
|
60 PRTime* thisUpdate, |
|
61 PRTime* validThrough) |
|
62 : trustDomain(trustDomain) |
|
63 , cert(cert) |
|
64 , issuerCert(issuerCert) |
|
65 , time(time) |
|
66 , maxLifetimeInDays(maxLifetimeInDays) |
|
67 , certStatus(CertStatus::Unknown) |
|
68 , thisUpdate(thisUpdate) |
|
69 , validThrough(validThrough) |
|
70 , expired(false) |
|
71 { |
|
72 if (thisUpdate) { |
|
73 *thisUpdate = 0; |
|
74 } |
|
75 if (validThrough) { |
|
76 *validThrough = 0; |
|
77 } |
|
78 } |
|
79 |
|
80 TrustDomain& trustDomain; |
|
81 const CERTCertificate& cert; |
|
82 CERTCertificate& issuerCert; |
|
83 const PRTime time; |
|
84 const uint16_t maxLifetimeInDays; |
|
85 CertStatus certStatus; |
|
86 PRTime* thisUpdate; |
|
87 PRTime* validThrough; |
|
88 bool expired; |
|
89 |
|
90 private: |
|
91 Context(const Context&); // delete |
|
92 void operator=(const Context&); // delete |
|
93 }; |
|
94 |
|
95 // Verify that potentialSigner is a valid delegated OCSP response signing cert |
|
96 // according to RFC 6960 section 4.2.2.2. |
|
97 static Result |
|
98 CheckOCSPResponseSignerCert(TrustDomain& trustDomain, |
|
99 CERTCertificate& potentialSigner, |
|
100 const CERTCertificate& issuerCert, PRTime time) |
|
101 { |
|
102 Result rv; |
|
103 |
|
104 BackCert cert(&potentialSigner, nullptr, BackCert::ExcludeCN); |
|
105 rv = cert.Init(); |
|
106 if (rv != Success) { |
|
107 return rv; |
|
108 } |
|
109 |
|
110 // We don't need to do a complete verification of the signer (i.e. we don't |
|
111 // have to call BuildCertChain to verify the entire chain) because we |
|
112 // already know that the issuerCert is valid, since revocation checking is |
|
113 // done from the root to the parent after we've built a complete chain that |
|
114 // we know is otherwise valid. Rather, we just need to do a one-step |
|
115 // validation from potentialSigner to issuerCert. |
|
116 // |
|
117 // It seems reasonable to require the KU_DIGITAL_SIGNATURE key usage on the |
|
118 // OCSP responder certificate if the OCSP responder certificate has a |
|
119 // key usage extension. However, according to bug 240456, some OCSP responder |
|
120 // certificates may have only the nonRepudiation bit set. Also, the OCSP |
|
121 // specification (RFC 6960) does not mandate any particular key usage to be |
|
122 // asserted for OCSP responde signers. Oddly, the CABForum Baseline |
|
123 // Requirements v.1.1.5 do say "If the Root CA Private Key is used for |
|
124 // signing OCSP responses, then the digitalSignature bit MUST be set." |
|
125 // |
|
126 // Note that CheckIssuerIndependentProperties processes |
|
127 // SEC_OID_OCSP_RESPONDER in the way that the OCSP specification requires us |
|
128 // to--in particular, it doesn't allow SEC_OID_OCSP_RESPONDER to be implied |
|
129 // by a missing EKU extension, unlike other EKUs. |
|
130 // |
|
131 // TODO(bug 926261): If we're validating for a policy then the policy OID we |
|
132 // are validating for should be passed to CheckIssuerIndependentProperties. |
|
133 rv = CheckIssuerIndependentProperties(trustDomain, cert, time, |
|
134 MustBeEndEntity, |
|
135 KeyUsage::noParticularKeyUsageRequired, |
|
136 SEC_OID_OCSP_RESPONDER, |
|
137 SEC_OID_X509_ANY_POLICY, 0); |
|
138 if (rv != Success) { |
|
139 return rv; |
|
140 } |
|
141 |
|
142 // It is possible that there exists a certificate with the same key as the |
|
143 // issuer but with a different name, so we need to compare names |
|
144 // TODO: needs test |
|
145 if (!SECITEM_ItemsAreEqual(&cert.GetNSSCert()->derIssuer, |
|
146 &issuerCert.derSubject) && |
|
147 CERT_CompareName(&cert.GetNSSCert()->issuer, |
|
148 &issuerCert.subject) != SECEqual) { |
|
149 return Fail(RecoverableError, SEC_ERROR_OCSP_RESPONDER_CERT_INVALID); |
|
150 } |
|
151 |
|
152 // TODO(bug 926260): check name constraints |
|
153 |
|
154 if (trustDomain.VerifySignedData(&potentialSigner.signatureWrap, |
|
155 &issuerCert) != SECSuccess) { |
|
156 return MapSECStatus(SECFailure); |
|
157 } |
|
158 |
|
159 // TODO: check for revocation of the OCSP responder certificate unless no-check |
|
160 // or the caller forcing no-check. To properly support the no-check policy, we'd |
|
161 // need to enforce policy constraints from the issuerChain. |
|
162 |
|
163 return Success; |
|
164 } |
|
165 |
|
166 //typedef enum { |
|
167 // ocspResponderID_byName = 1, |
|
168 // ocspResponderID_byKey = 2 |
|
169 //} ResponderIDType; |
|
170 |
|
171 ENUM_CLASS ResponderIDType : uint8_t |
|
172 { |
|
173 byName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, |
|
174 byKey = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 2 |
|
175 }; |
|
176 |
|
177 static inline der::Result OCSPResponse(der::Input&, Context&); |
|
178 static inline der::Result ResponseBytes(der::Input&, Context&); |
|
179 static inline der::Result BasicResponse(der::Input&, Context&); |
|
180 static inline der::Result ResponseData( |
|
181 der::Input& tbsResponseData, Context& context, |
|
182 const CERTSignedData& signedResponseData, |
|
183 /*const*/ SECItem* certs, size_t numCerts); |
|
184 static inline der::Result SingleResponse(der::Input& input, |
|
185 Context& context); |
|
186 static inline der::Result CheckExtensionsForCriticality(der::Input&); |
|
187 static inline der::Result CertID(der::Input& input, |
|
188 const Context& context, |
|
189 /*out*/ bool& match); |
|
190 static der::Result MatchIssuerKey(const SECItem& issuerKeyHash, |
|
191 const CERTCertificate& issuer, |
|
192 /*out*/ bool& match); |
|
193 |
|
194 // RFC 6960 section 4.2.2.2: The OCSP responder must either be the issuer of |
|
195 // the cert or it must be a delegated OCSP response signing cert directly |
|
196 // issued by the issuer. If the OCSP responder is a delegated OCSP response |
|
197 // signer, then its certificate is (probably) embedded within the OCSP |
|
198 // response and we'll need to verify that it is a valid certificate that chains |
|
199 // *directly* to issuerCert. |
|
200 static CERTCertificate* |
|
201 GetOCSPSignerCertificate(TrustDomain& trustDomain, |
|
202 ResponderIDType responderIDType, |
|
203 const SECItem& responderIDItem, |
|
204 const SECItem* certs, size_t numCerts, |
|
205 CERTCertificate& issuerCert, PRTime time) |
|
206 { |
|
207 bool isIssuer = true; |
|
208 size_t i = 0; |
|
209 for (;;) { |
|
210 ScopedCERTCertificate potentialSigner; |
|
211 if (isIssuer) { |
|
212 potentialSigner = CERT_DupCertificate(&issuerCert); |
|
213 } else if (i < numCerts) { |
|
214 potentialSigner = CERT_NewTempCertificate( |
|
215 CERT_GetDefaultCertDB(), |
|
216 /*TODO*/const_cast<SECItem*>(&certs[i]), nullptr, |
|
217 false, false); |
|
218 if (!potentialSigner) { |
|
219 return nullptr; |
|
220 } |
|
221 ++i; |
|
222 } else { |
|
223 PR_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT, 0); |
|
224 return nullptr; |
|
225 } |
|
226 |
|
227 bool match; |
|
228 switch (responderIDType) { |
|
229 case ResponderIDType::byName: |
|
230 // The CA is very likely to have encoded the name in the OCSP response |
|
231 // exactly the same as the name is encoded in the signing certificate. |
|
232 // Consequently, most of the time we will avoid parsing the name |
|
233 // completely. We're assuming here that the signer's subject name is |
|
234 // correctly formatted. |
|
235 // TODO: need test for exact name |
|
236 // TODO: need test for non-exact name match |
|
237 match = SECITEM_ItemsAreEqual(&responderIDItem, |
|
238 &potentialSigner->derSubject); |
|
239 if (!match) { |
|
240 ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
|
241 if (!arena) { |
|
242 return nullptr; |
|
243 } |
|
244 CERTName name; |
|
245 if (SEC_QuickDERDecodeItem(arena.get(), &name, |
|
246 SEC_ASN1_GET(CERT_NameTemplate), |
|
247 &responderIDItem) != SECSuccess) { |
|
248 return nullptr; |
|
249 } |
|
250 match = CERT_CompareName(&name, &potentialSigner->subject) == SECEqual; |
|
251 } |
|
252 break; |
|
253 |
|
254 case ResponderIDType::byKey: |
|
255 { |
|
256 der::Input responderID; |
|
257 if (responderID.Init(responderIDItem.data, responderIDItem.len) |
|
258 != der::Success) { |
|
259 return nullptr; |
|
260 } |
|
261 SECItem issuerKeyHash; |
|
262 if (der::Skip(responderID, der::OCTET_STRING, issuerKeyHash) != der::Success) { |
|
263 return nullptr; |
|
264 } |
|
265 if (MatchIssuerKey(issuerKeyHash, *potentialSigner.get(), match) |
|
266 != der::Success) { |
|
267 return nullptr; |
|
268 } |
|
269 break; |
|
270 } |
|
271 |
|
272 default: |
|
273 PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0); |
|
274 return nullptr; |
|
275 } |
|
276 |
|
277 if (match && !isIssuer) { |
|
278 Result rv = CheckOCSPResponseSignerCert(trustDomain, |
|
279 *potentialSigner.get(), |
|
280 issuerCert, time); |
|
281 if (rv == RecoverableError) { |
|
282 match = false; |
|
283 } else if (rv != Success) { |
|
284 return nullptr; |
|
285 } |
|
286 } |
|
287 |
|
288 if (match) { |
|
289 return potentialSigner.release(); |
|
290 } |
|
291 |
|
292 isIssuer = false; |
|
293 } |
|
294 } |
|
295 |
|
296 static SECStatus |
|
297 VerifySignature(Context& context, ResponderIDType responderIDType, |
|
298 const SECItem& responderID, const SECItem* certs, |
|
299 size_t numCerts, const CERTSignedData& signedResponseData) |
|
300 { |
|
301 ScopedCERTCertificate signer( |
|
302 GetOCSPSignerCertificate(context.trustDomain, responderIDType, responderID, |
|
303 certs, numCerts, context.issuerCert, |
|
304 context.time)); |
|
305 if (!signer) { |
|
306 return SECFailure; |
|
307 } |
|
308 |
|
309 if (context.trustDomain.VerifySignedData(&signedResponseData, signer.get()) |
|
310 != SECSuccess) { |
|
311 if (PR_GetError() == SEC_ERROR_BAD_SIGNATURE) { |
|
312 PR_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE, 0); |
|
313 } |
|
314 return SECFailure; |
|
315 } |
|
316 |
|
317 return SECSuccess; |
|
318 } |
|
319 |
|
320 static inline void |
|
321 SetErrorToMalformedResponseOnBadDERError() |
|
322 { |
|
323 if (PR_GetError() == SEC_ERROR_BAD_DER) { |
|
324 PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0); |
|
325 } |
|
326 } |
|
327 |
|
328 SECStatus |
|
329 VerifyEncodedOCSPResponse(TrustDomain& trustDomain, |
|
330 const CERTCertificate* cert, |
|
331 CERTCertificate* issuerCert, PRTime time, |
|
332 uint16_t maxOCSPLifetimeInDays, |
|
333 const SECItem* encodedResponse, |
|
334 bool& expired, |
|
335 PRTime* thisUpdate, |
|
336 PRTime* validThrough) |
|
337 { |
|
338 PR_ASSERT(cert); |
|
339 PR_ASSERT(issuerCert); |
|
340 // TODO: PR_Assert(pinArg) |
|
341 PR_ASSERT(encodedResponse); |
|
342 if (!cert || !issuerCert || !encodedResponse || !encodedResponse->data) { |
|
343 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
|
344 return SECFailure; |
|
345 } |
|
346 |
|
347 // Always initialize this to something reasonable. |
|
348 expired = false; |
|
349 |
|
350 der::Input input; |
|
351 if (input.Init(encodedResponse->data, encodedResponse->len) != der::Success) { |
|
352 SetErrorToMalformedResponseOnBadDERError(); |
|
353 return SECFailure; |
|
354 } |
|
355 Context context(trustDomain, *cert, *issuerCert, time, maxOCSPLifetimeInDays, |
|
356 thisUpdate, validThrough); |
|
357 |
|
358 if (der::Nested(input, der::SEQUENCE, |
|
359 bind(OCSPResponse, _1, ref(context))) != der::Success) { |
|
360 SetErrorToMalformedResponseOnBadDERError(); |
|
361 return SECFailure; |
|
362 } |
|
363 |
|
364 if (der::End(input) != der::Success) { |
|
365 SetErrorToMalformedResponseOnBadDERError(); |
|
366 return SECFailure; |
|
367 } |
|
368 |
|
369 expired = context.expired; |
|
370 |
|
371 switch (context.certStatus) { |
|
372 case CertStatus::Good: |
|
373 if (expired) { |
|
374 PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0); |
|
375 return SECFailure; |
|
376 } |
|
377 return SECSuccess; |
|
378 case CertStatus::Revoked: |
|
379 PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0); |
|
380 return SECFailure; |
|
381 case CertStatus::Unknown: |
|
382 PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); |
|
383 return SECFailure; |
|
384 } |
|
385 |
|
386 PR_NOT_REACHED("unknown CertStatus"); |
|
387 PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); |
|
388 return SECFailure; |
|
389 } |
|
390 |
|
391 // OCSPResponse ::= SEQUENCE { |
|
392 // responseStatus OCSPResponseStatus, |
|
393 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } |
|
394 // |
|
395 static inline der::Result |
|
396 OCSPResponse(der::Input& input, Context& context) |
|
397 { |
|
398 // OCSPResponseStatus ::= ENUMERATED { |
|
399 // successful (0), -- Response has valid confirmations |
|
400 // malformedRequest (1), -- Illegal confirmation request |
|
401 // internalError (2), -- Internal error in issuer |
|
402 // tryLater (3), -- Try again later |
|
403 // -- (4) is not used |
|
404 // sigRequired (5), -- Must sign the request |
|
405 // unauthorized (6) -- Request unauthorized |
|
406 // } |
|
407 uint8_t responseStatus; |
|
408 |
|
409 if (der::Enumerated(input, responseStatus) != der::Success) { |
|
410 return der::Failure; |
|
411 } |
|
412 switch (responseStatus) { |
|
413 case 0: break; // successful |
|
414 case 1: return der::Fail(SEC_ERROR_OCSP_MALFORMED_REQUEST); |
|
415 case 2: return der::Fail(SEC_ERROR_OCSP_SERVER_ERROR); |
|
416 case 3: return der::Fail(SEC_ERROR_OCSP_TRY_SERVER_LATER); |
|
417 case 5: return der::Fail(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG); |
|
418 case 6: return der::Fail(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST); |
|
419 default: return der::Fail(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS); |
|
420 } |
|
421 |
|
422 return der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0, |
|
423 der::SEQUENCE, bind(ResponseBytes, _1, ref(context))); |
|
424 } |
|
425 |
|
426 // ResponseBytes ::= SEQUENCE { |
|
427 // responseType OBJECT IDENTIFIER, |
|
428 // response OCTET STRING } |
|
429 static inline der::Result |
|
430 ResponseBytes(der::Input& input, Context& context) |
|
431 { |
|
432 static const uint8_t id_pkix_ocsp_basic[] = { |
|
433 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 |
|
434 }; |
|
435 |
|
436 if (der::OID(input, id_pkix_ocsp_basic) != der::Success) { |
|
437 return der::Failure; |
|
438 } |
|
439 |
|
440 return der::Nested(input, der::OCTET_STRING, der::SEQUENCE, |
|
441 bind(BasicResponse, _1, ref(context))); |
|
442 } |
|
443 |
|
444 // BasicOCSPResponse ::= SEQUENCE { |
|
445 // tbsResponseData ResponseData, |
|
446 // signatureAlgorithm AlgorithmIdentifier, |
|
447 // signature BIT STRING, |
|
448 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } |
|
449 der::Result |
|
450 BasicResponse(der::Input& input, Context& context) |
|
451 { |
|
452 der::Input::Mark mark(input.GetMark()); |
|
453 |
|
454 uint16_t length; |
|
455 if (der::ExpectTagAndGetLength(input, der::SEQUENCE, length) |
|
456 != der::Success) { |
|
457 return der::Failure; |
|
458 } |
|
459 |
|
460 // The signature covers the entire DER encoding of tbsResponseData, including |
|
461 // the beginning tag and length. However, when we're parsing tbsResponseData, |
|
462 // we want to strip off the tag and length because we don't need it after |
|
463 // we've confirmed it's there and figured out what length it is. |
|
464 |
|
465 der::Input tbsResponseData; |
|
466 |
|
467 if (input.Skip(length, tbsResponseData) != der::Success) { |
|
468 return der::Failure; |
|
469 } |
|
470 |
|
471 CERTSignedData signedData; |
|
472 |
|
473 input.GetSECItem(siBuffer, mark, signedData.data); |
|
474 |
|
475 if (der::Nested(input, der::SEQUENCE, |
|
476 bind(der::AlgorithmIdentifier, _1, |
|
477 ref(signedData.signatureAlgorithm))) != der::Success) { |
|
478 return der::Failure; |
|
479 } |
|
480 |
|
481 if (der::Skip(input, der::BIT_STRING, signedData.signature) != der::Success) { |
|
482 return der::Failure; |
|
483 } |
|
484 if (signedData.signature.len == 0) { |
|
485 return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE); |
|
486 } |
|
487 unsigned int unusedBitsAtEnd = signedData.signature.data[0]; |
|
488 // XXX: Really the constraint should be that unusedBitsAtEnd must be less |
|
489 // than 7. But, we suspect there are no valid OCSP response signatures with |
|
490 // non-zero unused bits. It seems like NSS assumes this in various places, so |
|
491 // we enforce it. If we find compatibility issues, we'll know we're wrong. |
|
492 if (unusedBitsAtEnd != 0) { |
|
493 return der::Fail(SEC_ERROR_OCSP_BAD_SIGNATURE); |
|
494 } |
|
495 ++signedData.signature.data; |
|
496 --signedData.signature.len; |
|
497 signedData.signature.len = (signedData.signature.len << 3); // Bytes to bits |
|
498 |
|
499 // Parse certificates, if any |
|
500 |
|
501 SECItem certs[8]; |
|
502 size_t numCerts = 0; |
|
503 |
|
504 if (!input.AtEnd()) { |
|
505 // We ignore the lengths of the wrappers because we'll detect bad lengths |
|
506 // during parsing--too short and we'll run out of input for parsing a cert, |
|
507 // and too long and we'll have leftover data that won't parse as a cert. |
|
508 |
|
509 // [0] wrapper |
|
510 if (der::ExpectTagAndIgnoreLength( |
|
511 input, der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0) |
|
512 != der::Success) { |
|
513 return der::Failure; |
|
514 } |
|
515 |
|
516 // SEQUENCE wrapper |
|
517 if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) { |
|
518 return der::Failure; |
|
519 } |
|
520 |
|
521 // sequence of certificates |
|
522 while (!input.AtEnd()) { |
|
523 if (numCerts == PR_ARRAY_SIZE(certs)) { |
|
524 return der::Fail(SEC_ERROR_BAD_DER); |
|
525 } |
|
526 |
|
527 // Unwrap the SEQUENCE that contains the certificate, which is itself a |
|
528 // SEQUENCE. |
|
529 der::Input::Mark mark(input.GetMark()); |
|
530 if (der::Skip(input, der::SEQUENCE) != der::Success) { |
|
531 return der::Failure; |
|
532 } |
|
533 |
|
534 input.GetSECItem(siBuffer, mark, certs[numCerts]); |
|
535 ++numCerts; |
|
536 } |
|
537 } |
|
538 |
|
539 return ResponseData(tbsResponseData, context, signedData, certs, numCerts); |
|
540 } |
|
541 |
|
542 // ResponseData ::= SEQUENCE { |
|
543 // version [0] EXPLICIT Version DEFAULT v1, |
|
544 // responderID ResponderID, |
|
545 // producedAt GeneralizedTime, |
|
546 // responses SEQUENCE OF SingleResponse, |
|
547 // responseExtensions [1] EXPLICIT Extensions OPTIONAL } |
|
548 static inline der::Result |
|
549 ResponseData(der::Input& input, Context& context, |
|
550 const CERTSignedData& signedResponseData, |
|
551 /*const*/ SECItem* certs, size_t numCerts) |
|
552 { |
|
553 uint8_t version; |
|
554 if (der::OptionalVersion(input, version) != der::Success) { |
|
555 return der::Failure; |
|
556 } |
|
557 if (version != der::v1) { |
|
558 // TODO: more specific error code for bad version? |
|
559 return der::Fail(SEC_ERROR_BAD_DER); |
|
560 } |
|
561 |
|
562 // ResponderID ::= CHOICE { |
|
563 // byName [1] Name, |
|
564 // byKey [2] KeyHash } |
|
565 SECItem responderID; |
|
566 uint16_t responderIDLength; |
|
567 ResponderIDType responderIDType |
|
568 = input.Peek(static_cast<uint8_t>(ResponderIDType::byName)) |
|
569 ? ResponderIDType::byName |
|
570 : ResponderIDType::byKey; |
|
571 if (ExpectTagAndGetLength(input, static_cast<uint8_t>(responderIDType), |
|
572 responderIDLength) != der::Success) { |
|
573 return der::Failure; |
|
574 } |
|
575 // TODO: responderID probably needs to have another level of ASN1 tag/length |
|
576 // checked and stripped. |
|
577 if (input.Skip(responderIDLength, responderID) != der::Success) { |
|
578 return der::Failure; |
|
579 } |
|
580 |
|
581 // This is the soonest we can verify the signature. We verify the signature |
|
582 // right away to follow the principal of minimizing the processing of data |
|
583 // before verifying its signature. |
|
584 if (VerifySignature(context, responderIDType, responderID, certs, numCerts, |
|
585 signedResponseData) != SECSuccess) { |
|
586 return der::Failure; |
|
587 } |
|
588 |
|
589 // TODO: Do we even need to parse this? Should we just skip it? |
|
590 PRTime producedAt; |
|
591 if (der::GeneralizedTime(input, producedAt) != der::Success) { |
|
592 return der::Failure; |
|
593 } |
|
594 |
|
595 // We don't accept an empty sequence of responses. In practice, a legit OCSP |
|
596 // responder will never return an empty response, and handling the case of an |
|
597 // empty response makes things unnecessarily complicated. |
|
598 if (der::NestedOf(input, der::SEQUENCE, der::SEQUENCE, |
|
599 der::MustNotBeEmpty, |
|
600 bind(SingleResponse, _1, ref(context))) != der::Success) { |
|
601 return der::Failure; |
|
602 } |
|
603 |
|
604 if (!input.AtEnd()) { |
|
605 if (der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, |
|
606 CheckExtensionsForCriticality) != der::Success) { |
|
607 return der::Failure; |
|
608 } |
|
609 } |
|
610 |
|
611 return der::Success; |
|
612 } |
|
613 |
|
614 // SingleResponse ::= SEQUENCE { |
|
615 // certID CertID, |
|
616 // certStatus CertStatus, |
|
617 // thisUpdate GeneralizedTime, |
|
618 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, |
|
619 // singleExtensions [1] EXPLICIT Extensions{{re-ocsp-crl | |
|
620 // re-ocsp-archive-cutoff | |
|
621 // CrlEntryExtensions, ...} |
|
622 // } OPTIONAL } |
|
623 static inline der::Result |
|
624 SingleResponse(der::Input& input, Context& context) |
|
625 { |
|
626 bool match = false; |
|
627 if (der::Nested(input, der::SEQUENCE, |
|
628 bind(CertID, _1, cref(context), ref(match))) |
|
629 != der::Success) { |
|
630 return der::Failure; |
|
631 } |
|
632 |
|
633 if (!match) { |
|
634 // This response does not reference the certificate we're interested in. |
|
635 // By consuming the rest of our input and returning successfully, we can |
|
636 // continue processing and examine another response that might have what |
|
637 // we want. |
|
638 input.SkipToEnd(); |
|
639 return der::Success; |
|
640 } |
|
641 |
|
642 // CertStatus ::= CHOICE { |
|
643 // good [0] IMPLICIT NULL, |
|
644 // revoked [1] IMPLICIT RevokedInfo, |
|
645 // unknown [2] IMPLICIT UnknownInfo } |
|
646 // |
|
647 // In the event of multiple SingleResponses for a cert that have conflicting |
|
648 // statuses, we use the following precedence rules: |
|
649 // |
|
650 // * revoked overrides good and unknown |
|
651 // * good overrides unknown |
|
652 if (input.Peek(static_cast<uint8_t>(CertStatus::Good))) { |
|
653 if (ExpectTagAndLength(input, static_cast<uint8_t>(CertStatus::Good), 0) |
|
654 != der::Success) { |
|
655 return der::Failure; |
|
656 } |
|
657 if (context.certStatus != CertStatus::Revoked) { |
|
658 context.certStatus = CertStatus::Good; |
|
659 } |
|
660 } else if (input.Peek(static_cast<uint8_t>(CertStatus::Revoked))) { |
|
661 // We don't need any info from the RevokedInfo structure, so we don't even |
|
662 // parse it. TODO: We should mention issues like this in the explanation of |
|
663 // why we treat invalid OCSP responses equivalently to revoked for OCSP |
|
664 // stapling. |
|
665 if (der::Skip(input, static_cast<uint8_t>(CertStatus::Revoked)) |
|
666 != der::Success) { |
|
667 return der::Failure; |
|
668 } |
|
669 context.certStatus = CertStatus::Revoked; |
|
670 } else if (ExpectTagAndLength(input, |
|
671 static_cast<uint8_t>(CertStatus::Unknown), |
|
672 0) != der::Success) { |
|
673 return der::Failure; |
|
674 } |
|
675 |
|
676 // http://tools.ietf.org/html/rfc6960#section-3.2 |
|
677 // 5. The time at which the status being indicated is known to be |
|
678 // correct (thisUpdate) is sufficiently recent; |
|
679 // 6. When available, the time at or before which newer information will |
|
680 // be available about the status of the certificate (nextUpdate) is |
|
681 // greater than the current time. |
|
682 |
|
683 const PRTime maxLifetime = |
|
684 context.maxLifetimeInDays * ONE_DAY; |
|
685 |
|
686 PRTime thisUpdate; |
|
687 if (der::GeneralizedTime(input, thisUpdate) != der::Success) { |
|
688 return der::Failure; |
|
689 } |
|
690 |
|
691 if (thisUpdate > context.time + SLOP) { |
|
692 return der::Fail(SEC_ERROR_OCSP_FUTURE_RESPONSE); |
|
693 } |
|
694 |
|
695 PRTime notAfter; |
|
696 static const uint8_t NEXT_UPDATE_TAG = |
|
697 der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0; |
|
698 if (input.Peek(NEXT_UPDATE_TAG)) { |
|
699 PRTime nextUpdate; |
|
700 if (der::Nested(input, NEXT_UPDATE_TAG, |
|
701 bind(der::GeneralizedTime, _1, ref(nextUpdate))) |
|
702 != der::Success) { |
|
703 return der::Failure; |
|
704 } |
|
705 |
|
706 if (nextUpdate < thisUpdate) { |
|
707 return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE); |
|
708 } |
|
709 if (nextUpdate - thisUpdate <= maxLifetime) { |
|
710 notAfter = nextUpdate; |
|
711 } else { |
|
712 notAfter = thisUpdate + maxLifetime; |
|
713 } |
|
714 } else { |
|
715 // NSS requires all OCSP responses without a nextUpdate to be recent. |
|
716 // Match that stricter behavior. |
|
717 notAfter = thisUpdate + ONE_DAY; |
|
718 } |
|
719 |
|
720 if (context.time < SLOP) { // prevent underflow |
|
721 return der::Fail(SEC_ERROR_INVALID_ARGS); |
|
722 } |
|
723 |
|
724 if (context.time - SLOP > notAfter) { |
|
725 context.expired = true; |
|
726 } |
|
727 |
|
728 if (!input.AtEnd()) { |
|
729 if (der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, |
|
730 CheckExtensionsForCriticality) != der::Success) { |
|
731 return der::Failure; |
|
732 } |
|
733 } |
|
734 |
|
735 if (context.thisUpdate) { |
|
736 *context.thisUpdate = thisUpdate; |
|
737 } |
|
738 if (context.validThrough) { |
|
739 *context.validThrough = notAfter; |
|
740 } |
|
741 |
|
742 return der::Success; |
|
743 } |
|
744 |
|
745 // CertID ::= SEQUENCE { |
|
746 // hashAlgorithm AlgorithmIdentifier, |
|
747 // issuerNameHash OCTET STRING, -- Hash of issuer's DN |
|
748 // issuerKeyHash OCTET STRING, -- Hash of issuer's public key |
|
749 // serialNumber CertificateSerialNumber } |
|
750 static inline der::Result |
|
751 CertID(der::Input& input, const Context& context, /*out*/ bool& match) |
|
752 { |
|
753 match = false; |
|
754 |
|
755 SECAlgorithmID hashAlgorithm; |
|
756 if (der::Nested(input, der::SEQUENCE, |
|
757 bind(der::AlgorithmIdentifier, _1, ref(hashAlgorithm))) |
|
758 != der::Success) { |
|
759 return der::Failure; |
|
760 } |
|
761 |
|
762 SECItem issuerNameHash; |
|
763 if (der::Skip(input, der::OCTET_STRING, issuerNameHash) != der::Success) { |
|
764 return der::Failure; |
|
765 } |
|
766 |
|
767 SECItem issuerKeyHash; |
|
768 if (der::Skip(input, der::OCTET_STRING, issuerKeyHash) != der::Success) { |
|
769 return der::Failure; |
|
770 } |
|
771 |
|
772 SECItem serialNumber; |
|
773 if (der::CertificateSerialNumber(input, serialNumber) != der::Success) { |
|
774 return der::Failure; |
|
775 } |
|
776 |
|
777 const CERTCertificate& cert = context.cert; |
|
778 const CERTCertificate& issuerCert = context.issuerCert; |
|
779 |
|
780 if (!SECITEM_ItemsAreEqual(&serialNumber, &cert.serialNumber)) { |
|
781 // This does not reference the certificate we're interested in. |
|
782 // Consume the rest of the input and return successfully to |
|
783 // potentially continue processing other responses. |
|
784 input.SkipToEnd(); |
|
785 return der::Success; |
|
786 } |
|
787 |
|
788 // TODO: support SHA-2 hashes. |
|
789 |
|
790 SECOidTag hashAlg = SECOID_GetAlgorithmTag(&hashAlgorithm); |
|
791 if (hashAlg != SEC_OID_SHA1) { |
|
792 // Again, not interested in this response. Consume input, return success. |
|
793 input.SkipToEnd(); |
|
794 return der::Success; |
|
795 } |
|
796 |
|
797 if (issuerNameHash.len != SHA1_LENGTH) { |
|
798 return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE); |
|
799 } |
|
800 |
|
801 // From http://tools.ietf.org/html/rfc6960#section-4.1.1: |
|
802 // "The hash shall be calculated over the DER encoding of the |
|
803 // issuer's name field in the certificate being checked." |
|
804 uint8_t hashBuf[SHA1_LENGTH]; |
|
805 if (PK11_HashBuf(SEC_OID_SHA1, hashBuf, cert.derIssuer.data, |
|
806 cert.derIssuer.len) != SECSuccess) { |
|
807 return der::Failure; |
|
808 } |
|
809 if (memcmp(hashBuf, issuerNameHash.data, issuerNameHash.len)) { |
|
810 // Again, not interested in this response. Consume input, return success. |
|
811 input.SkipToEnd(); |
|
812 return der::Success; |
|
813 } |
|
814 |
|
815 return MatchIssuerKey(issuerKeyHash, issuerCert, match); |
|
816 } |
|
817 |
|
818 // From http://tools.ietf.org/html/rfc6960#section-4.1.1: |
|
819 // "The hash shall be calculated over the value (excluding tag and length) of |
|
820 // the subject public key field in the issuer's certificate." |
|
821 static der::Result |
|
822 MatchIssuerKey(const SECItem& issuerKeyHash, const CERTCertificate& issuer, |
|
823 /*out*/ bool& match) |
|
824 { |
|
825 if (issuerKeyHash.len != SHA1_LENGTH) { |
|
826 return der::Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE); |
|
827 } |
|
828 |
|
829 // TODO(bug 966856): support SHA-2 hashes |
|
830 |
|
831 // Copy just the length and data pointer (nothing needs to be freed) of the |
|
832 // subject public key so we can convert the length from bits to bytes, which |
|
833 // is what the digest function expects. |
|
834 SECItem spk = issuer.subjectPublicKeyInfo.subjectPublicKey; |
|
835 DER_ConvertBitString(&spk); |
|
836 |
|
837 static uint8_t hashBuf[SHA1_LENGTH]; |
|
838 if (PK11_HashBuf(SEC_OID_SHA1, hashBuf, spk.data, spk.len) != SECSuccess) { |
|
839 return der::Failure; |
|
840 } |
|
841 |
|
842 match = !memcmp(hashBuf, issuerKeyHash.data, issuerKeyHash.len); |
|
843 return der::Success; |
|
844 } |
|
845 |
|
846 // Extension ::= SEQUENCE { |
|
847 // extnID OBJECT IDENTIFIER, |
|
848 // critical BOOLEAN DEFAULT FALSE, |
|
849 // extnValue OCTET STRING |
|
850 // } |
|
851 static der::Result |
|
852 CheckExtensionForCriticality(der::Input& input) |
|
853 { |
|
854 uint16_t toSkip; |
|
855 if (ExpectTagAndGetLength(input, der::OIDTag, toSkip) != der::Success) { |
|
856 return der::Failure; |
|
857 } |
|
858 |
|
859 // TODO: maybe we should check the syntax of the OID value |
|
860 if (input.Skip(toSkip) != der::Success) { |
|
861 return der::Failure; |
|
862 } |
|
863 |
|
864 // The only valid explicit encoding of the value is TRUE, so don't even |
|
865 // bother parsing it, since we're going to fail either way. |
|
866 if (input.Peek(der::BOOLEAN)) { |
|
867 return der::Fail(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); |
|
868 } |
|
869 |
|
870 if (ExpectTagAndGetLength(input, der::OCTET_STRING, toSkip) |
|
871 != der::Success) { |
|
872 return der::Failure; |
|
873 } |
|
874 return input.Skip(toSkip); |
|
875 } |
|
876 |
|
877 // Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension |
|
878 static der::Result |
|
879 CheckExtensionsForCriticality(der::Input& input) |
|
880 { |
|
881 // TODO(bug 997994): some responders include an empty SEQUENCE OF |
|
882 // Extension, which is invalid (der::MayBeEmpty should really be |
|
883 // der::MustNotBeEmpty). |
|
884 return der::NestedOf(input, der::SEQUENCE, der::SEQUENCE, |
|
885 der::MayBeEmpty, CheckExtensionForCriticality); |
|
886 } |
|
887 |
|
888 // 1. The certificate identified in a received response corresponds to |
|
889 // the certificate that was identified in the corresponding request; |
|
890 // 2. The signature on the response is valid; |
|
891 // 3. The identity of the signer matches the intended recipient of the |
|
892 // request; |
|
893 // 4. The signer is currently authorized to provide a response for the |
|
894 // certificate in question; |
|
895 // 5. The time at which the status being indicated is known to be |
|
896 // correct (thisUpdate) is sufficiently recent; |
|
897 // 6. When available, the time at or before which newer information will |
|
898 // be available about the status of the certificate (nextUpdate) is |
|
899 // greater than the current time. |
|
900 // |
|
901 // Responses whose nextUpdate value is earlier than |
|
902 // the local system time value SHOULD be considered unreliable. |
|
903 // Responses whose thisUpdate time is later than the local system time |
|
904 // SHOULD be considered unreliable. |
|
905 // |
|
906 // If nextUpdate is not set, the responder is indicating that newer |
|
907 // revocation information is available all the time. |
|
908 // |
|
909 // http://tools.ietf.org/html/rfc5019#section-4 |
|
910 |
|
911 SECItem* |
|
912 CreateEncodedOCSPRequest(PLArenaPool* arena, |
|
913 const CERTCertificate* cert, |
|
914 const CERTCertificate* issuerCert) |
|
915 { |
|
916 if (!arena || !cert || !issuerCert) { |
|
917 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
|
918 return nullptr; |
|
919 } |
|
920 |
|
921 // We do not add any extensions to the request. |
|
922 |
|
923 // RFC 6960 says "An OCSP client MAY wish to specify the kinds of response |
|
924 // types it understands. To do so, it SHOULD use an extension with the OID |
|
925 // id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11 |
|
926 // on Windows 8.1 does not include any extensions, whereas NSS has always |
|
927 // included the id-pkix-ocsp-response extension. Avoiding the sending the |
|
928 // extension is better for OCSP GET because it makes the request smaller, |
|
929 // and thus more likely to fit within the 255 byte limit for OCSP GET that |
|
930 // is specified in RFC 5019 Section 5. |
|
931 |
|
932 // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension. |
|
933 |
|
934 // Since we don't know whether the OCSP responder supports anything other |
|
935 // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and |
|
936 // issuerKeyHash. |
|
937 static const uint8_t hashAlgorithm[11] = { |
|
938 0x30, 0x09, // SEQUENCE |
|
939 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJECT IDENTIFIER id-sha1 |
|
940 0x05, 0x00, // NULL |
|
941 }; |
|
942 static const uint8_t hashLen = SHA1_LENGTH; |
|
943 |
|
944 static const unsigned int totalLenWithoutSerialNumberData |
|
945 = 2 // OCSPRequest |
|
946 + 2 // tbsRequest |
|
947 + 2 // requestList |
|
948 + 2 // Request |
|
949 + 2 // reqCert (CertID) |
|
950 + PR_ARRAY_SIZE(hashAlgorithm) // hashAlgorithm |
|
951 + 2 + hashLen // issuerNameHash |
|
952 + 2 + hashLen // issuerKeyHash |
|
953 + 2; // serialNumber (header) |
|
954 |
|
955 // The only way we could have a request this large is if the serialNumber was |
|
956 // ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST |
|
957 // NOT use serialNumber values longer than 20 octets." With this restriction, |
|
958 // we allow for some amount of non-conformance with that requirement while |
|
959 // still ensuring we can encode the length values in the ASN.1 TLV structures |
|
960 // in a single byte. |
|
961 if (issuerCert->serialNumber.len > 127u - totalLenWithoutSerialNumberData) { |
|
962 PR_SetError(SEC_ERROR_BAD_DATA, 0); |
|
963 return nullptr; |
|
964 } |
|
965 |
|
966 uint8_t totalLen = static_cast<uint8_t>(totalLenWithoutSerialNumberData + |
|
967 cert->serialNumber.len); |
|
968 |
|
969 SECItem* encodedRequest = SECITEM_AllocItem(arena, nullptr, totalLen); |
|
970 if (!encodedRequest) { |
|
971 return nullptr; |
|
972 } |
|
973 |
|
974 uint8_t* d = encodedRequest->data; |
|
975 *d++ = 0x30; *d++ = totalLen - 2; // OCSPRequest (SEQUENCE) |
|
976 *d++ = 0x30; *d++ = totalLen - 4; // tbsRequest (SEQUENCE) |
|
977 *d++ = 0x30; *d++ = totalLen - 6; // requestList (SEQUENCE OF) |
|
978 *d++ = 0x30; *d++ = totalLen - 8; // Request (SEQUENCE) |
|
979 *d++ = 0x30; *d++ = totalLen - 10; // reqCert (CertID SEQUENCE) |
|
980 |
|
981 // reqCert.hashAlgorithm |
|
982 for (size_t i = 0; i < PR_ARRAY_SIZE(hashAlgorithm); ++i) { |
|
983 *d++ = hashAlgorithm[i]; |
|
984 } |
|
985 |
|
986 // reqCert.issuerNameHash (OCTET STRING) |
|
987 *d++ = 0x04; |
|
988 *d++ = hashLen; |
|
989 if (PK11_HashBuf(SEC_OID_SHA1, d, issuerCert->derSubject.data, |
|
990 issuerCert->derSubject.len) != SECSuccess) { |
|
991 return nullptr; |
|
992 } |
|
993 d += hashLen; |
|
994 |
|
995 // reqCert.issuerKeyHash (OCTET STRING) |
|
996 *d++ = 0x04; |
|
997 *d++ = hashLen; |
|
998 SECItem key = issuerCert->subjectPublicKeyInfo.subjectPublicKey; |
|
999 DER_ConvertBitString(&key); |
|
1000 if (PK11_HashBuf(SEC_OID_SHA1, d, key.data, key.len) != SECSuccess) { |
|
1001 return nullptr; |
|
1002 } |
|
1003 d += hashLen; |
|
1004 |
|
1005 // reqCert.serialNumber (INTEGER) |
|
1006 *d++ = 0x02; // INTEGER |
|
1007 *d++ = static_cast<uint8_t>(cert->serialNumber.len); |
|
1008 for (size_t i = 0; i < cert->serialNumber.len; ++i) { |
|
1009 *d++ = cert->serialNumber.data[i]; |
|
1010 } |
|
1011 |
|
1012 PR_ASSERT(d == encodedRequest->data + totalLen); |
|
1013 |
|
1014 return encodedRequest; |
|
1015 } |
|
1016 |
|
1017 } } // namespace mozilla::pkix |