]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ocspd/client/ocspdClient.cpp
Security-59754.80.3.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
320 return krtn;
321 }
322
323 /*
324 * Refresh the CRL cache.
325 */
326 CSSM_RETURN ocspdCRLRefresh(
327 unsigned staleDays,
328 unsigned expireOverlapSeconds,
329 bool purgeAll,
330 bool fullCryptoVerify)
331 {
332 mach_port_t serverPort = 0;
333 kern_return_t krtn;
334 try {
335 serverPort = OcspdGlobals().serverPort();
336 }
337 catch(...) {
338 ocspdErrorLog("ocspdCRLRefresh: OCSPD server error\n");
339 return CSSMERR_TP_INTERNAL_ERROR;
340 }
341
342 krtn = ocsp_client_crlRefresh(serverPort, staleDays, expireOverlapSeconds,
343 purgeAll, fullCryptoVerify);
344 if(krtn) {
345 if (krtn == MACH_SEND_INVALID_DEST)
346 OcspdGlobals().resetServerPort();
347 ocspdErrorLog("ocspdCRLRefresh: RPC returned %d\n", krtn);
348 return CSSMERR_APPLETP_NETWORK_FAILURE;
349 }
350
351 return CSSM_OK;
352 }
353
354 /*
355 * Flush all CRLs obtained from specified URL from cache. Called by client when
356 * *it* detects a bad CRL.
357 */
358 CSSM_RETURN ocspdCRLFlush(
359 const CSSM_DATA &crlURL)
360 {
361 mach_port_t serverPort = 0;
362 kern_return_t krtn;
363
364 try {
365 serverPort = OcspdGlobals().serverPort();
366 }
367 catch(...) {
368 ocspdErrorLog("ocspdCRLFlush: OCSPD server error\n");
369 return CSSMERR_TP_INTERNAL_ERROR;
370 }
371
372 krtn = ocsp_client_crlFlush(serverPort, crlURL.Data, (mach_msg_type_number_t)crlURL.Length);
373 if(krtn) {
374 if (krtn == MACH_SEND_INVALID_DEST)
375 OcspdGlobals().resetServerPort();
376 ocspdErrorLog("ocspdCRLFlush: RPC returned %d\n", krtn);
377 return CSSMERR_APPLETP_NETWORK_FAILURE;
378 }
379 return CSSM_OK;
380 }
381
382 /*
383 * Obtain TrustSettings.
384 */
385 OSStatus ocspdTrustSettingsRead(
386 Allocator &alloc,
387 SecTrustSettingsDomain domain,
388 CSSM_DATA &trustSettings) // mallocd via alloc and RETURNED
389 {
390 mach_port_t serverPort = 0;
391 kern_return_t krtn;
392 unsigned char *rtnData = NULL;
393 unsigned rtnLen = 0;
394 OSStatus ortn;
395
396 try {
397 serverPort = OcspdGlobals().serverPort();
398 }
399 catch(...) {
400 ocspdErrorLog("ocspdTrustSettingsRead: OCSPD server error\n");
401 return errSecInternalComponent;
402 }
403
404 krtn = ocsp_client_trustSettingsRead(serverPort, domain,
405 (void **)&rtnData, &rtnLen, &ortn);
406 if(krtn) {
407 if (krtn == MACH_SEND_INVALID_DEST)
408 OcspdGlobals().resetServerPort();
409 ocspdErrorLog("ocspdTrustSettingsRead: RPC returned %d\n", krtn);
410 return errSecNotAvailable;
411 }
412 if(ortn) {
413 /* e.g., errSecNoUserTrustRecord */
414 return ortn;
415 }
416 if((rtnData == NULL) || (rtnLen == 0)) {
417 ocspdErrorLog("ocspdTrustSettingsRead: RPC returned NULL data\n");
418 return errSecItemNotFound;
419 }
420 trustSettings.Data = (uint8 *)alloc.malloc(rtnLen);
421 trustSettings.Length = rtnLen;
422 memmove(trustSettings.Data, rtnData, rtnLen);
423 mig_deallocate((vm_address_t)rtnData, rtnLen);
424 return errSecSuccess;
425 }
426
427 /*
428 * Write TrustSettings to disk. Results in authentication dialog.
429 */
430 OSStatus ocspdTrustSettingsWrite(
431 SecTrustSettingsDomain domain,
432 const CSSM_DATA &authBlob,
433 const CSSM_DATA &trustSettings)
434 {
435 mach_port_t serverPort = 0;
436 mach_port_t clientPort = 0;
437 kern_return_t krtn;
438 OSStatus ortn;
439
440 try {
441 serverPort = OcspdGlobals().serverPort();
442 clientPort = MachPlusPlus::Bootstrap();
443 }
444 catch(...) {
445 ocspdErrorLog("ocspdTrustSettingsWrite: OCSPD server error\n");
446 return errSecInternalComponent;
447 }
448
449 krtn = ocsp_client_trustSettingsWrite(serverPort, clientPort, domain,
450 authBlob.Data, (mach_msg_type_number_t)authBlob.Length,
451 trustSettings.Data, (mach_msg_type_number_t)trustSettings.Length,
452 &ortn);
453 if(krtn) {
454 if (krtn == MACH_SEND_INVALID_DEST)
455 OcspdGlobals().resetServerPort();
456 ocspdErrorLog("ocspdTrustSettingsWrite: RPC returned %d\n", krtn);
457 return errSecInternalComponent;
458 }
459 return ortn;
460 }