Home | History | Annotate | Download | only in cert
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/cert/x509_util_mac.h"
      6 
      7 #include "base/logging.h"
      8 #include "third_party/apple_apsl/cssmapplePriv.h"
      9 
     10 namespace net {
     11 
     12 namespace x509_util {
     13 
     14 namespace {
     15 
     16 // Creates a SecPolicyRef for the given OID, with optional value.
     17 OSStatus CreatePolicy(const CSSM_OID* policy_oid,
     18                       void* option_data,
     19                       size_t option_length,
     20                       SecPolicyRef* policy) {
     21   SecPolicySearchRef search;
     22   OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_oid, NULL,
     23                                        &search);
     24   if (err)
     25     return err;
     26   err = SecPolicySearchCopyNext(search, policy);
     27   CFRelease(search);
     28   if (err)
     29     return err;
     30 
     31   if (option_data) {
     32     CSSM_DATA options_data = {
     33       option_length,
     34       reinterpret_cast<uint8_t*>(option_data)
     35     };
     36     err = SecPolicySetValue(*policy, &options_data);
     37     if (err) {
     38       CFRelease(*policy);
     39       return err;
     40     }
     41   }
     42   return noErr;
     43 }
     44 
     45 }  // namespace
     46 
     47 
     48 OSStatus CreateSSLClientPolicy(SecPolicyRef* policy) {
     49   CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
     50   memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
     51   tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
     52   tp_ssl_options.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
     53 
     54   return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
     55                       sizeof(tp_ssl_options), policy);
     56 }
     57 
     58 OSStatus CreateSSLServerPolicy(const std::string& hostname,
     59                                SecPolicyRef* policy) {
     60   CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options;
     61   memset(&tp_ssl_options, 0, sizeof(tp_ssl_options));
     62   tp_ssl_options.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
     63   if (!hostname.empty()) {
     64     tp_ssl_options.ServerName = hostname.data();
     65     tp_ssl_options.ServerNameLen = hostname.size();
     66   }
     67 
     68   return CreatePolicy(&CSSMOID_APPLE_TP_SSL, &tp_ssl_options,
     69                       sizeof(tp_ssl_options), policy);
     70 }
     71 
     72 OSStatus CreateBasicX509Policy(SecPolicyRef* policy) {
     73   return CreatePolicy(&CSSMOID_APPLE_X509_BASIC, NULL, 0, policy);
     74 }
     75 
     76 OSStatus CreateRevocationPolicies(bool enable_revocation_checking,
     77                                   bool enable_ev_checking,
     78                                   CFMutableArrayRef policies) {
     79   OSStatus status = noErr;
     80 
     81   // In order to bypass the system revocation checking settings, the
     82   // SecTrustRef must have at least one revocation policy associated with it.
     83   // Since it is not known prior to verification whether the Apple TP will
     84   // consider a certificate as an EV candidate, the default policy used is a
     85   // CRL policy, since it does not communicate over the network.
     86   // If the TP believes the leaf is an EV cert, it will explicitly add an
     87   // OCSP policy to perform the online checking, and if it doesn't believe
     88   // that the leaf is EV, then the default CRL policy will effectively no-op.
     89   // This behaviour is used to implement EV-only revocation checking.
     90   if (enable_ev_checking || enable_revocation_checking) {
     91     CSSM_APPLE_TP_CRL_OPTIONS tp_crl_options;
     92     memset(&tp_crl_options, 0, sizeof(tp_crl_options));
     93     tp_crl_options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
     94     // Only allow network CRL fetches if the caller explicitly requests
     95     // online revocation checking. Note that, as of OS X 10.7.2, the system
     96     // will set force this flag on according to system policies, so
     97     // online revocation checks cannot be completely disabled.
     98     if (enable_revocation_checking)
     99       tp_crl_options.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
    100 
    101     SecPolicyRef crl_policy;
    102     status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL, &tp_crl_options,
    103                           sizeof(tp_crl_options), &crl_policy);
    104     if (status)
    105       return status;
    106     CFArrayAppendValue(policies, crl_policy);
    107     CFRelease(crl_policy);
    108   }
    109 
    110   // If revocation checking is explicitly enabled, then add an OCSP policy
    111   // and allow network access. If both revocation checking and EV checking
    112   // are disabled, then the added OCSP policy will be prevented from
    113   // accessing the network. This is done because the TP will force an OCSP
    114   // policy to be present when it believes the certificate is EV. If network
    115   // fetching was not explicitly disabled, then it would be as if
    116   // enable_ev_checking was always set to true.
    117   if (enable_revocation_checking || !enable_ev_checking) {
    118     CSSM_APPLE_TP_OCSP_OPTIONS tp_ocsp_options;
    119     memset(&tp_ocsp_options, 0, sizeof(tp_ocsp_options));
    120     tp_ocsp_options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
    121 
    122     if (enable_revocation_checking) {
    123       // The default for the OCSP policy is to fetch responses via the network,
    124       // unlike the CRL policy default. The policy is further modified to
    125       // prefer OCSP over CRLs, if both are specified on the certificate. This
    126       // is because an OCSP response is both sufficient and typically
    127       // significantly smaller than the CRL counterpart.
    128       tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT;
    129     } else {
    130       // Effectively disable OCSP checking by making it impossible to get an
    131       // OCSP response. Even if the Apple TP forces OCSP, no checking will
    132       // be able to succeed. If this happens, the Apple TP will report an error
    133       // that OCSP was unavailable, but this will be handled and suppressed in
    134       // X509Certificate::Verify().
    135       tp_ocsp_options.Flags = CSSM_TP_ACTION_OCSP_DISABLE_NET |
    136                               CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE;
    137     }
    138 
    139     SecPolicyRef ocsp_policy;
    140     status = CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP, &tp_ocsp_options,
    141                           sizeof(tp_ocsp_options), &ocsp_policy);
    142     if (status)
    143       return status;
    144     CFArrayAppendValue(policies, ocsp_policy);
    145     CFRelease(ocsp_policy);
    146   }
    147 
    148   return status;
    149 }
    150 
    151 CSSMFieldValue::CSSMFieldValue()
    152     : cl_handle_(CSSM_INVALID_HANDLE),
    153       oid_(NULL),
    154       field_(NULL) {
    155 }
    156 CSSMFieldValue::CSSMFieldValue(CSSM_CL_HANDLE cl_handle,
    157                                const CSSM_OID* oid,
    158                                CSSM_DATA_PTR field)
    159     : cl_handle_(cl_handle),
    160       oid_(const_cast<CSSM_OID_PTR>(oid)),
    161       field_(field) {
    162 }
    163 
    164 CSSMFieldValue::~CSSMFieldValue() {
    165   Reset(CSSM_INVALID_HANDLE, NULL, NULL);
    166 }
    167 
    168 void CSSMFieldValue::Reset(CSSM_CL_HANDLE cl_handle,
    169                            CSSM_OID_PTR oid,
    170                            CSSM_DATA_PTR field) {
    171   if (cl_handle_ && oid_ && field_)
    172     CSSM_CL_FreeFieldValue(cl_handle_, oid_, field_);
    173   cl_handle_ = cl_handle;
    174   oid_ = oid;
    175   field_ = field;
    176 }
    177 
    178 CSSMCachedCertificate::CSSMCachedCertificate()
    179     : cl_handle_(CSSM_INVALID_HANDLE),
    180       cached_cert_handle_(CSSM_INVALID_HANDLE) {
    181 }
    182 CSSMCachedCertificate::~CSSMCachedCertificate() {
    183   if (cl_handle_ && cached_cert_handle_)
    184     CSSM_CL_CertAbortCache(cl_handle_, cached_cert_handle_);
    185 }
    186 
    187 OSStatus CSSMCachedCertificate::Init(SecCertificateRef os_cert_handle) {
    188   DCHECK(!cl_handle_ && !cached_cert_handle_);
    189   DCHECK(os_cert_handle);
    190   CSSM_DATA cert_data;
    191   OSStatus status = SecCertificateGetData(os_cert_handle, &cert_data);
    192   if (status)
    193     return status;
    194   status = SecCertificateGetCLHandle(os_cert_handle, &cl_handle_);
    195   if (status) {
    196     DCHECK(!cl_handle_);
    197     return status;
    198   }
    199 
    200   status = CSSM_CL_CertCache(cl_handle_, &cert_data, &cached_cert_handle_);
    201   if (status)
    202     DCHECK(!cached_cert_handle_);
    203   return status;
    204 }
    205 
    206 OSStatus CSSMCachedCertificate::GetField(const CSSM_OID* field_oid,
    207                                          CSSMFieldValue* field) const {
    208   DCHECK(cl_handle_);
    209   DCHECK(cached_cert_handle_);
    210 
    211   CSSM_OID_PTR oid = const_cast<CSSM_OID_PTR>(field_oid);
    212   CSSM_DATA_PTR field_ptr = NULL;
    213   CSSM_HANDLE results_handle = CSSM_INVALID_HANDLE;
    214   uint32 field_value_count = 0;
    215   CSSM_RETURN status = CSSM_CL_CertGetFirstCachedFieldValue(
    216       cl_handle_, cached_cert_handle_, oid, &results_handle,
    217       &field_value_count, &field_ptr);
    218   if (status)
    219     return status;
    220 
    221   // Note: |field_value_count| may be > 1, indicating that more than one
    222   // value is present. This may happen with extensions, but for current
    223   // usages, only the first value is returned.
    224   CSSM_CL_CertAbortQuery(cl_handle_, results_handle);
    225   field->Reset(cl_handle_, oid, field_ptr);
    226   return CSSM_OK;
    227 }
    228 
    229 }  // namespace x509_util
    230 
    231 }  // namespace net
    232