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