x509_util_mac.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/base/x509_util_mac.h"
6
7#include "base/logging.h"
8#include "third_party/apple_apsl/cssmapplePriv.h"
9
10namespace net {
11
12namespace x509_util {
13
14namespace {
15
16// Creates a SecPolicyRef for the given OID, with optional value.
17OSStatus 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
48OSStatus 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
58OSStatus 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
72OSStatus CreateBasicX509Policy(SecPolicyRef* policy) {
73  return CreatePolicy(&CSSMOID_APPLE_X509_BASIC, NULL, 0, policy);
74}
75
76OSStatus 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
151CSSMFieldValue::CSSMFieldValue()
152    : cl_handle_(CSSM_INVALID_HANDLE),
153      oid_(NULL),
154      field_(NULL) {
155}
156CSSMFieldValue::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
164CSSMFieldValue::~CSSMFieldValue() {
165  Reset(CSSM_INVALID_HANDLE, NULL, NULL);
166}
167
168void 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
178CSSMCachedCertificate::CSSMCachedCertificate()
179    : cl_handle_(CSSM_INVALID_HANDLE),
180      cached_cert_handle_(CSSM_INVALID_HANDLE) {
181}
182CSSMCachedCertificate::~CSSMCachedCertificate() {
183  if (cl_handle_ && cached_cert_handle_)
184    CSSM_CL_CertAbortCache(cl_handle_, cached_cert_handle_);
185}
186
187OSStatus 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
206OSStatus 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