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>
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/mac/mac_logging.h"
18 #include "base/mac/scoped_cftyperef.h"
19 #include "base/memory/singleton.h"
20 #include "base/pickle.h"
21 #include "base/sha1.h"
22 #include "base/strings/string_piece.h"
23 #include "base/strings/sys_string_conversions.h"
24 #include "base/synchronization/lock.h"
25 #include "crypto/cssm_init.h"
26 #include "crypto/mac_security_services_lock.h"
27 #include "crypto/nss_util.h"
28 #include "net/cert/x509_util_mac.h"
30 using base::ScopedCFTypeRef
;
37 void GetCertDistinguishedName(
38 const x509_util::CSSMCachedCertificate
& cached_cert
,
40 CertPrincipal
* result
) {
41 x509_util::CSSMFieldValue distinguished_name
;
42 OSStatus status
= cached_cert
.GetField(oid
, &distinguished_name
);
43 if (status
|| !distinguished_name
.field())
45 result
->ParseDistinguishedName(distinguished_name
.field()->Data
,
46 distinguished_name
.field()->Length
);
49 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle
,
50 const std::vector
<std::string
>& issuers
) {
51 x509_util::CSSMCachedCertificate cached_cert
;
52 if (cached_cert
.Init(cert_handle
) != CSSM_OK
)
55 x509_util::CSSMFieldValue distinguished_name
;
56 OSStatus status
= cached_cert
.GetField(&CSSMOID_X509V1IssuerNameStd
,
58 if (status
|| !distinguished_name
.field())
61 base::StringPiece
name_piece(
62 reinterpret_cast<const char*>(distinguished_name
.field()->Data
),
63 static_cast<size_t>(distinguished_name
.field()->Length
));
65 for (std::vector
<std::string
>::const_iterator it
= issuers
.begin();
66 it
!= issuers
.end(); ++it
) {
67 base::StringPiece
issuer_piece(*it
);
68 if (name_piece
== issuer_piece
)
75 void GetCertDateForOID(const x509_util::CSSMCachedCertificate
& cached_cert
,
78 *result
= Time::Time();
80 x509_util::CSSMFieldValue field
;
81 OSStatus status
= cached_cert
.GetField(oid
, &field
);
85 const CSSM_X509_TIME
* x509_time
= field
.GetAs
<CSSM_X509_TIME
>();
86 if (x509_time
->timeType
!= BER_TAG_UTC_TIME
&&
87 x509_time
->timeType
!= BER_TAG_GENERALIZED_TIME
) {
88 LOG(ERROR
) << "Unsupported date/time format "
89 << x509_time
->timeType
;
93 base::StringPiece
time_string(
94 reinterpret_cast<const char*>(x509_time
->time
.Data
),
95 x509_time
->time
.Length
);
96 CertDateFormat format
= x509_time
->timeType
== BER_TAG_UTC_TIME
?
97 CERT_DATE_FORMAT_UTC_TIME
: CERT_DATE_FORMAT_GENERALIZED_TIME
;
98 if (!ParseCertificateDate(time_string
, format
, result
))
99 LOG(ERROR
) << "Invalid certificate date/time " << time_string
;
102 std::string
GetCertSerialNumber(
103 const x509_util::CSSMCachedCertificate
& cached_cert
) {
104 x509_util::CSSMFieldValue serial_number
;
105 OSStatus status
= cached_cert
.GetField(&CSSMOID_X509V1SerialNumber
,
107 if (status
|| !serial_number
.field())
108 return std::string();
111 reinterpret_cast<const char*>(serial_number
.field()->Data
),
112 serial_number
.field()->Length
);
115 // Returns true if |purpose| is listed as allowed in |usage|. This
116 // function also considers the "Any" purpose. If the attribute is
117 // present and empty, we return false.
118 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage
* usage
,
119 const CSSM_OID
* purpose
) {
120 for (unsigned p
= 0; p
< usage
->numPurposes
; ++p
) {
121 if (CSSMOIDEqual(&usage
->purposes
[p
], purpose
))
123 if (CSSMOIDEqual(&usage
->purposes
[p
], &CSSMOID_ExtendedKeyUsageAny
))
129 // Test that a given |cert_handle| is actually a valid X.509 certificate, and
130 // return true if it is.
132 // On OS X, SecCertificateCreateFromData() does not return any errors if
133 // called with invalid data, as long as data is present. The actual decoding
134 // of the certificate does not happen until an API that requires a CSSM
135 // handle is called. While SecCertificateGetCLHandle is the most likely
136 // candidate, as it performs the parsing, it does not check whether the
137 // parsing was actually successful. Instead, SecCertificateGetSubject is
138 // used (supported since 10.3), as a means to check that the certificate
139 // parsed as a valid X.509 certificate.
140 bool IsValidOSCertHandle(SecCertificateRef cert_handle
) {
141 const CSSM_X509_NAME
* sanity_check
= NULL
;
142 OSStatus status
= SecCertificateGetSubject(cert_handle
, &sanity_check
);
143 return status
== noErr
&& sanity_check
;
146 // Parses |data| of length |length|, attempting to decode it as the specified
147 // |format|. If |data| is in the specified format, any certificates contained
148 // within are stored into |output|.
149 void AddCertificatesFromBytes(const char* data
, size_t length
,
150 SecExternalFormat format
,
151 X509Certificate::OSCertHandles
* output
) {
152 SecExternalFormat input_format
= format
;
153 ScopedCFTypeRef
<CFDataRef
> local_data(CFDataCreateWithBytesNoCopy(
154 kCFAllocatorDefault
, reinterpret_cast<const UInt8
*>(data
), length
,
157 CFArrayRef items
= NULL
;
160 base::AutoLock
lock(crypto::GetMacSecurityServicesLock());
161 status
= SecKeychainItemImport(local_data
, NULL
, &input_format
,
162 NULL
, 0, NULL
, NULL
, &items
);
166 OSSTATUS_DLOG(WARNING
, status
)
167 << "Unable to import items from data of length " << length
;
171 ScopedCFTypeRef
<CFArrayRef
> scoped_items(items
);
172 CFTypeID cert_type_id
= SecCertificateGetTypeID();
174 for (CFIndex i
= 0; i
< CFArrayGetCount(items
); ++i
) {
175 SecKeychainItemRef item
= reinterpret_cast<SecKeychainItemRef
>(
176 const_cast<void*>(CFArrayGetValueAtIndex(items
, i
)));
178 // While inputFormat implies only certificates will be imported, if/when
179 // other formats (eg: PKCS#12) are supported, this may also include
180 // private keys or other items types, so filter appropriately.
181 if (CFGetTypeID(item
) == cert_type_id
) {
182 SecCertificateRef cert
= reinterpret_cast<SecCertificateRef
>(item
);
183 // OS X ignores |input_format| if it detects that |local_data| is PEM
184 // encoded, attempting to decode data based on internal rules for PEM
185 // block headers. If a PKCS#7 blob is encoded with a PEM block of
186 // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
187 // based on the decoded data. If this happens, the certificate should
188 // not be included in |output|. Because |output| is empty,
189 // CreateCertificateListfromBytes will use PEMTokenizer to decode the
190 // data. When called again with the decoded data, OS X will honor
191 // |input_format|, causing decode to succeed. On OS X 10.6, the data
192 // is properly decoded as a PKCS#7, whether PEM or not, which avoids
193 // the need to fallback to internal decoding.
194 if (IsValidOSCertHandle(cert
)) {
196 output
->push_back(cert
);
202 struct CSSMOIDString
{
203 const CSSM_OID
* oid_
;
207 typedef std::vector
<CSSMOIDString
> CSSMOIDStringVector
;
209 class ScopedCertName
{
211 explicit ScopedCertName(CERTName
* name
) : name_(name
) { }
213 if (name_
) CERT_DestroyName(name_
);
215 operator CERTName
*() { return name_
; }
221 class ScopedEncodedCertResults
{
223 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET
* results
)
224 : results_(results
) { }
225 ~ScopedEncodedCertResults() {
227 CSSM_ENCODED_CERT
* encCert
=
228 reinterpret_cast<CSSM_ENCODED_CERT
*>(results_
->Results
);
229 for (uint32 i
= 0; i
< results_
->NumberOfResults
; i
++) {
230 crypto::CSSMFree(encCert
[i
].CertBlob
.Data
);
232 crypto::CSSMFree(results_
->Results
);
233 crypto::CSSMFree(results_
);
238 CSSM_TP_RESULT_SET
* results_
;
243 void X509Certificate::Initialize() {
244 x509_util::CSSMCachedCertificate cached_cert
;
245 if (cached_cert
.Init(cert_handle_
) == CSSM_OK
) {
246 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1SubjectNameStd
,
248 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1IssuerNameStd
,
250 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotBefore
,
252 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotAfter
,
254 serial_number_
= GetCertSerialNumber(cached_cert
);
257 fingerprint_
= CalculateFingerprint(cert_handle_
);
258 ca_fingerprint_
= CalculateCAFingerprint(intermediate_ca_certs_
);
261 bool X509Certificate::IsIssuedByEncoded(
262 const std::vector
<std::string
>& valid_issuers
) {
263 if (IsCertIssuerInEncodedList(cert_handle_
, valid_issuers
))
266 for (OSCertHandles::iterator it
= intermediate_ca_certs_
.begin();
267 it
!= intermediate_ca_certs_
.end(); ++it
) {
268 if (IsCertIssuerInEncodedList(*it
, valid_issuers
))
274 void X509Certificate::GetSubjectAltName(
275 std::vector
<std::string
>* dns_names
,
276 std::vector
<std::string
>* ip_addrs
) const {
282 x509_util::CSSMCachedCertificate cached_cert
;
283 OSStatus status
= cached_cert
.Init(cert_handle_
);
286 x509_util::CSSMFieldValue subject_alt_name
;
287 status
= cached_cert
.GetField(&CSSMOID_SubjectAltName
, &subject_alt_name
);
288 if (status
|| !subject_alt_name
.field())
290 const CSSM_X509_EXTENSION
* cssm_ext
=
291 subject_alt_name
.GetAs
<CSSM_X509_EXTENSION
>();
292 if (!cssm_ext
|| !cssm_ext
->value
.parsedValue
)
294 const CE_GeneralNames
* alt_name
=
295 reinterpret_cast<const CE_GeneralNames
*>(cssm_ext
->value
.parsedValue
);
297 for (size_t name
= 0; name
< alt_name
->numNames
; ++name
) {
298 const CE_GeneralName
& name_struct
= alt_name
->generalName
[name
];
299 const CSSM_DATA
& name_data
= name_struct
.name
;
300 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
301 // respectively, both of which can be byte copied from
302 // CSSM_DATA::data into the appropriate output vector.
303 if (dns_names
&& name_struct
.nameType
== GNT_DNSName
) {
304 dns_names
->push_back(std::string(
305 reinterpret_cast<const char*>(name_data
.Data
),
307 } else if (ip_addrs
&& name_struct
.nameType
== GNT_IPAddress
) {
308 ip_addrs
->push_back(std::string(
309 reinterpret_cast<const char*>(name_data
.Data
),
316 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle
,
317 std::string
* encoded
) {
319 if (SecCertificateGetData(cert_handle
, &der_data
) != noErr
)
321 encoded
->assign(reinterpret_cast<char*>(der_data
.Data
),
327 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a
,
328 X509Certificate::OSCertHandle b
) {
334 CSSM_DATA a_data
, b_data
;
335 return SecCertificateGetData(a
, &a_data
) == noErr
&&
336 SecCertificateGetData(b
, &b_data
) == noErr
&&
337 a_data
.Length
== b_data
.Length
&&
338 memcmp(a_data
.Data
, b_data
.Data
, a_data
.Length
) == 0;
342 X509Certificate::OSCertHandle
X509Certificate::CreateOSCertHandleFromBytes(
343 const char* data
, int length
) {
345 cert_data
.Data
= const_cast<uint8
*>(reinterpret_cast<const uint8
*>(data
));
346 cert_data
.Length
= length
;
348 OSCertHandle cert_handle
= NULL
;
349 OSStatus status
= SecCertificateCreateFromData(&cert_data
,
351 CSSM_CERT_ENCODING_DER
,
355 if (!IsValidOSCertHandle(cert_handle
)) {
356 CFRelease(cert_handle
);
363 X509Certificate::OSCertHandles
X509Certificate::CreateOSCertHandlesFromBytes(
364 const char* data
, int length
, Format format
) {
365 OSCertHandles results
;
368 case FORMAT_SINGLE_CERTIFICATE
: {
369 OSCertHandle handle
= CreateOSCertHandleFromBytes(data
, length
);
371 results
.push_back(handle
);
375 AddCertificatesFromBytes(data
, length
, kSecFormatPKCS7
, &results
);
378 NOTREACHED() << "Certificate format " << format
<< " unimplemented";
386 X509Certificate::OSCertHandle
X509Certificate::DupOSCertHandle(
387 OSCertHandle handle
) {
390 return reinterpret_cast<OSCertHandle
>(const_cast<void*>(CFRetain(handle
)));
394 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle
) {
395 CFRelease(cert_handle
);
399 SHA1HashValue
X509Certificate::CalculateFingerprint(
402 memset(sha1
.data
, 0, sizeof(sha1
.data
));
405 OSStatus status
= SecCertificateGetData(cert
, &cert_data
);
409 DCHECK(cert_data
.Data
);
410 DCHECK_NE(cert_data
.Length
, 0U);
412 CC_SHA1(cert_data
.Data
, cert_data
.Length
, sha1
.data
);
418 SHA1HashValue
X509Certificate::CalculateCAFingerprint(
419 const OSCertHandles
& intermediates
) {
421 memset(sha1
.data
, 0, sizeof(sha1
.data
));
423 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
424 // we don't check their return values.
425 CC_SHA1_CTX sha1_ctx
;
426 CC_SHA1_Init(&sha1_ctx
);
428 for (size_t i
= 0; i
< intermediates
.size(); ++i
) {
429 OSStatus status
= SecCertificateGetData(intermediates
[i
], &cert_data
);
432 CC_SHA1_Update(&sha1_ctx
, cert_data
.Data
, cert_data
.Length
);
434 CC_SHA1_Final(sha1
.data
, &sha1_ctx
);
439 bool X509Certificate::SupportsSSLClientAuth() const {
440 x509_util::CSSMCachedCertificate cached_cert
;
441 OSStatus status
= cached_cert
.Init(cert_handle_
);
445 // RFC5280 says to take the intersection of the two extensions.
447 // Our underlying crypto libraries don't expose
448 // ClientCertificateType, so for now we will not support fixed
449 // Diffie-Hellman mechanisms. For rsa_sign, we need the
450 // digitalSignature bit.
452 // In particular, if a key has the nonRepudiation bit and not the
453 // digitalSignature one, we will not offer it to the user.
454 x509_util::CSSMFieldValue key_usage
;
455 status
= cached_cert
.GetField(&CSSMOID_KeyUsage
, &key_usage
);
456 if (status
== CSSM_OK
&& key_usage
.field()) {
457 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
458 const CE_KeyUsage
* key_usage_value
=
459 reinterpret_cast<const CE_KeyUsage
*>(ext
->value
.parsedValue
);
460 if (!((*key_usage_value
) & CE_KU_DigitalSignature
))
464 status
= cached_cert
.GetField(&CSSMOID_ExtendedKeyUsage
, &key_usage
);
465 if (status
== CSSM_OK
&& key_usage
.field()) {
466 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
467 const CE_ExtendedKeyUsage
* ext_key_usage
=
468 reinterpret_cast<const CE_ExtendedKeyUsage
*>(ext
->value
.parsedValue
);
469 if (!ExtendedKeyUsageAllows(ext_key_usage
, &CSSMOID_ClientAuth
))
475 CFArrayRef
X509Certificate::CreateOSCertChainForCert() const {
476 CFMutableArrayRef cert_list
=
477 CFArrayCreateMutable(kCFAllocatorDefault
, 0,
478 &kCFTypeArrayCallBacks
);
482 CFArrayAppendValue(cert_list
, os_cert_handle());
483 for (size_t i
= 0; i
< intermediate_ca_certs_
.size(); ++i
)
484 CFArrayAppendValue(cert_list
, intermediate_ca_certs_
[i
]);
490 X509Certificate::OSCertHandle
491 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator
* pickle_iter
) {
494 if (!pickle_iter
->ReadData(&data
, &length
))
497 return CreateOSCertHandleFromBytes(data
, length
);
501 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle
,
504 OSStatus status
= SecCertificateGetData(cert_handle
, &cert_data
);
508 return pickle
->WriteData(reinterpret_cast<char*>(cert_data
.Data
),
513 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle
,
515 PublicKeyType
* type
) {
516 // Since we might fail, set the output parameters to default values first.
517 *type
= kPublicKeyTypeUnknown
;
521 OSStatus status
= SecCertificateCopyPublicKey(cert_handle
, &key
);
523 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status
;
526 ScopedCFTypeRef
<SecKeyRef
> scoped_key(key
);
528 const CSSM_KEY
* cssm_key
;
529 status
= SecKeyGetCSSMKey(key
, &cssm_key
);
531 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status
;
535 *size_bits
= cssm_key
->KeyHeader
.LogicalKeySizeInBits
;
537 switch (cssm_key
->KeyHeader
.AlgorithmId
) {
539 *type
= kPublicKeyTypeRSA
;
542 *type
= kPublicKeyTypeDSA
;
544 case CSSM_ALGID_ECDSA
:
545 *type
= kPublicKeyTypeECDSA
;
548 *type
= kPublicKeyTypeDH
;
551 *type
= kPublicKeyTypeUnknown
;