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.
4
5 #include "net/cert/x509_certificate.h"
6
7 #include <CommonCrypto/CommonDigest.h>
8 #include <CoreServices/CoreServices.h>
9 #include <Security/Security.h>
10
11 #include <vector>
12
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"
26
27 using base::ScopedCFTypeRef;
28 using base::Time;
29
30 namespace net {
31
32 namespace {
33
GetCertDistinguishedName(const x509_util::CSSMCachedCertificate & cached_cert,const CSSM_OID * oid,CertPrincipal * result)34 void GetCertDistinguishedName(
35 const x509_util::CSSMCachedCertificate& cached_cert,
36 const CSSM_OID* oid,
37 CertPrincipal* result) {
38 x509_util::CSSMFieldValue distinguished_name;
39 OSStatus status = cached_cert.GetField(oid, &distinguished_name);
40 if (status || !distinguished_name.field())
41 return;
42 result->ParseDistinguishedName(distinguished_name.field()->Data,
43 distinguished_name.field()->Length);
44 }
45
IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle,const std::vector<std::string> & issuers)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)
50 return false;
51
52 x509_util::CSSMFieldValue distinguished_name;
53 OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd,
54 &distinguished_name);
55 if (status || !distinguished_name.field())
56 return false;
57
58 base::StringPiece name_piece(
59 reinterpret_cast<const char*>(distinguished_name.field()->Data),
60 static_cast<size_t>(distinguished_name.field()->Length));
61
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)
66 return true;
67 }
68
69 return false;
70 }
71
GetCertDateForOID(const x509_util::CSSMCachedCertificate & cached_cert,const CSSM_OID * oid,Time * result)72 void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert,
73 const CSSM_OID* oid,
74 Time* result) {
75 *result = Time::Time();
76
77 x509_util::CSSMFieldValue field;
78 OSStatus status = cached_cert.GetField(oid, &field);
79 if (status)
80 return;
81
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;
87 return;
88 }
89
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;
97 }
98
GetCertSerialNumber(const x509_util::CSSMCachedCertificate & cached_cert)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,
103 &serial_number);
104 if (status || !serial_number.field())
105 return std::string();
106
107 return std::string(
108 reinterpret_cast<const char*>(serial_number.field()->Data),
109 serial_number.field()->Length);
110 }
111
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.
ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage * usage,const CSSM_OID * purpose)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))
119 return true;
120 if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny))
121 return true;
122 }
123 return false;
124 }
125
126 // Test that a given |cert_handle| is actually a valid X.509 certificate, and
127 // return true if it is.
128 //
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.
IsValidOSCertHandle(SecCertificateRef cert_handle)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;
141 }
142
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|.
AddCertificatesFromBytes(const char * data,size_t length,SecExternalFormat format,X509Certificate::OSCertHandles * 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,
152 kCFAllocatorNull));
153
154 CFArrayRef items = NULL;
155 OSStatus status;
156 {
157 base::AutoLock lock(crypto::GetMacSecurityServicesLock());
158 status = SecKeychainItemImport(local_data, NULL, &input_format,
159 NULL, 0, NULL, NULL, &items);
160 }
161
162 if (status) {
163 OSSTATUS_DLOG(WARNING, status)
164 << "Unable to import items from data of length " << length;
165 return;
166 }
167
168 ScopedCFTypeRef<CFArrayRef> scoped_items(items);
169 CFTypeID cert_type_id = SecCertificateGetTypeID();
170
171 for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
172 SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>(
173 const_cast<void*>(CFArrayGetValueAtIndex(items, i)));
174
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)) {
192 CFRetain(cert);
193 output->push_back(cert);
194 }
195 }
196 }
197 }
198
199 } // namespace
200
Initialize()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,
205 &subject_);
206 GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
207 &issuer_);
208 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
209 &valid_start_);
210 GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
211 &valid_expiry_);
212 serial_number_ = GetCertSerialNumber(cached_cert);
213 }
214
215 fingerprint_ = CalculateFingerprint(cert_handle_);
216 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
217 }
218
IsIssuedByEncoded(const std::vector<std::string> & valid_issuers)219 bool X509Certificate::IsIssuedByEncoded(
220 const std::vector<std::string>& valid_issuers) {
221 if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
222 return true;
223
224 for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
225 it != intermediate_ca_certs_.end(); ++it) {
226 if (IsCertIssuerInEncodedList(*it, valid_issuers))
227 return true;
228 }
229 return false;
230 }
231
GetSubjectAltName(std::vector<std::string> * dns_names,std::vector<std::string> * ip_addrs) const232 void X509Certificate::GetSubjectAltName(
233 std::vector<std::string>* dns_names,
234 std::vector<std::string>* ip_addrs) const {
235 if (dns_names)
236 dns_names->clear();
237 if (ip_addrs)
238 ip_addrs->clear();
239
240 x509_util::CSSMCachedCertificate cached_cert;
241 OSStatus status = cached_cert.Init(cert_handle_);
242 if (status)
243 return;
244 x509_util::CSSMFieldValue subject_alt_name;
245 status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
246 if (status || !subject_alt_name.field())
247 return;
248 const CSSM_X509_EXTENSION* cssm_ext =
249 subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
250 if (!cssm_ext || !cssm_ext->value.parsedValue)
251 return;
252 const CE_GeneralNames* alt_name =
253 reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
254
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),
264 name_data.Length));
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),
268 name_data.Length));
269 }
270 }
271 }
272
273 // static
GetDEREncoded(X509Certificate::OSCertHandle cert_handle,std::string * encoded)274 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
275 std::string* encoded) {
276 CSSM_DATA der_data;
277 if (!cert_handle || SecCertificateGetData(cert_handle, &der_data) != noErr)
278 return false;
279 encoded->assign(reinterpret_cast<char*>(der_data.Data),
280 der_data.Length);
281 return true;
282 }
283
284 // static
IsSameOSCert(X509Certificate::OSCertHandle a,X509Certificate::OSCertHandle b)285 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
286 X509Certificate::OSCertHandle b) {
287 DCHECK(a && b);
288 if (a == b)
289 return true;
290 if (CFEqual(a, b))
291 return true;
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;
297 }
298
299 // static
CreateOSCertHandleFromBytes(const char * data,int length)300 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
301 const char* data, int length) {
302 CSSM_DATA cert_data;
303 cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
304 cert_data.Length = length;
305
306 OSCertHandle cert_handle = NULL;
307 OSStatus status = SecCertificateCreateFromData(&cert_data,
308 CSSM_CERT_X_509v3,
309 CSSM_CERT_ENCODING_DER,
310 &cert_handle);
311 if (status != noErr)
312 return NULL;
313 if (!IsValidOSCertHandle(cert_handle)) {
314 CFRelease(cert_handle);
315 return NULL;
316 }
317 return cert_handle;
318 }
319
320 // static
CreateOSCertHandlesFromBytes(const char * data,int length,Format format)321 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
322 const char* data, int length, Format format) {
323 OSCertHandles results;
324
325 switch (format) {
326 case FORMAT_SINGLE_CERTIFICATE: {
327 OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
328 if (handle)
329 results.push_back(handle);
330 break;
331 }
332 case FORMAT_PKCS7:
333 AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
334 break;
335 default:
336 NOTREACHED() << "Certificate format " << format << " unimplemented";
337 break;
338 }
339
340 return results;
341 }
342
343 // static
DupOSCertHandle(OSCertHandle handle)344 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
345 OSCertHandle handle) {
346 if (!handle)
347 return NULL;
348 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
349 }
350
351 // static
FreeOSCertHandle(OSCertHandle cert_handle)352 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
353 if (cert_handle)
354 CFRelease(cert_handle);
355 }
356
357 // static
CalculateFingerprint(OSCertHandle cert)358 SHA1HashValue X509Certificate::CalculateFingerprint(
359 OSCertHandle cert) {
360 SHA1HashValue sha1;
361 memset(sha1.data, 0, sizeof(sha1.data));
362
363 CSSM_DATA cert_data;
364 OSStatus status = SecCertificateGetData(cert, &cert_data);
365 if (status)
366 return sha1;
367
368 DCHECK(cert_data.Data);
369 DCHECK_NE(cert_data.Length, 0U);
370
371 CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
372
373 return sha1;
374 }
375
376 // static
CalculateCAFingerprint(const OSCertHandles & intermediates)377 SHA1HashValue X509Certificate::CalculateCAFingerprint(
378 const OSCertHandles& intermediates) {
379 SHA1HashValue sha1;
380 memset(sha1.data, 0, sizeof(sha1.data));
381
382 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
383 // we don't check their return values.
384 CC_SHA1_CTX sha1_ctx;
385 CC_SHA1_Init(&sha1_ctx);
386 CSSM_DATA cert_data;
387 for (size_t i = 0; i < intermediates.size(); ++i) {
388 OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
389 if (status)
390 return sha1;
391 CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
392 }
393 CC_SHA1_Final(sha1.data, &sha1_ctx);
394
395 return sha1;
396 }
397
SupportsSSLClientAuth() const398 bool X509Certificate::SupportsSSLClientAuth() const {
399 x509_util::CSSMCachedCertificate cached_cert;
400 OSStatus status = cached_cert.Init(cert_handle_);
401 if (status)
402 return false;
403
404 // RFC5280 says to take the intersection of the two extensions.
405 //
406 // Our underlying crypto libraries don't expose
407 // ClientCertificateType, so for now we will not support fixed
408 // Diffie-Hellman mechanisms. For rsa_sign, we need the
409 // digitalSignature bit.
410 //
411 // In particular, if a key has the nonRepudiation bit and not the
412 // digitalSignature one, we will not offer it to the user.
413 x509_util::CSSMFieldValue key_usage;
414 status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage);
415 if (status == CSSM_OK && key_usage.field()) {
416 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
417 const CE_KeyUsage* key_usage_value =
418 reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue);
419 if (!((*key_usage_value) & CE_KU_DigitalSignature))
420 return false;
421 }
422
423 status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage);
424 if (status == CSSM_OK && key_usage.field()) {
425 const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
426 const CE_ExtendedKeyUsage* ext_key_usage =
427 reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
428 if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth))
429 return false;
430 }
431 return true;
432 }
433
CreateOSCertChainForCert() const434 CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
435 CFMutableArrayRef cert_list =
436 CFArrayCreateMutable(kCFAllocatorDefault, 0,
437 &kCFTypeArrayCallBacks);
438 if (!cert_list)
439 return NULL;
440
441 CFArrayAppendValue(cert_list, os_cert_handle());
442 for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
443 CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
444
445 return cert_list;
446 }
447
448 // static
449 X509Certificate::OSCertHandle
ReadOSCertHandleFromPickle(PickleIterator * pickle_iter)450 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
451 const char* data;
452 int length;
453 if (!pickle_iter->ReadData(&data, &length))
454 return NULL;
455
456 return CreateOSCertHandleFromBytes(data, length);
457 }
458
459 // static
WriteOSCertHandleToPickle(OSCertHandle cert_handle,Pickle * pickle)460 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
461 Pickle* pickle) {
462 CSSM_DATA cert_data;
463 OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
464 if (status)
465 return false;
466
467 return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
468 cert_data.Length);
469 }
470
471 // static
GetPublicKeyInfo(OSCertHandle cert_handle,size_t * size_bits,PublicKeyType * type)472 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
473 size_t* size_bits,
474 PublicKeyType* type) {
475 // Since we might fail, set the output parameters to default values first.
476 *type = kPublicKeyTypeUnknown;
477 *size_bits = 0;
478
479 SecKeyRef key;
480 OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
481 if (status) {
482 NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
483 return;
484 }
485 ScopedCFTypeRef<SecKeyRef> scoped_key(key);
486
487 const CSSM_KEY* cssm_key;
488 status = SecKeyGetCSSMKey(key, &cssm_key);
489 if (status) {
490 NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
491 return;
492 }
493
494 *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
495
496 switch (cssm_key->KeyHeader.AlgorithmId) {
497 case CSSM_ALGID_RSA:
498 *type = kPublicKeyTypeRSA;
499 break;
500 case CSSM_ALGID_DSA:
501 *type = kPublicKeyTypeDSA;
502 break;
503 case CSSM_ALGID_ECDSA:
504 *type = kPublicKeyTypeECDSA;
505 break;
506 case CSSM_ALGID_DH:
507 *type = kPublicKeyTypeDH;
508 break;
509 default:
510 *type = kPublicKeyTypeUnknown;
511 *size_bits = 0;
512 break;
513 }
514 }
515
516 } // namespace net
517