|
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/pkix.h" |
|
21 #include "pkixcheck.h" |
|
22 #include "pkixder.h" |
|
23 #include "pkixutil.h" |
|
24 #include "secder.h" |
|
25 |
|
26 namespace mozilla { namespace pkix { |
|
27 |
|
28 Result |
|
29 CheckTimes(const CERTCertificate* cert, PRTime time) |
|
30 { |
|
31 PR_ASSERT(cert); |
|
32 |
|
33 SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, time, false); |
|
34 if (validity != secCertTimeValid) { |
|
35 return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE); |
|
36 } |
|
37 |
|
38 return Success; |
|
39 } |
|
40 |
|
41 // 4.2.1.3. Key Usage (id-ce-keyUsage) |
|
42 |
|
43 // As explained in the comment in CheckKeyUsage, bit 0 is the most significant |
|
44 // bit and bit 7 is the least significant bit. |
|
45 inline uint8_t KeyUsageToBitMask(KeyUsage keyUsage) |
|
46 { |
|
47 PR_ASSERT(keyUsage != KeyUsage::noParticularKeyUsageRequired); |
|
48 return 0x80u >> static_cast<uint8_t>(keyUsage); |
|
49 } |
|
50 |
|
51 Result |
|
52 CheckKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedKeyUsage, |
|
53 KeyUsage requiredKeyUsageIfPresent) |
|
54 { |
|
55 if (!encodedKeyUsage) { |
|
56 // TODO(bug 970196): Reject certificates that are being used to verify |
|
57 // certificate signatures unless the certificate is a trust anchor, to |
|
58 // reduce the chances of an end-entity certificate being abused as a CA |
|
59 // certificate. |
|
60 // if (endEntityOrCA == EndEntityOrCA::MustBeCA && !isTrustAnchor) { |
|
61 // return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
62 // } |
|
63 // |
|
64 // TODO: Users may configure arbitrary certificates as trust anchors, not |
|
65 // just roots. We should only allow a certificate without a key usage to be |
|
66 // used as a CA when it is self-issued and self-signed. |
|
67 return Success; |
|
68 } |
|
69 |
|
70 der::Input input; |
|
71 if (input.Init(encodedKeyUsage->data, encodedKeyUsage->len) != der::Success) { |
|
72 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
73 } |
|
74 der::Input value; |
|
75 if (der::ExpectTagAndGetValue(input, der::BIT_STRING, value) != der::Success) { |
|
76 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
77 } |
|
78 |
|
79 uint8_t numberOfPaddingBits; |
|
80 if (value.Read(numberOfPaddingBits) != der::Success) { |
|
81 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
82 } |
|
83 if (numberOfPaddingBits > 7) { |
|
84 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
85 } |
|
86 |
|
87 uint8_t bits; |
|
88 if (value.Read(bits) != der::Success) { |
|
89 // Reject empty bit masks. |
|
90 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
91 } |
|
92 |
|
93 // The most significant bit is numbered 0 (digitalSignature) and the least |
|
94 // significant bit is numbered 7 (encipherOnly), and the padding is in the |
|
95 // least significant bits of the last byte. The numbering of bits in a byte |
|
96 // is backwards from how we usually interpret them. |
|
97 // |
|
98 // For example, let's say bits is encoded in one byte with of value 0xB0 and |
|
99 // numberOfPaddingBits == 4. Then, bits is 10110000 in binary: |
|
100 // |
|
101 // bit 0 bit 3 |
|
102 // | | |
|
103 // v v |
|
104 // 10110000 |
|
105 // ^^^^ |
|
106 // | |
|
107 // 4 padding bits |
|
108 // |
|
109 // Since bits is the last byte, we have to consider the padding by ensuring |
|
110 // that the least significant 4 bits are all zero, since DER rules require |
|
111 // all padding bits to be zero. Then we have to look at the bit N bits to the |
|
112 // right of the most significant bit, where N is a value from the KeyUsage |
|
113 // enumeration. |
|
114 // |
|
115 // Let's say we're interested in the keyCertSign (5) bit. We'd need to look |
|
116 // at bit 5, which is zero, so keyCertSign is not asserted. (Since we check |
|
117 // that the padding is all zeros, it is OK to read from the padding bits.) |
|
118 // |
|
119 // Let's say we're interested in the digitalSignature (0) bit. We'd need to |
|
120 // look at the bit 0 (the most significant bit), which is set, so that means |
|
121 // digitalSignature is asserted. Similarly, keyEncipherment (2) and |
|
122 // dataEncipherment (3) are asserted. |
|
123 // |
|
124 // Note that since the KeyUsage enumeration is limited to values 0-7, we |
|
125 // only ever need to examine the first byte test for |
|
126 // requiredKeyUsageIfPresent. |
|
127 |
|
128 if (requiredKeyUsageIfPresent != KeyUsage::noParticularKeyUsageRequired) { |
|
129 // Check that the required key usage bit is set. |
|
130 if ((bits & KeyUsageToBitMask(requiredKeyUsageIfPresent)) == 0) { |
|
131 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
132 } |
|
133 } |
|
134 |
|
135 if (endEntityOrCA != EndEntityOrCA::MustBeCA) { |
|
136 // RFC 5280 says "The keyCertSign bit is asserted when the subject public |
|
137 // key is used for verifying signatures on public key certificates. If the |
|
138 // keyCertSign bit is asserted, then the cA bit in the basic constraints |
|
139 // extension (Section 4.2.1.9) MUST also be asserted." |
|
140 if ((bits & KeyUsageToBitMask(KeyUsage::keyCertSign)) != 0) { |
|
141 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
142 } |
|
143 } |
|
144 |
|
145 // The padding applies to the last byte, so skip to the last byte. |
|
146 while (!value.AtEnd()) { |
|
147 if (value.Read(bits) != der::Success) { |
|
148 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
149 } |
|
150 } |
|
151 |
|
152 // All of the padding bits must be zero, according to DER rules. |
|
153 uint8_t paddingMask = static_cast<uint8_t>((1 << numberOfPaddingBits) - 1); |
|
154 if ((bits & paddingMask) != 0) { |
|
155 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
156 } |
|
157 |
|
158 return Success; |
|
159 } |
|
160 |
|
161 // RFC5820 4.2.1.4. Certificate Policies |
|
162 // |
|
163 // "The user-initial-policy-set contains the special value any-policy if the |
|
164 // user is not concerned about certificate policy." |
|
165 Result |
|
166 CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA, |
|
167 bool isTrustAnchor, SECOidTag requiredPolicy) |
|
168 { |
|
169 if (requiredPolicy == SEC_OID_X509_ANY_POLICY) { |
|
170 return Success; |
|
171 } |
|
172 |
|
173 // It is likely some callers will pass SEC_OID_UNKNOWN when they don't care, |
|
174 // instead of passing SEC_OID_X509_ANY_POLICY. Help them out by failing hard. |
|
175 if (requiredPolicy == SEC_OID_UNKNOWN) { |
|
176 PR_SetError(SEC_ERROR_INVALID_ARGS, 0); |
|
177 return FatalError; |
|
178 } |
|
179 |
|
180 // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when |
|
181 // inhibitAnyPolicy extension is present and we need to evaluate certificate |
|
182 // policies. |
|
183 if (cert.encodedInhibitAnyPolicy) { |
|
184 PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); |
|
185 return RecoverableError; |
|
186 } |
|
187 |
|
188 // The root CA certificate may omit the policies that it has been |
|
189 // trusted for, so we cannot require the policies to be present in those |
|
190 // certificates. Instead, the determination of which roots are trusted for |
|
191 // which policies is made by the TrustDomain's GetCertTrust method. |
|
192 if (isTrustAnchor && endEntityOrCA == MustBeCA) { |
|
193 return Success; |
|
194 } |
|
195 |
|
196 if (!cert.encodedCertificatePolicies) { |
|
197 PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); |
|
198 return RecoverableError; |
|
199 } |
|
200 |
|
201 ScopedPtr<CERTCertificatePolicies, CERT_DestroyCertificatePoliciesExtension> |
|
202 policies(CERT_DecodeCertificatePoliciesExtension( |
|
203 cert.encodedCertificatePolicies)); |
|
204 if (!policies) { |
|
205 return MapSECStatus(SECFailure); |
|
206 } |
|
207 |
|
208 for (const CERTPolicyInfo* const* policyInfos = policies->policyInfos; |
|
209 *policyInfos; ++policyInfos) { |
|
210 if ((*policyInfos)->oid == requiredPolicy) { |
|
211 return Success; |
|
212 } |
|
213 // Intermediate certs are allowed to have the anyPolicy OID |
|
214 if (endEntityOrCA == MustBeCA && |
|
215 (*policyInfos)->oid == SEC_OID_X509_ANY_POLICY) { |
|
216 return Success; |
|
217 } |
|
218 } |
|
219 |
|
220 PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); |
|
221 return RecoverableError; |
|
222 } |
|
223 |
|
224 // BasicConstraints ::= SEQUENCE { |
|
225 // cA BOOLEAN DEFAULT FALSE, |
|
226 // pathLenConstraint INTEGER (0..MAX) OPTIONAL } |
|
227 der::Result |
|
228 DecodeBasicConstraints(const SECItem* encodedBasicConstraints, |
|
229 CERTBasicConstraints& basicConstraints) |
|
230 { |
|
231 PR_ASSERT(encodedBasicConstraints); |
|
232 if (!encodedBasicConstraints) { |
|
233 return der::Fail(SEC_ERROR_INVALID_ARGS); |
|
234 } |
|
235 |
|
236 basicConstraints.isCA = false; |
|
237 basicConstraints.pathLenConstraint = 0; |
|
238 |
|
239 der::Input input; |
|
240 if (input.Init(encodedBasicConstraints->data, encodedBasicConstraints->len) |
|
241 != der::Success) { |
|
242 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
243 } |
|
244 |
|
245 if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) { |
|
246 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
247 } |
|
248 |
|
249 bool isCA = false; |
|
250 // TODO(bug 989518): cA is by default false. According to DER, default |
|
251 // values must not be explicitly encoded in a SEQUENCE. So, if this |
|
252 // value is present and false, it is an encoding error. However, Go Daddy |
|
253 // has issued many certificates with this improper encoding, so we can't |
|
254 // enforce this yet (hence passing true for allowInvalidExplicitEncoding |
|
255 // to der::OptionalBoolean). |
|
256 if (der::OptionalBoolean(input, true, isCA) != der::Success) { |
|
257 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
258 } |
|
259 basicConstraints.isCA = isCA; |
|
260 |
|
261 if (input.Peek(der::INTEGER)) { |
|
262 SECItem pathLenConstraintEncoded; |
|
263 if (der::Integer(input, pathLenConstraintEncoded) != der::Success) { |
|
264 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
265 } |
|
266 long pathLenConstraint = DER_GetInteger(&pathLenConstraintEncoded); |
|
267 if (pathLenConstraint >= std::numeric_limits<int>::max() || |
|
268 pathLenConstraint < 0) { |
|
269 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
270 } |
|
271 basicConstraints.pathLenConstraint = static_cast<int>(pathLenConstraint); |
|
272 // TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT |
|
273 // be included (as per RFC 5280 section 4.2.1.9), but for compatibility |
|
274 // reasons, we don't check this for now. |
|
275 } else if (basicConstraints.isCA) { |
|
276 // If this is a CA but the path length is omitted, it is unlimited. |
|
277 basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; |
|
278 } |
|
279 |
|
280 if (der::End(input) != der::Success) { |
|
281 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
282 } |
|
283 return der::Success; |
|
284 } |
|
285 |
|
286 // RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints) |
|
287 Result |
|
288 CheckBasicConstraints(const BackCert& cert, |
|
289 EndEntityOrCA endEntityOrCA, |
|
290 bool isTrustAnchor, |
|
291 unsigned int subCACount) |
|
292 { |
|
293 CERTBasicConstraints basicConstraints; |
|
294 if (cert.encodedBasicConstraints) { |
|
295 if (DecodeBasicConstraints(cert.encodedBasicConstraints, |
|
296 basicConstraints) != der::Success) { |
|
297 return RecoverableError; |
|
298 } |
|
299 } else { |
|
300 // Synthesize a non-CA basic constraints by default |
|
301 basicConstraints.isCA = false; |
|
302 basicConstraints.pathLenConstraint = 0; |
|
303 |
|
304 // "If the basic constraints extension is not present in a version 3 |
|
305 // certificate, or the extension is present but the cA boolean is not |
|
306 // asserted, then the certified public key MUST NOT be used to verify |
|
307 // certificate signatures." |
|
308 // |
|
309 // For compatibility, we must accept v1 trust anchors without basic |
|
310 // constraints as CAs. |
|
311 // |
|
312 // TODO: add check for self-signedness? |
|
313 if (endEntityOrCA == MustBeCA && isTrustAnchor) { |
|
314 const CERTCertificate* nssCert = cert.GetNSSCert(); |
|
315 // We only allow trust anchor CA certs to omit the |
|
316 // basicConstraints extension if they are v1. v1 is encoded |
|
317 // implicitly. |
|
318 if (!nssCert->version.data && !nssCert->version.len) { |
|
319 basicConstraints.isCA = true; |
|
320 basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; |
|
321 } |
|
322 } |
|
323 } |
|
324 |
|
325 if (endEntityOrCA == MustBeEndEntity) { |
|
326 // CA certificates are not trusted as EE certs. |
|
327 |
|
328 if (basicConstraints.isCA) { |
|
329 // XXX: We use SEC_ERROR_CA_CERT_INVALID here so we can distinguish |
|
330 // this error from other errors, given that NSS does not have a "CA cert |
|
331 // used as end-entity" error code since it doesn't have such a |
|
332 // prohibition. We should add such an error code and stop abusing |
|
333 // SEC_ERROR_CA_CERT_INVALID this way. |
|
334 // |
|
335 // Note, in particular, that this check prevents a delegated OCSP |
|
336 // response signing certificate with the CA bit from successfully |
|
337 // validating when we check it from pkixocsp.cpp, which is a good thing. |
|
338 // |
|
339 return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID); |
|
340 } |
|
341 |
|
342 return Success; |
|
343 } |
|
344 |
|
345 PORT_Assert(endEntityOrCA == MustBeCA); |
|
346 |
|
347 // End-entity certificates are not allowed to act as CA certs. |
|
348 if (!basicConstraints.isCA) { |
|
349 return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID); |
|
350 } |
|
351 |
|
352 if (basicConstraints.pathLenConstraint >= 0) { |
|
353 if (subCACount > |
|
354 static_cast<unsigned int>(basicConstraints.pathLenConstraint)) { |
|
355 return Fail(RecoverableError, SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); |
|
356 } |
|
357 } |
|
358 |
|
359 return Success; |
|
360 } |
|
361 |
|
362 Result |
|
363 BackCert::GetConstrainedNames(/*out*/ const CERTGeneralName** result) |
|
364 { |
|
365 if (!constrainedNames) { |
|
366 if (!GetArena()) { |
|
367 return FatalError; |
|
368 } |
|
369 |
|
370 constrainedNames = |
|
371 CERT_GetConstrainedCertificateNames(nssCert, arena.get(), |
|
372 cnOptions == IncludeCN); |
|
373 if (!constrainedNames) { |
|
374 return MapSECStatus(SECFailure); |
|
375 } |
|
376 } |
|
377 |
|
378 *result = constrainedNames; |
|
379 return Success; |
|
380 } |
|
381 |
|
382 // 4.2.1.10. Name Constraints |
|
383 Result |
|
384 CheckNameConstraints(BackCert& cert) |
|
385 { |
|
386 static const char constraintFranceGov[] = |
|
387 "\x30\x5D" /* sequence len 93*/ |
|
388 "\xA0\x5B" /* element len 91 */ |
|
389 "\x30\x05" /* sequence len 5 */ |
|
390 "\x82\x03" /* entry len 3 */ |
|
391 ".fr" |
|
392 "\x30\x05\x82\x03" /* sequence len 5, entry len 3 */ |
|
393 ".gp" |
|
394 "\x30\x05\x82\x03" |
|
395 ".gf" |
|
396 "\x30\x05\x82\x03" |
|
397 ".mq" |
|
398 "\x30\x05\x82\x03" |
|
399 ".re" |
|
400 "\x30\x05\x82\x03" |
|
401 ".yt" |
|
402 "\x30\x05\x82\x03" |
|
403 ".pm" |
|
404 "\x30\x05\x82\x03" |
|
405 ".bl" |
|
406 "\x30\x05\x82\x03" |
|
407 ".mf" |
|
408 "\x30\x05\x82\x03" |
|
409 ".wf" |
|
410 "\x30\x05\x82\x03" |
|
411 ".pf" |
|
412 "\x30\x05\x82\x03" |
|
413 ".nc" |
|
414 "\x30\x05\x82\x03" |
|
415 ".tf"; |
|
416 |
|
417 /* The stringified value for the subject is: |
|
418 E=igca@sgdn.pm.gouv.fr,CN=IGC/A,OU=DCSSI,O=PM/SGDN,L=Paris,ST=France,C=FR |
|
419 */ |
|
420 static const char rawANSSISubject[] = |
|
421 "\x30\x81\x85\x31\x0B\x30\x09\x06\x03\x55\x04" |
|
422 "\x06\x13\x02\x46\x52\x31\x0F\x30\x0D\x06\x03" |
|
423 "\x55\x04\x08\x13\x06\x46\x72\x61\x6E\x63\x65" |
|
424 "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05" |
|
425 "\x50\x61\x72\x69\x73\x31\x10\x30\x0E\x06\x03" |
|
426 "\x55\x04\x0A\x13\x07\x50\x4D\x2F\x53\x47\x44" |
|
427 "\x4E\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13" |
|
428 "\x05\x44\x43\x53\x53\x49\x31\x0E\x30\x0C\x06" |
|
429 "\x03\x55\x04\x03\x13\x05\x49\x47\x43\x2F\x41" |
|
430 "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7" |
|
431 "\x0D\x01\x09\x01\x16\x14\x69\x67\x63\x61\x40" |
|
432 "\x73\x67\x64\x6E\x2E\x70\x6D\x2E\x67\x6F\x75" |
|
433 "\x76\x2E\x66\x72"; |
|
434 |
|
435 const SECItem ANSSI_SUBJECT = { |
|
436 siBuffer, |
|
437 reinterpret_cast<uint8_t *>(const_cast<char *>(rawANSSISubject)), |
|
438 sizeof(rawANSSISubject) - 1 |
|
439 }; |
|
440 |
|
441 const SECItem PERMIT_FRANCE_GOV_NC = { |
|
442 siBuffer, |
|
443 reinterpret_cast<uint8_t *>(const_cast<char *>(constraintFranceGov)), |
|
444 sizeof(constraintFranceGov) - 1 |
|
445 }; |
|
446 |
|
447 const SECItem* nameConstraintsToUse = cert.encodedNameConstraints; |
|
448 |
|
449 if (!nameConstraintsToUse) { |
|
450 if (SECITEM_ItemsAreEqual(&cert.GetNSSCert()->derSubject, &ANSSI_SUBJECT)) { |
|
451 nameConstraintsToUse = &PERMIT_FRANCE_GOV_NC; |
|
452 } else { |
|
453 return Success; |
|
454 } |
|
455 } |
|
456 |
|
457 PLArenaPool* arena = cert.GetArena(); |
|
458 if (!arena) { |
|
459 return FatalError; |
|
460 } |
|
461 |
|
462 // Owned by arena |
|
463 const CERTNameConstraints* constraints = |
|
464 CERT_DecodeNameConstraintsExtension(arena, nameConstraintsToUse); |
|
465 if (!constraints) { |
|
466 return MapSECStatus(SECFailure); |
|
467 } |
|
468 |
|
469 for (BackCert* prev = cert.childCert; prev; prev = prev->childCert) { |
|
470 const CERTGeneralName* names = nullptr; |
|
471 Result rv = prev->GetConstrainedNames(&names); |
|
472 if (rv != Success) { |
|
473 return rv; |
|
474 } |
|
475 PORT_Assert(names); |
|
476 CERTGeneralName* currentName = const_cast<CERTGeneralName*>(names); |
|
477 do { |
|
478 if (CERT_CheckNameSpace(arena, constraints, currentName) != SECSuccess) { |
|
479 // XXX: It seems like CERT_CheckNameSpace doesn't always call |
|
480 // PR_SetError when it fails. We set the error code here, though this |
|
481 // may be papering over some fatal errors. NSS's |
|
482 // cert_VerifyCertChainOld does something similar. |
|
483 PR_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, 0); |
|
484 return RecoverableError; |
|
485 } |
|
486 currentName = CERT_GetNextGeneralName(currentName); |
|
487 } while (currentName != names); |
|
488 } |
|
489 |
|
490 return Success; |
|
491 } |
|
492 |
|
493 // 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) |
|
494 // 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) |
|
495 Result |
|
496 CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs, |
|
497 SECOidTag requiredEKU) |
|
498 { |
|
499 // TODO: Either do not allow anyExtendedKeyUsage to be passed as requiredEKU, |
|
500 // or require that callers pass anyExtendedKeyUsage instead of |
|
501 // SEC_OID_UNKNWON and disallow SEC_OID_UNKNWON. |
|
502 |
|
503 // XXX: We're using SEC_ERROR_INADEQUATE_CERT_TYPE here so that callers can |
|
504 // distinguish EKU mismatch from KU mismatch from basic constraints mismatch. |
|
505 // We should probably add a new error code that is more clear for this type |
|
506 // of problem. |
|
507 |
|
508 bool foundOCSPSigning = false; |
|
509 |
|
510 if (encodedEKUs) { |
|
511 ScopedPtr<CERTOidSequence, CERT_DestroyOidSequence> |
|
512 seq(CERT_DecodeOidSequence(encodedEKUs)); |
|
513 if (!seq) { |
|
514 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); |
|
515 return RecoverableError; |
|
516 } |
|
517 |
|
518 bool found = false; |
|
519 |
|
520 // XXX: We allow duplicate entries. |
|
521 for (const SECItem* const* oids = seq->oids; oids && *oids; ++oids) { |
|
522 SECOidTag oidTag = SECOID_FindOIDTag(*oids); |
|
523 if (requiredEKU != SEC_OID_UNKNOWN && oidTag == requiredEKU) { |
|
524 found = true; |
|
525 } else { |
|
526 // Treat CA certs with step-up OID as also having SSL server type. |
|
527 // COMODO has issued certificates that require this behavior |
|
528 // that don't expire until June 2020! |
|
529 // TODO 982932: Limit this expection to old certificates |
|
530 if (endEntityOrCA == MustBeCA && |
|
531 requiredEKU == SEC_OID_EXT_KEY_USAGE_SERVER_AUTH && |
|
532 oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) { |
|
533 found = true; |
|
534 } |
|
535 } |
|
536 if (oidTag == SEC_OID_OCSP_RESPONDER) { |
|
537 foundOCSPSigning = true; |
|
538 } |
|
539 } |
|
540 |
|
541 // If the EKU extension was included, then the required EKU must be in the |
|
542 // list. |
|
543 if (!found) { |
|
544 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); |
|
545 return RecoverableError; |
|
546 } |
|
547 } |
|
548 |
|
549 // pkixocsp.cpp depends on the following additional checks. |
|
550 |
|
551 if (endEntityOrCA == MustBeEndEntity) { |
|
552 // When validating anything other than an delegated OCSP signing cert, |
|
553 // reject any cert that also claims to be an OCSP responder, because such |
|
554 // a cert does not make sense. For example, if an SSL certificate were to |
|
555 // assert id-kp-OCSPSigning then it could sign OCSP responses for itself, |
|
556 // if not for this check. |
|
557 // That said, we accept CA certificates with id-kp-OCSPSigning because |
|
558 // some CAs in Mozilla's CA program have issued such intermediate |
|
559 // certificates, and because some CAs have reported some Microsoft server |
|
560 // software wrongly requires CA certificates to have id-kp-OCSPSigning. |
|
561 // Allowing this exception does not cause any security issues because we |
|
562 // require delegated OCSP response signing certificates to be end-entity |
|
563 // certificates. |
|
564 if (foundOCSPSigning && requiredEKU != SEC_OID_OCSP_RESPONDER) { |
|
565 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); |
|
566 return RecoverableError; |
|
567 } |
|
568 // http://tools.ietf.org/html/rfc6960#section-4.2.2.2: |
|
569 // "OCSP signing delegation SHALL be designated by the inclusion of |
|
570 // id-kp-OCSPSigning in an extended key usage certificate extension |
|
571 // included in the OCSP response signer's certificate." |
|
572 // |
|
573 // id-kp-OCSPSigning is the only EKU that isn't implicitly assumed when the |
|
574 // EKU extension is missing from an end-entity certificate. However, any CA |
|
575 // certificate can issue a delegated OCSP response signing certificate, so |
|
576 // we can't require the EKU be explicitly included for CA certificates. |
|
577 if (!foundOCSPSigning && requiredEKU == SEC_OID_OCSP_RESPONDER) { |
|
578 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); |
|
579 return RecoverableError; |
|
580 } |
|
581 } |
|
582 |
|
583 return Success; |
|
584 } |
|
585 |
|
586 Result |
|
587 CheckIssuerIndependentProperties(TrustDomain& trustDomain, |
|
588 BackCert& cert, |
|
589 PRTime time, |
|
590 EndEntityOrCA endEntityOrCA, |
|
591 KeyUsage requiredKeyUsageIfPresent, |
|
592 SECOidTag requiredEKUIfPresent, |
|
593 SECOidTag requiredPolicy, |
|
594 unsigned int subCACount, |
|
595 /*optional out*/ TrustDomain::TrustLevel* trustLevelOut) |
|
596 { |
|
597 Result rv; |
|
598 |
|
599 TrustDomain::TrustLevel trustLevel; |
|
600 rv = MapSECStatus(trustDomain.GetCertTrust(endEntityOrCA, |
|
601 requiredPolicy, |
|
602 cert.GetNSSCert(), |
|
603 &trustLevel)); |
|
604 if (rv != Success) { |
|
605 return rv; |
|
606 } |
|
607 if (trustLevel == TrustDomain::ActivelyDistrusted) { |
|
608 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); |
|
609 return RecoverableError; |
|
610 } |
|
611 if (trustLevel != TrustDomain::TrustAnchor && |
|
612 trustLevel != TrustDomain::InheritsTrust) { |
|
613 // The TrustDomain returned a trust level that we weren't expecting. |
|
614 PORT_SetError(PR_INVALID_STATE_ERROR); |
|
615 return FatalError; |
|
616 } |
|
617 if (trustLevelOut) { |
|
618 *trustLevelOut = trustLevel; |
|
619 } |
|
620 |
|
621 bool isTrustAnchor = endEntityOrCA == MustBeCA && |
|
622 trustLevel == TrustDomain::TrustAnchor; |
|
623 |
|
624 PLArenaPool* arena = cert.GetArena(); |
|
625 if (!arena) { |
|
626 return FatalError; |
|
627 } |
|
628 |
|
629 // 4.2.1.1. Authority Key Identifier is ignored (see bug 965136). |
|
630 |
|
631 // 4.2.1.2. Subject Key Identifier is ignored (see bug 965136). |
|
632 |
|
633 // 4.2.1.3. Key Usage |
|
634 rv = CheckKeyUsage(endEntityOrCA, cert.encodedKeyUsage, |
|
635 requiredKeyUsageIfPresent); |
|
636 if (rv != Success) { |
|
637 return rv; |
|
638 } |
|
639 |
|
640 // 4.2.1.4. Certificate Policies |
|
641 rv = CheckCertificatePolicies(cert, endEntityOrCA, isTrustAnchor, |
|
642 requiredPolicy); |
|
643 if (rv != Success) { |
|
644 return rv; |
|
645 } |
|
646 |
|
647 // 4.2.1.5. Policy Mappings are not supported; see the documentation about |
|
648 // policy enforcement in pkix.h. |
|
649 |
|
650 // 4.2.1.6. Subject Alternative Name dealt with during name constraint |
|
651 // checking and during name verification (CERT_VerifyCertName). |
|
652 |
|
653 // 4.2.1.7. Issuer Alternative Name is not something that needs checking. |
|
654 |
|
655 // 4.2.1.8. Subject Directory Attributes is not something that needs |
|
656 // checking. |
|
657 |
|
658 // 4.2.1.9. Basic Constraints. |
|
659 rv = CheckBasicConstraints(cert, endEntityOrCA, isTrustAnchor, subCACount); |
|
660 if (rv != Success) { |
|
661 return rv; |
|
662 } |
|
663 |
|
664 // 4.2.1.10. Name Constraints is dealt with in during path building. |
|
665 |
|
666 // 4.2.1.11. Policy Constraints are implicitly supported; see the |
|
667 // documentation about policy enforcement in pkix.h. |
|
668 |
|
669 // 4.2.1.12. Extended Key Usage |
|
670 rv = CheckExtendedKeyUsage(endEntityOrCA, cert.encodedExtendedKeyUsage, |
|
671 requiredEKUIfPresent); |
|
672 if (rv != Success) { |
|
673 return rv; |
|
674 } |
|
675 |
|
676 // 4.2.1.13. CRL Distribution Points is not supported, though the |
|
677 // TrustDomain's CheckRevocation method may parse it and process it |
|
678 // on its own. |
|
679 |
|
680 // 4.2.1.14. Inhibit anyPolicy is implicitly supported; see the documentation |
|
681 // about policy enforcement in pkix.h. |
|
682 |
|
683 // IMPORTANT: This check must come after the other checks in order for error |
|
684 // ranking to work correctly. |
|
685 rv = CheckTimes(cert.GetNSSCert(), time); |
|
686 if (rv != Success) { |
|
687 return rv; |
|
688 } |
|
689 |
|
690 return Success; |
|
691 } |
|
692 |
|
693 } } // namespace mozilla::pkix |