reSIProcate/stack  9694
MacSecurity.cxx
Go to the documentation of this file.
00001 
00002 #if defined(HAVE_CONFIG_H)
00003   #include "config.h"
00004 #endif
00005 
00006 #ifdef USE_SSL
00007 // .amr. Must include Apple headers first, otherwise conflicts with rutil/compat.hxx happen due to SDK type differences
00008 #include <CoreFoundation/CoreFoundation.h>
00009 #include <CoreServices/CoreServices.h>
00010 #include <Security/Security.h>
00011 
00012 #include <openssl/e_os2.h>
00013 #include <openssl/evp.h>
00014 #include <openssl/crypto.h>
00015 #include <openssl/err.h>
00016 #include <openssl/pem.h>
00017 #include <openssl/pkcs7.h>
00018 #include <openssl/ossl_typ.h>
00019 #include <openssl/x509.h>
00020 #include <openssl/x509v3.h>
00021 #include <openssl/ssl.h>
00022 
00023 #include "resip/stack/ssl/MacSecurity.hxx"
00024 #include "rutil/Logger.hxx"
00025 
00026 using namespace resip;
00027 using namespace std;
00028 
00029 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
00030 
00031 int verifyCallback(int iInCode, X509_STORE_CTX *pInStore);
00032 
00033 void
00034 MacSecurity::preload()
00035 {
00036    // load the root certificates
00037    getCerts();
00038 }
00039 
00040 // Opens a search handle to certificates store in
00041 // the X509Anchors keychain
00042 KeychainHandle
00043 MacSecurity::openSystemCertStore()
00044 {
00045    OSStatus status = noErr;
00046 
00047    const char *pathName = nil;
00048    SInt32 MacVersion = 0;
00049     
00050    if (Gestalt(gestaltSystemVersion, &MacVersion) == noErr)
00051    {
00052       if (MacVersion >= 0x1050)
00053       {
00054          //for Leopard OSX, the root certificate are located in SystemRootCertificates.keychain
00055              pathName = "/System/Library/Keychains/SystemRootCertificates.keychain"; 
00056       }
00057       else
00058       {
00059          //for earlier OSX (including Tiger), the root certificate are located in X509Anchors
00060          pathName = "/System/Library/Keychains/X509Anchors";
00061       }
00062    }
00063    if(nil == pathName)
00064    {
00065       ErrLog( << "Cannot retrieve OS version");
00066       return NULL;
00067    }
00068    // NOTE: instead of hardcoding the "/System" portion of the path
00069    // we could retrieve it using ::FSFindFolder instead. But it
00070    // doesn't seem useful right now.
00071    SecKeychainRef systemCertsKeyChain;
00072    status = ::SecKeychainOpen(
00073       pathName,
00074       &systemCertsKeyChain
00075    );
00076 
00077    if (status != noErr)
00078    {
00079       ErrLog( << "X509Anchors keychain could not be opened");
00080       assert(0);
00081       return NULL;
00082    }
00083 
00084    // Create a handle to search that iterates over root certificates
00085    // in the X509Anchors keychain
00086 
00087    SecKeychainSearchRef searchReference = nil;
00088    status = ::SecKeychainSearchCreateFromAttributes(
00089       systemCertsKeyChain,
00090       kSecCertificateItemClass,
00091       NULL,
00092       &searchReference
00093    );
00094    
00095    // Now that we have the search handle we don't need an explicit
00096    // reference to the keychain
00097    
00098    ::CFRelease(systemCertsKeyChain);
00099    
00100    if (status != noErr)
00101    {      
00102       ErrLog( << "System certificate store cannot be opened");
00103       assert(0);
00104       return NULL;
00105    }
00106 
00107    InfoLog( << "System certificate store opened");
00108    return searchReference;
00109 }
00110 
00111 void 
00112 MacSecurity::closeCertifStore(KeychainHandle searchReference)
00113 {
00114    if (NULL == searchReference)
00115       return;
00116     
00117    ::CFRelease(searchReference);
00118 }
00119 
00120 void
00121 MacSecurity::getCerts()
00122 {
00123    SecKeychainSearchRef searchReference = NULL;
00124    searchReference = (SecKeychainSearchRef) openSystemCertStore();
00125 
00126    // nothing to do, error already reported
00127    if (searchReference == NULL)
00128       return;
00129    
00130    // iterate over each certificate
00131    for (;;)
00132    {
00133       OSStatus status = noErr;
00134       SecKeychainItemRef itemRef = nil;
00135       
00136       // get the next certificate in the search
00137       status = ::SecKeychainSearchCopyNext(
00138          searchReference,
00139          &itemRef
00140       );
00141       if (status == errSecItemNotFound)
00142       {
00143          // no more certificates left
00144          break;
00145       }      
00146 
00147       // get data from the certificate
00148       if (status == noErr)
00149       {        
00150          void *data;
00151          UInt32 dataSize;
00152          status = ::SecKeychainItemCopyAttributesAndData(
00153             itemRef,
00154             NULL,
00155             NULL,
00156             NULL,
00157             &dataSize,
00158             &data
00159          );
00160                   
00161          if (status == noErr && data != NULL)
00162          {
00163             Data certDER(Data::Borrow, (const char*)data, dataSize);
00164             addCertDER(BaseSecurity::RootCert, NULL, certDER, false);
00165             
00166             status = ::SecKeychainItemFreeAttributesAndData(NULL, data);
00167          }
00168       }
00169       
00170       // free the certificate handle
00171       if (itemRef != NULL)
00172          ::CFRelease(itemRef);
00173       
00174       if (status != noErr)
00175       {
00176          // there was an error loading the certificate
00177          ErrLog( << "Couldn't load certificate, error code: " << status);
00178          assert(0);
00179       }
00180    }
00181    
00182    closeCertifStore(searchReference);
00183 }
00184 
00185 // TODO: this needs to be refactored with WinSecurity.cxx
00186 int 
00187 verifyCallback(int iInCode, X509_STORE_CTX *pInStore)
00188 {
00189    char cBuf1[500];
00190    char cBuf2[500];
00191    X509 *pErrCert;
00192    int iErr = 0;
00193    int iDepth = 0;
00194    pErrCert = X509_STORE_CTX_get_current_cert(pInStore);
00195    iErr = X509_STORE_CTX_get_error(pInStore);
00196    iDepth =     X509_STORE_CTX_get_error_depth(pInStore);
00197 
00198    if (NULL != pErrCert)
00199       X509_NAME_oneline(X509_get_subject_name(pErrCert),cBuf1,256);
00200 
00201    sprintf(cBuf2,"depth=%d %s\n",iDepth,cBuf1);
00202    if(!iInCode)
00203    {
00204       memset(cBuf2, 0, sizeof(cBuf2) ); 
00205       sprintf(cBuf2, "\n Error %s", X509_verify_cert_error_string(pInStore->error) );
00206    }
00207  
00208    return iInCode;
00209 }
00210 
00211 #endif /* USE_SSL */
00212 
00213 /* ====================================================================
00214  * The Vovida Software License, Version 1.0 
00215  * 
00216  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00217  * 
00218  * Redistribution and use in source and binary forms, with or without
00219  * modification, are permitted provided that the following conditions
00220  * are met:
00221  * 
00222  * 1. Redistributions of source code must retain the above copyright
00223  *    notice, this list of conditions and the following disclaimer.
00224  * 
00225  * 2. Redistributions in binary form must reproduce the above copyright
00226  *    notice, this list of conditions and the following disclaimer in
00227  *    the documentation and/or other materials provided with the
00228  *    distribution.
00229  * 
00230  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00231  *    and "Vovida Open Communication Application Library (VOCAL)" must
00232  *    not be used to endorse or promote products derived from this
00233  *    software without prior written permission. For written
00234  *    permission, please contact vocal@vovida.org.
00235  *
00236  * 4. Products derived from this software may not be called "VOCAL", nor
00237  *    may "VOCAL" appear in their name, without prior written
00238  *    permission of Vovida Networks, Inc.
00239  * 
00240  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00241  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00242  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00243  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00244  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00245  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00246  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00247  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00248  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00249  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00250  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00251  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00252  * DAMAGE.
00253  * 
00254  * ====================================================================
00255  * 
00256  * This software consists of voluntary contributions made by Vovida
00257  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00258  * Inc.  For more information on Vovida Networks, Inc., please see
00259  * <http://www.vovida.org/>.
00260  *
00261  */