]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp
Security-58286.1.32.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 <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>
41
42 #include <security_ocspd/ocspdClient.h>
43 #include <security_ocspd/ocspdUtils.h>
44
45 #include <CoreFoundation/CoreFoundation.h>
46 #include <dispatch/dispatch.h>
47 #include <AssertMacros.h>
48 #include <notify.h>
49
50
51 void SecTrustLegacySourcesListenForKeychainEvents(void) {
52 /* Register for CertificateTrustNotification */
53 int out_token = 0;
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();
61
62 });
63 }
64
65 /*
66 * MARK: ocspd CRL Interface
67 */
68 /* lengths of time strings without trailing NULL */
69 #define CSSM_TIME_STRLEN 14 /* no trailing 'Z' */
70 #define GENERALIZED_TIME_STRLEN 15
71
72 OSStatus SecTrustLegacyCRLStatus(SecCertificateRef cert, CFArrayRef chain, CFURLRef currCRLDP);
73 OSStatus SecTrustLegacyCRLFetch(CFURLRef currCRLDP, CFAbsoluteTime verifyTime);
74
75 static OSStatus cssmReturnToOSStatus(CSSM_RETURN crtn) {
76 OSStatus status = errSecInternalComponent;
77
78 switch (crtn) {
79 case CSSM_OK:
80 status = errSecSuccess;
81 break;
82 case CSSMERR_TP_CERT_REVOKED:
83 status = errSecCertificateRevoked;
84 break;
85 case CSSMERR_APPLETP_NETWORK_FAILURE:
86 status = errSecNetworkFailure;
87 break;
88 case CSSMERR_APPLETP_CRL_NOT_FOUND:
89 status = errSecCRLNotFound;
90 break;
91 default:
92 status = errSecInternalComponent;
93 }
94 return status;
95 }
96
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,
108 NULL, result), out);
109 }
110 out:
111 return result;
112 }
113
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;
119
120 if (!cert || !chain) {
121 return result;
122 }
123
124 /* serialNumber is a CSSM_DATA with the value from the TBS Certificate. */
125 CSSM_DATA serialNumber = { 0, NULL };
126 serialData = SecCertificateCopySerialNumber(cert, NULL);
127 if (serialData) {
128 serialNumber.Data = (uint8_t *)CFDataGetBytePtr(serialData);
129 serialNumber.Length = CFDataGetLength(serialData);
130 }
131
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);
135 if (issuersArray) {
136 CFArrayRemoveValueAtIndex(issuersArray, 0);
137 pemIssuers = serializedPathToPemSequences(issuersArray);
138 }
139 if (pemIssuers) {
140 issuers.Data = (uint8_t *)CFDataGetBytePtr(pemIssuers);
141 issuers.Length = CFDataGetLength(pemIssuers);
142 }
143
144 /* crlUrl is CSSM_DATA with the CRLDP url*/
145 CSSM_DATA crlUrl = { 0, NULL };
146 crlDP = CFURLCreateData(NULL, currCRLDP, kCFStringEncodingASCII, true);
147 if (crlDP) {
148 crlUrl.Data = (uint8_t *)CFDataGetBytePtr(crlDP);
149 crlUrl.Length = CFDataGetLength(crlDP);
150 }
151
152 if (serialNumber.Data && issuers.Data && crlUrl.Data) {
153 crtn = ocspdCRLStatus(serialNumber, issuers, NULL, &crlUrl);
154 }
155
156 result = cssmReturnToOSStatus(crtn);
157
158 if (serialData) { CFRelease(serialData); }
159 if (issuersArray) { CFRelease(issuersArray); }
160 if (pemIssuers) { CFRelease(pemIssuers); }
161 if (crlDP) { CFRelease(crlDP); }
162 return result;
163 }
164
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 };
169 CSSM_RETURN crtn;
170
171 crtn = ocspdCRLFetch(alloc, crlURL, NULL, true, true, verifyTime, crlData);
172 if (crlData.Data) { alloc.free(crlData.Data); }
173 return crtn;
174 }
175
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;
181
182 if (!currCRLDP) {
183 return result;
184 }
185
186 /* crlUrl is CSSM_DATA with the CRLDP url*/
187 CSSM_DATA crlUrl = { 0, NULL };
188 crlDP = CFURLCreateData(NULL, currCRLDP, kCFStringEncodingASCII, true);
189 if (crlDP) {
190 crlUrl.Data = (uint8_t *)CFDataGetBytePtr(crlDP);
191 crlUrl.Length = CFDataGetLength(crlDP);
192 }
193
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);
200 } else {
201 cfAbsTimeToGgenTime(CFAbsoluteTimeGetCurrent(), genTime);
202 }
203 memmove(cssmTime, genTime, GENERAL_TIME_STRLEN - 1); // don't copy the Z
204 cssmTime[CSSM_TIME_STRLEN] = '\0';
205 }
206
207 if (crlUrl.Data && cssmTime) {
208 crtn = ocspdCRLFetchToCache(crlUrl, (CSSM_TIMESTRING)cssmTime);
209 }
210
211 result = cssmReturnToOSStatus(crtn);
212
213 if (crlDP) { CFRelease(crlDP); }
214 if (cssmTime) { free(cssmTime); }
215 if (genTime) { free(genTime); }
216 return result;
217 }
218
219 /*
220 * MARK: async_ocspd methods
221 */
222 static void async_ocspd_complete(async_ocspd_t *ocspd) {
223 if (ocspd->completed) {
224 ocspd->completed(ocspd);
225 }
226 }
227
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);
234 switch (status) {
235 case errSecSuccess:
236 ocspd->response= SecTrustLegacyCRLStatus(cert, chain, currCRLDP);
237 break;
238 default:
239 ocspd->response = status;
240 break;
241 }
242 async_ocspd_complete(ocspd);
243 if (chain) { CFRelease(chain); }
244 });
245
246 return false; /* false -> something was scheduled. */
247 }