2 * Copyright (c) 2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecTrustOSXEntryPoints - Interface for unified SecTrust into OS X Security
29 #include "SecTrustOSXEntryPoints.h"
31 #include <Security/Security.h>
32 #include <Security/cssmtype.h>
33 #include <Security/SecKeychain.h>
34 #include <Security/SecItemPriv.h>
35 #include <Security/SecTrustSettingsPriv.h>
36 #include <Security/SecCertificate.h>
37 #include <Security/SecImportExport.h>
38 #include <security_keychain/SecImportExportPem.h>
39 #include <security_utilities/debugging.h>
40 #include <Security/SecItemInternal.h>
42 #include <security_ocspd/ocspdClient.h>
43 #include <security_ocspd/ocspdUtils.h>
45 #include <CoreFoundation/CoreFoundation.h>
46 #include <dispatch/dispatch.h>
47 #include <AssertMacros.h>
51 void SecTrustLegacySourcesListenForKeychainEvents(void) {
52 /* Register for CertificateTrustNotification */
54 notify_register_dispatch(kSecServerCertificateTrustNotification
, &out_token
,
55 dispatch_get_main_queue(),
56 ^(int token __unused
) {
57 // Purge keychain parent cache
58 SecItemParentCachePurge();
59 // Purge unrestricted roots cache
60 SecTrustSettingsPurgeUserAdminCertsCache();
66 * MARK: ocspd CRL Interface
68 /* lengths of time strings without trailing NULL */
69 #define CSSM_TIME_STRLEN 14 /* no trailing 'Z' */
70 #define GENERALIZED_TIME_STRLEN 15
72 OSStatus
SecTrustLegacyCRLStatus(SecCertificateRef cert
, CFArrayRef chain
, CFURLRef currCRLDP
);
73 OSStatus
SecTrustLegacyCRLFetch(CFURLRef currCRLDP
, CFAbsoluteTime verifyTime
);
75 static OSStatus
cssmReturnToOSStatus(CSSM_RETURN crtn
) {
76 OSStatus status
= errSecInternalComponent
;
80 status
= errSecSuccess
;
82 case CSSMERR_TP_CERT_REVOKED
:
83 status
= errSecCertificateRevoked
;
85 case CSSMERR_APPLETP_NETWORK_FAILURE
:
86 status
= errSecNetworkFailure
;
88 case CSSMERR_APPLETP_CRL_NOT_FOUND
:
89 status
= errSecCRLNotFound
;
92 status
= errSecInternalComponent
;
97 #define PEM_STRING_X509 "CERTIFICATE"
98 static CFDataRef CF_RETURNS_RETAINED
serializedPathToPemSequences(CFArrayRef certs
) {
99 CFMutableDataRef result
= NULL
;
100 CFIndex certIX
, certCount
;
101 require_quiet(certs
, out
);
102 certCount
= CFArrayGetCount(certs
);
103 require_quiet(certCount
> 0, out
);
104 require_quiet(result
= CFDataCreateMutable(NULL
, 0), out
);
105 for (certIX
= 0; certIX
< certCount
; certIX
++) {
106 CFDataRef certData
= (CFDataRef
)CFArrayGetValueAtIndex(certs
, certIX
);
107 require_noerr_quiet(impExpPemEncodeExportRep(certData
, PEM_STRING_X509
,
114 OSStatus
SecTrustLegacyCRLStatus(SecCertificateRef cert
, CFArrayRef chain
, CFURLRef currCRLDP
) {
115 OSStatus result
= errSecParam
;
116 CSSM_RETURN crtn
= CSSMERR_TP_INTERNAL_ERROR
;
117 CFDataRef serialData
= NULL
, pemIssuers
= NULL
, crlDP
= NULL
;
118 CFMutableArrayRef issuersArray
= NULL
;
120 if (!cert
|| !chain
) {
124 /* serialNumber is a CSSM_DATA with the value from the TBS Certificate. */
125 CSSM_DATA serialNumber
= { 0, NULL
};
126 serialData
= SecCertificateCopySerialNumber(cert
, NULL
);
128 serialNumber
.Data
= (uint8_t *)CFDataGetBytePtr(serialData
);
129 serialNumber
.Length
= CFDataGetLength(serialData
);
132 /* issuers is CSSM_DATA containing pem sequence of all issuers in the chain */
133 CSSM_DATA issuers
= { 0, NULL
};
134 issuersArray
= CFArrayCreateMutableCopy(NULL
, 0, chain
);
136 CFArrayRemoveValueAtIndex(issuersArray
, 0);
137 pemIssuers
= serializedPathToPemSequences(issuersArray
);
140 issuers
.Data
= (uint8_t *)CFDataGetBytePtr(pemIssuers
);
141 issuers
.Length
= CFDataGetLength(pemIssuers
);
144 /* crlUrl is CSSM_DATA with the CRLDP url*/
145 CSSM_DATA crlUrl
= { 0, NULL
};
146 crlDP
= CFURLCreateData(NULL
, currCRLDP
, kCFStringEncodingASCII
, true);
148 crlUrl
.Data
= (uint8_t *)CFDataGetBytePtr(crlDP
);
149 crlUrl
.Length
= CFDataGetLength(crlDP
);
152 if (serialNumber
.Data
&& issuers
.Data
&& crlUrl
.Data
) {
153 crtn
= ocspdCRLStatus(serialNumber
, issuers
, NULL
, &crlUrl
);
156 result
= cssmReturnToOSStatus(crtn
);
158 if (serialData
) { CFRelease(serialData
); }
159 if (issuersArray
) { CFRelease(issuersArray
); }
160 if (pemIssuers
) { CFRelease(pemIssuers
); }
161 if (crlDP
) { CFRelease(crlDP
); }
165 static CSSM_RETURN
ocspdCRLFetchToCache(const CSSM_DATA
&crlURL
,
166 CSSM_TIMESTRING verifyTime
) {
167 Allocator
&alloc(Allocator::standard(Allocator::normal
));
168 CSSM_DATA crlData
= { 0, NULL
};
171 crtn
= ocspdCRLFetch(alloc
, crlURL
, NULL
, true, true, verifyTime
, crlData
);
172 if (crlData
.Data
) { alloc
.free(crlData
.Data
); }
176 static OSStatus
fetchCRL(CFURLRef currCRLDP
, CFAbsoluteTime verifyTime
) {
177 OSStatus result
= errSecParam
;
178 CSSM_RETURN crtn
= CSSMERR_TP_INTERNAL_ERROR
;
179 CFDataRef crlDP
= NULL
;
180 char *cssmTime
= NULL
, *genTime
= NULL
;
186 /* crlUrl is CSSM_DATA with the CRLDP url*/
187 CSSM_DATA crlUrl
= { 0, NULL
};
188 crlDP
= CFURLCreateData(NULL
, currCRLDP
, kCFStringEncodingASCII
, true);
190 crlUrl
.Data
= (uint8_t *)CFDataGetBytePtr(crlDP
);
191 crlUrl
.Length
= CFDataGetLength(crlDP
);
194 /* determine verification time */
195 cssmTime
= (char *)malloc(CSSM_TIME_STRLEN
+ 1);
196 genTime
= (char *)malloc(GENERAL_TIME_STRLEN
+ 1);
197 if (cssmTime
&& genTime
) {
198 if (verifyTime
!= 0.0) {
199 cfAbsTimeToGgenTime(verifyTime
, genTime
);
201 cfAbsTimeToGgenTime(CFAbsoluteTimeGetCurrent(), genTime
);
203 memmove(cssmTime
, genTime
, GENERAL_TIME_STRLEN
- 1); // don't copy the Z
204 cssmTime
[CSSM_TIME_STRLEN
] = '\0';
207 if (crlUrl
.Data
&& cssmTime
) {
208 crtn
= ocspdCRLFetchToCache(crlUrl
, (CSSM_TIMESTRING
)cssmTime
);
211 result
= cssmReturnToOSStatus(crtn
);
213 if (crlDP
) { CFRelease(crlDP
); }
214 if (cssmTime
) { free(cssmTime
); }
215 if (genTime
) { free(genTime
); }
220 * MARK: async_ocspd methods
222 static void async_ocspd_complete(async_ocspd_t
*ocspd
) {
223 if (ocspd
->completed
) {
224 ocspd
->completed(ocspd
);
228 /* Return true, iff we didn't schedule any work, return false if we did. */
229 bool SecTrustLegacyCRLFetch(async_ocspd_t
*ocspd
,
230 CFURLRef currCRLDP
, CFAbsoluteTime verifyTime
,
231 SecCertificateRef cert
, CFArrayRef chain
) {
232 dispatch_async(ocspd
->queue
, ^ {
233 OSStatus status
= fetchCRL(currCRLDP
, verifyTime
);
236 ocspd
->response
= SecTrustLegacyCRLStatus(cert
, chain
, currCRLDP
);
239 ocspd
->response
= status
;
242 async_ocspd_complete(ocspd
);
243 if (chain
) { CFRelease(chain
); }
246 return false; /* false -> something was scheduled. */