• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
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/test/cert_test_util.h"
6 
7 #include <certdb.h>
8 #include <pk11pub.h>
9 #include <secmod.h>
10 #include <secmodt.h>
11 #include <string.h>
12 
13 #include <memory>
14 
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/logging.h"
18 #include "crypto/nss_key_util.h"
19 #include "crypto/nss_util_internal.h"
20 #include "crypto/scoped_nss_types.h"
21 #include "net/cert/cert_type.h"
22 #include "net/cert/known_roots_nss.h"
23 #include "net/cert/x509_util_nss.h"
24 
25 namespace net {
26 
27 namespace {
28 
29 // Returns true if the provided slot looks like it contains built-in root.
IsNssBuiltInRootSlot(PK11SlotInfo * slot)30 bool IsNssBuiltInRootSlot(PK11SlotInfo* slot) {
31   if (!PK11_IsPresent(slot) || !PK11_HasRootCerts(slot)) {
32     return false;
33   }
34   crypto::ScopedCERTCertList cert_list(PK11_ListCertsInSlot(slot));
35   if (!cert_list) {
36     return false;
37   }
38   bool built_in_cert_found = false;
39   for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
40        !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) {
41     if (IsKnownRoot(node->cert)) {
42       built_in_cert_found = true;
43       break;
44     }
45   }
46   return built_in_cert_found;
47 }
48 
49 // Returns the slot which holds the built-in root certificates.
GetNssBuiltInRootCertsSlot()50 crypto::ScopedPK11Slot GetNssBuiltInRootCertsSlot() {
51   crypto::AutoSECMODListReadLock auto_lock;
52   SECMODModuleList* head = SECMOD_GetDefaultModuleList();
53   for (SECMODModuleList* item = head; item != nullptr; item = item->next) {
54     int slot_count = item->module->loaded ? item->module->slotCount : 0;
55     for (int i = 0; i < slot_count; i++) {
56       PK11SlotInfo* slot = item->module->slots[i];
57       if (IsNssBuiltInRootSlot(slot)) {
58         return crypto::ScopedPK11Slot(PK11_ReferenceSlot(slot));
59       }
60     }
61   }
62   return crypto::ScopedPK11Slot();
63 }
64 
65 }  // namespace
66 
ImportSensitiveKeyFromFile(const base::FilePath & dir,base::StringPiece key_filename,PK11SlotInfo * slot)67 bool ImportSensitiveKeyFromFile(const base::FilePath& dir,
68                                 base::StringPiece key_filename,
69                                 PK11SlotInfo* slot) {
70   base::FilePath key_path = dir.AppendASCII(key_filename);
71   std::string key_pkcs8;
72   bool success = base::ReadFileToString(key_path, &key_pkcs8);
73   if (!success) {
74     LOG(ERROR) << "Failed to read file " << key_path.value();
75     return false;
76   }
77 
78   crypto::ScopedSECKEYPrivateKey private_key(
79       crypto::ImportNSSKeyFromPrivateKeyInfo(
80           slot, base::as_bytes(base::make_span(key_pkcs8)),
81           /*permanent=*/true));
82   LOG_IF(ERROR, !private_key)
83       << "Could not create key from file " << key_path.value();
84   return !!private_key;
85 }
86 
ImportClientCertToSlot(CERTCertificate * nss_cert,PK11SlotInfo * slot)87 bool ImportClientCertToSlot(CERTCertificate* nss_cert, PK11SlotInfo* slot) {
88   std::string nickname =
89       x509_util::GetDefaultUniqueNickname(nss_cert, USER_CERT, slot);
90   SECStatus rv = PK11_ImportCert(slot, nss_cert, CK_INVALID_HANDLE,
91                                  nickname.c_str(), PR_FALSE);
92   if (rv != SECSuccess) {
93     LOG(ERROR) << "Could not import cert";
94     return false;
95   }
96   return true;
97 }
98 
ImportClientCertToSlot(const scoped_refptr<X509Certificate> & cert,PK11SlotInfo * slot)99 ScopedCERTCertificate ImportClientCertToSlot(
100     const scoped_refptr<X509Certificate>& cert,
101     PK11SlotInfo* slot) {
102   ScopedCERTCertificate nss_cert =
103       x509_util::CreateCERTCertificateFromX509Certificate(cert.get());
104   if (!nss_cert)
105     return nullptr;
106 
107   if (!ImportClientCertToSlot(nss_cert.get(), slot))
108     return nullptr;
109 
110   return nss_cert;
111 }
112 
ImportClientCertAndKeyFromFile(const base::FilePath & dir,base::StringPiece cert_filename,base::StringPiece key_filename,PK11SlotInfo * slot,ScopedCERTCertificate * nss_cert)113 scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile(
114     const base::FilePath& dir,
115     base::StringPiece cert_filename,
116     base::StringPiece key_filename,
117     PK11SlotInfo* slot,
118     ScopedCERTCertificate* nss_cert) {
119   if (!ImportSensitiveKeyFromFile(dir, key_filename, slot)) {
120     LOG(ERROR) << "Could not import private key from file " << key_filename;
121     return nullptr;
122   }
123 
124   scoped_refptr<X509Certificate> cert(ImportCertFromFile(dir, cert_filename));
125 
126   if (!cert.get()) {
127     LOG(ERROR) << "Failed to parse cert from file " << cert_filename;
128     return nullptr;
129   }
130 
131   *nss_cert = ImportClientCertToSlot(cert, slot);
132   if (!*nss_cert)
133     return nullptr;
134 
135   // |cert| continues to point to the original X509Certificate before the
136   // import to |slot|. However this should not make a difference as NSS handles
137   // state globally.
138   return cert;
139 }
140 
ImportClientCertAndKeyFromFile(const base::FilePath & dir,base::StringPiece cert_filename,base::StringPiece key_filename,PK11SlotInfo * slot)141 scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile(
142     const base::FilePath& dir,
143     base::StringPiece cert_filename,
144     base::StringPiece key_filename,
145     PK11SlotInfo* slot) {
146   ScopedCERTCertificate nss_cert;
147   return ImportClientCertAndKeyFromFile(dir, cert_filename, key_filename, slot,
148                                         &nss_cert);
149 }
150 
ImportCERTCertificateFromFile(const base::FilePath & certs_dir,base::StringPiece cert_file)151 ScopedCERTCertificate ImportCERTCertificateFromFile(
152     const base::FilePath& certs_dir,
153     base::StringPiece cert_file) {
154   scoped_refptr<X509Certificate> cert =
155       ImportCertFromFile(certs_dir, cert_file);
156   if (!cert)
157     return nullptr;
158   return x509_util::CreateCERTCertificateFromX509Certificate(cert.get());
159 }
160 
CreateCERTCertificateListFromFile(const base::FilePath & certs_dir,base::StringPiece cert_file,int format)161 ScopedCERTCertificateList CreateCERTCertificateListFromFile(
162     const base::FilePath& certs_dir,
163     base::StringPiece cert_file,
164     int format) {
165   CertificateList certs =
166       CreateCertificateListFromFile(certs_dir, cert_file, format);
167   ScopedCERTCertificateList nss_certs;
168   for (const auto& cert : certs) {
169     ScopedCERTCertificate nss_cert =
170         x509_util::CreateCERTCertificateFromX509Certificate(cert.get());
171     if (!nss_cert)
172       return {};
173     nss_certs.push_back(std::move(nss_cert));
174   }
175   return nss_certs;
176 }
177 
GetAnNssBuiltinSslTrustedRoot()178 ScopedCERTCertificate GetAnNssBuiltinSslTrustedRoot() {
179   crypto::ScopedPK11Slot root_certs_slot = GetNssBuiltInRootCertsSlot();
180   if (!root_certs_slot) {
181     return nullptr;
182   }
183 
184   scoped_refptr<X509Certificate> ssl_trusted_root;
185 
186   crypto::ScopedCERTCertList cert_list(
187       PK11_ListCertsInSlot(root_certs_slot.get()));
188   if (!cert_list) {
189     return nullptr;
190   }
191   for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
192        !CERT_LIST_END(node, cert_list); node = CERT_LIST_NEXT(node)) {
193     CERTCertTrust trust;
194     if (CERT_GetCertTrust(node->cert, &trust) != SECSuccess) {
195       continue;
196     }
197     int trust_flags = SEC_GET_TRUST_FLAGS(&trust, trustSSL);
198     if ((trust_flags & CERTDB_TRUSTED_CA) == CERTDB_TRUSTED_CA) {
199       return x509_util::DupCERTCertificate(node->cert);
200     }
201   }
202 
203   return nullptr;
204 }
205 
206 }  // namespace net
207