1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Use of this source code is governed by a BSD-style license that can be
321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// found in the LICENSE file.
421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/base/test_root_certs.h"
621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <cert.h>
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/logging.h"
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/stl_util-inl.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/nss_util.h"
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/base/x509_certificate.h"
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsennamespace net {
1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// TrustEntry is used to store the original CERTCertificate and CERTCertTrust
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// for a certificate whose trust status has been changed by the
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// TestRootCerts.
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass TestRootCerts::TrustEntry {
2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen public:
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Creates a new TrustEntry by incrementing the reference to |certificate|
2221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // and copying |trust|.
2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  TrustEntry(CERTCertificate* certificate, CERTCertTrust trust);
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ~TrustEntry();
2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertificate* certificate() const { return certificate_; }
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertTrust trust() const { return trust_; }
2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
2921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen private:
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // The temporary root certificate.
3121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertificate* certificate_;
3221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
3321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // The original trust settings, before |certificate_| was manipulated to
3421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // be a temporarily trusted root.
3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertTrust trust_;
3621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DISALLOW_COPY_AND_ASSIGN(TrustEntry);
3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen};
3921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTestRootCerts::TrustEntry::TrustEntry(CERTCertificate* certificate,
4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                      CERTCertTrust trust)
4221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : certificate_(CERT_DupCertificate(certificate)),
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      trust_(trust) {
4421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
4521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
4621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTestRootCerts::TrustEntry::~TrustEntry() {
4721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERT_DestroyCertificate(certificate_);
4821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
4921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
5021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool TestRootCerts::Add(X509Certificate* certificate) {
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Preserve the original trust bits so that they can be restored when
5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // the certificate is removed.
5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertTrust original_trust;
5421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SECStatus rv = CERT_GetCertTrust(certificate->os_cert_handle(),
5521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                   &original_trust);
5621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (rv != SECSuccess) {
5721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // CERT_GetCertTrust will fail if the certificate does not have any
5821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // particular trust settings associated with it, and attempts to use
5921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // |original_trust| later to restore the original trust settings will not
6021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // cause the trust settings to be revoked. If the certificate has no
6121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // particular trust settings associated with it, mark the certificate as
6221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // a valid CA certificate with no specific trust.
6321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    rv = CERT_DecodeTrustString(&original_trust, "c,c,c");
6421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
6521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Change the trust bits to unconditionally trust this certificate.
6721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CERTCertTrust new_trust;
6821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  rv = CERT_DecodeTrustString(&new_trust, "TCu,Cu,Tu");
6921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (rv != SECSuccess) {
7021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    LOG(ERROR) << "Cannot decode certificate trust string.";
7121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
7221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
7321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
7521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            certificate->os_cert_handle(),
7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                            &new_trust);
7721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (rv != SECSuccess) {
7821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    LOG(ERROR) << "Cannot change certificate trust.";
7921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
8021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
8121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  trust_cache_.push_back(new TrustEntry(certificate->os_cert_handle(),
8321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                        original_trust));
8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
8621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid TestRootCerts::Clear() {
8821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Restore the certificate trusts to what they were originally, before
8921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Add() was called. Work from the rear first, since if a certificate was
9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // added twice, the second entry's original trust status will be that of
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // the first entry, while the first entry contains the desired resultant
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // status.
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  for (std::list<TrustEntry*>::reverse_iterator it = trust_cache_.rbegin();
9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen       it != trust_cache_.rend(); ++it) {
9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CERTCertTrust original_trust = (*it)->trust();
9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    SECStatus rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(),
9721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                        (*it)->certificate(),
9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                        &original_trust);
9921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // DCHECK(), rather than LOG(), as a failure to restore the original
10021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // trust can cause flake or hard-to-trace errors in any unit tests that
10121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // occur after Clear() has been called.
10221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DCHECK_EQ(SECSuccess, rv) << "Cannot restore certificate trust.";
10321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  STLDeleteElements(&trust_cache_);
10521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
10721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool TestRootCerts::IsEmpty() const {
10821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return trust_cache_.empty();
10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
11021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTestRootCerts::~TestRootCerts() {
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  Clear();
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid TestRootCerts::Init() {
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  crypto::EnsureNSSInit();
11721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
11821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}  // namespace net
120