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 "crypto/rsa_private_key.h"
29 #include "net/cert/x509_util_mac.h"
31 using base::mac::ScopedCFTypeRef
;
38 void GetCertDistinguishedName(
39 const x509_util::CSSMCachedCertificate
& cached_cert
,
41 CertPrincipal
* result
) {
42 x509_util::CSSMFieldValue distinguished_name
;
43 OSStatus status
= cached_cert
.GetField(oid
, &distinguished_name
);
44 if (status
|| !distinguished_name
.field())
46 result
->ParseDistinguishedName(distinguished_name
.field()->Data
,
47 distinguished_name
.field()->Length
);
50 bool IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle
,
51 const std::vector
<std::string
>& issuers
) {
52 x509_util::CSSMCachedCertificate cached_cert
;
53 if (cached_cert
.Init(cert_handle
) != CSSM_OK
)
56 x509_util::CSSMFieldValue distinguished_name
;
57 OSStatus status
= cached_cert
.GetField(&CSSMOID_X509V1IssuerNameStd
,
59 if (status
|| !distinguished_name
.field())
62 base::StringPiece
name_piece(
63 reinterpret_cast<const char*>(distinguished_name
.field()->Data
),
64 static_cast<size_t>(distinguished_name
.field()->Length
));
66 for (std::vector
<std::string
>::const_iterator it
= issuers
.begin();
67 it
!= issuers
.end(); ++it
) {
68 base::StringPiece
issuer_piece(*it
);
69 if (name_piece
== issuer_piece
)
76 void GetCertDateForOID(const x509_util::CSSMCachedCertificate
& cached_cert
,
79 *result
= Time::Time();
81 x509_util::CSSMFieldValue field
;
82 OSStatus status
= cached_cert
.GetField(oid
, &field
);
86 const CSSM_X509_TIME
* x509_time
= field
.GetAs
<CSSM_X509_TIME
>();
87 if (x509_time
->timeType
!= BER_TAG_UTC_TIME
&&
88 x509_time
->timeType
!= BER_TAG_GENERALIZED_TIME
) {
89 LOG(ERROR
) << "Unsupported date/time format "
90 << x509_time
->timeType
;
94 base::StringPiece
time_string(
95 reinterpret_cast<const char*>(x509_time
->time
.Data
),
96 x509_time
->time
.Length
);
97 CertDateFormat format
= x509_time
->timeType
== BER_TAG_UTC_TIME
?
98 CERT_DATE_FORMAT_UTC_TIME
: CERT_DATE_FORMAT_GENERALIZED_TIME
;
99 if (!ParseCertificateDate(time_string
, format
, result
))
100 LOG(ERROR
) << "Invalid certificate date/time " << time_string
;
103 std::string
GetCertSerialNumber(
104 const x509_util::CSSMCachedCertificate
& cached_cert
) {
105 x509_util::CSSMFieldValue serial_number
;
106 OSStatus status
= cached_cert
.GetField(&CSSMOID_X509V1SerialNumber
,
108 if (status
|| !serial_number
.field())
109 return std::string();
112 reinterpret_cast<const char*>(serial_number
.field()->Data
),
113 serial_number
.field()->Length
);
116 // Returns true if |purpose| is listed as allowed in |usage|. This
117 // function also considers the "Any" purpose. If the attribute is
118 // present and empty, we return false.
119 bool ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage
* usage
,
120 const CSSM_OID
* purpose
) {
121 for (unsigned p
= 0; p
< usage
->numPurposes
; ++p
) {
122 if (CSSMOIDEqual(&usage
->purposes
[p
], purpose
))
124 if (CSSMOIDEqual(&usage
->purposes
[p
], &CSSMOID_ExtendedKeyUsageAny
))
130 // Test that a given |cert_handle| is actually a valid X.509 certificate, and
131 // return true if it is.
133 // On OS X, SecCertificateCreateFromData() does not return any errors if
134 // called with invalid data, as long as data is present. The actual decoding
135 // of the certificate does not happen until an API that requires a CSSM
136 // handle is called. While SecCertificateGetCLHandle is the most likely
137 // candidate, as it performs the parsing, it does not check whether the
138 // parsing was actually successful. Instead, SecCertificateGetSubject is
139 // used (supported since 10.3), as a means to check that the certificate
140 // parsed as a valid X.509 certificate.
141 bool IsValidOSCertHandle(SecCertificateRef cert_handle
) {
142 const CSSM_X509_NAME
* sanity_check
= NULL
;
143 OSStatus status
= SecCertificateGetSubject(cert_handle
, &sanity_check
);
144 return status
== noErr
&& sanity_check
;
147 // Parses |data| of length |length|, attempting to decode it as the specified
148 // |format|. If |data| is in the specified format, any certificates contained
149 // within are stored into |output|.
150 void AddCertificatesFromBytes(const char* data
, size_t length
,
151 SecExternalFormat format
,
152 X509Certificate::OSCertHandles
* output
) {
153 SecExternalFormat input_format
= format
;
154 ScopedCFTypeRef
<CFDataRef
> local_data(CFDataCreateWithBytesNoCopy(
155 kCFAllocatorDefault
, reinterpret_cast<const UInt8
*>(data
), length
,
158 CFArrayRef items
= NULL
;
161 base::AutoLock
lock(crypto::GetMacSecurityServicesLock());
162 status
= SecKeychainItemImport(local_data
, NULL
, &input_format
,
163 NULL
, 0, NULL
, NULL
, &items
);
167 OSSTATUS_DLOG(WARNING
, status
)
168 << "Unable to import items from data of length " << length
;
172 ScopedCFTypeRef
<CFArrayRef
> scoped_items(items
);
173 CFTypeID cert_type_id
= SecCertificateGetTypeID();
175 for (CFIndex i
= 0; i
< CFArrayGetCount(items
); ++i
) {
176 SecKeychainItemRef item
= reinterpret_cast<SecKeychainItemRef
>(
177 const_cast<void*>(CFArrayGetValueAtIndex(items
, i
)));
179 // While inputFormat implies only certificates will be imported, if/when
180 // other formats (eg: PKCS#12) are supported, this may also include
181 // private keys or other items types, so filter appropriately.
182 if (CFGetTypeID(item
) == cert_type_id
) {
183 SecCertificateRef cert
= reinterpret_cast<SecCertificateRef
>(item
);
184 // OS X ignores |input_format| if it detects that |local_data| is PEM
185 // encoded, attempting to decode data based on internal rules for PEM
186 // block headers. If a PKCS#7 blob is encoded with a PEM block of
187 // CERTIFICATE, OS X 10.5 will return a single, invalid certificate
188 // based on the decoded data. If this happens, the certificate should
189 // not be included in |output|. Because |output| is empty,
190 // CreateCertificateListfromBytes will use PEMTokenizer to decode the
191 // data. When called again with the decoded data, OS X will honor
192 // |input_format|, causing decode to succeed. On OS X 10.6, the data
193 // is properly decoded as a PKCS#7, whether PEM or not, which avoids
194 // the need to fallback to internal decoding.
195 if (IsValidOSCertHandle(cert
)) {
197 output
->push_back(cert
);
203 struct CSSMOIDString
{
204 const CSSM_OID
* oid_
;
208 typedef std::vector
<CSSMOIDString
> CSSMOIDStringVector
;
210 bool CERTNameToCSSMOIDVector(CERTName
* name
, CSSMOIDStringVector
* out_values
) {
213 const CSSM_OID
* cssm_OID_
;
216 const OIDCSSMMap kOIDs
[] = {
217 { SEC_OID_AVA_COMMON_NAME
, &CSSMOID_CommonName
},
218 { SEC_OID_AVA_COUNTRY_NAME
, &CSSMOID_CountryName
},
219 { SEC_OID_AVA_LOCALITY
, &CSSMOID_LocalityName
},
220 { SEC_OID_AVA_STATE_OR_PROVINCE
, &CSSMOID_StateProvinceName
},
221 { SEC_OID_AVA_STREET_ADDRESS
, &CSSMOID_StreetAddress
},
222 { SEC_OID_AVA_ORGANIZATION_NAME
, &CSSMOID_OrganizationName
},
223 { SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME
, &CSSMOID_OrganizationalUnitName
},
224 { SEC_OID_AVA_DN_QUALIFIER
, &CSSMOID_DNQualifier
},
225 { SEC_OID_RFC1274_UID
, &CSSMOID_UniqueIdentifier
},
226 { SEC_OID_PKCS9_EMAIL_ADDRESS
, &CSSMOID_EmailAddress
},
229 CERTRDN
** rdns
= name
->rdns
;
230 for (size_t rdn
= 0; rdns
[rdn
]; ++rdn
) {
231 CERTAVA
** avas
= rdns
[rdn
]->avas
;
232 for (size_t pair
= 0; avas
[pair
] != 0; ++pair
) {
233 SECOidTag tag
= CERT_GetAVATag(avas
[pair
]);
234 if (tag
== SEC_OID_UNKNOWN
) {
237 CSSMOIDString oidString
;
238 bool found_oid
= false;
239 for (size_t oid
= 0; oid
< ARRAYSIZE_UNSAFE(kOIDs
); ++oid
) {
240 if (kOIDs
[oid
].sec_OID_
== tag
) {
241 SECItem
* decode_item
= CERT_DecodeAVAValue(&avas
[pair
]->value
);
245 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
246 std::string
value(reinterpret_cast<char*>(decode_item
->data
),
248 oidString
.oid_
= kOIDs
[oid
].cssm_OID_
;
249 oidString
.string_
= value
;
250 out_values
->push_back(oidString
);
251 SECITEM_FreeItem(decode_item
, PR_TRUE
);
257 DLOG(ERROR
) << "Unrecognized OID: " << tag
;
264 class ScopedCertName
{
266 explicit ScopedCertName(CERTName
* name
) : name_(name
) { }
268 if (name_
) CERT_DestroyName(name_
);
270 operator CERTName
*() { return name_
; }
276 class ScopedEncodedCertResults
{
278 explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET
* results
)
279 : results_(results
) { }
280 ~ScopedEncodedCertResults() {
282 CSSM_ENCODED_CERT
* encCert
=
283 reinterpret_cast<CSSM_ENCODED_CERT
*>(results_
->Results
);
284 for (uint32 i
= 0; i
< results_
->NumberOfResults
; i
++) {
285 crypto::CSSMFree(encCert
[i
].CertBlob
.Data
);
288 crypto::CSSMFree(results_
->Results
);
289 crypto::CSSMFree(results_
);
293 CSSM_TP_RESULT_SET
* results_
;
298 void X509Certificate::Initialize() {
299 x509_util::CSSMCachedCertificate cached_cert
;
300 if (cached_cert
.Init(cert_handle_
) == CSSM_OK
) {
301 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1SubjectNameStd
,
303 GetCertDistinguishedName(cached_cert
, &CSSMOID_X509V1IssuerNameStd
,
305 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotBefore
,
307 GetCertDateForOID(cached_cert
, &CSSMOID_X509V1ValidityNotAfter
,
309 serial_number_
= GetCertSerialNumber(cached_cert
);
312 fingerprint_
= CalculateFingerprint(cert_handle_
);
313 ca_fingerprint_
= CalculateCAFingerprint(intermediate_ca_certs_
);
316 bool X509Certificate::IsIssuedByEncoded(
317 const std::vector
<std::string
>& valid_issuers
) {
318 if (IsCertIssuerInEncodedList(cert_handle_
, valid_issuers
))
321 for (OSCertHandles::iterator it
= intermediate_ca_certs_
.begin();
322 it
!= intermediate_ca_certs_
.end(); ++it
) {
323 if (IsCertIssuerInEncodedList(*it
, valid_issuers
))
330 X509Certificate
* X509Certificate::CreateSelfSigned(
331 crypto::RSAPrivateKey
* key
,
332 const std::string
& subject
,
333 uint32 serial_number
,
334 base::TimeDelta valid_duration
) {
336 DCHECK(!subject
.empty());
338 if (valid_duration
.InSeconds() > kuint32max
) {
339 LOG(ERROR
) << "valid_duration too big " << valid_duration
.InSeconds();
340 valid_duration
= base::TimeDelta::FromSeconds(kuint32max
);
343 // There is a comment in
344 // http://www.opensource.apple.com/source/security_certtool/security_certtool-31828/src/CertTool.cpp
345 // that serial_numbers being passed into CSSM_TP_SubmitCredRequest can't have
346 // their high bit set. We will continue though and mask it out below.
347 if (serial_number
& 0x80000000)
348 LOG(ERROR
) << "serial_number has high bit set " << serial_number
;
350 // NSS is used to parse the subject string into a set of
351 // CSSM_OID/string pairs. There doesn't appear to be a system routine for
352 // parsing Distinguished Name strings.
353 crypto::EnsureNSSInit();
355 CSSMOIDStringVector subject_name_oids
;
356 ScopedCertName
subject_name(
357 CERT_AsciiToName(const_cast<char*>(subject
.c_str())));
358 if (!CERTNameToCSSMOIDVector(subject_name
, &subject_name_oids
)) {
359 DLOG(ERROR
) << "Unable to generate CSSMOIDMap from " << subject
;
363 // Convert the map of oid/string pairs into an array of
364 // CSSM_APPLE_TP_NAME_OIDs.
365 std::vector
<CSSM_APPLE_TP_NAME_OID
> cssm_subject_names
;
366 for (CSSMOIDStringVector::iterator iter
= subject_name_oids
.begin();
367 iter
!= subject_name_oids
.end(); ++iter
) {
368 CSSM_APPLE_TP_NAME_OID cssm_subject_name
;
369 cssm_subject_name
.oid
= iter
->oid_
;
370 cssm_subject_name
.string
= iter
->string_
.c_str();
371 cssm_subject_names
.push_back(cssm_subject_name
);
374 if (cssm_subject_names
.empty()) {
375 DLOG(ERROR
) << "cssm_subject_names.size() == 0. Input: " << subject
;
379 // Set up a certificate request.
380 CSSM_APPLE_TP_CERT_REQUEST certReq
;
381 memset(&certReq
, 0, sizeof(certReq
));
382 certReq
.cspHand
= crypto::GetSharedCSPHandle();
383 certReq
.clHand
= crypto::GetSharedCLHandle();
384 // See comment about serial numbers above.
385 certReq
.serialNumber
= serial_number
& 0x7fffffff;
386 certReq
.numSubjectNames
= cssm_subject_names
.size();
387 certReq
.subjectNames
= &cssm_subject_names
[0];
388 certReq
.numIssuerNames
= 0; // Root.
389 certReq
.issuerNames
= NULL
;
390 certReq
.issuerNameX509
= NULL
;
391 certReq
.certPublicKey
= key
->public_key();
392 certReq
.issuerPrivateKey
= key
->key();
393 // These are the Apple defaults.
394 certReq
.signatureAlg
= CSSM_ALGID_SHA1WithRSA
;
395 certReq
.signatureOid
= CSSMOID_SHA1WithRSA
;
396 certReq
.notBefore
= 0;
397 certReq
.notAfter
= static_cast<uint32
>(valid_duration
.InSeconds());
398 certReq
.numExtensions
= 0;
399 certReq
.extensions
= NULL
;
400 certReq
.challengeString
= NULL
;
402 CSSM_TP_REQUEST_SET reqSet
;
403 reqSet
.NumberOfRequests
= 1;
404 reqSet
.Requests
= &certReq
;
407 memset(&policyId
, 0, sizeof(policyId
));
408 policyId
.FieldOid
= CSSMOID_APPLE_TP_LOCAL_CERT_GEN
;
410 CSSM_TP_CALLERAUTH_CONTEXT callerAuthContext
;
411 memset(&callerAuthContext
, 0, sizeof(callerAuthContext
));
412 callerAuthContext
.Policy
.NumberOfPolicyIds
= 1;
413 callerAuthContext
.Policy
.PolicyIds
= &policyId
;
415 CSSM_TP_HANDLE tp_handle
= crypto::GetSharedTPHandle();
417 memset(&refId
, 0, sizeof(refId
));
419 CSSM_RETURN crtn
= CSSM_TP_SubmitCredRequest(tp_handle
, NULL
,
420 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE
, &reqSet
, &callerAuthContext
,
423 DLOG(ERROR
) << "CSSM_TP_SubmitCredRequest failed " << crtn
;
427 CSSM_BOOL confirmRequired
;
428 CSSM_TP_RESULT_SET
* resultSet
= NULL
;
429 crtn
= CSSM_TP_RetrieveCredResult(tp_handle
, &refId
, NULL
, &estTime
,
430 &confirmRequired
, &resultSet
);
431 ScopedEncodedCertResults
scopedResults(resultSet
);
432 crypto::CSSMFree(refId
.Data
);
434 DLOG(ERROR
) << "CSSM_TP_RetrieveCredResult failed " << crtn
;
438 if (confirmRequired
) {
439 // Potential leak here of resultSet. |confirmRequired| should never be
441 DLOG(ERROR
) << "CSSM_TP_RetrieveCredResult required confirmation";
445 if (resultSet
->NumberOfResults
!= 1) {
446 DLOG(ERROR
) << "Unexpected number of results: "
447 << resultSet
->NumberOfResults
;
451 CSSM_ENCODED_CERT
* encCert
=
452 reinterpret_cast<CSSM_ENCODED_CERT
*>(resultSet
->Results
);
453 ScopedCFTypeRef
<SecCertificateRef
> scoped_cert
;
454 SecCertificateRef certificate_ref
= NULL
;
456 SecCertificateCreateFromData(&encCert
->CertBlob
, encCert
->CertType
,
457 encCert
->CertEncoding
, &certificate_ref
);
458 if (os_status
!= 0) {
459 OSSTATUS_DLOG(ERROR
, os_status
) << "SecCertificateCreateFromData failed";
462 scoped_cert
.reset(certificate_ref
);
464 return CreateFromHandle(scoped_cert
, X509Certificate::OSCertHandles());
467 void X509Certificate::GetSubjectAltName(
468 std::vector
<std::string
>* dns_names
,
469 std::vector
<std::string
>* ip_addrs
) const {
475 x509_util::CSSMCachedCertificate cached_cert
;
476 OSStatus status
= cached_cert
.Init(cert_handle_
);
479 x509_util::CSSMFieldValue subject_alt_name
;
480 status
= cached_cert
.GetField(&CSSMOID_SubjectAltName
, &subject_alt_name
);
481 if (status
|| !subject_alt_name
.field())
483 const CSSM_X509_EXTENSION
* cssm_ext
=
484 subject_alt_name
.GetAs
<CSSM_X509_EXTENSION
>();
485 if (!cssm_ext
|| !cssm_ext
->value
.parsedValue
)
487 const CE_GeneralNames
* alt_name
=
488 reinterpret_cast<const CE_GeneralNames
*>(cssm_ext
->value
.parsedValue
);
490 for (size_t name
= 0; name
< alt_name
->numNames
; ++name
) {
491 const CE_GeneralName
& name_struct
= alt_name
->generalName
[name
];
492 const CSSM_DATA
& name_data
= name_struct
.name
;
493 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
494 // respectively, both of which can be byte copied from
495 // CSSM_DATA::data into the appropriate output vector.
496 if (dns_names
&& name_struct
.nameType
== GNT_DNSName
) {
497 dns_names
->push_back(std::string(
498 reinterpret_cast<const char*>(name_data
.Data
),
500 } else if (ip_addrs
&& name_struct
.nameType
== GNT_IPAddress
) {
501 ip_addrs
->push_back(std::string(
502 reinterpret_cast<const char*>(name_data
.Data
),
509 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle
,
510 std::string
* encoded
) {
512 if (SecCertificateGetData(cert_handle
, &der_data
) != noErr
)
514 encoded
->assign(reinterpret_cast<char*>(der_data
.Data
),
520 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a
,
521 X509Certificate::OSCertHandle b
) {
527 CSSM_DATA a_data
, b_data
;
528 return SecCertificateGetData(a
, &a_data
) == noErr
&&
529 SecCertificateGetData(b
, &b_data
) == noErr
&&
530 a_data
.Length
== b_data
.Length
&&
531 memcmp(a_data
.Data
, b_data
.Data
, a_data
.Length
) == 0;
535 X509Certificate::OSCertHandle
X509Certificate::CreateOSCertHandleFromBytes(
536 const char* data
, int length
) {
538 cert_data
.Data
= const_cast<uint8
*>(reinterpret_cast<const uint8
*>(data
));
539 cert_data
.Length
= length
;
541 OSCertHandle cert_handle
= NULL
;
542 OSStatus status
= SecCertificateCreateFromData(&cert_data
,
544 CSSM_CERT_ENCODING_DER
,
548 if (!IsValidOSCertHandle(cert_handle
)) {
549 CFRelease(cert_handle
);
556 X509Certificate::OSCertHandles
X509Certificate::CreateOSCertHandlesFromBytes(
557 const char* data
, int length
, Format format
) {
558 OSCertHandles results
;
561 case FORMAT_SINGLE_CERTIFICATE
: {
562 OSCertHandle handle
= CreateOSCertHandleFromBytes(data
, length
);
564 results
.push_back(handle
);
568 AddCertificatesFromBytes(data
, length
, kSecFormatPKCS7
, &results
);
571 NOTREACHED() << "Certificate format " << format
<< " unimplemented";
579 X509Certificate::OSCertHandle
X509Certificate::DupOSCertHandle(
580 OSCertHandle handle
) {
583 return reinterpret_cast<OSCertHandle
>(const_cast<void*>(CFRetain(handle
)));
587 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle
) {
588 CFRelease(cert_handle
);
592 SHA1HashValue
X509Certificate::CalculateFingerprint(
595 memset(sha1
.data
, 0, sizeof(sha1
.data
));
598 OSStatus status
= SecCertificateGetData(cert
, &cert_data
);
602 DCHECK(cert_data
.Data
);
603 DCHECK_NE(cert_data
.Length
, 0U);
605 CC_SHA1(cert_data
.Data
, cert_data
.Length
, sha1
.data
);
611 SHA1HashValue
X509Certificate::CalculateCAFingerprint(
612 const OSCertHandles
& intermediates
) {
614 memset(sha1
.data
, 0, sizeof(sha1
.data
));
616 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
617 // we don't check their return values.
618 CC_SHA1_CTX sha1_ctx
;
619 CC_SHA1_Init(&sha1_ctx
);
621 for (size_t i
= 0; i
< intermediates
.size(); ++i
) {
622 OSStatus status
= SecCertificateGetData(intermediates
[i
], &cert_data
);
625 CC_SHA1_Update(&sha1_ctx
, cert_data
.Data
, cert_data
.Length
);
627 CC_SHA1_Final(sha1
.data
, &sha1_ctx
);
632 bool X509Certificate::SupportsSSLClientAuth() const {
633 x509_util::CSSMCachedCertificate cached_cert
;
634 OSStatus status
= cached_cert
.Init(cert_handle_
);
638 // RFC5280 says to take the intersection of the two extensions.
640 // Our underlying crypto libraries don't expose
641 // ClientCertificateType, so for now we will not support fixed
642 // Diffie-Hellman mechanisms. For rsa_sign, we need the
643 // digitalSignature bit.
645 // In particular, if a key has the nonRepudiation bit and not the
646 // digitalSignature one, we will not offer it to the user.
647 x509_util::CSSMFieldValue key_usage
;
648 status
= cached_cert
.GetField(&CSSMOID_KeyUsage
, &key_usage
);
649 if (status
== CSSM_OK
&& key_usage
.field()) {
650 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
651 const CE_KeyUsage
* key_usage_value
=
652 reinterpret_cast<const CE_KeyUsage
*>(ext
->value
.parsedValue
);
653 if (!((*key_usage_value
) & CE_KU_DigitalSignature
))
657 status
= cached_cert
.GetField(&CSSMOID_ExtendedKeyUsage
, &key_usage
);
658 if (status
== CSSM_OK
&& key_usage
.field()) {
659 const CSSM_X509_EXTENSION
* ext
= key_usage
.GetAs
<CSSM_X509_EXTENSION
>();
660 const CE_ExtendedKeyUsage
* ext_key_usage
=
661 reinterpret_cast<const CE_ExtendedKeyUsage
*>(ext
->value
.parsedValue
);
662 if (!ExtendedKeyUsageAllows(ext_key_usage
, &CSSMOID_ClientAuth
))
668 CFArrayRef
X509Certificate::CreateOSCertChainForCert() const {
669 CFMutableArrayRef cert_list
=
670 CFArrayCreateMutable(kCFAllocatorDefault
, 0,
671 &kCFTypeArrayCallBacks
);
675 CFArrayAppendValue(cert_list
, os_cert_handle());
676 for (size_t i
= 0; i
< intermediate_ca_certs_
.size(); ++i
)
677 CFArrayAppendValue(cert_list
, intermediate_ca_certs_
[i
]);
683 X509Certificate::OSCertHandle
684 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator
* pickle_iter
) {
687 if (!pickle_iter
->ReadData(&data
, &length
))
690 return CreateOSCertHandleFromBytes(data
, length
);
694 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle
,
697 OSStatus status
= SecCertificateGetData(cert_handle
, &cert_data
);
701 return pickle
->WriteData(reinterpret_cast<char*>(cert_data
.Data
),
706 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle
,
708 PublicKeyType
* type
) {
709 // Since we might fail, set the output parameters to default values first.
710 *type
= kPublicKeyTypeUnknown
;
714 OSStatus status
= SecCertificateCopyPublicKey(cert_handle
, &key
);
716 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status
;
719 ScopedCFTypeRef
<SecKeyRef
> scoped_key(key
);
721 const CSSM_KEY
* cssm_key
;
722 status
= SecKeyGetCSSMKey(key
, &cssm_key
);
724 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status
;
728 *size_bits
= cssm_key
->KeyHeader
.LogicalKeySizeInBits
;
730 switch (cssm_key
->KeyHeader
.AlgorithmId
) {
732 *type
= kPublicKeyTypeRSA
;
735 *type
= kPublicKeyTypeDSA
;
737 case CSSM_ALGID_ECDSA
:
738 *type
= kPublicKeyTypeECDSA
;
741 *type
= kPublicKeyTypeDH
;
744 *type
= kPublicKeyTypeUnknown
;