/* * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * ocspdClient.cpp - Client interface to OCSP helper daemon */ #include "ocspdClient.h" #include "ocspdTypes.h" #include "ocspdDebug.h" #include #include #include #include #include /* MIG interface */ #include class ocspdGlobals { public: ocspdGlobals(); ~ocspdGlobals(); mach_port_t serverPort(); private: UnixPlusPlus::StaticForkMonitor mForkMonitor; MachPlusPlus::Port mServerPort; Mutex mLock; }; ocspdGlobals::ocspdGlobals() : mServerPort(0) { /* nothing here, the real work is done in serverPort() */ } ocspdGlobals::~ocspdGlobals() { /* I don't believe this should ever execute */ } mach_port_t ocspdGlobals::serverPort() { StLock _(mLock); // Guard against fork-without-exec. If we are the child of a fork // (that has not exec'ed), our apparent connection to SecurityServer // is just a mirage, and we better reset it. mach_port_t rtnPort = mServerPort.port(); if (mForkMonitor()) { rtnPort = 0; } if(rtnPort != 0) { return rtnPort; } char *serverName = NULL; #ifndef NDEBUG serverName = getenv(OCSPD_BOOTSTRAP_ENV); #endif if(serverName == NULL) { serverName = OCSPD_BOOTSTRAP_NAME; } try { mServerPort = MachPlusPlus::Bootstrap().lookup(serverName); } catch(...) { ocspdErrorLog("ocspdGlobals: error contacting server\n"); throw; } return mServerPort; } static ModuleNexus OcspdGlobals; /* * Perform network fetch of an OCSP response. Result is not verified in any * way. */ CSSM_RETURN ocspdFetch( Allocator &alloc, const CSSM_DATA &ocspdReq, // DER-encoded SecAsn1OCSPDRequests CSSM_DATA &ocspdResp) // DER-encoded kSecAsn1OCSPDReplies { mach_port_t serverPort = 0; kern_return_t krtn; unsigned char *rtnData = NULL; unsigned rtnLen = 0; try { serverPort = OcspdGlobals().serverPort(); } catch(...) { ocspdErrorLog("ocspdFetch: OCSPD server error\n"); return CSSMERR_TP_INTERNAL_ERROR; } krtn = ocsp_client_ocspdFetch(serverPort, ocspdReq.Data, ocspdReq.Length, (void **)&rtnData, &rtnLen); if(krtn) { ocspdErrorLog("ocspdFetch: RPC returned %d\n", krtn); return CSSMERR_APPLETP_OCSP_UNAVAILABLE; } if((rtnData == NULL) || (rtnLen == 0)) { ocspdErrorLog("ocspdFetch: RPC returned NULL data\n"); return CSSMERR_APPLETP_OCSP_UNAVAILABLE; } ocspdResp.Data = (uint8 *)alloc.malloc(rtnLen); ocspdResp.Length = rtnLen; memmove(ocspdResp.Data, rtnData, rtnLen); mig_deallocate((vm_address_t)rtnData, rtnLen); return CSSM_OK; } /* * Flush all responses associated with specifed CertID from cache. */ CSSM_RETURN ocspdCacheFlush( const CSSM_DATA &certID) { mach_port_t serverPort = 0; kern_return_t krtn; try { serverPort = OcspdGlobals().serverPort(); } catch(...) { ocspdErrorLog("ocspdCacheFlush: OCSPD server error\n"); return CSSMERR_TP_INTERNAL_ERROR; } krtn = ocsp_client_ocspdCacheFlush(serverPort, certID.Data, certID.Length); if(krtn) { ocspdErrorLog("ocspdCacheFlush: RPC returned %d\n", krtn); return CSSMERR_APPLETP_OCSP_UNAVAILABLE; } return CSSM_OK; } /* * Flush stale entries from cache. */ CSSM_RETURN ocspdCacheFlushStale() { mach_port_t serverPort = 0; kern_return_t krtn; try { serverPort = OcspdGlobals().serverPort(); } catch(...) { ocspdErrorLog("ocspdCacheFlush: OCSPD server error\n"); return CSSMERR_TP_INTERNAL_ERROR; } krtn = ocsp_client_ocspdCacheFlushStale(serverPort); if(krtn) { ocspdErrorLog("ocsp_client_ocspdCacheFlushStale: RPC returned %d\n", krtn); return (CSSM_RETURN)krtn; } return CSSM_OK; } /* * fetch a certificate from the net. */ CSSM_RETURN ocspdCertFetch( Allocator &alloc, const CSSM_DATA &certURL, CSSM_DATA &certData) // mallocd via alloc and RETURNED { mach_port_t serverPort = 0; kern_return_t krtn; unsigned char *rtnData = NULL; unsigned rtnLen = 0; try { serverPort = OcspdGlobals().serverPort(); } catch(...) { ocspdErrorLog("ocspdCertFetch: OCSPD server error\n"); return CSSMERR_TP_INTERNAL_ERROR; } krtn = ocsp_client_certFetch(serverPort, certURL.Data, certURL.Length, (void **)&rtnData, &rtnLen); if(krtn) { ocspdErrorLog("ocspdCertFetch: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } if((rtnData == NULL) || (rtnLen == 0)) { ocspdErrorLog("ocspdCertFetch: RPC returned NULL data\n"); return CSSMERR_APPLETP_CERT_NOT_FOUND_FROM_ISSUER; } certData.Data = (uint8 *)alloc.malloc(rtnLen); certData.Length = rtnLen; memmove(certData.Data, rtnData, rtnLen); mig_deallocate((vm_address_t)rtnData, rtnLen); return CSSM_OK; } /* * Fetch a CRL from net with optional cache lookup and store. * verifyTime only used for cache lookup. */ CSSM_RETURN ocspdCRLFetch( Allocator &alloc, const CSSM_DATA &crlURL, bool cacheReadEnable, bool cacheWriteEnable, CSSM_TIMESTRING verifyTime, CSSM_DATA &crlData) // mallocd via alloc and RETURNED { mach_port_t serverPort = 0; kern_return_t krtn; unsigned char *rtnData = NULL; unsigned rtnLen = 0; if(verifyTime == NULL) { ocspdErrorLog("ocspdCRLFetch: verifyTime NOT OPTIONAL\n"); return CSSMERR_TP_INTERNAL_ERROR; } try { serverPort = OcspdGlobals().serverPort(); } catch(...) { ocspdErrorLog("ocspdCRLFetch: OCSPD server error\n"); return CSSMERR_TP_INTERNAL_ERROR; } krtn = ocsp_client_crlFetch(serverPort, crlURL.Data, crlURL.Length, cacheReadEnable, cacheWriteEnable, verifyTime, strlen(verifyTime), (void **)&rtnData, &rtnLen); if(krtn) { ocspdErrorLog("ocspdCRLFetch: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } if((rtnData == NULL) || (rtnLen == 0)) { ocspdErrorLog("ocspdCRLFetch: RPC returned NULL data\n"); return CSSMERR_APPLETP_CRL_NOT_FOUND; } crlData.Data = (uint8 *)alloc.malloc(rtnLen); crlData.Length = rtnLen; memmove(crlData.Data, rtnData, rtnLen); mig_deallocate((vm_address_t)rtnData, rtnLen); return CSSM_OK; } /* * Refresh the CRL cache. */ CSSM_RETURN ocspdCRLRefresh( unsigned staleDays, unsigned expireOverlapSeconds, bool purgeAll, bool fullCryptoVerify) { mach_port_t serverPort = 0; kern_return_t krtn; try { serverPort = OcspdGlobals().serverPort(); } catch(...) { ocspdErrorLog("ocspdCRLRefresh: OCSPD server error\n"); return CSSMERR_TP_INTERNAL_ERROR; } krtn = ocsp_client_crlRefresh(serverPort, staleDays, expireOverlapSeconds, purgeAll, fullCryptoVerify); if(krtn) { ocspdErrorLog("ocspdCRLRefresh: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } return CSSM_OK; } /* * Flush all CRLs obtained from specified URL from cache. Called by client when * *it* detects a bad CRL. */ CSSM_RETURN ocspdCRLFlush( const CSSM_DATA &crlURL) { mach_port_t serverPort = 0; kern_return_t krtn; try { serverPort = OcspdGlobals().serverPort(); } catch(...) { ocspdErrorLog("ocspdCRLFlush: OCSPD server error\n"); return CSSMERR_TP_INTERNAL_ERROR; } krtn = ocsp_client_crlFlush(serverPort, crlURL.Data, crlURL.Length); if(krtn) { ocspdErrorLog("ocspdCRLFlush: RPC returned %d\n", krtn); return CSSMERR_APPLETP_NETWORK_FAILURE; } return CSSM_OK; }