OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/x509_certificate.h" | 5 #include "net/base/x509_certificate.h" |
6 | 6 |
7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
8 #include <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
9 #include <Security/Security.h> | 9 #include <Security/Security.h> |
10 #include <time.h> | 10 #include <time.h> |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 base::mac::ScopedCFTypeRef<CFStringRef> error_string( | 122 base::mac::ScopedCFTypeRef<CFStringRef> error_string( |
123 SecCopyErrorMessageString(status, NULL)); | 123 SecCopyErrorMessageString(status, NULL)); |
124 LOG(WARNING) << "Unknown error " << status | 124 LOG(WARNING) << "Unknown error " << status |
125 << " (" << base::SysCFStringRefToUTF8(error_string) << ")" | 125 << " (" << base::SysCFStringRefToUTF8(error_string) << ")" |
126 << " mapped to CERT_STATUS_INVALID"; | 126 << " mapped to CERT_STATUS_INVALID"; |
127 return CERT_STATUS_INVALID; | 127 return CERT_STATUS_INVALID; |
128 } | 128 } |
129 } | 129 } |
130 } | 130 } |
131 | 131 |
132 struct CSSMFields { | 132 // Wrapper for a CSSM_DATA_PTR that was obtained via one of the CSSM field |
133 CSSMFields() : cl_handle(NULL), num_of_fields(0), fields(NULL) {} | 133 // accessors (such as CSSM_CL_CertGet[First/Next]Value or |
134 ~CSSMFields() { | 134 // CSSM_CL_CertGet[First/Next]CachedValue). |
135 if (cl_handle) | 135 class CSSMFieldValue { |
136 CSSM_CL_FreeFields(cl_handle, num_of_fields, &fields); | 136 public: |
| 137 CSSMFieldValue() : cl_handle_(NULL), oid_(NULL), field_(NULL) {} |
| 138 CSSMFieldValue(CSSM_CL_HANDLE cl_handle, |
| 139 const CSSM_OID* oid, |
| 140 CSSM_DATA_PTR field) |
| 141 : cl_handle_(cl_handle), |
| 142 oid_(const_cast<CSSM_OID_PTR>(oid)), |
| 143 field_(field) { |
137 } | 144 } |
138 | 145 |
139 CSSM_CL_HANDLE cl_handle; | 146 ~CSSMFieldValue() { |
140 uint32 num_of_fields; | 147 Reset(NULL, NULL, NULL); |
141 CSSM_FIELD_PTR fields; | 148 } |
| 149 |
| 150 CSSM_OID_PTR oid() const { return oid_; } |
| 151 CSSM_DATA_PTR field() const { return field_; } |
| 152 |
| 153 // Returns the field as if it was an arbitrary type - most commonly, by |
| 154 // interpreting the field as a specific CSSM/CDSA parsed type, such as |
| 155 // CSSM_X509_SUBJECT_PUBLIC_KEY_INFO or CSSM_X509_ALGORITHM_IDENTIFIER. |
| 156 // An added check is applied to ensure that the current field is large |
| 157 // enough to actually contain the requested type. |
| 158 template <typename T> const T* GetAs() const { |
| 159 if (!field_ || field_->Length < sizeof(T)) |
| 160 return NULL; |
| 161 return reinterpret_cast<const T*>(field_->Data); |
| 162 } |
| 163 |
| 164 void Reset(CSSM_CL_HANDLE cl_handle, |
| 165 CSSM_OID_PTR oid, |
| 166 CSSM_DATA_PTR field) { |
| 167 if (cl_handle_ && oid_ && field_) |
| 168 CSSM_CL_FreeFieldValue(cl_handle_, oid_, field_); |
| 169 cl_handle_ = cl_handle; |
| 170 oid_ = oid; |
| 171 field_ = field; |
| 172 } |
| 173 |
| 174 private: |
| 175 CSSM_CL_HANDLE cl_handle_; |
| 176 CSSM_OID_PTR oid_; |
| 177 CSSM_DATA_PTR field_; |
| 178 |
| 179 DISALLOW_COPY_AND_ASSIGN(CSSMFieldValue); |
142 }; | 180 }; |
143 | 181 |
144 OSStatus GetCertFields(X509Certificate::OSCertHandle cert_handle, | 182 // CSSMCachedCertificate is a container class that is used to wrap the |
145 CSSMFields* fields) { | 183 // CSSM_CL_CertCache APIs and provide safe and efficient access to |
146 DCHECK(cert_handle); | 184 // certificate fields in their CSSM form. |
147 DCHECK(fields); | 185 // |
| 186 // To provide efficient access to certificate/CRL fields, CSSM provides an |
| 187 // API/SPI to "cache" a certificate/CRL. The exact meaning of a cached |
| 188 // certificate is not defined by CSSM, but is documented to generally be some |
| 189 // intermediate or parsed form of the certificate. In the case of Apple's |
| 190 // CSSM CL implementation, the intermediate form is the parsed certificate |
| 191 // stored in an internal format (which happens to be NSS). By caching the |
| 192 // certificate, callers that wish to access multiple fields (such as subject, |
| 193 // issuer, and validity dates) do not need to repeatedly parse the entire |
| 194 // certificate, nor are they forced to convert all fields from their NSS types |
| 195 // to their CSSM equivalents. This latter point is especially helpful when |
| 196 // running on OS X 10.5, as it will fail to convert some fields that reference |
| 197 // unsupported algorithms, such as ECC. |
| 198 class CSSMCachedCertificate { |
| 199 public: |
| 200 CSSMCachedCertificate() : cl_handle_(NULL), cached_cert_handle_(NULL) {} |
| 201 ~CSSMCachedCertificate() { |
| 202 if (cl_handle_ && cached_cert_handle_) |
| 203 CSSM_CL_CertAbortCache(cl_handle_, cached_cert_handle_); |
| 204 } |
148 | 205 |
149 CSSM_DATA cert_data; | 206 // Initializes the CSSMCachedCertificate by caching the specified |
150 OSStatus status = SecCertificateGetData(cert_handle, &cert_data); | 207 // |os_cert_handle|. On success, returns noErr. |
151 if (status) | 208 // Note: Once initialized, the cached certificate should only be accessed |
152 return status; | 209 // from a single thread. |
| 210 OSStatus Init(SecCertificateRef os_cert_handle) { |
| 211 DCHECK(!cl_handle_ && !cached_cert_handle_); |
| 212 DCHECK(os_cert_handle); |
| 213 CSSM_DATA cert_data; |
| 214 OSStatus status = SecCertificateGetData(os_cert_handle, &cert_data); |
| 215 if (status) |
| 216 return status; |
| 217 status = SecCertificateGetCLHandle(os_cert_handle, &cl_handle_); |
| 218 if (status) { |
| 219 DCHECK(!cl_handle_); |
| 220 return status; |
| 221 } |
153 | 222 |
154 status = SecCertificateGetCLHandle(cert_handle, &fields->cl_handle); | 223 status = CSSM_CL_CertCache(cl_handle_, &cert_data, &cached_cert_handle_); |
155 if (status) { | 224 if (status) |
156 DCHECK(!fields->cl_handle); | 225 DCHECK(!cached_cert_handle_); |
157 return status; | 226 return status; |
158 } | 227 } |
159 | 228 |
160 status = CSSM_CL_CertGetAllFields(fields->cl_handle, &cert_data, | 229 // Fetches the first value for the field associated with |field_oid|. |
161 &fields->num_of_fields, &fields->fields); | 230 // If |field_oid| is a valid OID and is present in the current certificate, |
162 return status; | 231 // returns CSSM_OK and stores the first value in |field|. If additional |
163 } | 232 // values are associated with |field_oid|, they are ignored. |
| 233 OSStatus GetField(const CSSM_OID* field_oid, |
| 234 CSSMFieldValue* field) const { |
| 235 DCHECK(cl_handle_); |
| 236 DCHECK(cached_cert_handle_); |
164 | 237 |
165 void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle, | 238 CSSM_OID_PTR oid = const_cast<CSSM_OID_PTR>(field_oid); |
166 CSSM_OID oid, Time* result) { | 239 CSSM_DATA_PTR field_ptr = NULL; |
| 240 CSSM_HANDLE results_handle = NULL; |
| 241 uint32 field_value_count = 0; |
| 242 CSSM_RETURN status = CSSM_CL_CertGetFirstCachedFieldValue( |
| 243 cl_handle_, cached_cert_handle_, oid, &results_handle, |
| 244 &field_value_count, &field_ptr); |
| 245 if (status) |
| 246 return status; |
| 247 |
| 248 // Note: |field_value_count| may be > 1, indicating that more than one |
| 249 // value is present. This may happen with extensions, but for current |
| 250 // usages, only the first value is returned. |
| 251 CSSM_CL_CertAbortQuery(cl_handle_, results_handle); |
| 252 field->Reset(cl_handle_, oid, field_ptr); |
| 253 return CSSM_OK; |
| 254 } |
| 255 |
| 256 private: |
| 257 CSSM_CL_HANDLE cl_handle_; |
| 258 CSSM_HANDLE cached_cert_handle_; |
| 259 }; |
| 260 |
| 261 void GetCertDateForOID(const CSSMCachedCertificate& cached_cert, |
| 262 const CSSM_OID* oid, |
| 263 Time* result) { |
167 *result = Time::Time(); | 264 *result = Time::Time(); |
168 | 265 |
169 CSSMFields fields; | 266 CSSMFieldValue field; |
170 OSStatus status = GetCertFields(cert_handle, &fields); | 267 OSStatus status = cached_cert.GetField(oid, &field); |
171 if (status) | 268 if (status) |
172 return; | 269 return; |
173 | 270 |
174 for (size_t field = 0; field < fields.num_of_fields; ++field) { | 271 const CSSM_X509_TIME* x509_time = field.GetAs<CSSM_X509_TIME>(); |
175 if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) { | 272 if (x509_time->timeType != BER_TAG_UTC_TIME && |
176 CSSM_X509_TIME* x509_time = reinterpret_cast<CSSM_X509_TIME*>( | 273 x509_time->timeType != BER_TAG_GENERALIZED_TIME) { |
177 fields.fields[field].FieldValue.Data); | 274 LOG(ERROR) << "Unsupported date/time format " |
178 if (x509_time->timeType != BER_TAG_UTC_TIME && | 275 << x509_time->timeType; |
179 x509_time->timeType != BER_TAG_GENERALIZED_TIME) { | 276 return; |
180 LOG(ERROR) << "Unsupported date/time format " | 277 } |
181 << x509_time->timeType; | |
182 return; | |
183 } | |
184 | 278 |
185 base::StringPiece time_string( | 279 base::StringPiece time_string( |
186 reinterpret_cast<const char*>(x509_time->time.Data), | 280 reinterpret_cast<const char*>(x509_time->time.Data), |
187 x509_time->time.Length); | 281 x509_time->time.Length); |
188 CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? | 282 CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ? |
189 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; | 283 CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME; |
190 if (!ParseCertificateDate(time_string, format, result)) | 284 if (!ParseCertificateDate(time_string, format, result)) |
191 LOG(ERROR) << "Invalid certificate date/time " << time_string; | 285 LOG(ERROR) << "Invalid certificate date/time " << time_string; |
192 return; | |
193 } | |
194 } | |
195 } | 286 } |
196 | 287 |
197 std::string GetCertSerialNumber(X509Certificate::OSCertHandle cert_handle) { | 288 std::string GetCertSerialNumber(const CSSMCachedCertificate& cached_cert) { |
198 CSSMFields fields; | 289 CSSMFieldValue serial_number; |
199 OSStatus status = GetCertFields(cert_handle, &fields); | 290 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber, |
200 if (status) | 291 &serial_number); |
201 return ""; | 292 if (status || !serial_number.field()) |
| 293 return std::string(); |
202 | 294 |
203 std::string ret; | 295 return std::string( |
204 for (size_t field = 0; field < fields.num_of_fields; ++field) { | 296 reinterpret_cast<const char*>(serial_number.field()->Data), |
205 if (!CSSMOIDEqual(&fields.fields[field].FieldOid, | 297 serial_number.field()->Length); |
206 &CSSMOID_X509V1SerialNumber)) { | |
207 continue; | |
208 } | |
209 ret.assign( | |
210 reinterpret_cast<char*>(fields.fields[field].FieldValue.Data), | |
211 fields.fields[field].FieldValue.Length); | |
212 break; | |
213 } | |
214 | |
215 return ret; | |
216 } | 298 } |
217 | 299 |
218 // Creates a SecPolicyRef for the given OID, with optional value. | 300 // Creates a SecPolicyRef for the given OID, with optional value. |
219 OSStatus CreatePolicy(const CSSM_OID* policy_OID, | 301 OSStatus CreatePolicy(const CSSM_OID* policy_oid, |
220 void* option_data, | 302 void* option_data, |
221 size_t option_length, | 303 size_t option_length, |
222 SecPolicyRef* policy) { | 304 SecPolicyRef* policy) { |
223 SecPolicySearchRef search; | 305 SecPolicySearchRef search; |
224 OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_OID, NULL, | 306 OSStatus err = SecPolicySearchCreate(CSSM_CERT_X_509v3, policy_oid, NULL, |
225 &search); | 307 &search); |
226 if (err) | 308 if (err) |
227 return err; | 309 return err; |
228 err = SecPolicySearchCopyNext(search, policy); | 310 err = SecPolicySearchCopyNext(search, policy); |
229 CFRelease(search); | 311 CFRelease(search); |
230 if (err) | 312 if (err) |
231 return err; | 313 return err; |
232 | 314 |
233 if (option_data) { | 315 if (option_data) { |
234 CSSM_DATA options_data = { | 316 CSSM_DATA options_data = { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 if ((chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_IN_ANCHORS) || | 397 if ((chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_IN_ANCHORS) || |
316 (chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_ROOT)) { | 398 (chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_ROOT)) { |
317 // The current certificate is either in the user's trusted store or is | 399 // The current certificate is either in the user's trusted store or is |
318 // a root (self-signed) certificate. Ignore the signature algorithm for | 400 // a root (self-signed) certificate. Ignore the signature algorithm for |
319 // these certificates, as it is meaningless for security. We allow | 401 // these certificates, as it is meaningless for security. We allow |
320 // self-signed certificates (i == 0 & IS_ROOT), since we accept that | 402 // self-signed certificates (i == 0 & IS_ROOT), since we accept that |
321 // any security assertions by such a cert are inherently meaningless. | 403 // any security assertions by such a cert are inherently meaningless. |
322 continue; | 404 continue; |
323 } | 405 } |
324 | 406 |
325 CSSMFields cssm_fields; | 407 CSSMCachedCertificate cached_cert; |
326 OSStatus status = GetCertFields(chain_cert, &cssm_fields); | 408 OSStatus status = cached_cert.Init(chain_cert); |
327 if (status) | 409 if (status) |
328 continue; | 410 continue; |
329 CSSM_FIELD_PTR fields = cssm_fields.fields; | 411 CSSMFieldValue signature_field; |
330 for (size_t field = 0; field < cssm_fields.num_of_fields; ++field) { | 412 status = cached_cert.GetField(&CSSMOID_X509V1SignatureAlgorithm, |
331 if (!CSSMOIDEqual(&fields[field].FieldOid, | 413 &signature_field); |
332 &CSSMOID_X509V1SignatureAlgorithm)) { | 414 if (status || !signature_field.field()) |
333 continue; | 415 continue; |
334 } | 416 // Match the behaviour of OS X system tools and defensively check that |
| 417 // sizes are appropriate. This would indicate a critical failure of the |
| 418 // OS X certificate library, but based on history, it is best to play it |
| 419 // safe. |
| 420 const CSSM_X509_ALGORITHM_IDENTIFIER* sig_algorithm = |
| 421 signature_field.GetAs<CSSM_X509_ALGORITHM_IDENTIFIER>(); |
| 422 if (!sig_algorithm) |
| 423 continue; |
335 | 424 |
336 CSSM_X509_ALGORITHM_IDENTIFIER* signature_algorithm = | 425 const CSSM_OID* alg_oid = &sig_algorithm->algorithm; |
337 reinterpret_cast<CSSM_X509_ALGORITHM_IDENTIFIER*>( | 426 if (CSSMOIDEqual(alg_oid, &CSSMOID_MD2WithRSA)) { |
338 fields[field].FieldValue.Data); | 427 verify_result->has_md2 = true; |
339 // Match the behaviour of OS X system tools and defensively check that | 428 if (i != 0) |
340 // sizes are appropriate. This would indicate a critical failure of the | 429 verify_result->has_md2_ca = true; |
341 // OS X certificate library, but based on history, it is best to play it | 430 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD4WithRSA)) { |
342 // safe. | 431 verify_result->has_md4 = true; |
343 if (!signature_algorithm || (fields[field].FieldValue.Length != | 432 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD5WithRSA)) { |
344 sizeof(CSSM_X509_ALGORITHM_IDENTIFIER))) { | 433 verify_result->has_md5 = true; |
345 break; | 434 if (i != 0) |
346 } | 435 verify_result->has_md5_ca = true; |
347 CSSM_OID_PTR alg_oid = &signature_algorithm->algorithm; | |
348 if (CSSMOIDEqual(alg_oid, &CSSMOID_MD2WithRSA)) { | |
349 verify_result->has_md2 = true; | |
350 if (i != 0) | |
351 verify_result->has_md2_ca = true; | |
352 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD4WithRSA)) { | |
353 verify_result->has_md4 = true; | |
354 } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD5WithRSA)) { | |
355 verify_result->has_md5 = true; | |
356 if (i != 0) | |
357 verify_result->has_md5_ca = true; | |
358 } | |
359 break; | |
360 } | 436 } |
361 } | 437 } |
362 if (!verified_cert) | 438 if (!verified_cert) |
363 return; | 439 return; |
364 | 440 |
365 verify_result->verified_cert = | 441 verify_result->verified_cert = |
366 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | 442 X509Certificate::CreateFromHandle(verified_cert, verified_chain); |
367 } | 443 } |
368 | 444 |
369 // Gets the issuer for a given cert, starting with the cert itself and | 445 // Gets the issuer for a given cert, starting with the cert itself and |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 void X509Certificate::Initialize() { | 679 void X509Certificate::Initialize() { |
604 const CSSM_X509_NAME* name; | 680 const CSSM_X509_NAME* name; |
605 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); | 681 OSStatus status = SecCertificateGetSubject(cert_handle_, &name); |
606 if (!status) | 682 if (!status) |
607 subject_.Parse(name); | 683 subject_.Parse(name); |
608 | 684 |
609 status = SecCertificateGetIssuer(cert_handle_, &name); | 685 status = SecCertificateGetIssuer(cert_handle_, &name); |
610 if (!status) | 686 if (!status) |
611 issuer_.Parse(name); | 687 issuer_.Parse(name); |
612 | 688 |
613 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore, | 689 CSSMCachedCertificate cached_cert; |
614 &valid_start_); | 690 if (cached_cert.Init(cert_handle_) == CSSM_OK) { |
615 GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotAfter, | 691 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore, |
616 &valid_expiry_); | 692 &valid_start_); |
| 693 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter, |
| 694 &valid_expiry_); |
| 695 serial_number_ = GetCertSerialNumber(cached_cert); |
| 696 } |
617 | 697 |
618 fingerprint_ = CalculateFingerprint(cert_handle_); | 698 fingerprint_ = CalculateFingerprint(cert_handle_); |
619 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); | 699 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); |
620 serial_number_ = GetCertSerialNumber(cert_handle_); | |
621 } | 700 } |
622 | 701 |
623 // IsIssuedByKnownRoot returns true if the given chain is rooted at a root CA | 702 // IsIssuedByKnownRoot returns true if the given chain is rooted at a root CA |
624 // that we recognise as a standard root. | 703 // that we recognise as a standard root. |
625 // static | 704 // static |
626 bool X509Certificate::IsIssuedByKnownRoot(CFArrayRef chain) { | 705 bool X509Certificate::IsIssuedByKnownRoot(CFArrayRef chain) { |
627 int n = CFArrayGetCount(chain); | 706 int n = CFArrayGetCount(chain); |
628 if (n < 1) | 707 if (n < 1) |
629 return false; | 708 return false; |
630 SecCertificateRef root_ref = reinterpret_cast<SecCertificateRef>( | 709 SecCertificateRef root_ref = reinterpret_cast<SecCertificateRef>( |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 } | 852 } |
774 | 853 |
775 void X509Certificate::GetSubjectAltName( | 854 void X509Certificate::GetSubjectAltName( |
776 std::vector<std::string>* dns_names, | 855 std::vector<std::string>* dns_names, |
777 std::vector<std::string>* ip_addrs) const { | 856 std::vector<std::string>* ip_addrs) const { |
778 if (dns_names) | 857 if (dns_names) |
779 dns_names->clear(); | 858 dns_names->clear(); |
780 if (ip_addrs) | 859 if (ip_addrs) |
781 ip_addrs->clear(); | 860 ip_addrs->clear(); |
782 | 861 |
783 CSSMFields fields; | 862 CSSMCachedCertificate cached_cert; |
784 OSStatus status = GetCertFields(cert_handle_, &fields); | 863 OSStatus status = cached_cert.Init(cert_handle_); |
785 if (status) | 864 if (status) |
786 return; | 865 return; |
| 866 CSSMFieldValue subject_alt_name; |
| 867 status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name); |
| 868 if (status || !subject_alt_name.field()) |
| 869 return; |
| 870 const CSSM_X509_EXTENSION* cssm_ext = |
| 871 subject_alt_name.GetAs<CSSM_X509_EXTENSION>(); |
| 872 if (!cssm_ext || !cssm_ext->value.parsedValue) |
| 873 return; |
| 874 const CE_GeneralNames* alt_name = |
| 875 reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue); |
787 | 876 |
788 for (size_t field = 0; field < fields.num_of_fields; ++field) { | 877 for (size_t name = 0; name < alt_name->numNames; ++name) { |
789 if (!CSSMOIDEqual(&fields.fields[field].FieldOid, &CSSMOID_SubjectAltName)) | 878 const CE_GeneralName& name_struct = alt_name->generalName[name]; |
790 continue; | 879 const CSSM_DATA& name_data = name_struct.name; |
791 CSSM_X509_EXTENSION_PTR cssm_ext = | 880 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs |
792 reinterpret_cast<CSSM_X509_EXTENSION_PTR>( | 881 // respectively, both of which can be byte copied from |
793 fields.fields[field].FieldValue.Data); | 882 // CSSM_DATA::data into the appropriate output vector. |
794 CE_GeneralNames* alt_name = | 883 if (dns_names && name_struct.nameType == GNT_DNSName) { |
795 reinterpret_cast<CE_GeneralNames*>(cssm_ext->value.parsedValue); | 884 dns_names->push_back(std::string( |
796 | 885 reinterpret_cast<const char*>(name_data.Data), |
797 for (size_t name = 0; name < alt_name->numNames; ++name) { | 886 name_data.Length)); |
798 const CE_GeneralName& name_struct = alt_name->generalName[name]; | 887 } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) { |
799 const CSSM_DATA& name_data = name_struct.name; | 888 ip_addrs->push_back(std::string( |
800 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs | 889 reinterpret_cast<const char*>(name_data.Data), |
801 // respectively, both of which can be byte copied from | 890 name_data.Length)); |
802 // CSSM_DATA::data into the appropriate output vector. | |
803 if (dns_names && name_struct.nameType == GNT_DNSName) { | |
804 dns_names->push_back(std::string( | |
805 reinterpret_cast<const char*>(name_data.Data), | |
806 name_data.Length)); | |
807 } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) { | |
808 ip_addrs->push_back(std::string( | |
809 reinterpret_cast<const char*>(name_data.Data), | |
810 name_data.Length)); | |
811 } | |
812 } | 891 } |
813 } | 892 } |
814 } | 893 } |
815 | 894 |
816 int X509Certificate::VerifyInternal(const std::string& hostname, | 895 int X509Certificate::VerifyInternal(const std::string& hostname, |
817 int flags, | 896 int flags, |
818 CRLSet* crl_set, | 897 CRLSet* crl_set, |
819 CertVerifyResult* verify_result) const { | 898 CertVerifyResult* verify_result) const { |
820 ScopedCFTypeRef<CFArrayRef> trust_policies; | 899 ScopedCFTypeRef<CFArrayRef> trust_policies; |
821 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); | 900 OSStatus status = CreateTrustPolicies(hostname, flags, &trust_policies); |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1140 if (status) | 1219 if (status) |
1141 return sha1; | 1220 return sha1; |
1142 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length); | 1221 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length); |
1143 } | 1222 } |
1144 CC_SHA1_Final(sha1.data, &sha1_ctx); | 1223 CC_SHA1_Final(sha1.data, &sha1_ctx); |
1145 | 1224 |
1146 return sha1; | 1225 return sha1; |
1147 } | 1226 } |
1148 | 1227 |
1149 bool X509Certificate::SupportsSSLClientAuth() const { | 1228 bool X509Certificate::SupportsSSLClientAuth() const { |
1150 CSSMFields fields; | 1229 CSSMCachedCertificate cached_cert; |
1151 if (GetCertFields(cert_handle_, &fields) != noErr) | 1230 OSStatus status = cached_cert.Init(cert_handle_); |
| 1231 if (status) |
1152 return false; | 1232 return false; |
1153 | 1233 |
1154 // Gather the extensions we care about. We do not support | |
1155 // CSSMOID_NetscapeCertType on OS X. | |
1156 const CE_ExtendedKeyUsage* ext_key_usage = NULL; | |
1157 const CE_KeyUsage* key_usage = NULL; | |
1158 for (unsigned f = 0; f < fields.num_of_fields; ++f) { | |
1159 const CSSM_FIELD& field = fields.fields[f]; | |
1160 const CSSM_X509_EXTENSION* ext = | |
1161 reinterpret_cast<const CSSM_X509_EXTENSION*>(field.FieldValue.Data); | |
1162 if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_KeyUsage)) { | |
1163 key_usage = reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); | |
1164 } else if (CSSMOIDEqual(&field.FieldOid, &CSSMOID_ExtendedKeyUsage)) { | |
1165 ext_key_usage = | |
1166 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); | |
1167 } | |
1168 } | |
1169 | |
1170 // RFC5280 says to take the intersection of the two extensions. | 1234 // RFC5280 says to take the intersection of the two extensions. |
1171 // | 1235 // |
1172 // Our underlying crypto libraries don't expose | 1236 // Our underlying crypto libraries don't expose |
1173 // ClientCertificateType, so for now we will not support fixed | 1237 // ClientCertificateType, so for now we will not support fixed |
1174 // Diffie-Hellman mechanisms. For rsa_sign, we need the | 1238 // Diffie-Hellman mechanisms. For rsa_sign, we need the |
1175 // digitalSignature bit. | 1239 // digitalSignature bit. |
1176 // | 1240 // |
1177 // In particular, if a key has the nonRepudiation bit and not the | 1241 // In particular, if a key has the nonRepudiation bit and not the |
1178 // digitalSignature one, we will not offer it to the user. | 1242 // digitalSignature one, we will not offer it to the user. |
1179 if (key_usage && !((*key_usage) & CE_KU_DigitalSignature)) | 1243 CSSMFieldValue key_usage; |
1180 return false; | 1244 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage); |
1181 if (ext_key_usage && !ExtendedKeyUsageAllows(ext_key_usage, | 1245 if (status == CSSM_OK && key_usage.field()) { |
1182 &CSSMOID_ClientAuth)) | 1246 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); |
1183 return false; | 1247 const CE_KeyUsage* key_usage_value = |
| 1248 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue); |
| 1249 if (!((*key_usage_value) & CE_KU_DigitalSignature)) |
| 1250 return false; |
| 1251 } |
| 1252 |
| 1253 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage); |
| 1254 if (status == CSSM_OK && key_usage.field()) { |
| 1255 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>(); |
| 1256 const CE_ExtendedKeyUsage* ext_key_usage = |
| 1257 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue); |
| 1258 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth)) |
| 1259 return false; |
| 1260 } |
1184 return true; | 1261 return true; |
1185 } | 1262 } |
1186 | 1263 |
1187 bool X509Certificate::IsIssuedBy( | 1264 bool X509Certificate::IsIssuedBy( |
1188 const std::vector<CertPrincipal>& valid_issuers) { | 1265 const std::vector<CertPrincipal>& valid_issuers) { |
1189 // Get the cert's issuer chain. | 1266 // Get the cert's issuer chain. |
1190 CFArrayRef cert_chain = NULL; | 1267 CFArrayRef cert_chain = NULL; |
1191 OSStatus result; | 1268 OSStatus result; |
1192 result = CopyCertChain(os_cert_handle(), &cert_chain); | 1269 result = CopyCertChain(os_cert_handle(), &cert_chain); |
1193 if (result) | 1270 if (result) |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1431 CSSM_DATA cert_data; | 1508 CSSM_DATA cert_data; |
1432 OSStatus status = SecCertificateGetData(cert_handle, &cert_data); | 1509 OSStatus status = SecCertificateGetData(cert_handle, &cert_data); |
1433 if (status) | 1510 if (status) |
1434 return false; | 1511 return false; |
1435 | 1512 |
1436 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), | 1513 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), |
1437 cert_data.Length); | 1514 cert_data.Length); |
1438 } | 1515 } |
1439 | 1516 |
1440 } // namespace net | 1517 } // namespace net |
OLD | NEW |