2  * Copyright (c) 2016 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25  * SecTrustOSXEntryPoints - Interface for unified SecTrust into OS X Security 
  29 #include "SecTrustOSXEntryPoints.h" 
  31 #include <CoreFoundation/CoreFoundation.h> 
  32 #include <dispatch/dispatch.h> 
  33 #include <AssertMacros.h> 
  35 #include <mach/mach_time.h> 
  37 #include <Security/Security.h> 
  38 #include <Security/cssmtype.h> 
  39 #include <Security/SecKeychain.h> 
  40 #include <Security/SecItemPriv.h> 
  41 #include <Security/SecTrustSettingsPriv.h> 
  42 #include <Security/SecCertificate.h> 
  43 #include <Security/SecImportExport.h> 
  44 #include <security_keychain/SecImportExportPem.h> 
  45 #include <security_utilities/debugging.h> 
  46 #include <Security/SecItemInternal.h> 
  48 #include <security_ocspd/ocspdClient.h> 
  49 #include <security_ocspd/ocspdUtils.h> 
  52 void SecTrustLegacySourcesListenForKeychainEvents(void) { 
  53     /* Register for CertificateTrustNotification */ 
  55     notify_register_dispatch(kSecServerCertificateTrustNotification
, &out_token
, 
  56                              dispatch_get_main_queue(), 
  57                              ^(int token __unused
) { 
  58                                  // Purge keychain parent cache 
  59                                  SecItemParentCachePurge(); 
  60                                  // Purge unrestricted roots cache 
  61                                  SecTrustSettingsPurgeUserAdminCertsCache(); 
  67  * MARK: ocspd CRL Interface 
  69 /* lengths of time strings without trailing NULL */ 
  70 #define CSSM_TIME_STRLEN                        14              /* no trailing 'Z' */ 
  71 #define GENERALIZED_TIME_STRLEN         15 
  73 OSStatus 
SecTrustLegacyCRLStatus(SecCertificateRef cert
, CFArrayRef chain
, CFURLRef currCRLDP
); 
  74 OSStatus 
SecTrustLegacyCRLFetch(CFURLRef currCRLDP
, CFAbsoluteTime verifyTime
); 
  76 static OSStatus 
cssmReturnToOSStatus(CSSM_RETURN crtn
) { 
  77     OSStatus status 
= errSecInternalComponent
; 
  81             status 
= errSecSuccess
; 
  83         case CSSMERR_TP_CERT_REVOKED
: 
  84             status 
= errSecCertificateRevoked
; 
  86         case CSSMERR_APPLETP_NETWORK_FAILURE
: 
  87             status 
= errSecNetworkFailure
; 
  89         case CSSMERR_APPLETP_CRL_NOT_FOUND
: 
  90             status 
= errSecCRLNotFound
; 
  93             status 
= errSecInternalComponent
; 
  98 #define PEM_STRING_X509         "CERTIFICATE" 
  99 static CFDataRef CF_RETURNS_RETAINED 
serializedPathToPemSequences(CFArrayRef certs
) { 
 100     CFMutableDataRef result 
= NULL
; 
 101     CFIndex certIX
, certCount
; 
 102     require_quiet(certs
, out
); 
 103     certCount 
= CFArrayGetCount(certs
); 
 104     require_quiet(certCount 
> 0, out
); 
 105     require_quiet(result 
= CFDataCreateMutable(NULL
, 0), out
); 
 106     for (certIX 
= 0; certIX 
< certCount
; certIX
++) { 
 107         CFDataRef certData 
= (CFDataRef
)CFArrayGetValueAtIndex(certs
, certIX
); 
 108         require_noerr_quiet(impExpPemEncodeExportRep(certData
, PEM_STRING_X509
, 
 115 OSStatus 
SecTrustLegacyCRLStatus(SecCertificateRef cert
, CFArrayRef chain
, CFURLRef currCRLDP
) { 
 116     OSStatus result 
= errSecParam
; 
 117     CSSM_RETURN crtn 
= CSSMERR_TP_INTERNAL_ERROR
; 
 118     CFDataRef serialData 
= NULL
, pemIssuers 
= NULL
, crlDP 
= NULL
; 
 119     CFMutableArrayRef issuersArray 
= NULL
; 
 121     if (!cert 
|| !chain
) { 
 125     /* serialNumber is a CSSM_DATA with the value from the TBS Certificate. */ 
 126     CSSM_DATA serialNumber 
= { 0, NULL 
}; 
 127     serialData 
= SecCertificateCopySerialNumberData(cert
, NULL
); 
 129         serialNumber
.Data 
= (uint8_t *)CFDataGetBytePtr(serialData
); 
 130         serialNumber
.Length 
= CFDataGetLength(serialData
); 
 133     /* issuers is CSSM_DATA containing pem sequence of all issuers in the chain */ 
 134     CSSM_DATA issuers 
= { 0, NULL 
}; 
 135     issuersArray 
= CFArrayCreateMutableCopy(NULL
, 0, chain
); 
 137         CFArrayRemoveValueAtIndex(issuersArray
, 0); 
 138         pemIssuers 
= serializedPathToPemSequences(issuersArray
); 
 141         issuers
.Data 
= (uint8_t *)CFDataGetBytePtr(pemIssuers
); 
 142         issuers
.Length 
= CFDataGetLength(pemIssuers
); 
 145     /* crlUrl is CSSM_DATA with the CRLDP url*/ 
 146     CSSM_DATA crlUrl 
= { 0, NULL 
}; 
 147     crlDP 
= CFURLCreateData(NULL
, currCRLDP
, kCFStringEncodingASCII
, true); 
 149         crlUrl
.Data 
= (uint8_t *)CFDataGetBytePtr(crlDP
); 
 150         crlUrl
.Length 
= CFDataGetLength(crlDP
); 
 153     if (serialNumber
.Data 
&& issuers
.Data 
&& crlUrl
.Data
) { 
 154         crtn 
= ocspdCRLStatus(serialNumber
, issuers
, NULL
, &crlUrl
); 
 157     result 
= cssmReturnToOSStatus(crtn
); 
 159     if (serialData
) { CFRelease(serialData
); } 
 160     if (issuersArray
) { CFRelease(issuersArray
); } 
 161     if (pemIssuers
) { CFRelease(pemIssuers
); } 
 162     if (crlDP
) { CFRelease(crlDP
); } 
 166 static CSSM_RETURN 
ocspdCRLFetchToCache(const CSSM_DATA         
&crlURL
, 
 167                                  CSSM_TIMESTRING        verifyTime
) { 
 168     Allocator 
&alloc(Allocator::standard(Allocator::normal
)); 
 169     CSSM_DATA crlData  
= { 0, NULL 
}; 
 172     crtn 
= ocspdCRLFetch(alloc
, crlURL
, NULL
, true, true, verifyTime
, crlData
); 
 173     if (crlData
.Data
) { alloc
.free(crlData
.Data
); } 
 177 static OSStatus 
fetchCRL(CFURLRef currCRLDP
, CFAbsoluteTime verifyTime
) { 
 178     OSStatus result 
= errSecParam
; 
 179     CSSM_RETURN crtn 
= CSSMERR_TP_INTERNAL_ERROR
; 
 180     CFDataRef crlDP 
= NULL
; 
 181     char *cssmTime 
= NULL
, *genTime 
= NULL
; 
 187     /* crlUrl is CSSM_DATA with the CRLDP url*/ 
 188     CSSM_DATA crlUrl 
= { 0, NULL 
}; 
 189     crlDP 
= CFURLCreateData(NULL
, currCRLDP
, kCFStringEncodingASCII
, true); 
 191         crlUrl
.Data 
= (uint8_t *)CFDataGetBytePtr(crlDP
); 
 192         crlUrl
.Length 
= CFDataGetLength(crlDP
); 
 195     /* determine verification time */ 
 196     cssmTime 
= (char *)malloc(CSSM_TIME_STRLEN 
+ 1); 
 197     genTime 
= (char *)malloc(GENERAL_TIME_STRLEN 
+ 1); 
 198     if (cssmTime 
&& genTime
) { 
 199         if (verifyTime 
!= 0.0) { 
 200             cfAbsTimeToGgenTime(verifyTime
, genTime
); 
 202             cfAbsTimeToGgenTime(CFAbsoluteTimeGetCurrent(), genTime
); 
 204         memmove(cssmTime
, genTime
, GENERAL_TIME_STRLEN 
- 1);    // don't copy the Z 
 205         cssmTime
[CSSM_TIME_STRLEN
] = '\0'; 
 208     if (crlUrl
.Data 
&& cssmTime
) { 
 209        crtn 
= ocspdCRLFetchToCache(crlUrl
, (CSSM_TIMESTRING
)cssmTime
); 
 212     result 
= cssmReturnToOSStatus(crtn
); 
 214     if (crlDP
) { CFRelease(crlDP
); } 
 215     if (cssmTime
) { free(cssmTime
); } 
 216     if (genTime
) { free(genTime
); } 
 221  * MARK: async_ocspd methods 
 223 static void async_ocspd_complete(async_ocspd_t 
*ocspd
) { 
 224     if (ocspd
->completed
) { 
 225         ocspd
->completed(ocspd
); 
 229 /* Return true, iff we didn't schedule any work, return false if we did. */ 
 230 bool SecTrustLegacyCRLFetch(async_ocspd_t 
*ocspd
, 
 231                        CFURLRef currCRLDP
, CFAbsoluteTime verifyTime
, 
 232                        SecCertificateRef cert
, CFArrayRef chain
) { 
 233     ocspd
->start_time 
= mach_absolute_time(); 
 234     dispatch_async(ocspd
->queue
, ^ { 
 235         OSStatus status 
= fetchCRL(currCRLDP
, verifyTime
); 
 238                 ocspd
->response
= SecTrustLegacyCRLStatus(cert
, chain
, currCRLDP
); 
 241                 ocspd
->response 
= status
; 
 244         async_ocspd_complete(ocspd
); 
 245         if (chain
) { CFRelease(chain
); } 
 248     return false; /* false -> something was scheduled. */