]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp
Security-58286.51.6.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecTrustOSXEntryPoints.cpp
1 /*
2 * Copyright (c) 2016 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 * SecTrustOSXEntryPoints - Interface for unified SecTrust into OS X Security
26 * Framework.
27 */
28
29 #include "SecTrustOSXEntryPoints.h"
30
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <dispatch/dispatch.h>
33 #include <AssertMacros.h>
34 #include <notify.h>
35 #include <mach/mach_time.h>
36
37 #include <Security/Security.h>
38 #include <Security/cssmtype.h>
39 #include <Security/SecKeychain.h>
40 #include <Security/SecItemPriv.h>
41 #include <Security/SecTrustSettingsPriv.h>
42 #include <Security/SecCertificate.h>
43 #include <Security/SecImportExport.h>
44 #include <security_keychain/SecImportExportPem.h>
45 #include <security_utilities/debugging.h>
46 #include <Security/SecItemInternal.h>
47
48 #include <security_ocspd/ocspdClient.h>
49 #include <security_ocspd/ocspdUtils.h>
50
51
52 void SecTrustLegacySourcesListenForKeychainEvents(void) {
53 /* Register for CertificateTrustNotification */
54 int out_token = 0;
55 notify_register_dispatch(kSecServerCertificateTrustNotification, &out_token,
56 dispatch_get_main_queue(),
57 ^(int token __unused) {
58 // Purge keychain parent cache
59 SecItemParentCachePurge();
60 // Purge unrestricted roots cache
61 SecTrustSettingsPurgeUserAdminCertsCache();
62
63 });
64 }
65
66 /*
67 * MARK: ocspd CRL Interface
68 */
69 /* lengths of time strings without trailing NULL */
70 #define CSSM_TIME_STRLEN 14 /* no trailing 'Z' */
71 #define GENERALIZED_TIME_STRLEN 15
72
73 OSStatus SecTrustLegacyCRLStatus(SecCertificateRef cert, CFArrayRef chain, CFURLRef currCRLDP);
74 OSStatus SecTrustLegacyCRLFetch(CFURLRef currCRLDP, CFAbsoluteTime verifyTime);
75
76 static OSStatus cssmReturnToOSStatus(CSSM_RETURN crtn) {
77 OSStatus status = errSecInternalComponent;
78
79 switch (crtn) {
80 case CSSM_OK:
81 status = errSecSuccess;
82 break;
83 case CSSMERR_TP_CERT_REVOKED:
84 status = errSecCertificateRevoked;
85 break;
86 case CSSMERR_APPLETP_NETWORK_FAILURE:
87 status = errSecNetworkFailure;
88 break;
89 case CSSMERR_APPLETP_CRL_NOT_FOUND:
90 status = errSecCRLNotFound;
91 break;
92 default:
93 status = errSecInternalComponent;
94 }
95 return status;
96 }
97
98 #define PEM_STRING_X509 "CERTIFICATE"
99 static CFDataRef CF_RETURNS_RETAINED serializedPathToPemSequences(CFArrayRef certs) {
100 CFMutableDataRef result = NULL;
101 CFIndex certIX, certCount;
102 require_quiet(certs, out);
103 certCount = CFArrayGetCount(certs);
104 require_quiet(certCount > 0, out);
105 require_quiet(result = CFDataCreateMutable(NULL, 0), out);
106 for (certIX = 0; certIX < certCount; certIX++) {
107 CFDataRef certData = (CFDataRef)CFArrayGetValueAtIndex(certs, certIX);
108 require_noerr_quiet(impExpPemEncodeExportRep(certData, PEM_STRING_X509,
109 NULL, result), out);
110 }
111 out:
112 return result;
113 }
114
115 OSStatus SecTrustLegacyCRLStatus(SecCertificateRef cert, CFArrayRef chain, CFURLRef currCRLDP) {
116 OSStatus result = errSecParam;
117 CSSM_RETURN crtn = CSSMERR_TP_INTERNAL_ERROR;
118 CFDataRef serialData = NULL, pemIssuers = NULL, crlDP = NULL;
119 CFMutableArrayRef issuersArray = NULL;
120
121 if (!cert || !chain) {
122 return result;
123 }
124
125 /* serialNumber is a CSSM_DATA with the value from the TBS Certificate. */
126 CSSM_DATA serialNumber = { 0, NULL };
127 serialData = SecCertificateCopySerialNumber(cert, NULL);
128 if (serialData) {
129 serialNumber.Data = (uint8_t *)CFDataGetBytePtr(serialData);
130 serialNumber.Length = CFDataGetLength(serialData);
131 }
132
133 /* issuers is CSSM_DATA containing pem sequence of all issuers in the chain */
134 CSSM_DATA issuers = { 0, NULL };
135 issuersArray = CFArrayCreateMutableCopy(NULL, 0, chain);
136 if (issuersArray) {
137 CFArrayRemoveValueAtIndex(issuersArray, 0);
138 pemIssuers = serializedPathToPemSequences(issuersArray);
139 }
140 if (pemIssuers) {
141 issuers.Data = (uint8_t *)CFDataGetBytePtr(pemIssuers);
142 issuers.Length = CFDataGetLength(pemIssuers);
143 }
144
145 /* crlUrl is CSSM_DATA with the CRLDP url*/
146 CSSM_DATA crlUrl = { 0, NULL };
147 crlDP = CFURLCreateData(NULL, currCRLDP, kCFStringEncodingASCII, true);
148 if (crlDP) {
149 crlUrl.Data = (uint8_t *)CFDataGetBytePtr(crlDP);
150 crlUrl.Length = CFDataGetLength(crlDP);
151 }
152
153 if (serialNumber.Data && issuers.Data && crlUrl.Data) {
154 crtn = ocspdCRLStatus(serialNumber, issuers, NULL, &crlUrl);
155 }
156
157 result = cssmReturnToOSStatus(crtn);
158
159 if (serialData) { CFRelease(serialData); }
160 if (issuersArray) { CFRelease(issuersArray); }
161 if (pemIssuers) { CFRelease(pemIssuers); }
162 if (crlDP) { CFRelease(crlDP); }
163 return result;
164 }
165
166 static CSSM_RETURN ocspdCRLFetchToCache(const CSSM_DATA &crlURL,
167 CSSM_TIMESTRING verifyTime) {
168 Allocator &alloc(Allocator::standard(Allocator::normal));
169 CSSM_DATA crlData = { 0, NULL };
170 CSSM_RETURN crtn;
171
172 crtn = ocspdCRLFetch(alloc, crlURL, NULL, true, true, verifyTime, crlData);
173 if (crlData.Data) { alloc.free(crlData.Data); }
174 return crtn;
175 }
176
177 static OSStatus fetchCRL(CFURLRef currCRLDP, CFAbsoluteTime verifyTime) {
178 OSStatus result = errSecParam;
179 CSSM_RETURN crtn = CSSMERR_TP_INTERNAL_ERROR;
180 CFDataRef crlDP = NULL;
181 char *cssmTime = NULL, *genTime = NULL;
182
183 if (!currCRLDP) {
184 return result;
185 }
186
187 /* crlUrl is CSSM_DATA with the CRLDP url*/
188 CSSM_DATA crlUrl = { 0, NULL };
189 crlDP = CFURLCreateData(NULL, currCRLDP, kCFStringEncodingASCII, true);
190 if (crlDP) {
191 crlUrl.Data = (uint8_t *)CFDataGetBytePtr(crlDP);
192 crlUrl.Length = CFDataGetLength(crlDP);
193 }
194
195 /* determine verification time */
196 cssmTime = (char *)malloc(CSSM_TIME_STRLEN + 1);
197 genTime = (char *)malloc(GENERAL_TIME_STRLEN + 1);
198 if (cssmTime && genTime) {
199 if (verifyTime != 0.0) {
200 cfAbsTimeToGgenTime(verifyTime, genTime);
201 } else {
202 cfAbsTimeToGgenTime(CFAbsoluteTimeGetCurrent(), genTime);
203 }
204 memmove(cssmTime, genTime, GENERAL_TIME_STRLEN - 1); // don't copy the Z
205 cssmTime[CSSM_TIME_STRLEN] = '\0';
206 }
207
208 if (crlUrl.Data && cssmTime) {
209 crtn = ocspdCRLFetchToCache(crlUrl, (CSSM_TIMESTRING)cssmTime);
210 }
211
212 result = cssmReturnToOSStatus(crtn);
213
214 if (crlDP) { CFRelease(crlDP); }
215 if (cssmTime) { free(cssmTime); }
216 if (genTime) { free(genTime); }
217 return result;
218 }
219
220 /*
221 * MARK: async_ocspd methods
222 */
223 static void async_ocspd_complete(async_ocspd_t *ocspd) {
224 if (ocspd->completed) {
225 ocspd->completed(ocspd);
226 }
227 }
228
229 /* Return true, iff we didn't schedule any work, return false if we did. */
230 bool SecTrustLegacyCRLFetch(async_ocspd_t *ocspd,
231 CFURLRef currCRLDP, CFAbsoluteTime verifyTime,
232 SecCertificateRef cert, CFArrayRef chain) {
233 ocspd->start_time = mach_absolute_time();
234 dispatch_async(ocspd->queue, ^ {
235 OSStatus status = fetchCRL(currCRLDP, verifyTime);
236 switch (status) {
237 case errSecSuccess:
238 ocspd->response= SecTrustLegacyCRLStatus(cert, chain, currCRLDP);
239 break;
240 default:
241 ocspd->response = status;
242 break;
243 }
244 async_ocspd_complete(ocspd);
245 if (chain) { CFRelease(chain); }
246 });
247
248 return false; /* false -> something was scheduled. */
249 }