• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 using base::ScopedCFTypeRef;
31 using base::Time;
32 
33 namespace net {
34 
35 namespace {
36 
GetCertDistinguishedName(const x509_util::CSSMCachedCertificate & cached_cert,const CSSM_OID * oid,CertPrincipal * result)37 void 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 
IsCertIssuerInEncodedList(X509Certificate::OSCertHandle cert_handle,const std::vector<std::string> & issuers)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)
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 
GetCertDateForOID(const x509_util::CSSMCachedCertificate & cached_cert,const CSSM_OID * oid,Time * result)75 void 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 
GetCertSerialNumber(const x509_util::CSSMCachedCertificate & cached_cert)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,
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.
ExtendedKeyUsageAllows(const CE_ExtendedKeyUsage * usage,const CSSM_OID * purpose)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))
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.
IsValidOSCertHandle(SecCertificateRef cert_handle)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;
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|.
AddCertificatesFromBytes(const char * data,size_t length,SecExternalFormat format,X509Certificate::OSCertHandles * 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,
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 
202 struct CSSMOIDString {
203   const CSSM_OID* oid_;
204   std::string string_;
205 };
206 
207 typedef std::vector<CSSMOIDString> CSSMOIDStringVector;
208 
209 class ScopedCertName {
210  public:
ScopedCertName(CERTName * name)211   explicit ScopedCertName(CERTName* name) : name_(name) { }
~ScopedCertName()212   ~ScopedCertName() {
213     if (name_) CERT_DestroyName(name_);
214   }
operator CERTName*()215   operator CERTName*() { return name_; }
216 
217  private:
218   CERTName* name_;
219 };
220 
221 class ScopedEncodedCertResults {
222  public:
ScopedEncodedCertResults(CSSM_TP_RESULT_SET * results)223   explicit ScopedEncodedCertResults(CSSM_TP_RESULT_SET* results)
224       : results_(results) { }
~ScopedEncodedCertResults()225   ~ScopedEncodedCertResults() {
226     if (results_) {
227       CSSM_ENCODED_CERT* encCert =
228           reinterpret_cast<CSSM_ENCODED_CERT*>(results_->Results);
229       for (uint32 i = 0; i < results_->NumberOfResults; i++) {
230         crypto::CSSMFree(encCert[i].CertBlob.Data);
231       }
232       crypto::CSSMFree(results_->Results);
233       crypto::CSSMFree(results_);
234     }
235   }
236 
237  private:
238   CSSM_TP_RESULT_SET* results_;
239 };
240 
241 }  // namespace
242 
Initialize()243 void X509Certificate::Initialize() {
244   x509_util::CSSMCachedCertificate cached_cert;
245   if (cached_cert.Init(cert_handle_) == CSSM_OK) {
246     GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1SubjectNameStd,
247                              &subject_);
248     GetCertDistinguishedName(cached_cert, &CSSMOID_X509V1IssuerNameStd,
249                              &issuer_);
250     GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotBefore,
251                       &valid_start_);
252     GetCertDateForOID(cached_cert, &CSSMOID_X509V1ValidityNotAfter,
253                       &valid_expiry_);
254     serial_number_ = GetCertSerialNumber(cached_cert);
255   }
256 
257   fingerprint_ = CalculateFingerprint(cert_handle_);
258   ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
259 }
260 
IsIssuedByEncoded(const std::vector<std::string> & valid_issuers)261 bool X509Certificate::IsIssuedByEncoded(
262     const std::vector<std::string>& valid_issuers) {
263   if (IsCertIssuerInEncodedList(cert_handle_, valid_issuers))
264     return true;
265 
266   for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
267        it != intermediate_ca_certs_.end(); ++it) {
268     if (IsCertIssuerInEncodedList(*it, valid_issuers))
269       return true;
270   }
271   return false;
272 }
273 
GetSubjectAltName(std::vector<std::string> * dns_names,std::vector<std::string> * ip_addrs) const274 void X509Certificate::GetSubjectAltName(
275     std::vector<std::string>* dns_names,
276     std::vector<std::string>* ip_addrs) const {
277   if (dns_names)
278     dns_names->clear();
279   if (ip_addrs)
280     ip_addrs->clear();
281 
282   x509_util::CSSMCachedCertificate cached_cert;
283   OSStatus status = cached_cert.Init(cert_handle_);
284   if (status)
285     return;
286   x509_util::CSSMFieldValue subject_alt_name;
287   status = cached_cert.GetField(&CSSMOID_SubjectAltName, &subject_alt_name);
288   if (status || !subject_alt_name.field())
289     return;
290   const CSSM_X509_EXTENSION* cssm_ext =
291       subject_alt_name.GetAs<CSSM_X509_EXTENSION>();
292   if (!cssm_ext || !cssm_ext->value.parsedValue)
293     return;
294   const CE_GeneralNames* alt_name =
295       reinterpret_cast<const CE_GeneralNames*>(cssm_ext->value.parsedValue);
296 
297   for (size_t name = 0; name < alt_name->numNames; ++name) {
298     const CE_GeneralName& name_struct = alt_name->generalName[name];
299     const CSSM_DATA& name_data = name_struct.name;
300     // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
301     // respectively, both of which can be byte copied from
302     // CSSM_DATA::data into the appropriate output vector.
303     if (dns_names && name_struct.nameType == GNT_DNSName) {
304       dns_names->push_back(std::string(
305           reinterpret_cast<const char*>(name_data.Data),
306           name_data.Length));
307     } else if (ip_addrs && name_struct.nameType == GNT_IPAddress) {
308       ip_addrs->push_back(std::string(
309           reinterpret_cast<const char*>(name_data.Data),
310           name_data.Length));
311     }
312   }
313 }
314 
315 // static
GetDEREncoded(X509Certificate::OSCertHandle cert_handle,std::string * encoded)316 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
317                                     std::string* encoded) {
318   CSSM_DATA der_data;
319   if (SecCertificateGetData(cert_handle, &der_data) != noErr)
320     return false;
321   encoded->assign(reinterpret_cast<char*>(der_data.Data),
322                   der_data.Length);
323   return true;
324 }
325 
326 // static
IsSameOSCert(X509Certificate::OSCertHandle a,X509Certificate::OSCertHandle b)327 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
328                                    X509Certificate::OSCertHandle b) {
329   DCHECK(a && b);
330   if (a == b)
331     return true;
332   if (CFEqual(a, b))
333     return true;
334   CSSM_DATA a_data, b_data;
335   return SecCertificateGetData(a, &a_data) == noErr &&
336       SecCertificateGetData(b, &b_data) == noErr &&
337       a_data.Length == b_data.Length &&
338       memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
339 }
340 
341 // static
CreateOSCertHandleFromBytes(const char * data,int length)342 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
343     const char* data, int length) {
344   CSSM_DATA cert_data;
345   cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data));
346   cert_data.Length = length;
347 
348   OSCertHandle cert_handle = NULL;
349   OSStatus status = SecCertificateCreateFromData(&cert_data,
350                                                  CSSM_CERT_X_509v3,
351                                                  CSSM_CERT_ENCODING_DER,
352                                                  &cert_handle);
353   if (status != noErr)
354     return NULL;
355   if (!IsValidOSCertHandle(cert_handle)) {
356     CFRelease(cert_handle);
357     return NULL;
358   }
359   return cert_handle;
360 }
361 
362 // static
CreateOSCertHandlesFromBytes(const char * data,int length,Format format)363 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
364     const char* data, int length, Format format) {
365   OSCertHandles results;
366 
367   switch (format) {
368     case FORMAT_SINGLE_CERTIFICATE: {
369       OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
370       if (handle)
371         results.push_back(handle);
372       break;
373     }
374     case FORMAT_PKCS7:
375       AddCertificatesFromBytes(data, length, kSecFormatPKCS7, &results);
376       break;
377     default:
378       NOTREACHED() << "Certificate format " << format << " unimplemented";
379       break;
380   }
381 
382   return results;
383 }
384 
385 // static
DupOSCertHandle(OSCertHandle handle)386 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
387     OSCertHandle handle) {
388   if (!handle)
389     return NULL;
390   return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
391 }
392 
393 // static
FreeOSCertHandle(OSCertHandle cert_handle)394 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
395   CFRelease(cert_handle);
396 }
397 
398 // static
CalculateFingerprint(OSCertHandle cert)399 SHA1HashValue X509Certificate::CalculateFingerprint(
400     OSCertHandle cert) {
401   SHA1HashValue sha1;
402   memset(sha1.data, 0, sizeof(sha1.data));
403 
404   CSSM_DATA cert_data;
405   OSStatus status = SecCertificateGetData(cert, &cert_data);
406   if (status)
407     return sha1;
408 
409   DCHECK(cert_data.Data);
410   DCHECK_NE(cert_data.Length, 0U);
411 
412   CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
413 
414   return sha1;
415 }
416 
417 // static
CalculateCAFingerprint(const OSCertHandles & intermediates)418 SHA1HashValue X509Certificate::CalculateCAFingerprint(
419     const OSCertHandles& intermediates) {
420   SHA1HashValue sha1;
421   memset(sha1.data, 0, sizeof(sha1.data));
422 
423   // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so
424   // we don't check their return values.
425   CC_SHA1_CTX sha1_ctx;
426   CC_SHA1_Init(&sha1_ctx);
427   CSSM_DATA cert_data;
428   for (size_t i = 0; i < intermediates.size(); ++i) {
429     OSStatus status = SecCertificateGetData(intermediates[i], &cert_data);
430     if (status)
431       return sha1;
432     CC_SHA1_Update(&sha1_ctx, cert_data.Data, cert_data.Length);
433   }
434   CC_SHA1_Final(sha1.data, &sha1_ctx);
435 
436   return sha1;
437 }
438 
SupportsSSLClientAuth() const439 bool X509Certificate::SupportsSSLClientAuth() const {
440   x509_util::CSSMCachedCertificate cached_cert;
441   OSStatus status = cached_cert.Init(cert_handle_);
442   if (status)
443     return false;
444 
445   // RFC5280 says to take the intersection of the two extensions.
446   //
447   // Our underlying crypto libraries don't expose
448   // ClientCertificateType, so for now we will not support fixed
449   // Diffie-Hellman mechanisms. For rsa_sign, we need the
450   // digitalSignature bit.
451   //
452   // In particular, if a key has the nonRepudiation bit and not the
453   // digitalSignature one, we will not offer it to the user.
454   x509_util::CSSMFieldValue key_usage;
455   status = cached_cert.GetField(&CSSMOID_KeyUsage, &key_usage);
456   if (status == CSSM_OK && key_usage.field()) {
457     const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
458     const CE_KeyUsage* key_usage_value =
459         reinterpret_cast<const CE_KeyUsage*>(ext->value.parsedValue);
460     if (!((*key_usage_value) & CE_KU_DigitalSignature))
461       return false;
462   }
463 
464   status = cached_cert.GetField(&CSSMOID_ExtendedKeyUsage, &key_usage);
465   if (status == CSSM_OK && key_usage.field()) {
466     const CSSM_X509_EXTENSION* ext = key_usage.GetAs<CSSM_X509_EXTENSION>();
467     const CE_ExtendedKeyUsage* ext_key_usage =
468         reinterpret_cast<const CE_ExtendedKeyUsage*>(ext->value.parsedValue);
469     if (!ExtendedKeyUsageAllows(ext_key_usage, &CSSMOID_ClientAuth))
470       return false;
471   }
472   return true;
473 }
474 
CreateOSCertChainForCert() const475 CFArrayRef X509Certificate::CreateOSCertChainForCert() const {
476   CFMutableArrayRef cert_list =
477       CFArrayCreateMutable(kCFAllocatorDefault, 0,
478                            &kCFTypeArrayCallBacks);
479   if (!cert_list)
480     return NULL;
481 
482   CFArrayAppendValue(cert_list, os_cert_handle());
483   for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
484     CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
485 
486   return cert_list;
487 }
488 
489 // static
490 X509Certificate::OSCertHandle
ReadOSCertHandleFromPickle(PickleIterator * pickle_iter)491 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
492   const char* data;
493   int length;
494   if (!pickle_iter->ReadData(&data, &length))
495     return NULL;
496 
497   return CreateOSCertHandleFromBytes(data, length);
498 }
499 
500 // static
WriteOSCertHandleToPickle(OSCertHandle cert_handle,Pickle * pickle)501 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
502                                                 Pickle* pickle) {
503   CSSM_DATA cert_data;
504   OSStatus status = SecCertificateGetData(cert_handle, &cert_data);
505   if (status)
506     return false;
507 
508   return pickle->WriteData(reinterpret_cast<char*>(cert_data.Data),
509                            cert_data.Length);
510 }
511 
512 // static
GetPublicKeyInfo(OSCertHandle cert_handle,size_t * size_bits,PublicKeyType * type)513 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
514                                        size_t* size_bits,
515                                        PublicKeyType* type) {
516   // Since we might fail, set the output parameters to default values first.
517   *type = kPublicKeyTypeUnknown;
518   *size_bits = 0;
519 
520   SecKeyRef key;
521   OSStatus status = SecCertificateCopyPublicKey(cert_handle, &key);
522   if (status) {
523     NOTREACHED() << "SecCertificateCopyPublicKey failed: " << status;
524     return;
525   }
526   ScopedCFTypeRef<SecKeyRef> scoped_key(key);
527 
528   const CSSM_KEY* cssm_key;
529   status = SecKeyGetCSSMKey(key, &cssm_key);
530   if (status) {
531     NOTREACHED() << "SecKeyGetCSSMKey failed: " << status;
532     return;
533   }
534 
535   *size_bits = cssm_key->KeyHeader.LogicalKeySizeInBits;
536 
537   switch (cssm_key->KeyHeader.AlgorithmId) {
538     case CSSM_ALGID_RSA:
539       *type = kPublicKeyTypeRSA;
540       break;
541     case CSSM_ALGID_DSA:
542       *type = kPublicKeyTypeDSA;
543       break;
544     case CSSM_ALGID_ECDSA:
545       *type = kPublicKeyTypeECDSA;
546       break;
547     case CSSM_ALGID_DH:
548       *type = kPublicKeyTypeDH;
549       break;
550     default:
551       *type = kPublicKeyTypeUnknown;
552       *size_bits = 0;
553       break;
554   }
555 }
556 
557 }  // namespace net
558