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 bool CERTNameToCSSMOIDVector(CERTName
* name
, CSSMOIDStringVector
* out_values
) {
212 const CSSM_OID
* cssm_OID_
;
215 const OIDCSSMMap kOIDs
[] = {
216 { SEC_OID_AVA_COMMON_NAME
, &CSSMOID_CommonName
},
217 { SEC_OID_AVA_COUNTRY_NAME
, &CSSMOID_CountryName
},
218 { SEC_OID_AVA_LOCALITY
, &CSSMOID_LocalityName
},
219 { SEC_OID_AVA_STATE_OR_PROVINCE
, &CSSMOID_StateProvinceName
},
220 { SEC_OID_AVA_STREET_ADDRESS
, &CSSMOID_StreetAddress
},
221 { SEC_OID_AVA_ORGANIZATION_NAME
, &CSSMOID_OrganizationName
},
222 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME
, &CSSMOID_OrganizationalUnitName
},
223 { SEC_OID_AVA_DN_QUALIFIER
, &CSSMOID_DNQualifier
},
224 { SEC_OID_RFC1274_UID
, &CSSMOID_UniqueIdentifier
},
225 { SEC_OID_PKCS9_EMAIL_ADDRESS
, &CSSMOID_EmailAddress
},
228 CERTRDN
** rdns
= name
->rdns
;
229 for (size_t rdn
= 0; rdns
[rdn
]; ++rdn
) {
230 CERTAVA
** avas
= rdns
[rdn
]->avas
;
231 for (size_t pair
= 0; avas
[pair
] != 0; ++pair
) {
232 SECOidTag tag
= CERT_GetAVATag(avas
[pair
]);
233 if (tag
== SEC_OID_UNKNOWN
) {
236 CSSMOIDString oidString
;
237 bool found_oid
= false;
238 for (size_t oid
= 0; oid
< ARRAYSIZE_UNSAFE(kOIDs
); ++oid
) {
239 if (kOIDs
[oid
].sec_OID_
== tag
) {
240 SECItem
* decode_item
= CERT_DecodeAVAValue(&avas
[pair
]->value
);
244 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
245 std::string
value(reinterpret_cast<char*>(decode_item
->data
),
247 oidString
.oid_
= kOIDs
[oid
].cssm_OID_
;
248 oidString
.string_
= value
;
249 out_values
->push_back(oidString
);
250 SECITEM_FreeItem(decode_item
, PR_TRUE
);
256 DLOG(ERROR
) << "Unrecognized OID: " << tag
;
263 class ScopedCertName
{
265 explicit ScopedCertName(CERTName
* name
) : name_(name
) { }
267 if (name_
) CERT_DestroyName(name_
);
269 operator CERTName
*() { return name_
; }
275 class ScopedEncodedCertResults
{
277 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET
* results
)
278 : results_(results
) { }
279 ~ScopedEncodedCertResults() {
281 CSSM_ENCODED_CERT
* encCert
=
282 reinterpret_cast<CSSM_ENCODED_CERT
*>(results_
->Results
);
283 for (uint32 i
= 0; i
< results_
->NumberOfResults
; i
++) {
284 crypto::CSSMFree(encCert
[i
].CertBlob
.Data
);
287 crypto::CSSMFree(results_
->Results
);
288 crypto::CSSMFree(results_
);
292 CSSM_TP_RESULT_SET
* results_
;
297 void X509Certificate::Initialize() {
298 x509_util::CSSMCachedCertificate cached_cert
;
299 if (cached_cert
.Init(cert_handle_
) == CSSM_OK
) {
300 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1SubjectNameStd
,
302 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1IssuerNameStd
,
304 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotBefore
,
306 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotAfter
,
308 serial_number_
= GetCertSerialNumber(cached_cert
);
311 fingerprint_
= CalculateFingerprint(cert_handle_
);
312 ca_fingerprint_
= CalculateCAFingerprint(intermediate_ca_certs_
);
315 bool X509Certificate::IsIssuedByEncoded(
316 const std::vector
<std::string
>& valid_issuers
) {
317 if (IsCertIssuerInEncodedList(cert_handle_
, valid_issuers
))
320 for (OSCertHandles::iterator it
= intermediate_ca_certs_
.begin();
321 it
!= intermediate_ca_certs_
.end(); ++it
) {
322 if (IsCertIssuerInEncodedList(*it
, valid_issuers
))
328 void X509Certificate::GetSubjectAltName(
329 std::vector
<std::string
>* dns_names
,
330 std::vector
<std::string
>* ip_addrs
) const {
336 x509_util::CSSMCachedCertificate cached_cert
;
337 OSStatus status
= cached_cert
.Init(cert_handle_
);
340 x509_util::CSSMFieldValue subject_alt_name
;
341 status
= cached_cert
.GetField(&CSSMOID_SubjectAltName
, &subject_alt_name
);
342 if (status
|| !subject_alt_name
.field())
344 const CSSM_X509_EXTENSION
* cssm_ext
=
345 subject_alt_name
.GetAs
<CSSM_X509_EXTENSION
>();
346 if (!cssm_ext
|| !cssm_ext
->value
.parsedValue
)
348 const CE_GeneralNames
* alt_name
=
349 reinterpret_cast<const CE_GeneralNames
*>(cssm_ext
->value
.parsedValue
);
351 for (size_t name
= 0; name
< alt_name
->numNames
; ++name
) {
352 const CE_GeneralName
& name_struct
= alt_name
->generalName
[name
];
353 const CSSM_DATA
& name_data
= name_struct
.name
;
354 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
355 // respectively, both of which can be byte copied from
356 // CSSM_DATA::data into the appropriate output vector.
357 if (dns_names
&& name_struct
.nameType
== GNT_DNSName
) {
358 dns_names
->push_back(std::string(
359 reinterpret_cast<const char*>(name_data
.Data
),
361 } else if (ip_addrs
&& name_struct
.nameType
== GNT_IPAddress
) {
362 ip_addrs
->push_back(std::string(
363 reinterpret_cast<const char*>(name_data
.Data
),
370 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle
,
371 std::string
* encoded
) {
373 if (SecCertificateGetData(cert_handle
, &der_data
) != noErr
)
375 encoded
->assign(reinterpret_cast<char*>(der_data
.Data
),
381 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a
,
382 X509Certificate::OSCertHandle b
) {
388 CSSM_DATA a_data
, b_data
;
389 return SecCertificateGetData(a
, &a_data
) == noErr
&&
390 SecCertificateGetData(b
, &b_data
) == noErr
&&
391 a_data
.Length
== b_data
.Length
&&
392 memcmp(a_data
.Data
, b_data
.Data
, a_data
.Length
) == 0;
396 X509Certificate::OSCertHandle
X509Certificate::CreateOSCertHandleFromBytes(
397 const char* data
, int length
) {
399 cert_data
.Data
= const_cast<uint8
*>(reinterpret_cast<const uint8
*>(data
));
400 cert_data
.Length
= length
;
402 OSCertHandle cert_handle
= NULL
;
403 OSStatus status
= SecCertificateCreateFromData(&cert_data
,
405 CSSM_CERT_ENCODING_DER
,
409 if (!IsValidOSCertHandle(cert_handle
)) {
410 CFRelease(cert_handle
);
417 X509Certificate::OSCertHandles
X509Certificate::CreateOSCertHandlesFromBytes(
418 const char* data
, int length
, Format format
) {
419 OSCertHandles results
;
422 case FORMAT_SINGLE_CERTIFICATE
: {
423 OSCertHandle handle
= CreateOSCertHandleFromBytes(data
, length
);
425 results
.push_back(handle
);
429 AddCertificatesFromBytes(data
, length
, kSecFormatPKCS7
, &results
);
432 NOTREACHED() << "Certificate format " << format
<< " unimplemented";
440 X509Certificate::OSCertHandle
X509Certificate::DupOSCertHandle(
441 OSCertHandle handle
) {
444 return reinterpret_cast<OSCertHandle
>(const_cast<void*>(CFRetain(handle
)));
448 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle
) {
449 CFRelease(cert_handle
);
453 SHA1HashValue
X509Certificate::CalculateFingerprint(
456 memset(sha1
.data
, 0, sizeof(sha1
.data
));
459 OSStatus status
= SecCertificateGetData(cert
, &cert_data
);
463 DCHECK(cert_data
.Data
);
464 DCHECK_NE(cert_data
.Length
, 0U);
466 CC_SHA1(cert_data
.Data
, cert_data
.Length
, sha1
.data
);
472 SHA1HashValue
X509Certificate::CalculateCAFingerprint(
473 const OSCertHandles
& intermediates
) {
475 memset(sha1
.data
, 0, sizeof(sha1
.data
));
477 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
478 // we don't check their return values.
479 CC_SHA1_CTX sha1_ctx
;
480 CC_SHA1_Init(&sha1_ctx
);
482 for (size_t i
= 0; i
< intermediates
.size(); ++i
) {
483 OSStatus status
= SecCertificateGetData(intermediates
[i
], &cert_data
);
486 CC_SHA1_Update(&sha1_ctx
, cert_data
.Data
, cert_data
.Length
);
488 CC_SHA1_Final(sha1
.data
, &sha1_ctx
);
493 bool X509Certificate::SupportsSSLClientAuth() const {
494 x509_util::CSSMCachedCertificate cached_cert
;
495 OSStatus status
= cached_cert
.Init(cert_handle_
);
499 // RFC5280 says to take the intersection of the two extensions.
501 // Our underlying crypto libraries don't expose
502 // ClientCertificateType, so for now we will not support fixed
503 // Diffie-Hellman mechanisms. For rsa_sign, we need the
504 // digitalSignature bit.
506 // In particular, if a key has the nonRepudiation bit and not the
507 // digitalSignature one, we will not offer it to the user.
508 x509_util::CSSMFieldValue key_usage
;
509 status
= cached_cert
.GetField(&CSSMOID_KeyUsage
, &key_usage
);
510 if (status
== CSSM_OK
&& key_usage
.field()) {
511 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
512 const CE_KeyUsage
* key_usage_value
=
513 reinterpret_cast<const CE_KeyUsage
*>(ext
->value
.parsedValue
);
514 if (!((*key_usage_value
) & CE_KU_DigitalSignature
))
518 status
= cached_cert
.GetField(&CSSMOID_ExtendedKeyUsage
, &key_usage
);
519 if (status
== CSSM_OK
&& key_usage
.field()) {
520 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
521 const CE_ExtendedKeyUsage
* ext_key_usage
=
522 reinterpret_cast<const CE_ExtendedKeyUsage
*>(ext
->value
.parsedValue
);
523 if (!ExtendedKeyUsageAllows(ext_key_usage
, &CSSMOID_ClientAuth
))
529 CFArrayRef
X509Certificate::CreateOSCertChainForCert() const {
530 CFMutableArrayRef cert_list
=
531 CFArrayCreateMutable(kCFAllocatorDefault
, 0,
532 &kCFTypeArrayCallBacks
);
536 CFArrayAppendValue(cert_list
, os_cert_handle());
537 for (size_t i
= 0; i
< intermediate_ca_certs_
.size(); ++i
)
538 CFArrayAppendValue(cert_list
, intermediate_ca_certs_
[i
]);
544 X509Certificate::OSCertHandle
545 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator
* pickle_iter
) {
548 if (!pickle_iter
->ReadData(&data
, &length
))
551 return CreateOSCertHandleFromBytes(data
, length
);
555 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle
,
558 OSStatus status
= SecCertificateGetData(cert_handle
, &cert_data
);
562 return pickle
->WriteData(reinterpret_cast<char*>(cert_data
.Data
),
567 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle
,
569 PublicKeyType
* type
) {
570 // Since we might fail, set the output parameters to default values first.
571 *type
= kPublicKeyTypeUnknown
;
575 OSStatus status
= SecCertificateCopyPublicKey(cert_handle
, &key
);
577 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status
;
580 ScopedCFTypeRef
<SecKeyRef
> scoped_key(key
);
582 const CSSM_KEY
* cssm_key
;
583 status
= SecKeyGetCSSMKey(key
, &cssm_key
);
585 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status
;
589 *size_bits
= cssm_key
->KeyHeader
.LogicalKeySizeInBits
;
591 switch (cssm_key
->KeyHeader
.AlgorithmId
) {
593 *type
= kPublicKeyTypeRSA
;
596 *type
= kPublicKeyTypeDSA
;
598 case CSSM_ALGID_ECDSA
:
599 *type
= kPublicKeyTypeECDSA
;
602 *type
= kPublicKeyTypeDH
;
605 *type
= kPublicKeyTypeUnknown
;