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_certificate.h"
7 #include <CommonCrypto/CommonDigest.h>
8 #include <CoreServices/CoreServices.h>
9 #include <Security/Security.h>
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/mac/mac_logging.h"
16 #include "base/mac/scoped_cftyperef.h"
17 #include "base/memory/singleton.h"
18 #include "base/pickle.h"
19 #include "base/sha1.h"
20 #include "base/strings/string_piece.h"
21 #include "base/strings/sys_string_conversions.h"
22 #include "base/synchronization/lock.h"
23 #include "crypto/cssm_init.h"
24 #include "crypto/mac_security_services_lock.h"
25 #include "net/cert/x509_util_mac.h"
27 using base::ScopedCFTypeRef
;
34 void GetCertDistinguishedName(
35 const x509_util::CSSMCachedCertificate
& cached_cert
,
37 CertPrincipal
* result
) {
38 x509_util::CSSMFieldValue distinguished_name
;
39 OSStatus status
= cached_cert
.GetField(oid
, &distinguished_name
);
40 if (status
|| !distinguished_name
.field())
42 result
->ParseDistinguishedName(distinguished_name
.field()->Data
,
43 distinguished_name
.field()->Length
);
46 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle
,
47 const std::vector
<std::string
>& issuers
) {
48 x509_util::CSSMCachedCertificate cached_cert
;
49 if (cached_cert
.Init(cert_handle
) != CSSM_OK
)
52 x509_util::CSSMFieldValue distinguished_name
;
53 OSStatus status
= cached_cert
.GetField(&CSSMOID_X509V1IssuerNameStd
,
55 if (status
|| !distinguished_name
.field())
58 base::StringPiece
name_piece(
59 reinterpret_cast<const char*>(distinguished_name
.field()->Data
),
60 static_cast<size_t>(distinguished_name
.field()->Length
));
62 for (std::vector
<std::string
>::const_iterator it
= issuers
.begin();
63 it
!= issuers
.end(); ++it
) {
64 base::StringPiece
issuer_piece(*it
);
65 if (name_piece
== issuer_piece
)
72 void GetCertDateForOID(const x509_util::CSSMCachedCertificate
& cached_cert
,
75 *result
= Time::Time();
77 x509_util::CSSMFieldValue field
;
78 OSStatus status
= cached_cert
.GetField(oid
, &field
);
82 const CSSM_X509_TIME
* x509_time
= field
.GetAs
<CSSM_X509_TIME
>();
83 if (x509_time
->timeType
!= BER_TAG_UTC_TIME
&&
84 x509_time
->timeType
!= BER_TAG_GENERALIZED_TIME
) {
85 LOG(ERROR
) << "Unsupported date/time format "
86 << x509_time
->timeType
;
90 base::StringPiece
time_string(
91 reinterpret_cast<const char*>(x509_time
->time
.Data
),
92 x509_time
->time
.Length
);
93 CertDateFormat format
= x509_time
->timeType
== BER_TAG_UTC_TIME
?
94 CERT_DATE_FORMAT_UTC_TIME
: CERT_DATE_FORMAT_GENERALIZED_TIME
;
95 if (!ParseCertificateDate(time_string
, format
, result
))
96 LOG(ERROR
) << "Invalid certificate date/time " << time_string
;
99 std::string
GetCertSerialNumber(
100 const x509_util::CSSMCachedCertificate
& cached_cert
) {
101 x509_util::CSSMFieldValue serial_number
;
102 OSStatus status
= cached_cert
.GetField(&CSSMOID_X509V1SerialNumber
,
104 if (status
|| !serial_number
.field())
105 return std::string();
108 reinterpret_cast<const char*>(serial_number
.field()->Data
),
109 serial_number
.field()->Length
);
112 // Returns true if |purpose| is listed as allowed in |usage|. This
113 // function also considers the "Any" purpose. If the attribute is
114 // present and empty, we return false.
115 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage
* usage
,
116 const CSSM_OID
* purpose
) {
117 for (unsigned p
= 0; p
< usage
->numPurposes
; ++p
) {
118 if (CSSMOIDEqual(&usage
->purposes
[p
], purpose
))
120 if (CSSMOIDEqual(&usage
->purposes
[p
], &CSSMOID_ExtendedKeyUsageAny
))
126 // Test that a given |cert_handle| is actually a valid X.509 certificate, and
127 // return true if it is.
129 // On OS X, SecCertificateCreateFromData() does not return any errors if
130 // called with invalid data, as long as data is present. The actual decoding
131 // of the certificate does not happen until an API that requires a CSSM
132 // handle is called. While SecCertificateGetCLHandle is the most likely
133 // candidate, as it performs the parsing, it does not check whether the
134 // parsing was actually successful. Instead, SecCertificateGetSubject is
135 // used (supported since 10.3), as a means to check that the certificate
136 // parsed as a valid X.509 certificate.
137 bool IsValidOSCertHandle(SecCertificateRef cert_handle
) {
138 const CSSM_X509_NAME
* sanity_check
= NULL
;
139 OSStatus status
= SecCertificateGetSubject(cert_handle
, &sanity_check
);
140 return status
== noErr
&& sanity_check
;
143 // Parses |data| of length |length|, attempting to decode it as the specified
144 // |format|. If |data| is in the specified format, any certificates contained
145 // within are stored into |output|.
146 void AddCertificatesFromBytes(const char* data
, size_t length
,
147 SecExternalFormat format
,
148 X509Certificate::OSCertHandles
* output
) {
149 SecExternalFormat input_format
= format
;
150 ScopedCFTypeRef
<CFDataRef
> local_data(CFDataCreateWithBytesNoCopy(
151 kCFAllocatorDefault
, reinterpret_cast<const UInt8
*>(data
), length
,
154 CFArrayRef items
= NULL
;
157 base::AutoLock
lock(crypto::GetMacSecurityServicesLock());
158 status
= SecKeychainItemImport(local_data
, NULL
, &input_format
,
159 NULL
, 0, NULL
, NULL
, &items
);
163 OSSTATUS_DLOG(WARNING
, status
)
164 << "Unable to import items from data of length " << length
;
168 ScopedCFTypeRef
<CFArrayRef
> scoped_items(items
);
169 CFTypeID cert_type_id
= SecCertificateGetTypeID();
171 for (CFIndex i
= 0; i
< CFArrayGetCount(items
); ++i
) {
172 SecKeychainItemRef item
= reinterpret_cast<SecKeychainItemRef
>(
173 const_cast<void*>(CFArrayGetValueAtIndex(items
, i
)));
175 // While inputFormat implies only certificates will be imported, if/when
176 // other formats (eg: PKCS#12) are supported, this may also include
177 // private keys or other items types, so filter appropriately.
178 if (CFGetTypeID(item
) == cert_type_id
) {
179 SecCertificateRef cert
= reinterpret_cast<SecCertificateRef
>(item
);
180 // OS X ignores |input_format| if it detects that |local_data| is PEM
181 // encoded, attempting to decode data based on internal rules for PEM
182 // block headers. If a PKCS#7 blob is encoded with a PEM block of
183 // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
184 // based on the decoded data. If this happens, the certificate should
185 // not be included in |output|. Because |output| is empty,
186 // CreateCertificateListfromBytes will use PEMTokenizer to decode the
187 // data. When called again with the decoded data, OS X will honor
188 // |input_format|, causing decode to succeed. On OS X 10.6, the data
189 // is properly decoded as a PKCS#7, whether PEM or not, which avoids
190 // the need to fallback to internal decoding.
191 if (IsValidOSCertHandle(cert
)) {
193 output
->push_back(cert
);
201 void X509Certificate::Initialize() {
202 x509_util::CSSMCachedCertificate cached_cert
;
203 if (cached_cert
.Init(cert_handle_
) == CSSM_OK
) {
204 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1SubjectNameStd
,
206 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1IssuerNameStd
,
208 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotBefore
,
210 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotAfter
,
212 serial_number_
= GetCertSerialNumber(cached_cert
);
215 fingerprint_
= CalculateFingerprint(cert_handle_
);
216 ca_fingerprint_
= CalculateCAFingerprint(intermediate_ca_certs_
);
219 bool X509Certificate::IsIssuedByEncoded(
220 const std::vector
<std::string
>& valid_issuers
) {
221 if (IsCertIssuerInEncodedList(cert_handle_
, valid_issuers
))
224 for (OSCertHandles::iterator it
= intermediate_ca_certs_
.begin();
225 it
!= intermediate_ca_certs_
.end(); ++it
) {
226 if (IsCertIssuerInEncodedList(*it
, valid_issuers
))
232 void X509Certificate::GetSubjectAltName(
233 std::vector
<std::string
>* dns_names
,
234 std::vector
<std::string
>* ip_addrs
) const {
240 x509_util::CSSMCachedCertificate cached_cert
;
241 OSStatus status
= cached_cert
.Init(cert_handle_
);
244 x509_util::CSSMFieldValue subject_alt_name
;
245 status
= cached_cert
.GetField(&CSSMOID_SubjectAltName
, &subject_alt_name
);
246 if (status
|| !subject_alt_name
.field())
248 const CSSM_X509_EXTENSION
* cssm_ext
=
249 subject_alt_name
.GetAs
<CSSM_X509_EXTENSION
>();
250 if (!cssm_ext
|| !cssm_ext
->value
.parsedValue
)
252 const CE_GeneralNames
* alt_name
=
253 reinterpret_cast<const CE_GeneralNames
*>(cssm_ext
->value
.parsedValue
);
255 for (size_t name
= 0; name
< alt_name
->numNames
; ++name
) {
256 const CE_GeneralName
& name_struct
= alt_name
->generalName
[name
];
257 const CSSM_DATA
& name_data
= name_struct
.name
;
258 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
259 // respectively, both of which can be byte copied from
260 // CSSM_DATA::data into the appropriate output vector.
261 if (dns_names
&& name_struct
.nameType
== GNT_DNSName
) {
262 dns_names
->push_back(std::string(
263 reinterpret_cast<const char*>(name_data
.Data
),
265 } else if (ip_addrs
&& name_struct
.nameType
== GNT_IPAddress
) {
266 ip_addrs
->push_back(std::string(
267 reinterpret_cast<const char*>(name_data
.Data
),
274 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle
,
275 std::string
* encoded
) {
277 if (!cert_handle
|| SecCertificateGetData(cert_handle
, &der_data
) != noErr
)
279 encoded
->assign(reinterpret_cast<char*>(der_data
.Data
),
285 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a
,
286 X509Certificate::OSCertHandle b
) {
292 CSSM_DATA a_data
, b_data
;
293 return SecCertificateGetData(a
, &a_data
) == noErr
&&
294 SecCertificateGetData(b
, &b_data
) == noErr
&&
295 a_data
.Length
== b_data
.Length
&&
296 memcmp(a_data
.Data
, b_data
.Data
, a_data
.Length
) == 0;
300 X509Certificate::OSCertHandle
X509Certificate::CreateOSCertHandleFromBytes(
301 const char* data
, int length
) {
303 cert_data
.Data
= const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(data
));
304 cert_data
.Length
= length
;
306 OSCertHandle cert_handle
= NULL
;
307 OSStatus status
= SecCertificateCreateFromData(&cert_data
,
309 CSSM_CERT_ENCODING_DER
,
313 if (!IsValidOSCertHandle(cert_handle
)) {
314 CFRelease(cert_handle
);
321 X509Certificate::OSCertHandles
X509Certificate::CreateOSCertHandlesFromBytes(
322 const char* data
, int length
, Format format
) {
323 OSCertHandles results
;
326 case FORMAT_SINGLE_CERTIFICATE
: {
327 OSCertHandle handle
= CreateOSCertHandleFromBytes(data
, length
);
329 results
.push_back(handle
);
333 AddCertificatesFromBytes(data
, length
, kSecFormatPKCS7
, &results
);
336 NOTREACHED() << "Certificate format " << format
<< " unimplemented";
344 X509Certificate::OSCertHandle
X509Certificate::DupOSCertHandle(
345 OSCertHandle handle
) {
348 return reinterpret_cast<OSCertHandle
>(const_cast<void*>(CFRetain(handle
)));
352 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle
) {
354 CFRelease(cert_handle
);
358 SHA1HashValue
X509Certificate::CalculateFingerprint(
361 memset(sha1
.data
, 0, sizeof(sha1
.data
));
364 OSStatus status
= SecCertificateGetData(cert
, &cert_data
);
368 DCHECK(cert_data
.Data
);
369 DCHECK_NE(cert_data
.Length
, 0U);
371 CC_SHA1(cert_data
.Data
, cert_data
.Length
, sha1
.data
);
377 SHA256HashValue
X509Certificate::CalculateFingerprint256(OSCertHandle cert
) {
378 SHA256HashValue sha256
;
379 memset(sha256
.data
, 0, sizeof(sha256
.data
));
382 OSStatus status
= SecCertificateGetData(cert
, &cert_data
);
386 DCHECK(cert_data
.Data
);
387 DCHECK_NE(cert_data
.Length
, 0U);
389 CC_SHA256(cert_data
.Data
, cert_data
.Length
, sha256
.data
);
395 SHA1HashValue
X509Certificate::CalculateCAFingerprint(
396 const OSCertHandles
& intermediates
) {
398 memset(sha1
.data
, 0, sizeof(sha1
.data
));
400 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
401 // we don't check their return values.
402 CC_SHA1_CTX sha1_ctx
;
403 CC_SHA1_Init(&sha1_ctx
);
405 for (size_t i
= 0; i
< intermediates
.size(); ++i
) {
406 OSStatus status
= SecCertificateGetData(intermediates
[i
], &cert_data
);
409 CC_SHA1_Update(&sha1_ctx
, cert_data
.Data
, cert_data
.Length
);
411 CC_SHA1_Final(sha1
.data
, &sha1_ctx
);
416 bool X509Certificate::SupportsSSLClientAuth() const {
417 x509_util::CSSMCachedCertificate cached_cert
;
418 OSStatus status
= cached_cert
.Init(cert_handle_
);
422 // RFC5280 says to take the intersection of the two extensions.
424 // Our underlying crypto libraries don't expose
425 // ClientCertificateType, so for now we will not support fixed
426 // Diffie-Hellman mechanisms. For rsa_sign, we need the
427 // digitalSignature bit.
429 // In particular, if a key has the nonRepudiation bit and not the
430 // digitalSignature one, we will not offer it to the user.
431 x509_util::CSSMFieldValue key_usage
;
432 status
= cached_cert
.GetField(&CSSMOID_KeyUsage
, &key_usage
);
433 if (status
== CSSM_OK
&& key_usage
.field()) {
434 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
435 const CE_KeyUsage
* key_usage_value
=
436 reinterpret_cast<const CE_KeyUsage
*>(ext
->value
.parsedValue
);
437 if (!((*key_usage_value
) & CE_KU_DigitalSignature
))
441 status
= cached_cert
.GetField(&CSSMOID_ExtendedKeyUsage
, &key_usage
);
442 if (status
== CSSM_OK
&& key_usage
.field()) {
443 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
444 const CE_ExtendedKeyUsage
* ext_key_usage
=
445 reinterpret_cast<const CE_ExtendedKeyUsage
*>(ext
->value
.parsedValue
);
446 if (!ExtendedKeyUsageAllows(ext_key_usage
, &CSSMOID_ClientAuth
))
452 CFMutableArrayRef
X509Certificate::CreateOSCertChainForCert() const {
453 CFMutableArrayRef cert_list
=
454 CFArrayCreateMutable(kCFAllocatorDefault
, 0,
455 &kCFTypeArrayCallBacks
);
459 CFArrayAppendValue(cert_list
, os_cert_handle());
460 for (size_t i
= 0; i
< intermediate_ca_certs_
.size(); ++i
)
461 CFArrayAppendValue(cert_list
, intermediate_ca_certs_
[i
]);
467 X509Certificate::OSCertHandle
X509Certificate::ReadOSCertHandleFromPickle(
468 base::PickleIterator
* pickle_iter
) {
471 if (!pickle_iter
->ReadData(&data
, &length
))
474 return CreateOSCertHandleFromBytes(data
, length
);
478 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle
,
479 base::Pickle
* pickle
) {
481 OSStatus status
= SecCertificateGetData(cert_handle
, &cert_data
);
485 return pickle
->WriteData(reinterpret_cast<char*>(cert_data
.Data
),
490 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle
,
492 PublicKeyType
* type
) {
493 // Since we might fail, set the output parameters to default values first.
494 *type
= kPublicKeyTypeUnknown
;
498 OSStatus status
= SecCertificateCopyPublicKey(cert_handle
, &key
);
500 // SecCertificateCopyPublicKey may fail if the certificate has an invalid
501 // key. See https://crbug.com/472291.
502 LOG(WARNING
) << "SecCertificateCopyPublicKey failed: " << status
;
505 ScopedCFTypeRef
<SecKeyRef
> scoped_key(key
);
507 const CSSM_KEY
* cssm_key
;
508 status
= SecKeyGetCSSMKey(key
, &cssm_key
);
510 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status
;
514 *size_bits
= cssm_key
->KeyHeader
.LogicalKeySizeInBits
;
516 switch (cssm_key
->KeyHeader
.AlgorithmId
) {
518 *type
= kPublicKeyTypeRSA
;
521 *type
= kPublicKeyTypeDSA
;
523 case CSSM_ALGID_ECDSA
:
524 *type
= kPublicKeyTypeECDSA
;
527 *type
= kPublicKeyTypeDH
;
530 *type
= kPublicKeyTypeUnknown
;
537 bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle
) {
538 x509_util::CSSMCachedCertificate cached_cert
;
539 OSStatus status
= cached_cert
.Init(cert_handle
);
543 x509_util::CSSMFieldValue subject
;
544 status
= cached_cert
.GetField(&CSSMOID_X509V1SubjectNameStd
, &subject
);
545 if (status
!= CSSM_OK
|| !subject
.field())
548 x509_util::CSSMFieldValue issuer
;
549 status
= cached_cert
.GetField(&CSSMOID_X509V1IssuerNameStd
, &issuer
);
550 if (status
!= CSSM_OK
|| !issuer
.field())
553 if (subject
.field()->Length
!= issuer
.field()->Length
||
554 memcmp(subject
.field()->Data
, issuer
.field()->Data
,
555 issuer
.field()->Length
) != 0) {
559 CSSM_CL_HANDLE cl_handle
= CSSM_INVALID_HANDLE
;
560 status
= SecCertificateGetCLHandle(cert_handle
, &cl_handle
);
564 status
= SecCertificateGetData(cert_handle
, &cert_data
);
568 if (CSSM_CL_CertVerify(cl_handle
, 0, &cert_data
, &cert_data
, NULL
, 0))