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.
5 #include "net/cert/x509_util_mac.h"
7 #include "base/logging.h"
8 #include "third_party/apple_apsl/cssmapplePriv.h"
16 // Creates a SecPolicyRef for the given OID, with optional value.
17 OSStatus
CreatePolicy(const CSSM_OID
* policy_oid
,
20 SecPolicyRef
* policy
) {
21 SecPolicySearchRef search
;
22 OSStatus err
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policy_oid
, NULL
,
26 err
= SecPolicySearchCopyNext(search
, policy
);
32 CSSM_DATA options_data
= {
34 reinterpret_cast<uint8_t*>(option_data
)
36 err
= SecPolicySetValue(*policy
, &options_data
);
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
;
54 return CreatePolicy(&CSSMOID_APPLE_TP_SSL
, &tp_ssl_options
,
55 sizeof(tp_ssl_options
), policy
);
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();
68 return CreatePolicy(&CSSMOID_APPLE_TP_SSL
, &tp_ssl_options
,
69 sizeof(tp_ssl_options
), policy
);
72 OSStatus
CreateBasicX509Policy(SecPolicyRef
* policy
) {
73 return CreatePolicy(&CSSMOID_APPLE_X509_BASIC
, NULL
, 0, policy
);
76 OSStatus
CreateRevocationPolicies(bool enable_revocation_checking
,
77 bool enable_ev_checking
,
78 CFMutableArrayRef policies
) {
79 OSStatus status
= noErr
;
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
;
101 SecPolicyRef crl_policy
;
102 status
= CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_CRL
, &tp_crl_options
,
103 sizeof(tp_crl_options
), &crl_policy
);
106 CFArrayAppendValue(policies
, crl_policy
);
107 CFRelease(crl_policy
);
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
;
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
;
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
;
139 SecPolicyRef ocsp_policy
;
140 status
= CreatePolicy(&CSSMOID_APPLE_TP_REVOCATION_OCSP
, &tp_ocsp_options
,
141 sizeof(tp_ocsp_options
), &ocsp_policy
);
144 CFArrayAppendValue(policies
, ocsp_policy
);
145 CFRelease(ocsp_policy
);
151 CSSMFieldValue::CSSMFieldValue()
152 : cl_handle_(CSSM_INVALID_HANDLE
),
156 CSSMFieldValue::CSSMFieldValue(CSSM_CL_HANDLE cl_handle
,
159 : cl_handle_(cl_handle
),
160 oid_(const_cast<CSSM_OID_PTR
>(oid
)),
164 CSSMFieldValue::~CSSMFieldValue() {
165 Reset(CSSM_INVALID_HANDLE
, NULL
, NULL
);
168 void CSSMFieldValue::Reset(CSSM_CL_HANDLE cl_handle
,
170 CSSM_DATA_PTR field
) {
171 if (cl_handle_
&& oid_
&& field_
)
172 CSSM_CL_FreeFieldValue(cl_handle_
, oid_
, field_
);
173 cl_handle_
= cl_handle
;
178 CSSMCachedCertificate::CSSMCachedCertificate()
179 : cl_handle_(CSSM_INVALID_HANDLE
),
180 cached_cert_handle_(CSSM_INVALID_HANDLE
) {
182 CSSMCachedCertificate::~CSSMCachedCertificate() {
183 if (cl_handle_
&& cached_cert_handle_
)
184 CSSM_CL_CertAbortCache(cl_handle_
, cached_cert_handle_
);
187 OSStatus
CSSMCachedCertificate::Init(SecCertificateRef os_cert_handle
) {
188 DCHECK(!cl_handle_
&& !cached_cert_handle_
);
189 DCHECK(os_cert_handle
);
191 OSStatus status
= SecCertificateGetData(os_cert_handle
, &cert_data
);
194 status
= SecCertificateGetCLHandle(os_cert_handle
, &cl_handle_
);
200 status
= CSSM_CL_CertCache(cl_handle_
, &cert_data
, &cached_cert_handle_
);
202 DCHECK(!cached_cert_handle_
);
206 OSStatus
CSSMCachedCertificate::GetField(const CSSM_OID
* field_oid
,
207 CSSMFieldValue
* field
) const {
209 DCHECK(cached_cert_handle_
);
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_t 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
);
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
);
229 } // namespace x509_util