diff options
-rw-r--r-- | net/SConscript | 3 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 23 | ||||
-rw-r--r-- | net/base/x509_certificate_mac.cc | 390 | ||||
-rw-r--r-- | net/base/x509_certificate_win.cc (renamed from net/base/x509_certificate.cc) | 0 | ||||
-rw-r--r-- | net/build/net.vcproj | 2 | ||||
-rw-r--r-- | net/net.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj | 4 |
7 files changed, 422 insertions, 6 deletions
diff --git a/net/SConscript b/net/SConscript index 8348602..fe95094 100644 --- a/net/SConscript +++ b/net/SConscript @@ -92,7 +92,7 @@ if env['PLATFORM'] == 'win32': 'base/upload_data_stream.cc', 'base/wininet_util.cc', 'base/winsock_init.cc', - 'base/x509_certificate.cc', + 'base/x509_certificate_win.cc', 'http/http_network_layer.cc', 'http/http_network_transaction.cc', 'http/http_transaction_winhttp.cc', @@ -126,6 +126,7 @@ if env['PLATFORM'] == 'win32': if env['PLATFORM'] == 'darwin': input_files.extend([ 'base/platform_mime_util_mac.mm', + 'base/x509_certificate_mac.cc', ]) if env['PLATFORM'] == 'posix': diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 4411322..645454e 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -15,6 +15,8 @@ #if defined(OS_WIN) #include <windows.h> #include <wincrypt.h> +#elif defined(OS_MACOSX) +#include <Security/Security.h> #endif class Pickle; @@ -44,6 +46,8 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { #if defined(OS_WIN) typedef PCCERT_CONTEXT OSCertHandle; +#elif defined(OS_MACOSX) + typedef SecCertificateRef OSCertHandle; #else // TODO(ericroman): not implemented typedef void* OSCertHandle; @@ -102,12 +106,14 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { }; // Create an X509Certificate from a handle to the certificate object - // in the underlying crypto library. + // in the underlying crypto library. This is a transfer of ownership; + // X509Certificate will properly dispose of |cert_handle| for you. static X509Certificate* CreateFromHandle(OSCertHandle cert_handle); // Create an X509Certificate from the representation stored in the given // pickle. The data for this object is found relative to the given // pickle_iter, which should be passed to the pickle's various Read* methods. + // Returns NULL on failure. static X509Certificate* CreateFromPickle(const Pickle& pickle, void** pickle_iter); @@ -127,6 +133,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // The issuer of the certificate. const Principal& issuer() const { return issuer_; } +#if defined(OS_WIN) // Time period during which the certificate is valid. More precisely, this // certificate is invalid before the |valid_start| date and invalid after // the |valid_expiry| date. @@ -134,6 +141,12 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // lacks either date), the date will be null (i.e., is_null() will be true). const Time& valid_start() const { return valid_start_; } const Time& valid_expiry() const { return valid_expiry_; } +#elif defined(OS_MACOSX) + // These are used only for some UI, where HasExpired is used to disambiguate a + // time error on the certificate as a "too old" or "too young" error. On the + // Mac you get different codes for those. There's no easy way of pulling dates + // out of the cert short of CSSM, so these remain unimplemented for now. +#endif // The fingerprint of this certificate. const Fingerprint& fingerprint() const { return fingerprint_; } @@ -144,9 +157,11 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // Otherwise, it gets the common name in the subject field. void GetDNSNames(std::vector<std::string>* dns_names) const; +#if defined(OS_WIN) // Convenience method that returns whether this certificate has expired as of // now. bool HasExpired() const; +#endif // Returns true if the certificate is an extended-validation (EV) // certificate. @@ -168,10 +183,12 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // Common object initialization code. Called by the constructors only. void Initialize(); +#if defined(OS_WIN) // Helper function to parse a principal from a WinInet description of that // principal. static void ParsePrincipal(const std::string& description, Principal* principal); +#endif // The subject of the certificate. Principal subject_; @@ -179,11 +196,13 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // The issuer of the certificate. Principal issuer_; +#if defined(OS_WIN) // This certificate is not valid before |valid_start_| Time valid_start_; // This certificate is not valid after |valid_expiry_| Time valid_expiry_; +#endif // The fingerprint of this certificate. Fingerprint fingerprint_; @@ -191,7 +210,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // A handle to the certificate object in the underlying crypto library. OSCertHandle cert_handle_; - DISALLOW_EVIL_CONSTRUCTORS(X509Certificate); + DISALLOW_COPY_AND_ASSIGN(X509Certificate); }; } // namespace net diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc new file mode 100644 index 0000000..a65bec1 --- /dev/null +++ b/net/base/x509_certificate_mac.cc @@ -0,0 +1,390 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/base/x509_certificate.h" + +#include <CommonCrypto/CommonDigest.h> +#include <map> + +#include "base/histogram.h" +#include "base/lock.h" +#include "base/pickle.h" +#include "base/singleton.h" +#include "base/string_tokenizer.h" +#include "base/string_util.h" +#include "net/base/cert_status_flags.h" +#include "net/base/ev_root_ca_metadata.h" + +// NOTE: This Mac implementation is almost entirely untested. TODO(avi): test +// it to make sure it does what the docs imply it does. +// NOTE: This implementation doesn't keep track of dates. Calling code is +// expected to use SecTrustEvaluate(x509cert.os_cert_handle()) and look at the +// result there. + +namespace net { + +namespace { + +// Returns true if this cert fingerprint is the null (all zero) fingerprint. +// We use this as a bogus fingerprint value. +bool IsNullFingerprint(const X509Certificate::Fingerprint& fingerprint) { + for (size_t i = 0; i < arraysize(fingerprint.data); ++i) { + if (fingerprint.data[i] != 0) + return false; + } + return true; +} + +// Calculates the SHA-1 fingerprint of the certificate. Returns an empty +// (all zero) fingerprint on failure. +X509Certificate::Fingerprint CalculateFingerprint( + X509Certificate::OSCertHandle cert) { + // The Windows code uses CryptHashCertificate, a function specially designed + // to hash certificates. I'm not sure what the difference between using it and + // just hashing the data is. WINE's implementation just hashes the data, and + // so we'll do that. + + X509Certificate::Fingerprint sha1; + memset(sha1.data, 0, sizeof(sha1.data)); + + CSSM_DATA cert_data; + OSStatus status = SecCertificateGetData(cert, &cert_data); + if (status) + return sha1; + + DCHECK(NULL != cert_data.Data); + DCHECK(0 != cert_data.Length); + + CC_SHA1(cert_data.Data, cert_data.Length, sha1.data); + + return sha1; +} + +inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) { + return oid1->Length == oid2->Length && + (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0); +} + +void ParsePrincipal(const CSSM_X509_NAME* name, + X509Certificate::Principal* principal) { + std::vector<std::string> common_names, locality_names, state_names, + country_names; + + // TODO(jcampan): add business_category and serial_number. + const CSSM_OID* kOIDs[] = { &CSSMOID_CommonName, + &CSSMOID_LocalityName, + &CSSMOID_StateProvinceName, + &CSSMOID_CountryName, + &CSSMOID_StreetAddress, + &CSSMOID_OrganizationName, + &CSSMOID_OrganizationalUnitName, + &CSSMOID_DNQualifier }; // This should be "DC" + // but is undoubtedly + // wrong. TODO(avi): + // Find the right OID. + + std::vector<std::string>* values[] = { + &common_names, &locality_names, + &state_names, &country_names, + &(principal->street_addresses), + &(principal->organization_names), + &(principal->organization_unit_names), + &(principal->domain_components) }; + DCHECK(arraysize(kOIDs) == arraysize(values)); + + for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) { + CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn]; + for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) { + CSSM_X509_TYPE_VALUE_PAIR pair_struct = + rdn_struct.AttributeTypeAndValue[pair]; + for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) { + if (CSSMOIDEqual(&pair_struct.type, kOIDs[oid])) { + std::string value = + std::string(reinterpret_cast<std::string::value_type*> + (pair_struct.value.Data), + pair_struct.value.Length); + values[oid]->push_back(value); + break; + } + } + } + } + + // We don't expect to have more than one CN, L, S, and C. + std::vector<std::string>* single_value_lists[4] = { + &common_names, &locality_names, &state_names, &country_names }; + std::string* single_values[4] = { + &principal->common_name, &principal->locality_name, + &principal->state_or_province_name, &principal->country_name }; + for (size_t i = 0; i < arraysize(single_value_lists); ++i) { + DCHECK(single_value_lists[i]->size() <= 1); + if (single_value_lists[i]->size() > 0) + *(single_values[i]) = (*(single_value_lists[i]))[0]; + } +} + +void GetCertFieldsForOID(X509Certificate::OSCertHandle cert_handle, + CSSM_OID oid, + std::vector<std::string>* result) { + CSSM_DATA cert_data; + OSStatus status = SecCertificateGetData(cert_handle, &cert_data); + if (status) + return; + + CSSM_CL_HANDLE clHandle; + status = SecCertificateGetCLHandle(cert_handle, &clHandle); + if (status) + return; + + uint32 numOfFields; + CSSM_FIELD_PTR fields; + status = CSSM_CL_CertGetAllFields(clHandle, &cert_data, &numOfFields, + &fields); + if (status) + return; + + for (size_t field = 0; field < numOfFields; ++field) { + if (CSSMOIDEqual(&fields[field].FieldOid, &oid)) { + std::string value = + std::string(reinterpret_cast<std::string::value_type*> + (fields[field].FieldValue.Data), + fields[field].FieldValue.Length); + result->push_back(value); + break; + } + } +} + +} // namespace + +bool X509Certificate::FingerprintLessThan::operator()( + const Fingerprint& lhs, + const Fingerprint& rhs) const { + for (size_t i = 0; i < sizeof(lhs.data); ++i) { + if (lhs.data[i] < rhs.data[i]) + return true; + if (lhs.data[i] > rhs.data[i]) + return false; + } + return false; +} + +bool X509Certificate::LessThan::operator()(X509Certificate* lhs, + X509Certificate* rhs) const { + if (lhs == rhs) + return false; + + X509Certificate::FingerprintLessThan fingerprint_functor; + return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_); +} + +// A thread-safe cache for X509Certificate objects. +// +// The cache does not hold a reference to the certificate objects. The objects +// must |Remove| themselves from the cache upon destruction (or else the cache +// will be holding dead pointers to the objects). +class X509Certificate::Cache { + public: + // Get the singleton object for the cache. + static X509Certificate::Cache* GetInstance() { + return Singleton<X509Certificate::Cache>::get(); + } + + // Insert |cert| into the cache. The cache does NOT AddRef |cert|. The cache + // must not already contain a certificate with the same fingerprint. + void Insert(X509Certificate* cert) { + AutoLock lock(lock_); + + DCHECK(!IsNullFingerprint(cert->fingerprint())) << + "Only insert certs with real fingerprints."; + DCHECK(cache_.find(cert->fingerprint()) == cache_.end()); + cache_[cert->fingerprint()] = cert; + }; + + // Remove |cert| from the cache. The cache does not assume that |cert| is + // already in the cache. + void Remove(X509Certificate* cert) { + AutoLock lock(lock_); + + CertMap::iterator pos(cache_.find(cert->fingerprint())); + if (pos == cache_.end()) + return; // It is not an error to remove a cert that is not in the cache. + cache_.erase(pos); + }; + + // Find a certificate in the cache with the given fingerprint. If one does + // not exist, this method returns NULL. + X509Certificate* Find(const Fingerprint& fingerprint) { + AutoLock lock(lock_); + + CertMap::iterator pos(cache_.find(fingerprint)); + if (pos == cache_.end()) + return NULL; + + return pos->second; + }; + + private: + typedef std::map<Fingerprint, X509Certificate*, FingerprintLessThan> CertMap; + + // Obtain an instance of X509Certificate::Cache via GetInstance(). + Cache() { } + friend class DefaultSingletonTraits<X509Certificate::Cache>; + + // You must acquire this lock before using any private data of this object. + // You must not block while holding this lock. + Lock lock_; + + // The certificate cache. You must acquire |lock_| before using |cache_|. + CertMap cache_; + + DISALLOW_COPY_AND_ASSIGN(Cache); +}; + +void X509Certificate::Initialize() { + const CSSM_X509_NAME* name; + OSStatus status = SecCertificateGetSubject(cert_handle_, &name); + if (!status) { + ParsePrincipal(name, &subject_); + } + status = SecCertificateGetIssuer(cert_handle_, &name); + if (!status) { + ParsePrincipal(name, &issuer_); + } + + fingerprint_ = CalculateFingerprint(cert_handle_); + + // Store the certificate in the cache in case we need it later. + X509Certificate::Cache::GetInstance()->Insert(this); +} + +// static +X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { + DCHECK(cert_handle); + + // Check if we already have this certificate in memory. + X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); + X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); + if (cert) { + // We've found a certificate with the same fingerprint in our cache. We own + // the |cert_handle|, which makes it our job to free it. + CFRelease(cert_handle); + DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); + return cert; + } + // Otherwise, allocate a new object. + return new X509Certificate(cert_handle); +} + +// static +X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, + void** pickle_iter) { + const char* data; + int length; + if (!pickle.ReadData(pickle_iter, &data, &length)) + return NULL; + CSSM_DATA cert_data; + cert_data.Data = const_cast<uint8*>(reinterpret_cast<const uint8*>(data)); + cert_data.Length = length; + + OSCertHandle cert_handle = NULL; + OSStatus status = SecCertificateCreateFromData(&cert_data, + CSSM_CERT_X_509v3, + CSSM_CERT_ENCODING_BER, + &cert_handle); + if (status) + return NULL; + + return CreateFromHandle(cert_handle); +} + +X509Certificate::X509Certificate(OSCertHandle cert_handle) + : cert_handle_(cert_handle) { + Initialize(); +} + +X509Certificate::X509Certificate(std::string subject, std::string issuer, + Time, Time) + : subject_(subject), + issuer_(issuer), + cert_handle_(NULL) { + memset(fingerprint_.data, 0, sizeof(fingerprint_.data)); +} + +void X509Certificate::Persist(Pickle* pickle) { + CSSM_DATA cert_data; + OSStatus status = SecCertificateGetData(cert_handle_, &cert_data); + if (status) { + NOTREACHED(); + return; + } + + pickle->WriteData(reinterpret_cast<char*>(cert_data.Data), cert_data.Length); +} + +X509Certificate::~X509Certificate() { + // We might not be in the cache, but it is safe to remove ourselves anyway. + X509Certificate::Cache::GetInstance()->Remove(this); + if (cert_handle_) + CFRelease(cert_handle_); +} + +void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { + dns_names->clear(); + + GetCertFieldsForOID(cert_handle_, CSSMOID_SubjectAltName, dns_names); + + if (dns_names->empty()) + dns_names->push_back(subject_.common_name); +} + +// Returns true if the certificate is an extended-validation certificate. +// +// The certificate has already been verified by the HTTP library. cert_status +// represents the result of that verification. This function performs +// additional checks of the certificatePolicies extensions of the certificates +// in the certificate chain according to Section 7 (pp. 11-12) of the EV +// Certificate Guidelines Version 1.0 at +// http://cabforum.org/EV_Certificate_Guidelines.pdf. +bool X509Certificate::IsEV(int cert_status) const { + // TODO(avi): implement this + NOTIMPLEMENTED(); + return false; +} + +X509Certificate::Policy::Judgment X509Certificate::Policy::Check( + X509Certificate* cert) const { + // It shouldn't matter which set we check first, but we check denied first + // in case something strange has happened. + + if (denied_.find(cert->fingerprint()) != denied_.end()) { + // DCHECK that the order didn't matter. + DCHECK(allowed_.find(cert->fingerprint()) == allowed_.end()); + return DENIED; + } + + if (allowed_.find(cert->fingerprint()) != allowed_.end()) { + // DCHECK that the order didn't matter. + DCHECK(denied_.find(cert->fingerprint()) == denied_.end()); + return ALLOWED; + } + + // We don't have a policy for this cert. + return UNKNOWN; +} + +void X509Certificate::Policy::Allow(X509Certificate* cert) { + // Put the cert in the allowed set and (maybe) remove it from the denied set. + denied_.erase(cert->fingerprint()); + allowed_.insert(cert->fingerprint()); +} + +void X509Certificate::Policy::Deny(X509Certificate* cert) { + // Put the cert in the denied set and (maybe) remove it from the allowed set. + allowed_.erase(cert->fingerprint()); + denied_.insert(cert->fingerprint()); +} + +} // namespace net + diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate_win.cc index ab3fe64..ab3fe64 100644 --- a/net/base/x509_certificate.cc +++ b/net/base/x509_certificate_win.cc diff --git a/net/build/net.vcproj b/net/build/net.vcproj index 069db63..d4e779b 100644 --- a/net/build/net.vcproj +++ b/net/build/net.vcproj @@ -477,7 +477,7 @@ > </File> <File - RelativePath="..\base\x509_certificate.cc" + RelativePath="..\base\x509_certificate_win.cc" > </File> <File diff --git a/net/net.xcodeproj/project.pbxproj b/net/net.xcodeproj/project.pbxproj index 89a3146..9402388 100644 --- a/net/net.xcodeproj/project.pbxproj +++ b/net/net.xcodeproj/project.pbxproj @@ -123,6 +123,7 @@ 821F23CA0E5E106B003C7E38 /* url_request_job.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33980E5A198600A747DB /* url_request_job.cc */; }; 821F23CC0E5E106D003C7E38 /* url_request_simple_job.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED339C0E5A198600A747DB /* url_request_simple_job.cc */; }; 825C2FCC0E5C968B00FDEAB7 /* ev_root_ca_metadata.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32BE0E5A181C00A747DB /* ev_root_ca_metadata.cc */; }; + 827E139D0E81611D00183614 /* x509_certificate_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32800E5A181C00A747DB /* x509_certificate_mac.cc */; }; 82ECB3090E5B651D00A913E3 /* mime_sniffer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32AD0E5A181C00A747DB /* mime_sniffer.cc */; }; B5F622260E805FC40076681A /* url_request_job_manager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33A30E5A198600A747DB /* url_request_job_manager.cc */; }; BAA46E3B0E5CE99A00E77460 /* net_util_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED329F0E5A181C00A747DB /* net_util_unittest.cc */; }; @@ -389,7 +390,7 @@ 7BED327D0E5A181C00A747DB /* address_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = address_list.h; sourceTree = "<group>"; }; 7BED327E0E5A181C00A747DB /* address_list.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = address_list.cc; sourceTree = "<group>"; }; 7BED327F0E5A181C00A747DB /* x509_certificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509_certificate.h; sourceTree = "<group>"; }; - 7BED32800E5A181C00A747DB /* x509_certificate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate.cc; sourceTree = "<group>"; }; + 7BED32800E5A181C00A747DB /* x509_certificate_mac.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate_mac.cc; sourceTree = "<group>"; }; 7BED32860E5A181C00A747DB /* upload_data_stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upload_data_stream.h; sourceTree = "<group>"; }; 7BED32870E5A181C00A747DB /* upload_data_stream.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = upload_data_stream.cc; sourceTree = "<group>"; }; 7BED32880E5A181C00A747DB /* upload_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upload_data.h; sourceTree = "<group>"; }; @@ -835,7 +836,7 @@ 7BED32880E5A181C00A747DB /* upload_data.h */, 7BED32870E5A181C00A747DB /* upload_data_stream.cc */, 7BED32860E5A181C00A747DB /* upload_data_stream.h */, - 7BED32800E5A181C00A747DB /* x509_certificate.cc */, + 7BED32800E5A181C00A747DB /* x509_certificate_mac.cc */, 7BED327F0E5A181C00A747DB /* x509_certificate.h */, ); path = base; @@ -1282,6 +1283,7 @@ 7B8504540E5B2E9600730B43 /* url_request_job_tracker.cc in Sources */, 821F23CC0E5E106D003C7E38 /* url_request_simple_job.cc in Sources */, 821F20A50E5CD414003C7E38 /* url_request_view_cache_job.cc in Sources */, + 827E139D0E81611D00183614 /* x509_certificate_mac.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj b/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj index f23c6d3..a966573 100644 --- a/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj +++ b/webkit/tools/test_shell/mac/TestShell.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 82F372150E82AE0500DF5AFE /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82F372140E82AE0500DF5AFE /* Security.framework */; }; 82F399480E7EE4D500785E15 /* libWebKitSystemInterfaceLeopard.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 82F399470E7EE4D500785E15 /* libWebKitSystemInterfaceLeopard.a */; }; 82F399B70E7EF75800785E15 /* libbase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8205260E770291008F45CF /* libbase.a */; }; 82F399B80E7EF75A00785E15 /* libbase_gfx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B8205280E770291008F45CF /* libbase_gfx.a */; }; @@ -527,6 +528,7 @@ 829E35270DC0C95300819EBF /* icu.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = icu.xcodeproj; path = third_party/icu38/icu.xcodeproj; sourceTree = "<group>"; }; 829E35590DC0D37B00819EBF /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = "<group>"; }; 829E355C0DC0D47400819EBF /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = "<group>"; }; + 82F372140E82AE0500DF5AFE /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; }; 82F399470E7EE4D500785E15 /* libWebKitSystemInterfaceLeopard.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libWebKitSystemInterfaceLeopard.a; path = temp/libWebKitSystemInterfaceLeopard.a; sourceTree = "<group>"; }; 82F39A1C0E7EF85C00785E15 /* gtest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = gtest.xcodeproj; path = testing/gtest.xcodeproj; sourceTree = "<group>"; }; 82F39CFF0E7EF95A00785E15 /* modp_b64.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = modp_b64.xcodeproj; path = third_party/modp_b64/modp_b64.xcodeproj; sourceTree = "<group>"; }; @@ -600,6 +602,7 @@ 82F39D400E7EFD9300785E15 /* libxml.a in Frameworks */, 82F39CF40E7EF90F00785E15 /* libzlib.a in Frameworks */, E456292D0E26B4FE005E4685 /* QuartzCore.framework in Frameworks */, + 82F372150E82AE0500DF5AFE /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -648,6 +651,7 @@ 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 829E355C0DC0D47400819EBF /* QuartzCore.framework */, + 82F372140E82AE0500DF5AFE /* Security.framework */, ); name = Frameworks; sourceTree = SDKROOT; |