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.
5 #include "chromeos/network/onc/onc_certificate_importer.h"
13 #include "base/logging.h"
14 #include "base/string_number_conversions.h"
15 #include "base/values.h"
16 #include "chromeos/network/onc/onc_constants.h"
17 #include "chromeos/network/onc/onc_test_utils.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"
29 // In NSS 3.13, CERTDB_VALID_PEER was renamed CERTDB_TERMINAL_RECORD. So we use
30 // the new name of the macro.
31 #if !defined(CERTDB_TERMINAL_RECORD)
32 #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER
35 net::CertType
GetCertType(net::X509Certificate::OSCertHandle cert
) {
36 CERTCertTrust trust
= {0};
37 CERT_GetCertTrust(cert
, &trust
);
39 unsigned all_flags
= trust
.sslFlags
| trust
.emailFlags
|
40 trust
.objectSigningFlags
;
42 if (cert
->nickname
&& (all_flags
& CERTDB_USER
))
43 return net::USER_CERT
;
44 if ((all_flags
& CERTDB_VALID_CA
) || CERT_IsCACert(cert
, NULL
))
46 // TODO(mattm): http://crbug.com/128633.
47 if (trust
.sslFlags
& CERTDB_TERMINAL_RECORD
)
48 return net::SERVER_CERT
;
49 return net::UNKNOWN_CERT
;
52 net::CertType
GetCertType(net::X509Certificate::OSCertHandle cert
) {
54 return net::UNKNOWN_CERT
;
58 class ONCCertificateImporterTest
: public testing::Test
{
60 virtual void SetUp() {
61 ASSERT_TRUE(test_nssdb_
.is_open());
63 slot_
= net::NSSCertDatabase::GetInstance()->GetPublicModule();
65 // Don't run the test if the setup failed.
66 ASSERT_TRUE(slot_
->os_module_handle());
68 // Test db should be empty at start of test.
69 EXPECT_EQ(0ul, ListCertsInSlot(slot_
->os_module_handle()).size());
72 virtual void TearDown() {
73 EXPECT_TRUE(CleanupSlotContents(slot_
->os_module_handle()));
74 EXPECT_EQ(0ul, ListCertsInSlot(slot_
->os_module_handle()).size());
77 virtual ~ONCCertificateImporterTest() {}
80 void AddCertificateFromFile(std::string filename
,
81 net::CertType expected_type
,
83 scoped_ptr
<base::DictionaryValue
> onc
=
84 test_utils::ReadTestDictionary(filename
);
85 base::ListValue
* certificates
;
86 onc
->GetListWithoutPathExpansion(kCertificates
, &certificates
);
88 base::DictionaryValue
* certificate
;
89 certificates
->GetDictionary(0, &certificate
);
90 certificate
->GetStringWithoutPathExpansion(kGUID
, guid
);
92 CertificateImporter
importer(ONC_SOURCE_USER_IMPORT
,
93 false /* don't allow web trust */);
94 EXPECT_EQ(CertificateImporter::IMPORT_OK
,
95 importer
.ParseAndStoreCertificates(*certificates
));
97 net::CertificateList result_list
;
98 CertificateImporter::ListCertsWithNickname(*guid
, &result_list
);
99 ASSERT_EQ(1ul, result_list
.size());
100 EXPECT_EQ(expected_type
, GetCertType(result_list
[0]->os_cert_handle()));
103 scoped_refptr
<net::CryptoModule
> slot_
;
106 net::CertificateList
ListCertsInSlot(PK11SlotInfo
* slot
) {
107 net::CertificateList result
;
108 CERTCertList
* cert_list
= PK11_ListCertsInSlot(slot
);
109 for (CERTCertListNode
* node
= CERT_LIST_HEAD(cert_list
);
110 !CERT_LIST_END(node
, cert_list
);
111 node
= CERT_LIST_NEXT(node
)) {
112 result
.push_back(net::X509Certificate::CreateFromHandle(
113 node
->cert
, net::X509Certificate::OSCertHandles()));
115 CERT_DestroyCertList(cert_list
);
117 // Sort the result so that test comparisons can be deterministic.
118 std::sort(result
.begin(), result
.end(), net::X509Certificate::LessThan());
122 bool CleanupSlotContents(PK11SlotInfo
* slot
) {
124 net::CertificateList certs
= ListCertsInSlot(slot
);
125 for (size_t i
= 0; i
< certs
.size(); ++i
) {
126 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(certs
[i
]))
132 crypto::ScopedTestNSSDB test_nssdb_
;
135 TEST_F(ONCCertificateImporterTest
, AddClientCertificate
) {
137 AddCertificateFromFile("certificate-client.onc", net::USER_CERT
, &guid
);
139 SECKEYPrivateKeyList
* privkey_list
=
140 PK11_ListPrivKeysInSlot(slot_
->os_module_handle(), NULL
, NULL
);
141 EXPECT_TRUE(privkey_list
);
143 SECKEYPrivateKeyListNode
* node
= PRIVKEY_LIST_HEAD(privkey_list
);
145 while (!PRIVKEY_LIST_END(node
, privkey_list
)) {
146 char* name
= PK11_GetPrivateKeyNickname(node
->key
);
147 EXPECT_STREQ(guid
.c_str(), name
);
150 node
= PRIVKEY_LIST_NEXT(node
);
153 SECKEY_DestroyPrivateKeyList(privkey_list
);
156 SECKEYPublicKeyList
* pubkey_list
=
157 PK11_ListPublicKeysInSlot(slot_
->os_module_handle(), NULL
);
158 EXPECT_TRUE(pubkey_list
);
160 SECKEYPublicKeyListNode
* node
= PUBKEY_LIST_HEAD(pubkey_list
);
162 while (!PUBKEY_LIST_END(node
, pubkey_list
)) {
164 node
= PUBKEY_LIST_NEXT(node
);
167 SECKEY_DestroyPublicKeyList(pubkey_list
);
171 TEST_F(ONCCertificateImporterTest
, AddServerCertificate
) {
173 AddCertificateFromFile("certificate-server.onc", net::SERVER_CERT
, &guid
);
175 SECKEYPrivateKeyList
* privkey_list
=
176 PK11_ListPrivKeysInSlot(slot_
->os_module_handle(), NULL
, NULL
);
177 EXPECT_FALSE(privkey_list
);
179 SECKEYPublicKeyList
* pubkey_list
=
180 PK11_ListPublicKeysInSlot(slot_
->os_module_handle(), NULL
);
181 EXPECT_FALSE(pubkey_list
);
184 TEST_F(ONCCertificateImporterTest
, AddWebAuthorityCertificate
) {
186 AddCertificateFromFile("certificate-web-authority.onc", net::CA_CERT
, &guid
);
188 SECKEYPrivateKeyList
* privkey_list
=
189 PK11_ListPrivKeysInSlot(slot_
->os_module_handle(), NULL
, NULL
);
190 EXPECT_FALSE(privkey_list
);
192 SECKEYPublicKeyList
* pubkey_list
=
193 PK11_ListPublicKeysInSlot(slot_
->os_module_handle(), NULL
);
194 EXPECT_FALSE(pubkey_list
);
197 class ONCCertificateImporterTestWithParam
:
198 public ONCCertificateImporterTest
,
199 public testing::WithParamInterface
<
200 std::pair
<net::CertType
, std::pair
<const char*, const char*> > > {
202 net::CertType
GetCertTypeParam() {
203 return GetParam().first
;
206 std::string
GetOriginalFilename() {
207 return GetParam().second
.first
;
210 std::string
GetUpdatedFilename() {
211 return GetParam().second
.second
;
215 TEST_P(ONCCertificateImporterTestWithParam
, UpdateCertificate
) {
216 // First we import a certificate.
218 SCOPED_TRACE("Import original certificate");
219 std::string guid_original
;
220 AddCertificateFromFile(GetOriginalFilename(), GetCertTypeParam(),
224 // Now we import the same certificate with a different GUID. The cert should
225 // be retrievable via the new GUID.
227 SCOPED_TRACE("Import updated certificate");
228 std::string guid_updated
;
229 AddCertificateFromFile(GetUpdatedFilename(), GetCertTypeParam(),
234 TEST_P(ONCCertificateImporterTestWithParam
, ReimportCertificate
) {
235 // Verify that reimporting a client certificate works.
236 for (int i
= 0; i
< 2; ++i
) {
237 SCOPED_TRACE("Import certificate, iteration " + base::IntToString(i
));
239 std::string guid_original
;
240 AddCertificateFromFile(GetOriginalFilename(), GetCertTypeParam(),
245 INSTANTIATE_TEST_CASE_P(
246 ONCCertificateImporterTestWithParam
,
247 ONCCertificateImporterTestWithParam
,
249 std::make_pair(net::USER_CERT
,
250 std::make_pair("certificate-client.onc",
251 "certificate-client-update.onc")),
252 std::make_pair(net::SERVER_CERT
,
253 std::make_pair("certificate-server.onc",
254 "certificate-server-update.onc")),
257 std::make_pair("certificate-web-authority.onc",
258 "certificate-web-authority-update.onc"))));
261 } // namespace chromeos