]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ocspd/client/ocspdClient.cpp
Security-59306.120.7.tar.gz
[apple/security.git] / OSX / libsecurity_ocspd / client / ocspdClient.cpp
1 /*
2 * Copyright (c) 2000,2002,2011-2014 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 * ocspdClient.cpp - Client interface to OCSP helper daemon
26 */
27
28 #include "ocspdClient.h"
29 #include "ocspdTypes.h"
30 #include "ocspdDebug.h"
31 #include <Security/cssmapple.h>
32 #include <security_utilities/threading.h>
33 #include <security_utilities/mach++.h>
34 #include <security_utilities/unix++.h>
35 #include <security_ocspd/ocspd.h> /* MIG interface */
36 #include <Security/SecBase.h>
37 class ocspdGlobals
38 {
39 public:
40 ocspdGlobals();
41 ~ocspdGlobals();
42 void resetServerPort();
43 mach_port_t serverPort();
44 private:
45 UnixPlusPlus::ForkMonitor mForkMonitor;
46 MachPlusPlus::Port mServerPort;
47 Mutex mLock;
48 };
49
50 ocspdGlobals::ocspdGlobals()
51 : mServerPort(0)
52 {
53 /* nothing here, the real work is done in serverPort() */
54 }
55
56 ocspdGlobals::~ocspdGlobals()
57 {
58 /* I don't believe this should ever execute */
59 }
60
61 mach_port_t ocspdGlobals::serverPort()
62 {
63 StLock<Mutex> _(mLock);
64
65 // Guard against fork-without-exec. If we are the child of a fork
66 // (that has not exec'ed), our apparent connection to SecurityServer
67 // is just a mirage, and we better reset it.
68 mach_port_t rtnPort = mServerPort.port();
69 if (mForkMonitor()) {
70 rtnPort = 0;
71 }
72 if(rtnPort != 0) {
73 return rtnPort;
74 }
75
76 const char *serverName = NULL;
77 #ifndef NDEBUG
78 serverName = getenv(OCSPD_BOOTSTRAP_ENV);
79 #endif
80 if(serverName == NULL) {
81 serverName = (char*) OCSPD_BOOTSTRAP_NAME;
82 }
83 try {
84 mServerPort = MachPlusPlus::Bootstrap().lookup2(serverName);
85 }
86 catch(...) {
87 ocspdErrorLog("ocspdGlobals: error contacting server\n");
88 throw;
89 }
90 return mServerPort;
91 }
92
93 void ocspdGlobals::resetServerPort()
94 {
95 try {
96 mServerPort.deallocate();
97 } catch(...) {
98 }
99 }
100
101
102 static ModuleNexus<ocspdGlobals> OcspdGlobals;
103
104 /*
105 * Perform network fetch of an OCSP response. Result is not verified in any
106 * way.
107 */
108 CSSM_RETURN ocspdFetch(
109 Allocator &alloc,
110 const CSSM_DATA &ocspdReq, // DER-encoded SecAsn1OCSPDRequests
111 CSSM_DATA &ocspdResp) // DER-encoded kSecAsn1OCSPDReplies
112 {
113 mach_port_t serverPort = 0;
114 kern_return_t krtn;
115 unsigned char *rtnData = NULL;
116 unsigned rtnLen = 0;
117
118 try {
119 serverPort = OcspdGlobals().serverPort();
120 }
121 catch(...) {
122 ocspdErrorLog("ocspdFetch: OCSPD server error\n");
123 return CSSMERR_TP_INTERNAL_ERROR;
124 }
125
126 krtn = ocsp_client_ocspdFetch(serverPort, ocspdReq.Data, (mach_msg_type_number_t)ocspdReq.Length,
127 (void **)&rtnData, &rtnLen);
128 if(krtn) {
129 ocspdErrorLog("ocspdFetch: RPC returned %d\n", krtn);
130 return CSSMERR_APPLETP_OCSP_UNAVAILABLE;
131 }
132 if((rtnData == NULL) || (rtnLen == 0)) {
133 ocspdErrorLog("ocspdFetch: RPC returned NULL data\n");
134 return CSSMERR_APPLETP_OCSP_UNAVAILABLE;
135 }
136 ocspdResp.Data = (uint8 *)alloc.malloc(rtnLen);
137 ocspdResp.Length = rtnLen;
138 memmove(ocspdResp.Data, rtnData, rtnLen);
139 mig_deallocate((vm_address_t)rtnData, rtnLen);
140 return CSSM_OK;
141 }
142
143 /*
144 * Flush all responses associated with specifed CertID from cache.
145 */
146 CSSM_RETURN ocspdCacheFlush(
147 const CSSM_DATA &certID)
148 {
149 mach_port_t serverPort = 0;
150 kern_return_t krtn;
151
152 try {
153 serverPort = OcspdGlobals().serverPort();
154 }
155 catch(...) {
156 ocspdErrorLog("ocspdCacheFlush: OCSPD server error\n");
157 return CSSMERR_TP_INTERNAL_ERROR;
158 }
159 krtn = ocsp_client_ocspdCacheFlush(serverPort, certID.Data, (mach_msg_type_number_t)certID.Length);
160 if(krtn) {
161 ocspdErrorLog("ocspdCacheFlush: RPC returned %d\n", krtn);
162 return CSSMERR_APPLETP_OCSP_UNAVAILABLE;
163 }
164 return CSSM_OK;
165 }
166
167 /*
168 * Flush stale entries from cache.
169 */
170 CSSM_RETURN ocspdCacheFlushStale()
171 {
172 mach_port_t serverPort = 0;
173 kern_return_t krtn;
174
175 try {
176 serverPort = OcspdGlobals().serverPort();
177 }
178 catch(...) {
179 ocspdErrorLog("ocspdCacheFlush: OCSPD server error\n");
180 return CSSMERR_TP_INTERNAL_ERROR;
181 }
182 krtn = ocsp_client_ocspdCacheFlushStale(serverPort);
183 if(krtn) {
184 if (krtn == MACH_SEND_INVALID_DEST)
185 OcspdGlobals().resetServerPort();
186 ocspdErrorLog("ocsp_client_ocspdCacheFlushStale: RPC returned %d\n", krtn);
187 return (CSSM_RETURN)krtn;
188 }
189 return CSSM_OK;
190 }
191
192 /*
193 * fetch a certificate from the net.
194 */
195 CSSM_RETURN ocspdCertFetch(
196 Allocator &alloc,
197 const CSSM_DATA &certURL,
198 CSSM_DATA &certData) // mallocd via alloc and RETURNED
199 {
200 mach_port_t serverPort = 0;
201 kern_return_t krtn;
202 unsigned char *rtnData = NULL;
203 unsigned rtnLen = 0;
204
205 try {
206 serverPort = OcspdGlobals().serverPort();
207 }
208 catch(...) {
209 ocspdErrorLog("ocspdCertFetch: OCSPD server error\n");
210 return CSSMERR_TP_INTERNAL_ERROR;
211 }
212
213 krtn = ocsp_client_certFetch(serverPort, certURL.Data, (mach_msg_type_number_t)certURL.Length,
214 (void **)&rtnData, &rtnLen);
215 if(krtn) {
216 if (krtn == MACH_SEND_INVALID_DEST)
217 OcspdGlobals().resetServerPort();
218 ocspdErrorLog("ocspdCertFetch: RPC returned %d\n", krtn);
219 return CSSMERR_APPLETP_NETWORK_FAILURE;
220 }
221
222 if((rtnData == NULL) || (rtnLen == 0)) {
223 ocspdErrorLog("ocspdCertFetch: RPC returned NULL data\n");
224 return CSSMERR_APPLETP_CERT_NOT_FOUND_FROM_ISSUER;
225 }
226 certData.Data = (uint8 *)alloc.malloc(rtnLen);
227 certData.Length = rtnLen;
228 memmove(certData.Data, rtnData, rtnLen);
229 mig_deallocate((vm_address_t)rtnData, rtnLen);
230 return CSSM_OK;
231 }
232
233 /*
234 * Fetch a CRL from net with optional cache lookup and store.
235 * verifyTime only used for cache lookup.
236 */
237 CSSM_RETURN ocspdCRLFetch(
238 Allocator &alloc,
239 const CSSM_DATA &crlURL,
240 const CSSM_DATA *crlIssuer, // optional
241 bool cacheReadEnable,
242 bool cacheWriteEnable,
243 CSSM_TIMESTRING verifyTime,
244 CSSM_DATA &crlData) // mallocd via alloc and RETURNED
245 {
246 mach_port_t serverPort = 0;
247 kern_return_t krtn;
248 unsigned char *rtnData = NULL;
249 unsigned rtnLen = 0;
250
251 if(verifyTime == NULL) {
252 ocspdErrorLog("ocspdCRLFetch: verifyTime NOT OPTIONAL\n");
253 return CSSMERR_TP_INTERNAL_ERROR;
254 }
255 try {
256 serverPort = OcspdGlobals().serverPort();
257 }
258 catch(...) {
259 ocspdErrorLog("ocspdCRLFetch: OCSPD server error\n");
260 return CSSMERR_TP_INTERNAL_ERROR;
261 }
262
263 krtn = ocsp_client_crlFetch(serverPort, crlURL.Data, (mach_msg_type_number_t)crlURL.Length,
264 crlIssuer ? crlIssuer->Data : NULL, crlIssuer ? (mach_msg_type_number_t)crlIssuer->Length : 0,
265 cacheReadEnable, cacheWriteEnable,
266 verifyTime, (mach_msg_type_number_t)strlen(verifyTime),
267 (void **)&rtnData, &rtnLen);
268 if(krtn) {
269 if (krtn == MACH_SEND_INVALID_DEST)
270 OcspdGlobals().resetServerPort();
271 ocspdErrorLog("ocspdCRLFetch: RPC returned %d\n", krtn);
272 return CSSMERR_APPLETP_NETWORK_FAILURE;
273 }
274
275 if((rtnData == NULL) || (rtnLen == 0)) {
276 ocspdErrorLog("ocspdCRLFetch: RPC returned NULL data\n");
277 return CSSMERR_APPLETP_CRL_NOT_FOUND;
278 }
279 crlData.Data = (uint8 *)alloc.malloc(rtnLen);
280 crlData.Length = rtnLen;
281 memmove(crlData.Data, rtnData, rtnLen);
282 mig_deallocate((vm_address_t)rtnData, rtnLen);
283 return CSSM_OK;
284 }
285
286
287 /*
288 * Get CRL status for given serial number and issuing entity
289 */
290 CSSM_RETURN ocspdCRLStatus(
291 const CSSM_DATA &serialNumber,
292 const CSSM_DATA &issuers,
293 const CSSM_DATA *crlIssuer, // optional if URL is supplied
294 const CSSM_DATA *crlURL) // optional if issuer is supplied
295 {
296 mach_port_t serverPort = 0;
297 kern_return_t krtn;
298
299 if(!crlIssuer && !crlURL) {
300 ocspdErrorLog("ocspdCRLStatus: either an issuer or URL is required\n");
301 return CSSMERR_TP_INTERNAL_ERROR;
302 }
303 try {
304 serverPort = OcspdGlobals().serverPort();
305 }
306 catch(...) {
307 ocspdErrorLog("ocspdCRLStatus: OCSPD server error\n");
308 return CSSMERR_TP_INTERNAL_ERROR;
309 }
310
311 krtn = ocsp_client_crlStatus(serverPort,
312 serialNumber.Data, (mach_msg_type_number_t)serialNumber.Length,
313 issuers.Data, (mach_msg_type_number_t)issuers.Length,
314 crlIssuer ? crlIssuer->Data : NULL, crlIssuer ? (mach_msg_type_number_t)crlIssuer->Length : 0,
315 crlURL ? crlURL->Data : NULL, crlURL ? (mach_msg_type_number_t)crlURL->Length : 0);
316 if (krtn == MACH_SEND_INVALID_DEST)
317 OcspdGlobals().resetServerPort();
318
319 return krtn;
320 }
321
322 /*
323 * Refresh the CRL cache.
324 */
325 CSSM_RETURN ocspdCRLRefresh(
326 unsigned staleDays,
327 unsigned expireOverlapSeconds,
328 bool purgeAll,
329 bool fullCryptoVerify)
330 {
331 mach_port_t serverPort = 0;
332 kern_return_t krtn;
333 try {
334 serverPort = OcspdGlobals().serverPort();
335 }
336 catch(...) {
337 ocspdErrorLog("ocspdCRLRefresh: OCSPD server error\n");
338 return CSSMERR_TP_INTERNAL_ERROR;
339 }
340
341 krtn = ocsp_client_crlRefresh(serverPort, staleDays, expireOverlapSeconds,
342 purgeAll, fullCryptoVerify);
343 if(krtn) {
344 if (krtn == MACH_SEND_INVALID_DEST)
345 OcspdGlobals().resetServerPort();
346 ocspdErrorLog("ocspdCRLRefresh: RPC returned %d\n", krtn);
347 return CSSMERR_APPLETP_NETWORK_FAILURE;
348 }
349
350 return CSSM_OK;
351 }
352
353 /*
354 * Flush all CRLs obtained from specified URL from cache. Called by client when
355 * *it* detects a bad CRL.
356 */
357 CSSM_RETURN ocspdCRLFlush(
358 const CSSM_DATA &crlURL)
359 {
360 mach_port_t serverPort = 0;
361 kern_return_t krtn;
362
363 try {
364 serverPort = OcspdGlobals().serverPort();
365 }
366 catch(...) {
367 ocspdErrorLog("ocspdCRLFlush: OCSPD server error\n");
368 return CSSMERR_TP_INTERNAL_ERROR;
369 }
370
371 krtn = ocsp_client_crlFlush(serverPort, crlURL.Data, (mach_msg_type_number_t)crlURL.Length);
372 if(krtn) {
373 if (krtn == MACH_SEND_INVALID_DEST)
374 OcspdGlobals().resetServerPort();
375 ocspdErrorLog("ocspdCRLFlush: RPC returned %d\n", krtn);
376 return CSSMERR_APPLETP_NETWORK_FAILURE;
377 }
378 return CSSM_OK;
379 }
380
381 /*
382 * Obtain TrustSettings.
383 */
384 OSStatus ocspdTrustSettingsRead(
385 Allocator &alloc,
386 SecTrustSettingsDomain domain,
387 CSSM_DATA &trustSettings) // mallocd via alloc and RETURNED
388 {
389 mach_port_t serverPort = 0;
390 kern_return_t krtn;
391 unsigned char *rtnData = NULL;
392 unsigned rtnLen = 0;
393 OSStatus ortn;
394
395 try {
396 serverPort = OcspdGlobals().serverPort();
397 }
398 catch(...) {
399 ocspdErrorLog("ocspdTrustSettingsRead: OCSPD server error\n");
400 return errSecInternalComponent;
401 }
402
403 krtn = ocsp_client_trustSettingsRead(serverPort, domain,
404 (void **)&rtnData, &rtnLen, &ortn);
405 if(krtn) {
406 if (krtn == MACH_SEND_INVALID_DEST)
407 OcspdGlobals().resetServerPort();
408 ocspdErrorLog("ocspdTrustSettingsRead: RPC returned %d\n", krtn);
409 return errSecNotAvailable;
410 }
411 if(ortn) {
412 /* e.g., errSecNoUserTrustRecord */
413 return ortn;
414 }
415 if((rtnData == NULL) || (rtnLen == 0)) {
416 ocspdErrorLog("ocspdTrustSettingsRead: RPC returned NULL data\n");
417 return errSecItemNotFound;
418 }
419 trustSettings.Data = (uint8 *)alloc.malloc(rtnLen);
420 trustSettings.Length = rtnLen;
421 memmove(trustSettings.Data, rtnData, rtnLen);
422 mig_deallocate((vm_address_t)rtnData, rtnLen);
423 return errSecSuccess;
424 }
425
426 /*
427 * Write TrustSettings to disk. Results in authentication dialog.
428 */
429 OSStatus ocspdTrustSettingsWrite(
430 SecTrustSettingsDomain domain,
431 const CSSM_DATA &authBlob,
432 const CSSM_DATA &trustSettings)
433 {
434 mach_port_t serverPort = 0;
435 mach_port_t clientPort = 0;
436 kern_return_t krtn;
437 OSStatus ortn;
438
439 try {
440 serverPort = OcspdGlobals().serverPort();
441 clientPort = MachPlusPlus::Bootstrap();
442 }
443 catch(...) {
444 ocspdErrorLog("ocspdTrustSettingsWrite: OCSPD server error\n");
445 return errSecInternalComponent;
446 }
447
448 krtn = ocsp_client_trustSettingsWrite(serverPort, clientPort, domain,
449 authBlob.Data, (mach_msg_type_number_t)authBlob.Length,
450 trustSettings.Data, (mach_msg_type_number_t)trustSettings.Length,
451 &ortn);
452 if(krtn) {
453 if (krtn == MACH_SEND_INVALID_DEST)
454 OcspdGlobals().resetServerPort();
455 ocspdErrorLog("ocspdTrustSettingsWrite: RPC returned %d\n", krtn);
456 return errSecInternalComponent;
457 }
458 return ortn;
459 }