summaryrefslogtreecommitdiffstats
path: root/net/ssl/openssl_client_key_store_unittest.cc
blob: f1d8a304b4c05fe9bab7c30f9c840bcfc5eb7f40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/ssl/openssl_client_key_store.h"

#include "base/memory/ref_counted.h"
#include "crypto/scoped_openssl_types.h"
#include "net/base/test_data_directory.h"
#include "net/test/cert_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

namespace {

// Return the internal reference count of a given EVP_PKEY.
int EVP_PKEY_get_refcount(EVP_PKEY* pkey) {
  return pkey->references;
}

// A common test class to ensure that the store is flushed after
// each test.
class OpenSSLClientKeyStoreTest : public ::testing::Test {
 public:
  OpenSSLClientKeyStoreTest()
    : store_(OpenSSLClientKeyStore::GetInstance()) {
  }

  ~OpenSSLClientKeyStoreTest() override {
    if (store_)
      store_->Flush();
  }

 protected:
  OpenSSLClientKeyStore* store_;
};

// Check that GetInstance() returns non-null
TEST_F(OpenSSLClientKeyStoreTest, GetInstance) {
  ASSERT_TRUE(store_);
}

// Check that Flush() works correctly.
TEST_F(OpenSSLClientKeyStoreTest, Flush) {
  ASSERT_TRUE(store_);

  scoped_refptr<X509Certificate> cert_1(
      ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
  ASSERT_TRUE(cert_1.get());

  crypto::ScopedEVP_PKEY priv_key(EVP_PKEY_new());
  ASSERT_TRUE(priv_key.get());

  ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
                                                 priv_key.get()));

  store_->Flush();

  // Retrieve the private key. This should fail because the store
  // was flushed.
  crypto::ScopedEVP_PKEY pkey = store_->FetchClientCertPrivateKey(cert_1.get());
  ASSERT_FALSE(pkey.get());
}

// Check that trying to retrieve the private key of an unknown certificate
// simply fails by returning null.
TEST_F(OpenSSLClientKeyStoreTest, FetchEmptyPrivateKey) {
  ASSERT_TRUE(store_);

  scoped_refptr<X509Certificate> cert_1(
      ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
  ASSERT_TRUE(cert_1.get());

  // Retrieve the private key now. This should fail because it was
  // never recorded in the store.
  crypto::ScopedEVP_PKEY pkey = store_->FetchClientCertPrivateKey(cert_1.get());
  ASSERT_FALSE(pkey.get());
}

// Check that any private key recorded through RecordClientCertPrivateKey
// can be retrieved with FetchClientCertPrivateKey.
TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchPrivateKey) {
  ASSERT_TRUE(store_);

  // Any certificate / key pair will do, the store is not supposed to
  // check that the private and certificate public keys match. This is
  // by design since the private EVP_PKEY could be a wrapper around a
  // JNI reference, with no way to access the real private key bits.
  scoped_refptr<X509Certificate> cert_1(
      ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
  ASSERT_TRUE(cert_1.get());

  crypto::ScopedEVP_PKEY priv_key(EVP_PKEY_new());
  ASSERT_TRUE(priv_key.get());
  ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key.get()));

  // Add the key a first time, this should increment its reference count.
  ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
                                                 priv_key.get()));
  ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get()));

  // Two successive calls with the same certificate / private key shall
  // also succeed, but the key's reference count should not be incremented.
  ASSERT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
                                                 priv_key.get()));
  ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get()));

  // Retrieve the private key. This should increment the private key's
  // reference count.
  crypto::ScopedEVP_PKEY pkey2 =
      store_->FetchClientCertPrivateKey(cert_1.get());
  ASSERT_EQ(pkey2.get(), priv_key.get());
  ASSERT_EQ(3, EVP_PKEY_get_refcount(priv_key.get()));

  // Flush the store explicitely, this should decrement the private
  // key's reference count.
  store_->Flush();
  ASSERT_EQ(2, EVP_PKEY_get_refcount(priv_key.get()));
}

// Same test, but with two certificates / private keys.
TEST_F(OpenSSLClientKeyStoreTest, RecordAndFetchTwoPrivateKeys) {
  scoped_refptr<X509Certificate> cert_1(
      ImportCertFromFile(GetTestCertsDirectory(), "client_1.pem"));
  ASSERT_TRUE(cert_1.get());

  scoped_refptr<X509Certificate> cert_2(
      ImportCertFromFile(GetTestCertsDirectory(), "client_2.pem"));
  ASSERT_TRUE(cert_2.get());

  crypto::ScopedEVP_PKEY priv_key1(EVP_PKEY_new());
  ASSERT_TRUE(priv_key1.get());
  ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key1.get()));

  crypto::ScopedEVP_PKEY priv_key2(EVP_PKEY_new());
  ASSERT_TRUE(priv_key2.get());
  ASSERT_EQ(1, EVP_PKEY_get_refcount(priv_key2.get()));

  ASSERT_NE(priv_key1.get(), priv_key2.get());

  // Add the key a first time, this shall succeed, and increment the
  // reference count.
  EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_1.get(),
                                                 priv_key1.get()));
  EXPECT_TRUE(store_->RecordClientCertPrivateKey(cert_2.get(),
                                                 priv_key2.get()));
  EXPECT_EQ(2, EVP_PKEY_get_refcount(priv_key1.get()));
  EXPECT_EQ(2, EVP_PKEY_get_refcount(priv_key2.get()));

  // Retrieve the private key now. This shall succeed and increment
  // the private key's reference count.
  crypto::ScopedEVP_PKEY fetch_key1 =
      store_->FetchClientCertPrivateKey(cert_1.get());
  crypto::ScopedEVP_PKEY fetch_key2 =
      store_->FetchClientCertPrivateKey(cert_2.get());

  EXPECT_TRUE(fetch_key1.get());
  EXPECT_TRUE(fetch_key2.get());

  EXPECT_EQ(fetch_key1.get(), priv_key1.get());
  EXPECT_EQ(fetch_key2.get(), priv_key2.get());

  EXPECT_EQ(3, EVP_PKEY_get_refcount(priv_key1.get()));
  EXPECT_EQ(3, EVP_PKEY_get_refcount(priv_key2.get()));
}

}  // namespace
}  // namespace net