X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_ocspd/client/ocspdClient.cpp?ds=inline diff --git a/OSX/libsecurity_ocspd/client/ocspdClient.cpp b/OSX/libsecurity_ocspd/client/ocspdClient.cpp new file mode 100644 index 00000000..b7b0372a --- /dev/null +++ b/OSX/libsecurity_ocspd/client/ocspdClient.cpp @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2000,2002,2011-2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The 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, QUIET ENJOYMENT 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::ForkMonitor 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; + } + + const char *serverName = NULL; + #ifndef NDEBUG + serverName = getenv(OCSPD_BOOTSTRAP_ENV); + #endif + if(serverName == NULL) { + serverName = (char*) OCSPD_BOOTSTRAP_NAME; + } + try { + mServerPort = MachPlusPlus::Bootstrap().lookup2(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, (mach_msg_type_number_t)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, (mach_msg_type_number_t)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, (mach_msg_type_number_t)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, + const CSSM_DATA *crlIssuer, // optional + 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, (mach_msg_type_number_t)crlURL.Length, + crlIssuer ? crlIssuer->Data : NULL, crlIssuer ? (mach_msg_type_number_t)crlIssuer->Length : 0, + cacheReadEnable, cacheWriteEnable, + verifyTime, (mach_msg_type_number_t)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; +} + + +/* + * Get CRL status for given serial number and issuing entity + */ +CSSM_RETURN ocspdCRLStatus( + const CSSM_DATA &serialNumber, + const CSSM_DATA &issuers, + const CSSM_DATA *crlIssuer, // optional if URL is supplied + const CSSM_DATA *crlURL) // optional if issuer is supplied +{ + mach_port_t serverPort = 0; + kern_return_t krtn; + + if(!crlIssuer && !crlURL) { + ocspdErrorLog("ocspdCRLStatus: either an issuer or URL is required\n"); + return CSSMERR_TP_INTERNAL_ERROR; + } + try { + serverPort = OcspdGlobals().serverPort(); + } + catch(...) { + ocspdErrorLog("ocspdCRLStatus: OCSPD server error\n"); + return CSSMERR_TP_INTERNAL_ERROR; + } + + krtn = ocsp_client_crlStatus(serverPort, + serialNumber.Data, (mach_msg_type_number_t)serialNumber.Length, + issuers.Data, (mach_msg_type_number_t)issuers.Length, + crlIssuer ? crlIssuer->Data : NULL, crlIssuer ? (mach_msg_type_number_t)crlIssuer->Length : 0, + crlURL ? crlURL->Data : NULL, crlURL ? (mach_msg_type_number_t)crlURL->Length : 0); + + return krtn; +} + +/* + * 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, (mach_msg_type_number_t)crlURL.Length); + if(krtn) { + ocspdErrorLog("ocspdCRLFlush: RPC returned %d\n", krtn); + return CSSMERR_APPLETP_NETWORK_FAILURE; + } + return CSSM_OK; +} + +/* + * Obtain TrustSettings. + */ +OSStatus ocspdTrustSettingsRead( + Allocator &alloc, + SecTrustSettingsDomain domain, + CSSM_DATA &trustSettings) // mallocd via alloc and RETURNED +{ + mach_port_t serverPort = 0; + kern_return_t krtn; + unsigned char *rtnData = NULL; + unsigned rtnLen = 0; + OSStatus ortn; + + try { + serverPort = OcspdGlobals().serverPort(); + } + catch(...) { + ocspdErrorLog("ocspdTrustSettingsRead: OCSPD server error\n"); + return errSecInternalComponent; + } + + krtn = ocsp_client_trustSettingsRead(serverPort, domain, + (void **)&rtnData, &rtnLen, &ortn); + if(krtn) { + ocspdErrorLog("ocspdTrustSettingsRead: RPC returned %d\n", krtn); + return errSecNotAvailable; + } + if(ortn) { + /* e.g., errSecNoUserTrustRecord */ + return ortn; + } + if((rtnData == NULL) || (rtnLen == 0)) { + ocspdErrorLog("ocspdTrustSettingsRead: RPC returned NULL data\n"); + return errSecItemNotFound; + } + trustSettings.Data = (uint8 *)alloc.malloc(rtnLen); + trustSettings.Length = rtnLen; + memmove(trustSettings.Data, rtnData, rtnLen); + mig_deallocate((vm_address_t)rtnData, rtnLen); + return errSecSuccess; +} + +/* + * Write TrustSettings to disk. Results in authentication dialog. + */ +OSStatus ocspdTrustSettingsWrite( + SecTrustSettingsDomain domain, + const CSSM_DATA &authBlob, + const CSSM_DATA &trustSettings) +{ + mach_port_t serverPort = 0; + mach_port_t clientPort = 0; + kern_return_t krtn; + OSStatus ortn; + + try { + serverPort = OcspdGlobals().serverPort(); + clientPort = MachPlusPlus::Bootstrap(); + } + catch(...) { + ocspdErrorLog("ocspdTrustSettingsWrite: OCSPD server error\n"); + return errSecInternalComponent; + } + + krtn = ocsp_client_trustSettingsWrite(serverPort, clientPort, domain, + authBlob.Data, (mach_msg_type_number_t)authBlob.Length, + trustSettings.Data, (mach_msg_type_number_t)trustSettings.Length, + &ortn); + if(krtn) { + ocspdErrorLog("ocspdTrustSettingsWrite: RPC returned %d\n", krtn); + return errSecInternalComponent; + } + return ortn; +}