]> git.saurik.com Git - apple/security.git/blob - trust/trustd/SecRevocationServer.c
Security-59306.61.1.tar.gz
[apple/security.git] / trust / trustd / SecRevocationServer.c
1 /*
2 * Copyright (c) 2008-2019 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecRevocationServer.c - Engine for evaluating certificate revocation.
26 */
27
28 #include <AssertMacros.h>
29
30 #include <mach/mach_time.h>
31
32 #include <Security/SecCertificatePriv.h>
33 #include <Security/SecCertificateInternal.h>
34 #include <Security/SecPolicyPriv.h>
35 #include <Security/SecTrustPriv.h>
36 #include <Security/SecInternal.h>
37
38 #include <utilities/debugging.h>
39 #include <utilities/SecCFWrappers.h>
40 #include <utilities/SecIOFormat.h>
41
42 #include "trust/trustd/SecTrustServer.h"
43 #include "trust/trustd/SecOCSPRequest.h"
44 #include "trust/trustd/SecOCSPResponse.h"
45 #include "trust/trustd/SecOCSPCache.h"
46 #include "trust/trustd/SecRevocationDb.h"
47 #include "trust/trustd/SecCertificateServer.h"
48 #include "trust/trustd/SecPolicyServer.h"
49 #include "trust/trustd/SecRevocationNetworking.h"
50
51 #include "trust/trustd/SecRevocationServer.h"
52
53 // MARK: SecORVCRef
54 /********************************************************
55 ****************** OCSP RVC Functions ******************
56 ********************************************************/
57 const CFAbsoluteTime kSecDefaultOCSPResponseTTL = 24.0 * 60.0 * 60.0;
58 const CFAbsoluteTime kSecOCSPResponseOnlineTTL = 5.0 * 60.0;
59 #define OCSP_RESPONSE_TIMEOUT (3 * NSEC_PER_SEC)
60
61 static void SecORVCFinish(SecORVCRef orvc) {
62 secdebug("alloc", "finish orvc %p", orvc);
63 if (orvc->ocspRequest) {
64 SecOCSPRequestFinalize(orvc->ocspRequest);
65 orvc->ocspRequest = NULL;
66 }
67 if (orvc->ocspResponse) {
68 SecOCSPResponseFinalize(orvc->ocspResponse);
69 orvc->ocspResponse = NULL;
70 if (orvc->ocspSingleResponse) {
71 SecOCSPSingleResponseDestroy(orvc->ocspSingleResponse);
72 orvc->ocspSingleResponse = NULL;
73 }
74 }
75 memset(orvc, 0, sizeof(struct OpaqueSecORVC));
76 }
77
78 /* Process a verified ocsp response for a given cert. Return true if the
79 certificate status was obtained. */
80 static bool SecOCSPSingleResponseProcess(SecOCSPSingleResponseRef this,
81 SecORVCRef rvc) {
82 bool processed;
83 switch (this->certStatus) {
84 case CS_Good:
85 secdebug("ocsp", "CS_Good for cert %" PRIdCFIndex, rvc->certIX);
86 /* @@@ Mark cert as valid until a given date (nextUpdate if we have one)
87 in the info dictionary. */
88 //cert.revokeCheckGood(true);
89 rvc->nextUpdate = this->nextUpdate == NULL_TIME ? this->thisUpdate + kSecDefaultOCSPResponseTTL : this->nextUpdate;
90 processed = true;
91 break;
92 case CS_Revoked:
93 secdebug("ocsp", "CS_Revoked for cert %" PRIdCFIndex, rvc->certIX);
94 /* @@@ Mark cert as revoked (with reason) at revocation date in
95 the info dictionary, or perhaps we should use a different key per
96 reason? That way a client using exceptions can ignore some but
97 not all reasons. */
98 SInt32 reason = this->crlReason;
99 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
100 SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX,
101 cfreason, true);
102 SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
103 if (path) {
104 SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason);
105 }
106 CFRelease(cfreason);
107 processed = true;
108 break;
109 case CS_Unknown:
110 /* not an error, no per-cert status, nothing here */
111 secdebug("ocsp", "CS_Unknown for cert %" PRIdCFIndex, rvc->certIX);
112 processed = false;
113 break;
114 default:
115 secnotice("ocsp", "BAD certStatus (%d) for cert %" PRIdCFIndex,
116 (int)this->certStatus, rvc->certIX);
117 processed = false;
118 break;
119 }
120
121 return processed;
122 }
123
124 void SecORVCUpdatePVC(SecORVCRef rvc) {
125 if (rvc->ocspSingleResponse) {
126 SecOCSPSingleResponseProcess(rvc->ocspSingleResponse, rvc);
127 }
128 if (rvc->ocspResponse) {
129 rvc->nextUpdate = SecOCSPResponseGetExpirationTime(rvc->ocspResponse);
130 }
131 }
132
133 typedef void (^SecOCSPEvaluationCompleted)(SecTrustResultType tr);
134
135 static void
136 SecOCSPEvaluateCompleted(const void *userData,
137 CFArrayRef chain, CFArrayRef details, CFDictionaryRef info,
138 SecTrustResultType result) {
139 SecOCSPEvaluationCompleted evaluated = (SecOCSPEvaluationCompleted)userData;
140 evaluated(result);
141 Block_release(evaluated);
142
143 }
144
145 static bool SecOCSPResponseEvaluateSigner(SecORVCRef rvc, CFArrayRef signers, CFArrayRef issuers, CFAbsoluteTime verifyTime) {
146 __block bool evaluated = false;
147 bool trusted = false;
148 if (!signers || !issuers) {
149 return trusted;
150 }
151
152 /* Verify the signer chain against the OCSPSigner policy, using the issuer chain as anchors. */
153 const void *ocspSigner = SecPolicyCreateOCSPSigner();
154 CFArrayRef policies = CFArrayCreate(kCFAllocatorDefault,
155 &ocspSigner, 1, &kCFTypeArrayCallBacks);
156 CFRelease(ocspSigner);
157
158 SecOCSPEvaluationCompleted completed = Block_copy(^(SecTrustResultType result) {
159 if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
160 evaluated = true;
161 }
162 });
163
164 CFDataRef clientAuditToken = SecPathBuilderCopyClientAuditToken(rvc->builder);
165 SecPathBuilderRef oBuilder = SecPathBuilderCreate(NULL, clientAuditToken,
166 signers, issuers, true, false,
167 policies, NULL, NULL, NULL,
168 verifyTime, NULL, NULL,
169 SecOCSPEvaluateCompleted, completed);
170 /* disable network access to avoid recursion */
171 SecPathBuilderSetCanAccessNetwork(oBuilder, false);
172
173 /* Build the chain(s), evaluate them, call the completed block, free the block and builder */
174 SecPathBuilderStep(oBuilder);
175 CFReleaseNull(clientAuditToken);
176 CFReleaseNull(policies);
177
178 /* verify the public key of the issuer signed the OCSP signer */
179 if (evaluated) {
180 SecCertificateRef issuer = NULL, signer = NULL;
181 SecKeyRef issuerPubKey = NULL;
182
183 issuer = (SecCertificateRef)CFArrayGetValueAtIndex(issuers, 0);
184 signer = (SecCertificateRef)CFArrayGetValueAtIndex(signers, 0);
185
186 if (issuer) {
187 issuerPubKey = SecCertificateCopyKey(issuer);
188 }
189 if (signer && issuerPubKey && (errSecSuccess == SecCertificateIsSignedBy(signer, issuerPubKey))) {
190 trusted = true;
191 } else {
192 secnotice("ocsp", "ocsp signer cert not signed by issuer");
193 }
194 CFReleaseNull(issuerPubKey);
195 }
196
197 return trusted;
198 }
199
200 static bool SecOCSPResponseVerify(SecOCSPResponseRef ocspResponse, SecORVCRef rvc, CFAbsoluteTime verifyTime) {
201 bool trusted;
202 SecCertificatePathVCRef issuers = SecCertificatePathVCCopyFromParent(SecPathBuilderGetPath(rvc->builder), rvc->certIX + 1);
203 SecCertificateRef issuer = issuers ? CFRetainSafe(SecCertificatePathVCGetCertificateAtIndex(issuers, 0)) : NULL;
204 CFArrayRef signers = SecOCSPResponseCopySigners(ocspResponse);
205 SecCertificateRef signer = SecOCSPResponseCopySigner(ocspResponse, issuer);
206
207 if (signer && signers) {
208 if (issuer && CFEqual(signer, issuer)) {
209 /* We already know we trust issuer since it's the issuer of the
210 * cert we are verifying. */
211 secinfo("ocsp", "ocsp responder: %@ response signed by issuer",
212 rvc->responder);
213 trusted = true;
214 } else {
215 secinfo("ocsp", "ocsp responder: %@ response signed by cert issued by issuer",
216 rvc->responder);
217 CFMutableArrayRef signerCerts = NULL;
218 CFArrayRef issuerCerts = NULL;
219
220 /* Ensure the signer cert is the 0th cert for trust evaluation */
221 signerCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
222 CFArrayAppendValue(signerCerts, signer);
223 CFArrayAppendArray(signerCerts, signers, CFRangeMake(0, CFArrayGetCount(signers)));
224
225 if (issuers) {
226 issuerCerts = SecCertificatePathVCCopyCertificates(issuers);
227 }
228
229 if (SecOCSPResponseEvaluateSigner(rvc, signerCerts, issuerCerts, verifyTime)) {
230 secdebug("ocsp", "response satisfies ocspSigner policy (%@)",
231 rvc->responder);
232 trusted = true;
233 } else {
234 /* @@@ We don't trust the cert so don't use this response. */
235 secnotice("ocsp", "ocsp response signed by certificate which "
236 "does not satisfy ocspSigner policy");
237 trusted = false;
238 }
239 CFReleaseNull(signerCerts);
240 CFReleaseNull(issuerCerts);
241 }
242 } else {
243 /* @@@ No signer found for this ocsp response, discard it. */
244 secnotice("ocsp", "ocsp responder: %@ no signer found for response",
245 rvc->responder);
246 trusted = false;
247 }
248
249 #if DUMP_OCSPRESPONSES
250 char buf[40];
251 snprintf(buf, 40, "/tmp/ocspresponse%ld%s.der",
252 rvc->certIX, (trusted ? "t" : "u"));
253 secdumpdata(ocspResponse->data, buf);
254 #endif
255 CFReleaseNull(issuers);
256 CFReleaseNull(issuer);
257 CFReleaseNull(signers);
258 CFReleaseNull(signer);
259 return trusted;
260 }
261
262 void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse /*CF_CONSUMED*/,
263 CFTimeInterval maxAge, bool updateCache, bool fromCache) {
264 SecOCSPSingleResponseRef sr = NULL;
265 require_quiet(ocspResponse, errOut);
266 SecOCSPResponseStatus orStatus = SecOCSPGetResponseStatus(ocspResponse);
267 require_action_quiet(orStatus == kSecOCSPSuccess, errOut,
268 secnotice("ocsp", "responder: %@ returned status: %d", rvc->responder, orStatus));
269 require_action_quiet(sr = SecOCSPResponseCopySingleResponse(ocspResponse, rvc->ocspRequest), errOut,
270 secnotice("ocsp", "ocsp responder: %@ did not include status of requested cert", rvc->responder));
271 // Check if this response is fresher than any (cached) response we might still have in the rvc.
272 require_quiet(!rvc->ocspSingleResponse || rvc->ocspSingleResponse->thisUpdate < sr->thisUpdate, errOut);
273
274 CFAbsoluteTime verifyTime = CFAbsoluteTimeGetCurrent();
275 #if TARGET_OS_IPHONE
276 /* Check the OCSP response signature and verify the response if not pulled from the cache.
277 * Performance optimization since we don't write invalid responses to the cache. */
278 if (!fromCache) {
279 require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
280 sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
281 }
282 #else
283 /* Always check the OCSP response signature and verify the response (since the cache is user-modifiable). */
284 require_quiet(SecOCSPResponseVerify(ocspResponse, rvc,
285 sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
286 #endif
287
288 // If we get here, we have a properly signed ocsp response
289 // but we haven't checked dates yet.
290
291 bool sr_valid = SecOCSPSingleResponseCalculateValidity(sr, kSecDefaultOCSPResponseTTL, verifyTime);
292 if (sr->certStatus == CS_Good) {
293 // Side effect of SecOCSPResponseCalculateValidity sets ocspResponse->expireTime
294 require_quiet(sr_valid && SecOCSPResponseCalculateValidity(ocspResponse, maxAge, kSecDefaultOCSPResponseTTL, verifyTime), errOut);
295 } else if (sr->certStatus == CS_Revoked) {
296 // Expire revoked responses when the subject certificate itself expires.
297 ocspResponse->expireTime = SecCertificateNotValidAfter(SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX));
298 }
299
300 // Ok we like the new response, let's toss the old one.
301 if (updateCache)
302 SecOCSPCacheReplaceResponse(rvc->ocspResponse, ocspResponse, rvc->responder, verifyTime);
303
304 if (rvc->ocspResponse) SecOCSPResponseFinalize(rvc->ocspResponse);
305 rvc->ocspResponse = ocspResponse;
306 ocspResponse = NULL;
307
308 if (rvc->ocspSingleResponse) SecOCSPSingleResponseDestroy(rvc->ocspSingleResponse);
309 rvc->ocspSingleResponse = sr;
310 sr = NULL;
311
312 rvc->done = sr_valid;
313
314 errOut:
315 if (sr) SecOCSPSingleResponseDestroy(sr);
316 if (ocspResponse) SecOCSPResponseFinalize(ocspResponse);
317 }
318
319 static SecORVCRef SecORVCCreate(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) {
320 SecORVCRef orvc = NULL;
321 orvc = malloc(sizeof(struct OpaqueSecORVC));
322 secdebug("alloc", "orvc %p", orvc);
323 if (orvc) {
324 memset(orvc, 0, sizeof(struct OpaqueSecORVC));
325 orvc->builder = builder;
326 orvc->rvc = rvc;
327 orvc->certIX = certIX;
328
329 SecCertificateRef cert = SecPathBuilderGetCertificateAtIndex(builder, certIX);
330 if (SecPathBuilderGetCertificateCount(builder) > (certIX + 1)) {
331 SecCertificateRef issuer = SecPathBuilderGetCertificateAtIndex(builder, certIX + 1);
332 orvc->ocspRequest = SecOCSPRequestCreate(cert, issuer);
333 }
334 }
335 return orvc;
336 }
337
338 static void SecORVCProcessStapledResponses(SecORVCRef rvc) {
339 /* Get stapled OCSP responses */
340 CFArrayRef ocspResponsesData = SecPathBuilderCopyOCSPResponses(rvc->builder);
341
342 if(ocspResponsesData) {
343 secdebug("rvc", "Checking stapled responses for cert %ld", rvc->certIX);
344 CFArrayForEach(ocspResponsesData, ^(const void *value) {
345 SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value);
346 SecORVCConsumeOCSPResponse(rvc, ocspResponse, NULL_TIME, false, false);
347 });
348 CFRelease(ocspResponsesData);
349 }
350 }
351
352 void SecRVCDelete(SecRVCRef rvc) {
353 secdebug("alloc", "delete rvc %p", rvc);
354 if (rvc->orvc) {
355 SecORVCFinish(rvc->orvc);
356 free(rvc->orvc);
357 rvc->orvc = NULL;
358 }
359 if (rvc->valid_info) {
360 CFReleaseNull(rvc->valid_info);
361 }
362 }
363
364 // Forward declaration
365 static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc);
366
367 static void SecRVCInit(SecRVCRef rvc, SecPathBuilderRef builder, CFIndex certIX) {
368 secdebug("alloc", "rvc %p", rvc);
369 rvc->builder = builder;
370 rvc->certIX = certIX;
371 rvc->orvc = SecORVCCreate(rvc, builder, certIX);
372 if (!rvc->orvc) {
373 SecRVCDelete(rvc);
374 SecRVCSetFinishedWithoutNetwork(rvc);
375 } else {
376 rvc->done = false;
377 }
378 }
379
380 static bool SecRVCShouldCheckOCSP(SecRVCRef rvc) {
381 return true;
382 }
383
384 static bool SecRVCPolicyConstraintsPermitPolicy(SecValidPolicy *constraints, CFIndex count, SecPolicyRef policy) {
385 if (!constraints || !policy) {
386 return true; /* nothing to constrain */
387 }
388 SecValidPolicy policyType = kSecValidPolicyAny;
389 CFStringRef policyName = SecPolicyGetName(policy);
390 /* determine if the policy is a candidate for being constrained */
391 if (CFEqualSafe(policyName, kSecPolicyNameSSLServer) ||
392 CFEqualSafe(policyName, kSecPolicyNameEAPServer) ||
393 CFEqualSafe(policyName, kSecPolicyNameIPSecServer)) {
394 policyType = kSecValidPolicyServerAuthentication;
395 } else if (CFEqualSafe(policyName, kSecPolicyNameSSLClient) ||
396 CFEqualSafe(policyName, kSecPolicyNameEAPClient) ||
397 CFEqualSafe(policyName, kSecPolicyNameIPSecClient)) {
398 policyType = kSecValidPolicyClientAuthentication;
399 } else if (CFEqualSafe(policyName, kSecPolicyNameSMIME)) {
400 policyType = kSecValidPolicyEmailProtection;
401 } else if (CFEqualSafe(policyName, kSecPolicyNameCodeSigning)) {
402 policyType = kSecValidPolicyCodeSigning;
403 } else if (CFEqualSafe(policyName, kSecPolicyNameTimeStamping)) {
404 policyType = kSecValidPolicyTimeStamping;
405 }
406 if (policyType == kSecValidPolicyAny) {
407 return true; /* policy not subject to constraint */
408 }
409 /* policy is subject to constraint; do the constraints allow it? */
410 bool result = false;
411 for (CFIndex ix = 0; ix < count; ix++) {
412 SecValidPolicy allowedPolicy = constraints[ix];
413 if (allowedPolicy == kSecValidPolicyAny ||
414 allowedPolicy == policyType) {
415 result = true;
416 break;
417 }
418 }
419 if (!result) {
420 secnotice("rvc", "%@ not allowed by policy constraints on issuing CA", policyName);
421 }
422 return result;
423 }
424
425 static bool SecRVCGetPolicyConstraints(CFDataRef data, SecValidPolicy **constraints, CFIndex *count) {
426 /* Sanity-check the input policy constraints data, returning pointer and
427 * count values in output arguments. Function result is true if successful.
428 *
429 * The first byte of the policy constraints data contains the number of entries,
430 * followed by an array of 0..n policy constraint values of type SecValidPolicy.
431 * The maximum number of defined policies is not expected to approach 127, i.e.
432 * the largest value which can be expressed in a signed byte.
433 */
434 bool result = false;
435 CFIndex length = 0;
436 SecValidPolicy *p = NULL;
437 if (data) {
438 length = CFDataGetLength(data);
439 p = (SecValidPolicy *)CFDataGetBytePtr(data);
440 }
441 /* Verify that count is 0 or greater, and equal to remaining number of bytes */
442 CFIndex c = (length > 0) ? *p++ : -1;
443 if (c < 0 || c != (length - 1)) {
444 secerror("invalid policy constraints array");
445 } else {
446 if (constraints) {
447 *constraints = p;
448 }
449 if (count) {
450 *count = c;
451 }
452 result = true;
453 }
454 return result;
455 }
456
457 static void SecRVCProcessValidPolicyConstraints(SecRVCRef rvc) {
458 if (!rvc || !rvc->valid_info || !rvc->builder) {
459 return;
460 }
461 if (!rvc->valid_info->hasPolicyConstraints) {
462 return;
463 }
464 CFIndex count = 0;
465 SecValidPolicy *constraints = NULL;
466 if (!SecRVCGetPolicyConstraints(rvc->valid_info->policyConstraints, &constraints, &count)) {
467 return;
468 }
469 secdebug("rvc", "found policy constraints for cert at index %ld", rvc->certIX);
470
471 /* check that policies being verified are permitted by the policy constraints */
472 bool policyDeniedByConstraints = false;
473 CFIndex ix, initialPVCCount = SecPathBuilderGetPVCCount(rvc->builder);
474 for (ix = 0; ix < initialPVCCount; ix++) {
475 SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, ix);
476 CFArrayRef policies = CFRetainSafe(pvc->policies);
477 CFIndex policyCount = (policies) ? CFArrayGetCount(policies) : 0;
478 for (CFIndex policyIX = 0; policyIX < policyCount; policyIX++) {
479 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(policies, policyIX);
480 if (!SecRVCPolicyConstraintsPermitPolicy(constraints, count, policy)) {
481 policyDeniedByConstraints = true;
482 SecPVCSetResultForced(pvc, kSecPolicyCheckIssuerPolicyConstraints, rvc->certIX,
483 kCFBooleanFalse, true);
484 pvc->result = kSecTrustResultRecoverableTrustFailure;
485 if (!rvc->valid_info->overridable) {
486 /* error for this check should be non-recoverable */
487 pvc->result = kSecTrustResultFatalTrustFailure;
488 }
489 }
490 }
491 CFReleaseSafe(policies);
492 }
493 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
494 if (analytics) {
495 TAValidStatus status = (policyDeniedByConstraints) ? TAValidPolicyConstrainedDenied : TAValidPolicyConstrainedOK;
496 analytics->valid_status |= status;
497 }
498 }
499
500 static void SecRVCProcessValidDateConstraints(SecRVCRef rvc) {
501 if (!rvc || !rvc->valid_info || !rvc->builder) {
502 return;
503 }
504 if (!rvc->valid_info->hasDateConstraints) {
505 return;
506 }
507 SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX);
508 if (!certificate) {
509 return;
510 }
511 CFAbsoluteTime certIssued = SecCertificateNotValidBefore(certificate);
512 CFAbsoluteTime caNotBefore = -3155760000.0; /* default: 1901-01-01 00:00:00-0000 */
513 CFAbsoluteTime caNotAfter = 31556908800.0; /* default: 3001-01-01 00:00:00-0000 */
514 if (rvc->valid_info->notBeforeDate) {
515 caNotBefore = CFDateGetAbsoluteTime(rvc->valid_info->notBeforeDate);
516 }
517 if (rvc->valid_info->notAfterDate) {
518 caNotAfter = CFDateGetAbsoluteTime(rvc->valid_info->notAfterDate);
519 /* per the Valid specification, if this date is in the past, we need to check CT. */
520 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
521 if (caNotAfter < now) {
522 rvc->valid_info->requireCT = true;
523 }
524 }
525 if ((certIssued < caNotBefore) && (rvc->certIX > 0)) {
526 /* not-before constraint is only applied to leaf certificate, for now. */
527 return;
528 }
529
530 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
531 if ((certIssued < caNotBefore) || (certIssued > caNotAfter)) {
532 /* We are outside the constrained validity period. */
533 secnotice("rvc", "certificate issuance date not within the allowed range for this CA%s",
534 (rvc->valid_info->overridable) ? "" : " (non-recoverable error)");
535 if (analytics) {
536 analytics->valid_status |= TAValidDateConstrainedRevoked;
537 }
538 if (rvc->valid_info->overridable) {
539 /* error is recoverable, treat certificate as untrusted
540 (note this date check is different from kSecPolicyCheckTemporalValidity) */
541 SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedKey, rvc->certIX,
542 kCFBooleanFalse, true);
543 } else {
544 /* error is non-overridable, treat certificate as revoked */
545 SInt32 reason = 0; /* unspecified reason code */
546 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
547 SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX,
548 cfreason, true);
549 SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
550 if (path) {
551 SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason);
552 }
553 CFReleaseNull(cfreason);
554 }
555 } else if (analytics) {
556 analytics->valid_status |= TAValidDateConstrainedOK;
557 }
558 }
559
560 bool SecRVCHasDefinitiveValidInfo(SecRVCRef rvc) {
561 if (!rvc || !rvc->valid_info) {
562 return false;
563 }
564 SecValidInfoRef info = rvc->valid_info;
565 /* outcomes as defined in Valid server specification */
566 if (info->format == kSecValidInfoFormatSerial ||
567 info->format == kSecValidInfoFormatSHA256) {
568 if (info->noCACheck || info->complete || info->isOnList) {
569 return true;
570 }
571 } else { /* info->format == kSecValidInfoFormatNto1 */
572 if (info->noCACheck || (info->complete && !info->isOnList)) {
573 return true;
574 }
575 }
576 return false;
577 }
578
579 bool SecRVCHasRevokedValidInfo(SecRVCRef rvc) {
580 if (!rvc || !rvc->valid_info) {
581 return false;
582 }
583 SecValidInfoRef info = rvc->valid_info;
584 /* either not present on an allowlist, or present on a blocklist */
585 return (!info->isOnList && info->valid) || (info->isOnList && !info->valid);
586 }
587
588 void SecRVCSetValidDeterminedErrorResult(SecRVCRef rvc) {
589 if (!rvc || !rvc->valid_info || !rvc->builder) {
590 return;
591 }
592 if (rvc->valid_info->overridable) {
593 /* error is recoverable, treat certificate as untrusted */
594 SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckGrayListedLeaf, rvc->certIX,
595 kCFBooleanFalse, true);
596 return;
597 }
598 /* error is fatal at this point */
599 if (!SecRVCHasRevokedValidInfo(rvc) || rvc->valid_info->noCACheck) {
600 /* result key should indicate blocked instead of revoked,
601 * but result must be non-recoverable */
602 SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckBlackListedLeaf, rvc->certIX,
603 kCFBooleanFalse, true);
604 return;
605 }
606 SInt32 reason = 0; /* unspecified, since the Valid db doesn't tell us */
607 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
608 SecPathBuilderSetResultInPVCs(rvc->builder, kSecPolicyCheckRevocation, rvc->certIX,
609 cfreason, true);
610 SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
611 if (path) {
612 SecCertificatePathVCSetRevocationReasonForCertificateAtIndex(path, rvc->certIX, cfreason);
613 }
614 CFReleaseNull(cfreason);
615 }
616
617 static void SecRVCProcessValidInfoResults(SecRVCRef rvc) {
618 if (!rvc || !rvc->valid_info || !rvc->builder) {
619 return;
620 }
621 SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
622 SecValidInfoRef info = rvc->valid_info;
623
624 bool definitive = SecRVCHasDefinitiveValidInfo(rvc);
625 bool revoked = SecRVCHasRevokedValidInfo(rvc);
626
627 /* set analytics */
628 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
629 if (analytics) {
630 if (revoked) {
631 analytics->valid_status |= definitive ? TAValidDefinitelyRevoked : TAValidProbablyRevoked;
632 } else {
633 analytics->valid_status |= definitive ? TAValidDefinitelyOK : TAValidProbablyOK;
634 }
635 analytics->valid_require_ct |= info->requireCT;
636 analytics->valid_known_intermediates_only |= info->knownOnly;
637 }
638
639 /* Handle no-ca cases */
640 if (info->noCACheck) {
641 bool allowed = (info->valid && info->complete && info->isOnList);
642 if (revoked) {
643 /* definitely revoked */
644 SecRVCSetValidDeterminedErrorResult(rvc);
645 } else if (allowed) {
646 /* definitely not revoked (allowlisted) */
647 SecCertificatePathVCSetIsAllowlisted(path, true);
648 }
649 /* no-ca is definitive; no need to check further. */
650 secdebug("validupdate", "rvc: definitely %s cert %" PRIdCFIndex,
651 (allowed) ? "allowed" : "revoked", rvc->certIX);
652 rvc->done = true;
653 return;
654 }
655
656 /* Handle policy constraints, if present. */
657 SecRVCProcessValidPolicyConstraints(rvc);
658
659 /* Handle date constraints, if present.
660 * Note: a not-after date may set the CT requirement,
661 * so check requireCT after this function is called. */
662 SecRVCProcessValidDateConstraints(rvc);
663
664 /* Set CT requirement on path, if present. */
665 if (info->requireCT) {
666 SecPathCTPolicy ctp = kSecPathCTRequired;
667 if (info->overridable) {
668 ctp = kSecPathCTRequiredOverridable;
669 }
670 SecCertificatePathVCSetRequiresCT(path, ctp);
671 }
672
673 /* Trigger OCSP for any non-definitive or revoked cases */
674 if (!definitive || revoked) {
675 info->checkOCSP = true;
676 }
677
678 if (info->checkOCSP) {
679 CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder);
680 CFIndex issuerIX = rvc->certIX + 1;
681 if (issuerIX >= count) {
682 /* cannot perform a revocation check on the last cert in the
683 chain, since we don't have its issuer. */
684 return;
685 }
686 secdebug("validupdate", "rvc: %s%s cert %" PRIdCFIndex " (will check OCSP)",
687 (info->complete) ? "" : "possibly ", (info->valid) ? "allowed" : "revoked",
688 rvc->certIX);
689 SecPathBuilderSetRevocationMethod(rvc->builder, kSecPolicyCheckRevocationAny);
690 if (analytics) {
691 /* Valid DB results caused us to do OCSP */
692 analytics->valid_trigger_ocsp = true;
693 }
694 }
695 }
696
697 static bool SecRVCCheckValidInfoDatabase(SecRVCRef rvc) {
698 /* Skip checking for OCSP Signer verification */
699 if (SecPathBuilderGetPVCCount(rvc->builder) == 1) {
700 SecPVCRef pvc = SecPathBuilderGetPVCAtIndex(rvc->builder, 0);
701 if (!pvc) { return false; }
702 SecPolicyRef policy = (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, 0);
703 CFStringRef policyName = (policy) ? SecPolicyGetName(policy) : NULL;
704 if (policyName && CFEqual(policyName, CFSTR("OCSPSigner"))) {
705 return false;
706 }
707 }
708
709 /* Make sure revocation db info is up-to-date.
710 * We don't care if the builder is allowed to access the network because
711 * the network fetching does not block the trust evaluation. */
712 SecRevocationDbCheckNextUpdate();
713
714 /* Check whether we have valid db info for this cert,
715 given the cert and its issuer */
716 SecValidInfoRef info = NULL;
717 CFIndex count = SecPathBuilderGetCertificateCount(rvc->builder);
718 if (count) {
719 bool isSelfSigned = false;
720 SecCertificateRef cert = NULL;
721 SecCertificateRef issuer = NULL;
722 CFIndex issuerIX = rvc->certIX + 1;
723 if (count > issuerIX) {
724 issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, issuerIX);
725 } else if (count == issuerIX) {
726 CFIndex rootIX = SecCertificatePathVCSelfSignedIndex(SecPathBuilderGetPath(rvc->builder));
727 if (rootIX == rvc->certIX) {
728 issuer = SecPathBuilderGetCertificateAtIndex(rvc->builder, rootIX);
729 isSelfSigned = true;
730 }
731 }
732 cert = SecPathBuilderGetCertificateAtIndex(rvc->builder, rvc->certIX);
733 if (!isSelfSigned) {
734 /* skip revocation db check for self-signed certificates [33137065] */
735 info = SecRevocationDbCopyMatching(cert, issuer);
736 }
737 SecValidInfoSetAnchor(info, SecPathBuilderGetCertificateAtIndex(rvc->builder, count-1));
738 }
739 if (info) {
740 SecValidInfoRef old_info = rvc->valid_info;
741 rvc->valid_info = info;
742 if (old_info) {
743 CFReleaseNull(old_info);
744 }
745 return true;
746 }
747 return false;
748 }
749
750 static void SecRVCCheckRevocationCaches(SecRVCRef rvc) {
751 /* Don't check OCSP cache if CRLs enabled and policy requested CRL only */
752 if (SecRVCShouldCheckOCSP(rvc) && (rvc->orvc->ocspRequest)) {
753 secdebug("ocsp", "Checking cached responses for cert %ld", rvc->certIX);
754 SecOCSPResponseRef response = NULL;
755 if (SecPathBuilderGetCheckRevocationOnline(rvc->builder)) {
756 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
757 response = SecOCSPCacheCopyMatchingWithMinInsertTime(rvc->orvc->ocspRequest, NULL, now - kSecOCSPResponseOnlineTTL);
758 } else {
759 response = SecOCSPCacheCopyMatching(rvc->orvc->ocspRequest, NULL);
760 }
761 SecORVCConsumeOCSPResponse(rvc->orvc, response, NULL_TIME, false, true);
762 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
763 if (rvc->orvc->done && analytics) {
764 /* We found a valid OCSP response in the cache */
765 analytics->ocsp_cache_hit = true;
766 }
767 }
768 }
769
770 static void SecRVCUpdatePVC(SecRVCRef rvc) {
771 SecRVCProcessValidInfoResults(rvc); /* restore the results we got from Valid */
772 if (rvc->orvc) { SecORVCUpdatePVC(rvc->orvc); }
773 }
774
775 static void SecRVCSetFinishedWithoutNetwork(SecRVCRef rvc) {
776 rvc->done = true;
777 SecRVCUpdatePVC(rvc);
778 (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder);
779 }
780
781 static bool SecRVCFetchNext(SecRVCRef rvc) {
782 bool OCSP_fetch_finished = true;
783 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
784 /* Don't send OCSP request only if CRLs enabled and policy requested CRL only */
785 if (SecRVCShouldCheckOCSP(rvc)) {
786 SecCertificatePathVCRef path = SecPathBuilderGetPath(rvc->builder);
787 SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, rvc->certIX);
788 OCSP_fetch_finished = SecORVCBeginFetches(rvc->orvc, cert);
789 if (analytics && !OCSP_fetch_finished) {
790 /* We did a network OCSP fetch, set report appropriately */
791 analytics->ocsp_network = true;
792 }
793 }
794 if (OCSP_fetch_finished) {
795 /* we didn't start an OCSP background job for this cert */
796 (void)SecPathBuilderDecrementAsyncJobCount(rvc->builder);
797 }
798 return OCSP_fetch_finished;
799 }
800
801 /* The SecPathBuilder state machine calls SecPathBuilderCheckRevocation twice --
802 * once in the ValidatePath state, and again in the ComputeDetails state. In the
803 * ValidatePath state we've not yet run the path checks, so for callers who set
804 * kSecRevocationCheckIfTrusted, we don't do any networking on that first call.
805 * Here, if we've already done revocation before (so we're in ComputeDetails now),
806 * we need to recheck (and enable networking) for trusted chains and
807 * kSecRevocationCheckIfTrusted. Otherwise, we skip the checks to save on the processing
808 * but update the PVCs with the revocation results from the last check. */
809 static bool SecRevocationDidCheckRevocation(SecPathBuilderRef builder, bool *first_check_done) {
810 SecCertificatePathVCRef path = SecPathBuilderGetPath(builder);
811 if (!SecCertificatePathVCIsRevocationDone(path)) {
812 return false;
813 }
814 if (first_check_done) {
815 *first_check_done = true;
816 }
817
818 SecPVCRef resultPVC = SecPathBuilderGetResultPVC(builder);
819 bool recheck = false;
820 if (SecPathBuilderGetCheckRevocationIfTrusted(builder) && SecPVCIsOkResult(resultPVC)) {
821 recheck = true;
822 secdebug("rvc", "Rechecking revocation because network now allowed");
823 } else {
824 secdebug("rvc", "Not rechecking revocation");
825 }
826
827 if (recheck) {
828 // reset the RVCs for the second pass
829 SecCertificatePathVCDeleteRVCs(path);
830 } else {
831 CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder);
832 for (certIX = 0; certIX < certCount; ++certIX) {
833 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX);
834 if (rvc) {
835 SecRVCUpdatePVC(rvc);
836 }
837 }
838 }
839
840 return !recheck;
841 }
842
843 static bool SecRevocationCanAccessNetwork(SecPathBuilderRef builder, bool first_check_done) {
844 /* CheckRevocationIfTrusted overrides NoNetworkAccess for revocation */
845 if (SecPathBuilderGetCheckRevocationIfTrusted(builder)) {
846 if (first_check_done) {
847 /* We're on the second pass. We need to now allow networking for revocation.
848 * SecRevocationDidCheckRevocation takes care of not running a second pass
849 * if the chain isn't trusted. */
850 return true;
851 } else {
852 /* We're on the first pass of the revocation checks, where we aren't
853 * supposed to do networking because we don't know if the chain
854 * is trusted yet. */
855 return false;
856 }
857 }
858 return SecPathBuilderCanAccessNetwork(builder);
859 }
860
861 void SecPathBuilderCheckKnownIntermediateConstraints(SecPathBuilderRef builder) {
862 SecCertificatePathVCRef path = SecPathBuilderGetPath(builder);
863 if (!path) {
864 return;
865 }
866 /* only perform this check once per path! */
867 CFIndex certIX = kCFNotFound;
868 if (SecCertificatePathVCCheckedIssuers(path)) {
869 certIX = SecCertificatePathVCUnknownCAIndex(path);
870 goto checkedIssuers;
871 }
872 /* check full path: start with anchor and decrement to leaf */
873 bool parentConstrained = false;
874 CFIndex certCount = SecPathBuilderGetCertificateCount(builder);
875 for (certIX = certCount - 1; certIX >= 0; --certIX) {
876 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX);
877 if (!rvc) {
878 continue;
879 }
880 if (parentConstrained && !rvc->valid_info) {
881 /* Parent had the known-only constraint, but our issuer is unknown.
882 Bump index to point back at the issuer since it fails the constraint. */
883 certIX++;
884 break;
885 }
886 parentConstrained = (rvc->valid_info && rvc->valid_info->knownOnly);
887 if (parentConstrained) {
888 secdebug("validupdate", "Valid db found a known-intermediate constraint on %@ (index=%ld)",
889 rvc->valid_info->issuerHash, certIX+1);
890 if (certIX == 0) {
891 /* check special case: unknown constrained CA in leaf position */
892 SecCertificateRef cert = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
893 if (cert && SecCertificateIsCA(cert) && !SecRevocationDbContainsIssuer(cert)) {
894 /* leaf is a CA which violates the constraint */
895 break;
896 }
897 }
898 }
899 }
900 /* At this point, certIX will either be -1, indicating no CA was found
901 which failed a known-intermediates-only constraint on its parent, or it
902 will be the index of the first unknown CA which fails the constraint. */
903 if (certIX >= 0) {
904 secnotice("validupdate", "CA at index %ld violates known-intermediate constraint", certIX);
905 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder);
906 if (analytics) {
907 analytics->valid_unknown_intermediate = true;
908 }
909 }
910 SecCertificatePathVCSetUnknownCAIndex(path, certIX);
911 SecCertificatePathVCSetCheckedIssuers(path, true);
912
913 checkedIssuers:
914 if (certIX >= 0) {
915 /* Error is set on CA certificate which failed the constraint. */
916 SecRVCSetValidDeterminedErrorResult(SecCertificatePathVCGetRVCAtIndex(path, certIX));
917 }
918 }
919
920 bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder) {
921 secdebug("rvc", "checking revocation");
922 CFIndex certIX, certCount = SecPathBuilderGetCertificateCount(builder);
923 SecCertificatePathVCRef path = SecPathBuilderGetPath(builder);
924 if (certCount <= 1) {
925 /* Can't verify without an issuer; we're done */
926 return true;
927 }
928
929 bool first_check_done = false;
930 if (SecRevocationDidCheckRevocation(builder, &first_check_done)) {
931 return true;
932 }
933
934 /* Setup things so we check revocation status of all certs. */
935 SecCertificatePathVCAllocateRVCs(path, certCount);
936
937 /* Note that if we are multi threaded and a job completes after it
938 is started but before we return from this function, we don't want
939 a callback to decrement asyncJobCount to zero before we finish issuing
940 all the jobs. To avoid this we pretend we issued certCount async jobs,
941 and decrement pvc->asyncJobCount for each cert that we don't start a
942 background fetch for. We include the root, even though we'll never start
943 an async job for it so that we count all active threads for this eval. */
944 SecPathBuilderSetAsyncJobCount(builder, (unsigned int)(certCount));
945
946 /* Loop though certificates again and issue an ocsp fetch if the
947 revocation status checking isn't done yet (and we have an issuer!) */
948 for (certIX = 0; certIX < certCount; ++certIX) {
949 secdebug("rvc", "checking revocation for cert: %ld", certIX);
950 SecRVCRef rvc = SecCertificatePathVCGetRVCAtIndex(path, certIX);
951 if (!rvc) {
952 continue;
953 }
954
955 SecRVCInit(rvc, builder, certIX);
956
957 /* RFC 6960: id-pkix-ocsp-nocheck extension says that we shouldn't check revocation. */
958 if (SecCertificateHasOCSPNoCheckMarkerExtension(SecCertificatePathVCGetCertificateAtIndex(path, certIX)))
959 {
960 secdebug("rvc", "skipping revocation checks for no-check cert: %ld", certIX);
961 TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(builder);
962 if (analytics) {
963 /* This certificate has OCSP No-Check, so add to reporting analytics */
964 analytics->ocsp_no_check = true;
965 }
966 SecRVCSetFinishedWithoutNetwork(rvc);
967 }
968
969 if (rvc->done) {
970 continue;
971 }
972
973 #if !TARGET_OS_BRIDGE
974 /* Check valid database first (separate from OCSP response cache) */
975 if (SecRVCCheckValidInfoDatabase(rvc)) {
976 SecRVCProcessValidInfoResults(rvc);
977 }
978 #endif
979 /* Any other revocation method requires an issuer certificate to verify the response;
980 * skip the last cert in the chain since it doesn't have one. */
981 if (certIX + 1 >= certCount) {
982 continue;
983 }
984
985 /* Ignore stapled OCSP responses only if CRLs are enabled and the
986 * policy specifically requested CRLs only. */
987 if (SecRVCShouldCheckOCSP(rvc)) {
988 /* If we have any OCSP stapled responses, check those first */
989 SecORVCProcessStapledResponses(rvc->orvc);
990 }
991
992 #if TARGET_OS_BRIDGE
993 /* The bridge has no writeable storage and no network. Nothing else we can
994 * do here. */
995 SecRVCSetFinishedWithoutNetwork(rvc);
996 continue;
997 #else // !TARGET_OS_BRIDGE
998 /* Then check the caches for revocation results. */
999 SecRVCCheckRevocationCaches(rvc);
1000
1001 /* The check is done if we found cached responses from either method. */
1002 if (rvc->done || rvc->orvc->done) {
1003 secdebug("rvc", "found cached response for cert: %ld", certIX);
1004 SecRVCSetFinishedWithoutNetwork(rvc);
1005 continue;
1006 }
1007
1008 /* If we got a cached response that is no longer valid (which can only be true for
1009 * revoked responses), let's try to get a fresher response even if no one asked.
1010 * This check resolves unrevocation events after the nextUpdate time. */
1011 bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse);
1012
1013 /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an
1014 async http request for this cert's revocation status, unless we already successfully checked
1015 the revocation status of this cert based on the cache or stapled responses. */
1016 bool allow_fetch = SecRevocationCanAccessNetwork(builder, first_check_done) &&
1017 (SecCertificatePathVCIsEV(path) || SecCertificatePathVCIsOptionallyEV(path) ||
1018 SecPathBuilderGetRevocationMethod(builder) || old_cached_response);
1019 if (rvc->done || !allow_fetch) {
1020 /* We got a cache hit or we aren't allowed to access the network */
1021 SecRVCUpdatePVC(rvc);
1022 /* We didn't really start any background jobs for this cert. */
1023 (void)SecPathBuilderDecrementAsyncJobCount(builder);
1024 } else {
1025 (void)SecRVCFetchNext(rvc);
1026 }
1027 #endif // !TARGET_OS_BRIDGE
1028 }
1029
1030 /* Return false if there are still async jobs running. */
1031 /* builder->asyncJobCount is atomic, so we know that if the job count is 0, all other
1032 * threads are finished. If the job count is > 0, other threads will decrement the job
1033 * count and SecPathBuilderStep to crank the state machine when the job count is 0. */
1034 return (SecPathBuilderDecrementAsyncJobCount(builder) == 0);
1035 }
1036
1037 CFAbsoluteTime SecRVCGetEarliestNextUpdate(SecRVCRef rvc) {
1038 CFAbsoluteTime enu = NULL_TIME;
1039 if (!rvc || !rvc->orvc) { return enu; }
1040 enu = rvc->orvc->nextUpdate;
1041 return enu;
1042 }