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