Home | History | Annotate | Download | only in cert
      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/test_root_certs.h"
      6 
      7 #include <Security/Security.h>
      8 
      9 #include "base/logging.h"
     10 #include "base/mac/mac_util.h"
     11 #include "base/mac/scoped_cftyperef.h"
     12 #include "net/cert/x509_certificate.h"
     13 
     14 namespace net {
     15 
     16 namespace {
     17 
     18 typedef OSStatus (*SecTrustSetAnchorCertificatesOnlyFuncPtr)(SecTrustRef,
     19                                                              Boolean);
     20 
     21 Boolean OurSecCertificateEqual(const void* value1, const void* value2) {
     22   if (CFGetTypeID(value1) != SecCertificateGetTypeID() ||
     23       CFGetTypeID(value2) != SecCertificateGetTypeID())
     24     return CFEqual(value1, value2);
     25   return X509Certificate::IsSameOSCert(
     26       reinterpret_cast<SecCertificateRef>(const_cast<void*>(value1)),
     27       reinterpret_cast<SecCertificateRef>(const_cast<void*>(value2)));
     28 }
     29 
     30 const void* RetainWrapper(CFAllocatorRef unused, const void* value) {
     31   return CFRetain(value);
     32 }
     33 
     34 void ReleaseWrapper(CFAllocatorRef unused, const void* value) {
     35   CFRelease(value);
     36 }
     37 
     38 // CFEqual prior to 10.6 only performed pointer checks on SecCertificateRefs,
     39 // rather than checking if they were the same (logical) certificate, so a
     40 // custom structure is used for the array callbacks.
     41 const CFArrayCallBacks kCertArrayCallbacks = {
     42   0,  // version
     43   RetainWrapper,
     44   ReleaseWrapper,
     45   CFCopyDescription,
     46   OurSecCertificateEqual,
     47 };
     48 
     49 }  // namespace
     50 
     51 bool TestRootCerts::Add(X509Certificate* certificate) {
     52   if (CFArrayContainsValue(temporary_roots_,
     53                            CFRangeMake(0, CFArrayGetCount(temporary_roots_)),
     54                            certificate->os_cert_handle()))
     55     return true;
     56   CFArrayAppendValue(temporary_roots_, certificate->os_cert_handle());
     57   return true;
     58 }
     59 
     60 void TestRootCerts::Clear() {
     61   CFArrayRemoveAllValues(temporary_roots_);
     62 }
     63 
     64 bool TestRootCerts::IsEmpty() const {
     65   return CFArrayGetCount(temporary_roots_) == 0;
     66 }
     67 
     68 OSStatus TestRootCerts::FixupSecTrustRef(SecTrustRef trust_ref) const {
     69   if (IsEmpty())
     70     return noErr;
     71 
     72   // Despite SecTrustSetAnchorCertificatesOnly existing in OS X 10.6, and
     73   // being documented as available, it is not actually implemented. On 10.7+,
     74   // however, it always works.
     75   if (base::mac::IsOSLionOrLater()) {
     76     OSStatus status = SecTrustSetAnchorCertificates(trust_ref,
     77                                                     temporary_roots_);
     78     if (status)
     79       return status;
     80     return SecTrustSetAnchorCertificatesOnly(trust_ref, !allow_system_trust_);
     81   }
     82 
     83   if (!allow_system_trust_) {
     84     // Avoid any copying if system roots are not to be trusted. This acts as
     85     // an exclusive list on 10.6, replacing the built-ins.
     86     return SecTrustSetAnchorCertificates(trust_ref, temporary_roots_);
     87   }
     88 
     89   // Otherwise, both system trust and temporary_roots_ must be trusted.
     90   // Emulate the functionality of SecTrustSetAnchorCertificatesOnly by
     91   // creating a copy of the system roots and merging with temporary_roots_.
     92   CFArrayRef system_roots = NULL;
     93   OSStatus status = SecTrustCopyAnchorCertificates(&system_roots);
     94   if (status)
     95     return status;
     96 
     97   base::ScopedCFTypeRef<CFArrayRef> scoped_system_roots(system_roots);
     98   base::ScopedCFTypeRef<CFMutableArrayRef> scoped_roots(
     99       CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, scoped_system_roots));
    100   CFArrayAppendArray(scoped_roots, temporary_roots_,
    101                      CFRangeMake(0, CFArrayGetCount(temporary_roots_)));
    102   return SecTrustSetAnchorCertificates(trust_ref, scoped_roots);
    103 }
    104 
    105 void TestRootCerts::SetAllowSystemTrust(bool allow_system_trust) {
    106   allow_system_trust_ = allow_system_trust;
    107 }
    108 
    109 TestRootCerts::~TestRootCerts() {}
    110 
    111 void TestRootCerts::Init() {
    112   temporary_roots_.reset(CFArrayCreateMutable(kCFAllocatorDefault, 0,
    113                                               &kCertArrayCallbacks));
    114   allow_system_trust_ = true;
    115 }
    116 
    117 }  // namespace net
    118