OLD | NEW |
| (Empty) |
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 "chrome/browser/chromeos/network_settings/onc_certificate_importer.h" | |
6 | |
7 #include <cert.h> | |
8 #include <keyhi.h> | |
9 #include <pk11pub.h> | |
10 #include <string> | |
11 | |
12 #include "base/logging.h" | |
13 #include "base/string_number_conversions.h" | |
14 #include "base/values.h" | |
15 #include "chrome/browser/chromeos/cros/onc_constants.h" | |
16 #include "chrome/browser/chromeos/network_settings/onc_test_utils.h" | |
17 #include "chrome/common/net/x509_certificate_model.h" | |
18 #include "crypto/nss_util.h" | |
19 #include "net/base/cert_type.h" | |
20 #include "net/base/crypto_module.h" | |
21 #include "net/base/nss_cert_database.h" | |
22 #include "net/base/x509_certificate.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 namespace { | |
26 | |
27 net::CertType GetCertType(const net::X509Certificate* cert) { | |
28 DCHECK(cert); | |
29 return x509_certificate_model::GetType(cert->os_cert_handle()); | |
30 } | |
31 | |
32 } // namespace | |
33 | |
34 namespace chromeos { | |
35 namespace onc { | |
36 | |
37 class ONCCertificateImporterTest : public testing::Test { | |
38 public: | |
39 virtual void SetUp() { | |
40 ASSERT_TRUE(test_nssdb_.is_open()); | |
41 | |
42 slot_ = net::NSSCertDatabase::GetInstance()->GetPublicModule(); | |
43 | |
44 // Don't run the test if the setup failed. | |
45 ASSERT_TRUE(slot_->os_module_handle()); | |
46 | |
47 // Test db should be empty at start of test. | |
48 EXPECT_EQ(0ul, ListCertsInSlot(slot_->os_module_handle()).size()); | |
49 } | |
50 | |
51 virtual void TearDown() { | |
52 EXPECT_TRUE(CleanupSlotContents(slot_->os_module_handle())); | |
53 EXPECT_EQ(0ul, ListCertsInSlot(slot_->os_module_handle()).size()); | |
54 } | |
55 | |
56 virtual ~ONCCertificateImporterTest() {} | |
57 | |
58 protected: | |
59 void AddCertificateFromFile(std::string filename, | |
60 net::CertType expected_type, | |
61 std::string* guid) { | |
62 scoped_ptr<base::DictionaryValue> onc = | |
63 test_utils::ReadTestDictionary(filename); | |
64 base::ListValue* certificates; | |
65 onc->GetListWithoutPathExpansion(kCertificates, &certificates); | |
66 | |
67 base::DictionaryValue* certificate; | |
68 certificates->GetDictionary(0, &certificate); | |
69 certificate->GetStringWithoutPathExpansion(kGUID, guid); | |
70 | |
71 CertificateImporter importer(NetworkUIData::ONC_SOURCE_USER_IMPORT, | |
72 false /* don't allow webtrust */); | |
73 std::string error; | |
74 EXPECT_TRUE(importer.ParseAndStoreCertificates(*certificates, &error)); | |
75 EXPECT_TRUE(error.empty()); | |
76 | |
77 net::CertificateList result_list; | |
78 CertificateImporter::ListCertsWithNickname(*guid, &result_list); | |
79 ASSERT_EQ(1ul, result_list.size()); | |
80 EXPECT_EQ(expected_type, GetCertType(result_list[0].get())); | |
81 } | |
82 | |
83 scoped_refptr<net::CryptoModule> slot_; | |
84 | |
85 private: | |
86 net::CertificateList ListCertsInSlot(PK11SlotInfo* slot) { | |
87 net::CertificateList result; | |
88 CERTCertList* cert_list = PK11_ListCertsInSlot(slot); | |
89 for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list); | |
90 !CERT_LIST_END(node, cert_list); | |
91 node = CERT_LIST_NEXT(node)) { | |
92 result.push_back(net::X509Certificate::CreateFromHandle( | |
93 node->cert, net::X509Certificate::OSCertHandles())); | |
94 } | |
95 CERT_DestroyCertList(cert_list); | |
96 | |
97 // Sort the result so that test comparisons can be deterministic. | |
98 std::sort(result.begin(), result.end(), net::X509Certificate::LessThan()); | |
99 return result; | |
100 } | |
101 | |
102 bool CleanupSlotContents(PK11SlotInfo* slot) { | |
103 bool ok = true; | |
104 net::CertificateList certs = ListCertsInSlot(slot); | |
105 for (size_t i = 0; i < certs.size(); ++i) { | |
106 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(certs[i])) | |
107 ok = false; | |
108 } | |
109 return ok; | |
110 } | |
111 | |
112 crypto::ScopedTestNSSDB test_nssdb_; | |
113 }; | |
114 | |
115 TEST_F(ONCCertificateImporterTest, AddClientCertificate) { | |
116 std::string guid; | |
117 AddCertificateFromFile("certificate-client.onc", net::USER_CERT, &guid); | |
118 | |
119 SECKEYPrivateKeyList* privkey_list = | |
120 PK11_ListPrivKeysInSlot(slot_->os_module_handle(), NULL, NULL); | |
121 EXPECT_TRUE(privkey_list); | |
122 if (privkey_list) { | |
123 SECKEYPrivateKeyListNode* node = PRIVKEY_LIST_HEAD(privkey_list); | |
124 int count = 0; | |
125 while (!PRIVKEY_LIST_END(node, privkey_list)) { | |
126 char* name = PK11_GetPrivateKeyNickname(node->key); | |
127 EXPECT_STREQ(guid.c_str(), name); | |
128 PORT_Free(name); | |
129 count++; | |
130 node = PRIVKEY_LIST_NEXT(node); | |
131 } | |
132 EXPECT_EQ(1, count); | |
133 SECKEY_DestroyPrivateKeyList(privkey_list); | |
134 } | |
135 | |
136 SECKEYPublicKeyList* pubkey_list = | |
137 PK11_ListPublicKeysInSlot(slot_->os_module_handle(), NULL); | |
138 EXPECT_TRUE(pubkey_list); | |
139 if (pubkey_list) { | |
140 SECKEYPublicKeyListNode* node = PUBKEY_LIST_HEAD(pubkey_list); | |
141 int count = 0; | |
142 while (!PUBKEY_LIST_END(node, pubkey_list)) { | |
143 count++; | |
144 node = PUBKEY_LIST_NEXT(node); | |
145 } | |
146 EXPECT_EQ(1, count); | |
147 SECKEY_DestroyPublicKeyList(pubkey_list); | |
148 } | |
149 } | |
150 | |
151 TEST_F(ONCCertificateImporterTest, AddServerCertificate) { | |
152 std::string guid; | |
153 AddCertificateFromFile("certificate-server.onc", net::SERVER_CERT, &guid); | |
154 | |
155 SECKEYPrivateKeyList* privkey_list = | |
156 PK11_ListPrivKeysInSlot(slot_->os_module_handle(), NULL, NULL); | |
157 EXPECT_FALSE(privkey_list); | |
158 | |
159 SECKEYPublicKeyList* pubkey_list = | |
160 PK11_ListPublicKeysInSlot(slot_->os_module_handle(), NULL); | |
161 EXPECT_FALSE(pubkey_list); | |
162 } | |
163 | |
164 TEST_F(ONCCertificateImporterTest, AddWebAuthorityCertificate) { | |
165 std::string guid; | |
166 AddCertificateFromFile("certificate-web-authority.onc", net::CA_CERT, &guid); | |
167 | |
168 SECKEYPrivateKeyList* privkey_list = | |
169 PK11_ListPrivKeysInSlot(slot_->os_module_handle(), NULL, NULL); | |
170 EXPECT_FALSE(privkey_list); | |
171 | |
172 SECKEYPublicKeyList* pubkey_list = | |
173 PK11_ListPublicKeysInSlot(slot_->os_module_handle(), NULL); | |
174 EXPECT_FALSE(pubkey_list); | |
175 } | |
176 | |
177 class ONCCertificateImporterTestWithParam : | |
178 public ONCCertificateImporterTest, | |
179 public testing::WithParamInterface< | |
180 std::pair<net::CertType, std::pair<const char*, const char*> > > { | |
181 protected: | |
182 net::CertType GetCertTypeParam() { | |
183 return GetParam().first; | |
184 } | |
185 | |
186 std::string GetOriginalFilename() { | |
187 return GetParam().second.first; | |
188 } | |
189 | |
190 std::string GetUpdatedFilename() { | |
191 return GetParam().second.second; | |
192 } | |
193 }; | |
194 | |
195 TEST_P(ONCCertificateImporterTestWithParam, UpdateCertificate) { | |
196 // First we import a certificate. | |
197 { | |
198 SCOPED_TRACE("Import original certificate"); | |
199 std::string guid_original; | |
200 AddCertificateFromFile(GetOriginalFilename(), GetCertTypeParam(), | |
201 &guid_original); | |
202 } | |
203 | |
204 // Now we import the same certificate with a different GUID. The cert should | |
205 // be retrievable via the new GUID. | |
206 { | |
207 SCOPED_TRACE("Import updated certificate"); | |
208 std::string guid_updated; | |
209 AddCertificateFromFile(GetUpdatedFilename(), GetCertTypeParam(), | |
210 &guid_updated); | |
211 } | |
212 } | |
213 | |
214 TEST_P(ONCCertificateImporterTestWithParam, ReimportCertificate) { | |
215 // Verify that reimporting a client certificate works. | |
216 for (int i = 0; i < 2; ++i) { | |
217 SCOPED_TRACE("Import certificate, iteration " + base::IntToString(i)); | |
218 | |
219 std::string guid_original; | |
220 AddCertificateFromFile(GetOriginalFilename(), GetCertTypeParam(), | |
221 &guid_original); | |
222 } | |
223 } | |
224 | |
225 INSTANTIATE_TEST_CASE_P( | |
226 ONCCertificateImporterTestWithParam, | |
227 ONCCertificateImporterTestWithParam, | |
228 ::testing::Values( | |
229 std::make_pair(net::USER_CERT, | |
230 std::make_pair("certificate-client.onc", | |
231 "certificate-client-update.onc")), | |
232 std::make_pair(net::SERVER_CERT, | |
233 std::make_pair("certificate-server.onc", | |
234 "certificate-server-update.onc")), | |
235 std::make_pair( | |
236 net::CA_CERT, | |
237 std::make_pair("certificate-web-authority.onc", | |
238 "certificate-web-authority-update.onc")))); | |
239 | |
240 } // namespace onc | |
241 } // namespace chromeos | |
OLD | NEW |