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 <cert.h>
12
13#include <vector>
14
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"
29
30using base::ScopedCFTypeRef;
31using base::Time;
32
33namespace net {
34
35namespace {
36
37void GetCertDistinguishedName(
38    const x509_util::CSSMCachedCertificate& cached_cert,
39    const CSSM_OID* oid,
40    CertPrincipal* result) {
41  x509_util::CSSMFieldValue distinguished_name;
42  OSStatus status = cached_cert.GetField(oid, &distinguished_name);
43  if (status || !distinguished_name.field())
44    return;
45  result->ParseDistinguishedName(distinguished_name.field()->Data,
46                                 distinguished_name.field()->Length);
47}
48
49bool 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)
53    return false;
54
55  x509_util::CSSMFieldValue distinguished_name;
56  OSStatus status = cached_cert.GetField(&CSSMOID_X509V1IssuerNameStd,
57                                         &distinguished_name);
58  if (status || !distinguished_name.field())
59    return false;
60
61  base::StringPiece name_piece(
62      reinterpret_cast<const char*>(distinguished_name.field()->Data),
63      static_cast<size_t>(distinguished_name.field()->Length));
64
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)
69      return true;
70  }
71
72  return false;
73}
74
75void GetCertDateForOID(const x509_util::CSSMCachedCertificate& cached_cert,
76                       const CSSM_OID* oid,
77                       Time* result) {
78  *result = Time::Time();
79
80  x509_util::CSSMFieldValue field;
81  OSStatus status = cached_cert.GetField(oid, &field);
82  if (status)
83    return;
84
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;
90    return;
91  }
92
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;
100}
101
102std::string GetCertSerialNumber(
103    const x509_util::CSSMCachedCertificate& cached_cert) {
104  x509_util::CSSMFieldValue serial_number;
105  OSStatus status = cached_cert.GetField(&CSSMOID_X509V1SerialNumber,
106                                         &serial_number);
107  if (status || !serial_number.field())
108    return std::string();
109
110  return std::string(
111      reinterpret_cast<const char*>(serial_number.field()->Data),
112      serial_number.field()->Length);
113}
114
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.
118bool 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))
122      return true;
123    if (CSSMOIDEqual(&usage->purposes[p], &CSSMOID_ExtendedKeyUsageAny))
124      return true;
125  }
126  return false;
127}
128
129// Test that a given |cert_handle| is actually a valid X.509 certificate, and
130// return true if it is.
131//
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.
140bool 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;
144}
145
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|.
149void 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,
155      kCFAllocatorNull));
156
157  CFArrayRef items = NULL;
158  OSStatus status;
159  {
160    base::AutoLock lock(crypto::GetMacSecurityServicesLock());
161    status = SecKeychainItemImport(local_data, NULL, &input_format,
162                                   NULL, 0, NULL, NULL, &items);
163  }
164
165  if (status) {
166    OSSTATUS_DLOG(WARNING, status)
167        << "Unable to import items from data of length " << length;
168    return;
169  }
170
171  ScopedCFTypeRef<CFArrayRef> scoped_items(items);
172  CFTypeID cert_type_id = SecCertificateGetTypeID();
173
174  for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
175    SecKeychainItemRef item = reinterpret_cast<SecKeychainItemRef>(
176        const_cast<void*>(CFArrayGetValueAtIndex(items, i)));
177
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)) {
195        CFRetain(cert);
196        output->push_back(cert);
197      }
198    }
199  }
200}
201
202struct CSSMOIDString {
203  const CSSM_OID* oid_;
204  std::string string_;
205};
206
207typedef std::vector<CSSMOIDString> CSSMOIDStringVector;
208
209bool CERTNameToCSSMOIDVector(CERTName* name, CSSMOIDStringVector* out_values) {
210  struct OIDCSSMMap {
211    SECOidTag sec_OID_;
212    const CSSM_OID* cssm_OID_;
213  };
214
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 },
226  };
227
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) {
234        return false;
235      }
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);
241          if (!decode_item)
242            return false;
243
244          // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
245          std::string value(reinterpret_cast<char*>(decode_item->data),
246                            decode_item->len);
247          oidString.oid_ = kOIDs[oid].cssm_OID_;
248          oidString.string_ = value;
249          out_values->push_back(oidString);
250          SECITEM_FreeItem(decode_item, PR_TRUE);
251          found_oid = true;
252          break;
253        }
254      }
255      if (!found_oid) {
256        DLOG(ERROR) << "Unrecognized OID: " << tag;
257      }
258    }
259  }
260  return true;
261}
262
263class ScopedCertName {
264 public:
265  explicit ScopedCertName(CERTName* name) : name_(name) { }
266  ~ScopedCertName() {
267    if (name_) CERT_DestroyName(name_);
268  }
269  operator CERTName*() { return name_; }
270
271 private:
272  CERTName* name_;
273};
274
275class ScopedEncodedCertResults {
276 public:
277  explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results)
278      : results_(results) { }
279  ~ScopedEncodedCertResults() {
280    if (results_) {
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);
285      }
286    }
287    crypto::CSSMFree(results_->Results);
288    crypto::CSSMFree(results_);
289  }
290
291 private:
292  CSSM_TP_RESULT_SET* results_;
293};
294
295}  // namespace
296
297void X509Certificate::Initialize() {
298  x509_util::CSSMCachedCertificate cached_cert;
299  if (cached_cert.Init(cert_handle_) == CSSM_OK) {
300    GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd,
301                             &subject_);
302    GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
303                             &issuer_);
304    GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
305                      &valid_start_);
306    GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
307                      &valid_expiry_);
308    serial_number_ = GetCertSerialNumber(cached_cert);
309  }
310
311  fingerprint_ = CalculateFingerprint(cert_handle_);
312  ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
313}
314
315bool X509Certificate::IsIssuedByEncoded(
316    const std::vector<std::string>& valid_issuers) {
317  if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
318    return true;
319
320  for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
321       it != intermediate_ca_certs_.end(); ++it) {
322    if (IsCertIssuerInEncodedList(*it, valid_issuers))
323      return true;
324  }
325  return false;
326}
327
328void X509Certificate::GetSubjectAltName(
329    std::vector<std::string>* dns_names,
330    std::vector<std::string>* ip_addrs) const {
331  if (dns_names)
332    dns_names->clear();
333  if (ip_addrs)
334    ip_addrs->clear();
335
336  x509_util::CSSMCachedCertificate cached_cert;
337  OSStatus status = cached_cert.Init(cert_handle_);
338  if (status)
339    return;
340  x509_util::CSSMFieldValue subject_alt_name;
341  status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
342  if (status || !subject_alt_name.field())
343    return;
344  const CSSM_X509_EXTENSION* cssm_ext =
345      subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
346  if (!cssm_ext || !cssm_ext->value.parsedValue)
347    return;
348  const CE_GeneralNames* alt_name =
349      reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
350
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),
360          name_data.Length));
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),
364          name_data.Length));
365    }
366  }
367}
368
369// static
370bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
371                                    std::string* encoded) {
372  CSSM_DATA der_data;
373  if (SecCertificateGetData(cert_handle, &der_data) != noErr)
374    return false;
375  encoded->assign(reinterpret_cast<char*>(der_data.Data),
376                  der_data.Length);
377  return true;
378}
379
380// static
381bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
382                                   X509Certificate::OSCertHandle b) {
383  DCHECK(a && b);
384  if (a == b)
385    return true;
386  if (CFEqual(a, b))
387    return true;
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;
393}
394
395// static
396X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
397    const char* data, int length) {
398  CSSM_DATA cert_data;
399  cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
400  cert_data.Length = length;
401
402  OSCertHandle cert_handle = NULL;
403  OSStatus status = SecCertificateCreateFromData(&cert_data,
404                                                 CSSM_CERT_X_509v3,
405                                                 CSSM_CERT_ENCODING_DER,
406                                                 &cert_handle);
407  if (status != noErr)
408    return NULL;
409  if (!IsValidOSCertHandle(cert_handle)) {
410    CFRelease(cert_handle);
411    return NULL;
412  }
413  return cert_handle;
414}
415
416// static
417X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
418    const char* data, int length, Format format) {
419  OSCertHandles results;
420
421  switch (format) {
422    case FORMAT_SINGLE_CERTIFICATE: {
423      OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
424      if (handle)
425        results.push_back(handle);
426      break;
427    }
428    case FORMAT_PKCS7:
429      AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
430      break;
431    default:
432      NOTREACHED() << "Certificate format " << format << " unimplemented";
433      break;
434  }
435
436  return results;
437}
438
439// static
440X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
441    OSCertHandle handle) {
442  if (!handle)
443    return NULL;
444  return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
445}
446
447// static
448void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
449  CFRelease(cert_handle);
450}
451
452// static
453SHA1HashValue X509Certificate::CalculateFingerprint(
454    OSCertHandle cert) {
455  SHA1HashValue sha1;
456  memset(sha1.data, 0, sizeof(sha1.data));
457
458  CSSM_DATA cert_data;
459  OSStatus status = SecCertificateGetData(cert, &cert_data);
460  if (status)
461    return sha1;
462
463  DCHECK(cert_data.Data);
464  DCHECK_NE(cert_data.Length, 0U);
465
466  CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
467
468  return sha1;
469}
470
471// static
472SHA1HashValue X509Certificate::CalculateCAFingerprint(
473    const OSCertHandles& intermediates) {
474  SHA1HashValue sha1;
475  memset(sha1.data, 0, sizeof(sha1.data));
476
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);
481  CSSM_DATA cert_data;
482  for (size_t i = 0; i < intermediates.size(); ++i) {
483    OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
484    if (status)
485      return sha1;
486    CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
487  }
488  CC_SHA1_Final(sha1.data, &sha1_ctx);
489
490  return sha1;
491}
492
493bool X509Certificate::SupportsSSLClientAuth() const {
494  x509_util::CSSMCachedCertificate cached_cert;
495  OSStatus status = cached_cert.Init(cert_handle_);
496  if (status)
497    return false;
498
499  // RFC5280 says to take the intersection of the two extensions.
500  //
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.
505  //
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))
515      return false;
516  }
517
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))
524      return false;
525  }
526  return true;
527}
528
529CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
530  CFMutableArrayRef cert_list =
531      CFArrayCreateMutable(kCFAllocatorDefault, 0,
532                           &kCFTypeArrayCallBacks);
533  if (!cert_list)
534    return NULL;
535
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]);
539
540  return cert_list;
541}
542
543// static
544X509Certificate::OSCertHandle
545X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
546  const char* data;
547  int length;
548  if (!pickle_iter->ReadData(&data, &length))
549    return NULL;
550
551  return CreateOSCertHandleFromBytes(data, length);
552}
553
554// static
555bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
556                                                Pickle* pickle) {
557  CSSM_DATA cert_data;
558  OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
559  if (status)
560    return false;
561
562  return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
563                           cert_data.Length);
564}
565
566// static
567void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
568                                       size_t* size_bits,
569                                       PublicKeyType* type) {
570  // Since we might fail, set the output parameters to default values first.
571  *type = kPublicKeyTypeUnknown;
572  *size_bits = 0;
573
574  SecKeyRef key;
575  OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
576  if (status) {
577    NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
578    return;
579  }
580  ScopedCFTypeRef<SecKeyRef> scoped_key(key);
581
582  const CSSM_KEY* cssm_key;
583  status = SecKeyGetCSSMKey(key, &cssm_key);
584  if (status) {
585    NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
586    return;
587  }
588
589  *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
590
591  switch (cssm_key->KeyHeader.AlgorithmId) {
592    case CSSM_ALGID_RSA:
593      *type = kPublicKeyTypeRSA;
594      break;
595    case CSSM_ALGID_DSA:
596      *type = kPublicKeyTypeDSA;
597      break;
598    case CSSM_ALGID_ECDSA:
599      *type = kPublicKeyTypeECDSA;
600      break;
601    case CSSM_ALGID_DH:
602      *type = kPublicKeyTypeDH;
603      break;
604    default:
605      *type = kPublicKeyTypeUnknown;
606      *size_bits = 0;
607      break;
608  }
609}
610
611}  // namespace net
612