b3815765265d941dc570d3a324e126f9161c72f1
[platform/framework/web/crosswalk.git] / src / net / cert / x509_certificate_mac.cc
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
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
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
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
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.
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.
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|.
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
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
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
232 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
274 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
275                                     std::string* encoded) {
276   CSSM_DATA der_data;
277   if (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
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
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
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
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
352 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
353   if (cert_handle)
354     CFRelease(cert_handle);
355 }
356
357 // static
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
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
398 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
434 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
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
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
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