]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_ocspd/client/ocspdClient.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_ocspd / client / ocspdClient.cpp
diff --git a/OSX/libsecurity_ocspd/client/ocspdClient.cpp b/OSX/libsecurity_ocspd/client/ocspdClient.cpp
new file mode 100644 (file)
index 0000000..b7b0372
--- /dev/null
@@ -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 <Security/cssmapple.h>
+#include <security_utilities/threading.h>
+#include <security_utilities/mach++.h>
+#include <security_utilities/unix++.h>
+#include <security_ocspd/ocspd.h>                      /* MIG interface */
+#include <Security/SecBase.h>
+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<Mutex> _(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> 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;
+}