Home | History | Annotate | Download | only in cert
      1 // Copyright (c) 2011 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 <cert.h>
      8 
      9 #include "base/logging.h"
     10 #include "base/stl_util.h"
     11 #include "crypto/nss_util.h"
     12 #include "net/cert/x509_certificate.h"
     13 
     14 #if defined(OS_IOS)
     15 #include "net/cert/x509_util_ios.h"
     16 #endif
     17 
     18 namespace net {
     19 
     20 // TrustEntry is used to store the original CERTCertificate and CERTCertTrust
     21 // for a certificate whose trust status has been changed by the
     22 // TestRootCerts.
     23 class TestRootCerts::TrustEntry {
     24  public:
     25   // Creates a new TrustEntry by incrementing the reference to |certificate|
     26   // and copying |trust|.
     27   TrustEntry(CERTCertificate* certificate, const CERTCertTrust& trust);
     28   ~TrustEntry();
     29 
     30   CERTCertificate* certificate() const { return certificate_; }
     31   const CERTCertTrust& trust() const { return trust_; }
     32 
     33  private:
     34   // The temporary root certificate.
     35   CERTCertificate* certificate_;
     36 
     37   // The original trust settings, before |certificate_| was manipulated to
     38   // be a temporarily trusted root.
     39   CERTCertTrust trust_;
     40 
     41   DISALLOW_COPY_AND_ASSIGN(TrustEntry);
     42 };
     43 
     44 TestRootCerts::TrustEntry::TrustEntry(CERTCertificate* certificate,
     45                                       const CERTCertTrust& trust)
     46     : certificate_(CERT_DupCertificate(certificate)),
     47       trust_(trust) {
     48 }
     49 
     50 TestRootCerts::TrustEntry::~TrustEntry() {
     51   CERT_DestroyCertificate(certificate_);
     52 }
     53 
     54 bool TestRootCerts::Add(X509Certificate* certificate) {
     55 #if defined(OS_IOS)
     56   x509_util_ios::NSSCertificate nss_certificate(certificate->os_cert_handle());
     57   CERTCertificate* cert_handle = nss_certificate.cert_handle();
     58 #else
     59   CERTCertificate* cert_handle = certificate->os_cert_handle();
     60 #endif
     61   // Preserve the original trust bits so that they can be restored when
     62   // the certificate is removed.
     63   CERTCertTrust original_trust;
     64   SECStatus rv = CERT_GetCertTrust(cert_handle, &original_trust);
     65   if (rv != SECSuccess) {
     66     // CERT_GetCertTrust will fail if the certificate does not have any
     67     // particular trust settings associated with it, and attempts to use
     68     // |original_trust| later to restore the original trust settings will not
     69     // cause the trust settings to be revoked. If the certificate has no
     70     // particular trust settings associated with it, mark the certificate as
     71     // a valid CA certificate with no specific trust.
     72     rv = CERT_DecodeTrustString(&original_trust, "c,c,c");
     73   }
     74 
     75   // Change the trust bits to unconditionally trust this certificate.
     76   CERTCertTrust new_trust;
     77   rv = CERT_DecodeTrustString(&new_trust, "TCu,Cu,Tu");
     78   if (rv != SECSuccess) {
     79     LOG(ERROR) << "Cannot decode certificate trust string.";
     80     return false;
     81   }
     82 
     83   rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert_handle, &new_trust);
     84   if (rv != SECSuccess) {
     85     LOG(ERROR) << "Cannot change certificate trust.";
     86     return false;
     87   }
     88 
     89   trust_cache_.push_back(new TrustEntry(cert_handle, original_trust));
     90   return true;
     91 }
     92 
     93 void TestRootCerts::Clear() {
     94   // Restore the certificate trusts to what they were originally, before
     95   // Add() was called. Work from the rear first, since if a certificate was
     96   // added twice, the second entry's original trust status will be that of
     97   // the first entry, while the first entry contains the desired resultant
     98   // status.
     99   for (std::list<TrustEntry*>::reverse_iterator it = trust_cache_.rbegin();
    100        it != trust_cache_.rend(); ++it) {
    101     CERTCertTrust original_trust = (*it)->trust();
    102     SECStatus rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
    103                                         (*it)->certificate(),
    104                                         &original_trust);
    105     // DCHECK(), rather than LOG(), as a failure to restore the original
    106     // trust can cause flake or hard-to-trace errors in any unit tests that
    107     // occur after Clear() has been called.
    108     DCHECK_EQ(SECSuccess, rv) << "Cannot restore certificate trust.";
    109   }
    110   STLDeleteElements(&trust_cache_);
    111 }
    112 
    113 bool TestRootCerts::IsEmpty() const {
    114   return trust_cache_.empty();
    115 }
    116 
    117 #if defined(USE_NSS)
    118 bool TestRootCerts::Contains(CERTCertificate* cert) const {
    119   for (std::list<TrustEntry*>::const_iterator it = trust_cache_.begin();
    120        it != trust_cache_.end(); ++it) {
    121     if (X509Certificate::IsSameOSCert(cert, (*it)->certificate()))
    122       return true;
    123   }
    124   return false;
    125 }
    126 #endif
    127 
    128 TestRootCerts::~TestRootCerts() {
    129   Clear();
    130 }
    131 
    132 void TestRootCerts::Init() {
    133   crypto::EnsureNSSInit();
    134 }
    135 
    136 }  // namespace net
    137