summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-22 01:46:19 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-22 01:46:19 +0000
commit4082fa2a9b307fc78675602bbcc0acade2029059 (patch)
treeaf99bc0b6de4414edea1b97af87316d203648095
parent25142ecaf7ff6a2ade87625b34d715700cb7e68f (diff)
downloadchromium_src-4082fa2a9b307fc78675602bbcc0acade2029059.zip
chromium_src-4082fa2a9b307fc78675602bbcc0acade2029059.tar.gz
chromium_src-4082fa2a9b307fc78675602bbcc0acade2029059.tar.bz2
Try#2: Handle Origin Bound Certificate expiration.
(Initialize test from raw time value to work around inability to parse dates past 2038 on 32-bit linux.) BUG=107047 TEST=net_unittests, unit_tests Review URL: http://codereview.chromium.org/9016002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115463 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/net/sqlite_origin_bound_cert_store.cc72
-rw-r--r--chrome/browser/net/sqlite_origin_bound_cert_store_unittest.cc223
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--net/base/default_origin_bound_cert_store.cc6
-rw-r--r--net/base/default_origin_bound_cert_store.h2
-rw-r--r--net/base/default_origin_bound_cert_store_unittest.cc91
-rw-r--r--net/base/origin_bound_cert_service.cc45
-rw-r--r--net/base/origin_bound_cert_service.h6
-rw-r--r--net/base/origin_bound_cert_service_unittest.cc50
-rw-r--r--net/base/origin_bound_cert_store.cc2
-rw-r--r--net/base/origin_bound_cert_store.h14
-rw-r--r--net/base/x509_certificate_nss.cc5
-rw-r--r--net/base/x509_util.h6
-rw-r--r--net/base/x509_util_nss.cc35
-rw-r--r--net/base/x509_util_nss.h3
-rw-r--r--net/base/x509_util_nss_unittest.cc22
-rw-r--r--net/base/x509_util_openssl.cc6
-rw-r--r--net/base/x509_util_openssl_unittest.cc11
18 files changed, 484 insertions, 116 deletions
diff --git a/chrome/browser/net/sqlite_origin_bound_cert_store.cc b/chrome/browser/net/sqlite_origin_bound_cert_store.cc
index 2223394..039530b 100644
--- a/chrome/browser/net/sqlite_origin_bound_cert_store.cc
+++ b/chrome/browser/net/sqlite_origin_bound_cert_store.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/diagnostics/sqlite_diagnostics.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/ssl_client_cert_type.h"
+#include "net/base/x509_certificate.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
@@ -117,7 +118,7 @@ class SQLiteOriginBoundCertStore::Backend
};
// Version number of the database.
-static const int kCurrentVersionNumber = 2;
+static const int kCurrentVersionNumber = 3;
static const int kCompatibleVersionNumber = 1;
namespace {
@@ -129,7 +130,8 @@ bool InitTable(sql::Connection* db) {
"origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
"private_key BLOB NOT NULL,"
"cert BLOB NOT NULL,"
- "cert_type INTEGER)"))
+ "cert_type INTEGER,"
+ "expiration_time INTEGER)"))
return false;
}
@@ -171,7 +173,8 @@ bool SQLiteOriginBoundCertStore::Backend::Load(
// Slurp all the certs into the out-vector.
sql::Statement smt(db_->GetUniqueStatement(
- "SELECT origin, private_key, cert, cert_type FROM origin_bound_certs"));
+ "SELECT origin, private_key, cert, cert_type, expiration_time "
+ "FROM origin_bound_certs"));
if (!smt) {
NOTREACHED() << "select statement prep failed";
db_.reset();
@@ -186,6 +189,7 @@ bool SQLiteOriginBoundCertStore::Backend::Load(
new net::DefaultOriginBoundCertStore::OriginBoundCert(
smt.ColumnString(0), // origin
static_cast<net::SSLClientCertType>(smt.ColumnInt(3)),
+ base::Time::FromInternalValue(smt.ColumnInt64(4)),
private_key_from_db,
cert_from_db));
certs->push_back(cert.release());
@@ -230,6 +234,63 @@ bool SQLiteOriginBoundCertStore::Backend::EnsureDatabaseVersion() {
transaction.Commit();
}
+ if (cur_version == 2) {
+ sql::Transaction transaction(db_.get());
+ if (!transaction.Begin())
+ return false;
+ if (!db_->Execute("ALTER TABLE origin_bound_certs ADD COLUMN "
+ "expiration_time INTEGER")) {
+ LOG(WARNING) << "Unable to update origin bound cert database to "
+ << "version 3.";
+ return false;
+ }
+
+ sql::Statement smt(db_->GetUniqueStatement(
+ "SELECT origin, cert FROM origin_bound_certs"));
+ if (!smt) {
+ LOG(WARNING) << "Unable to update origin bound cert database to "
+ << "version 3.";
+ return false;
+ }
+ sql::Statement update_expires_smt(db_->GetUniqueStatement(
+ "UPDATE origin_bound_certs SET expiration_time = ? WHERE origin = ?"));
+ if (!update_expires_smt) {
+ LOG(WARNING) << "Unable to update origin bound cert database to "
+ << "version 3.";
+ return false;
+ }
+ while (smt.Step()) {
+ std::string origin = smt.ColumnString(0);
+ std::string cert_from_db;
+ smt.ColumnBlobAsString(1, &cert_from_db);
+ // Parse the cert and extract the real value and then update the DB.
+ scoped_refptr<net::X509Certificate> cert(
+ net::X509Certificate::CreateFromBytes(
+ cert_from_db.data(), cert_from_db.size()));
+ if (cert) {
+ update_expires_smt.Reset();
+ update_expires_smt.BindInt64(0, cert->valid_expiry().ToInternalValue());
+ update_expires_smt.BindString(1, origin);
+ if (!update_expires_smt.Run()) {
+ LOG(WARNING) << "Unable to update origin bound cert database to "
+ << "version 3.";
+ return false;
+ }
+ } else {
+ // If there's a cert we can't parse, just leave it. It'll get replaced
+ // with a new one if we ever try to use it.
+ LOG(WARNING) << "Error parsing cert for database upgrade for origin "
+ << smt.ColumnString(0);
+ }
+ }
+
+ ++cur_version;
+ meta_table_.SetVersionNumber(cur_version);
+ meta_table_.SetCompatibleVersionNumber(
+ std::min(cur_version, kCompatibleVersionNumber));
+ transaction.Commit();
+ }
+
// Put future migration cases here.
// When the version is too old, we just try to continue anyway, there should
@@ -298,8 +359,8 @@ void SQLiteOriginBoundCertStore::Backend::Commit() {
return;
sql::Statement add_smt(db_->GetCachedStatement(SQL_FROM_HERE,
- "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type) "
- "VALUES (?,?,?,?)"));
+ "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type, "
+ "expiration_time) VALUES (?,?,?,?,?)"));
if (!add_smt) {
NOTREACHED();
return;
@@ -330,6 +391,7 @@ void SQLiteOriginBoundCertStore::Backend::Commit() {
const std::string& cert = po->cert().cert();
add_smt.BindBlob(2, cert.data(), cert.size());
add_smt.BindInt(3, po->cert().type());
+ add_smt.BindInt64(4, po->cert().expiration_time().ToInternalValue());
if (!add_smt.Run())
NOTREACHED() << "Could not add an origin bound cert to the DB.";
break;
diff --git a/chrome/browser/net/sqlite_origin_bound_cert_store_unittest.cc b/chrome/browser/net/sqlite_origin_bound_cert_store_unittest.cc
index cc3130d..5ee226e 100644
--- a/chrome/browser/net/sqlite_origin_bound_cert_store_unittest.cc
+++ b/chrome/browser/net/sqlite_origin_bound_cert_store_unittest.cc
@@ -5,6 +5,7 @@
#include "base/bind.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
#include "base/message_loop.h"
#include "base/scoped_temp_dir.h"
#include "base/stl_util.h"
@@ -12,6 +13,7 @@
#include "chrome/browser/net/sqlite_origin_bound_cert_store.h"
#include "chrome/common/chrome_constants.h"
#include "content/test/test_browser_thread.h"
+#include "net/base/cert_test_util.h"
#include "sql/statement.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,19 +26,38 @@ class SQLiteOriginBoundCertStoreTest : public testing::Test {
}
protected:
+ static void ReadTestKeyAndCert(std::string* key, std::string* cert) {
+ FilePath key_path = net::GetTestCertsDirectory().AppendASCII(
+ "unittest.originbound.key.der");
+ FilePath cert_path = net::GetTestCertsDirectory().AppendASCII(
+ "unittest.originbound.der");
+ ASSERT_TRUE(file_util::ReadFileToString(key_path, key));
+ ASSERT_TRUE(file_util::ReadFileToString(cert_path, cert));
+ }
+
+ static base::Time GetTestCertExpirationTime() {
+ // Cert expiration time from 'dumpasn1 unittest.originbound.der':
+ // GeneralizedTime 19/11/2111 02:23:45 GMT
+ // base::Time::FromUTCExploded can't generate values past 2038 on 32-bit
+ // linux, so we use the raw value here.
+ return base::Time::FromInternalValue(GG_INT64_C(16121816625000000));
+ }
+
virtual void SetUp() {
db_thread_.Start();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
store_ = new SQLiteOriginBoundCertStore(
temp_dir_.path().Append(chrome::kOBCertFilename));
- std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs;
- ASSERT_TRUE(store_->Load(&certs));
+ ScopedVector<net::DefaultOriginBoundCertStore::OriginBoundCert> certs;
+ ASSERT_TRUE(store_->Load(&certs.get()));
ASSERT_EQ(0u, certs.size());
// Make sure the store gets written at least once.
store_->AddOriginBoundCert(
net::DefaultOriginBoundCertStore::OriginBoundCert(
"https://encrypted.google.com:8443",
- net::CLIENT_CERT_RSA_SIGN, "a", "b"));
+ net::CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "a", "b"));
}
content::TestBrowserThread db_thread_;
@@ -79,9 +100,12 @@ TEST_F(SQLiteOriginBoundCertStoreTest, RemoveOnDestruction) {
TEST_F(SQLiteOriginBoundCertStoreTest, TestPersistence) {
store_->AddOriginBoundCert(
net::DefaultOriginBoundCertStore::OriginBoundCert(
- "https://www.google.com/", net::CLIENT_CERT_ECDSA_SIGN, "c", "d"));
+ "https://www.google.com/",
+ net::CLIENT_CERT_ECDSA_SIGN,
+ base::Time(),
+ "c", "d"));
- std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs;
+ ScopedVector<net::DefaultOriginBoundCertStore::OriginBoundCert> certs;
// Replace the store effectively destroying the current one and forcing it
// to write it's data to disk. Then we can see if after loading it again it
// is still there.
@@ -95,7 +119,7 @@ TEST_F(SQLiteOriginBoundCertStoreTest, TestPersistence) {
temp_dir_.path().Append(chrome::kOBCertFilename));
// Reload and test for persistence
- ASSERT_TRUE(store_->Load(&certs));
+ ASSERT_TRUE(store_->Load(&certs.get()));
ASSERT_EQ(2U, certs.size());
net::DefaultOriginBoundCertStore::OriginBoundCert* ec_cert;
net::DefaultOriginBoundCertStore::OriginBoundCert* rsa_cert;
@@ -121,22 +145,25 @@ TEST_F(SQLiteOriginBoundCertStoreTest, TestPersistence) {
store_ = NULL;
// Make sure we wait until the destructor has run.
ASSERT_TRUE(helper->Run());
- STLDeleteContainerPointers(certs.begin(), certs.end());
- certs.clear();
+ certs.reset();
store_ = new SQLiteOriginBoundCertStore(
temp_dir_.path().Append(chrome::kOBCertFilename));
// Reload and check if the cert has been removed.
- ASSERT_TRUE(store_->Load(&certs));
+ ASSERT_TRUE(store_->Load(&certs.get()));
ASSERT_EQ(0U, certs.size());
}
-TEST_F(SQLiteOriginBoundCertStoreTest, TestUpgrade) {
+TEST_F(SQLiteOriginBoundCertStoreTest, TestUpgradeV1) {
// Reset the store. We'll be using a different database for this test.
store_ = NULL;
FilePath v1_db_path(temp_dir_.path().AppendASCII("v1db"));
+ std::string key_data;
+ std::string cert_data;
+ ReadTestKeyAndCert(&key_data, &cert_data);
+
// Create a version 1 database.
{
sql::Connection db;
@@ -148,49 +175,156 @@ TEST_F(SQLiteOriginBoundCertStoreTest, TestUpgrade) {
"INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
"CREATE TABLE origin_bound_certs ("
"origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
- "private_key BLOB NOT NULL,cert BLOB NOT NULL);"
- "INSERT INTO \"origin_bound_certs\" VALUES("
- "'https://google.com',X'AA',X'BB');"
+ "private_key BLOB NOT NULL,cert BLOB NOT NULL);"));
+
+ sql::Statement add_smt(db.GetUniqueStatement(
+ "INSERT INTO origin_bound_certs (origin, private_key, cert) "
+ "VALUES (?,?,?)"));
+ add_smt.BindString(0, "https://www.google.com:443");
+ add_smt.BindBlob(1, key_data.data(), key_data.size());
+ add_smt.BindBlob(2, cert_data.data(), cert_data.size());
+ ASSERT_TRUE(add_smt.Run());
+
+ ASSERT_TRUE(db.Execute(
"INSERT INTO \"origin_bound_certs\" VALUES("
- "'https://foo.com',X'CC',X'DD');"
+ "'https://foo.com',X'AA',X'BB');"
));
}
- std::vector<net::DefaultOriginBoundCertStore::OriginBoundCert*> certs;
- store_ = new SQLiteOriginBoundCertStore(v1_db_path);
-
- // Load the database and ensure the certs can be read and are marked as RSA.
- ASSERT_TRUE(store_->Load(&certs));
- ASSERT_EQ(2U, certs.size());
- ASSERT_STREQ("https://google.com", certs[0]->origin().c_str());
- ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[0]->type());
- ASSERT_STREQ("\xaa", certs[0]->private_key().c_str());
- ASSERT_STREQ("\xbb", certs[0]->cert().c_str());
- ASSERT_STREQ("https://foo.com", certs[1]->origin().c_str());
- ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[1]->type());
- ASSERT_STREQ("\xcc", certs[1]->private_key().c_str());
- ASSERT_STREQ("\xdd", certs[1]->cert().c_str());
-
- STLDeleteContainerPointers(certs.begin(), certs.end());
- certs.clear();
+ // Load and test the DB contents twice. First time ensures that we can use
+ // the updated values immediately. Second time ensures that the updated
+ // values are stored and read correctly on next load.
+ for (int i = 0; i < 2; ++i) {
+ SCOPED_TRACE(i);
+
+ ScopedVector<net::DefaultOriginBoundCertStore::OriginBoundCert> certs;
+ store_ = new SQLiteOriginBoundCertStore(v1_db_path);
+
+ // Load the database and ensure the certs can be read and are marked as RSA.
+ ASSERT_TRUE(store_->Load(&certs.get()));
+ ASSERT_EQ(2U, certs.size());
+
+ ASSERT_STREQ("https://www.google.com:443", certs[0]->origin().c_str());
+ ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[0]->type());
+ ASSERT_EQ(GetTestCertExpirationTime(),
+ certs[0]->expiration_time());
+ ASSERT_EQ(key_data, certs[0]->private_key());
+ ASSERT_EQ(cert_data, certs[0]->cert());
+
+ ASSERT_STREQ("https://foo.com", certs[1]->origin().c_str());
+ ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[1]->type());
+ // Undecodable cert, expiration time will be uninitialized.
+ ASSERT_EQ(base::Time(), certs[1]->expiration_time());
+ ASSERT_STREQ("\xaa", certs[1]->private_key().c_str());
+ ASSERT_STREQ("\xbb", certs[1]->cert().c_str());
+
+ store_ = NULL;
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<base::ThreadTestHelper> helper(
+ new base::ThreadTestHelper(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
+ ASSERT_TRUE(helper->Run());
+
+ // Verify the database version is updated.
+ {
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(v1_db_path));
+ sql::Statement smt(db.GetUniqueStatement(
+ "SELECT value FROM meta WHERE key = \"version\""));
+ ASSERT_TRUE(smt);
+ ASSERT_TRUE(smt.Step());
+ EXPECT_EQ(3, smt.ColumnInt(0));
+ EXPECT_FALSE(smt.Step());
+ }
+ }
+}
+TEST_F(SQLiteOriginBoundCertStoreTest, TestUpgradeV2) {
+ // Reset the store. We'll be using a different database for this test.
store_ = NULL;
- // Make sure we wait until the destructor has run.
- scoped_refptr<base::ThreadTestHelper> helper(
- new base::ThreadTestHelper(
- BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
- ASSERT_TRUE(helper->Run());
- // Verify the database version is updated.
+ FilePath v2_db_path(temp_dir_.path().AppendASCII("v2db"));
+
+ std::string key_data;
+ std::string cert_data;
+ ReadTestKeyAndCert(&key_data, &cert_data);
+
+ // Create a version 2 database.
{
sql::Connection db;
- ASSERT_TRUE(db.Open(v1_db_path));
- sql::Statement smt(db.GetUniqueStatement(
- "SELECT value FROM meta WHERE key = \"version\""));
- ASSERT_TRUE(smt);
- ASSERT_TRUE(smt.Step());
- EXPECT_EQ(2, smt.ColumnInt(0));
- EXPECT_FALSE(smt.Step());
+ ASSERT_TRUE(db.Open(v2_db_path));
+ ASSERT_TRUE(db.Execute(
+ "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+ "value LONGVARCHAR);"
+ "INSERT INTO \"meta\" VALUES('version','2');"
+ "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
+ "CREATE TABLE origin_bound_certs ("
+ "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
+ "private_key BLOB NOT NULL,"
+ "cert BLOB NOT NULL,"
+ "cert_type INTEGER);"
+ ));
+
+ sql::Statement add_smt(db.GetUniqueStatement(
+ "INSERT INTO origin_bound_certs (origin, private_key, cert, cert_type) "
+ "VALUES (?,?,?,?)"));
+ add_smt.BindString(0, "https://www.google.com:443");
+ add_smt.BindBlob(1, key_data.data(), key_data.size());
+ add_smt.BindBlob(2, cert_data.data(), cert_data.size());
+ add_smt.BindInt64(3, 1);
+ ASSERT_TRUE(add_smt.Run());
+
+ ASSERT_TRUE(db.Execute(
+ "INSERT INTO \"origin_bound_certs\" VALUES("
+ "'https://foo.com',X'AA',X'BB',64);"
+ ));
+ }
+
+ // Load and test the DB contents twice. First time ensures that we can use
+ // the updated values immediately. Second time ensures that the updated
+ // values are saved and read correctly on next load.
+ for (int i = 0; i < 2; ++i) {
+ SCOPED_TRACE(i);
+
+ ScopedVector<net::DefaultOriginBoundCertStore::OriginBoundCert> certs;
+ store_ = new SQLiteOriginBoundCertStore(v2_db_path);
+
+ // Load the database and ensure the certs can be read and are marked as RSA.
+ ASSERT_TRUE(store_->Load(&certs.get()));
+ ASSERT_EQ(2U, certs.size());
+
+ ASSERT_STREQ("https://www.google.com:443", certs[0]->origin().c_str());
+ ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[0]->type());
+ ASSERT_EQ(GetTestCertExpirationTime(),
+ certs[0]->expiration_time());
+ ASSERT_EQ(key_data, certs[0]->private_key());
+ ASSERT_EQ(cert_data, certs[0]->cert());
+
+ ASSERT_STREQ("https://foo.com", certs[1]->origin().c_str());
+ ASSERT_EQ(net::CLIENT_CERT_ECDSA_SIGN, certs[1]->type());
+ // Undecodable cert, expiration time will be uninitialized.
+ ASSERT_EQ(base::Time(), certs[1]->expiration_time());
+ ASSERT_STREQ("\xaa", certs[1]->private_key().c_str());
+ ASSERT_STREQ("\xbb", certs[1]->cert().c_str());
+
+ store_ = NULL;
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<base::ThreadTestHelper> helper(
+ new base::ThreadTestHelper(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
+ ASSERT_TRUE(helper->Run());
+
+ // Verify the database version is updated.
+ {
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(v2_db_path));
+ sql::Statement smt(db.GetUniqueStatement(
+ "SELECT value FROM meta WHERE key = \"version\""));
+ ASSERT_TRUE(smt);
+ ASSERT_TRUE(smt.Step());
+ EXPECT_EQ(3, smt.ColumnInt(0));
+ EXPECT_FALSE(smt.Step());
+ }
}
}
@@ -212,6 +346,7 @@ TEST_F(SQLiteOriginBoundCertStoreTest, TestFlush) {
net::DefaultOriginBoundCertStore::OriginBoundCert(
origin,
net::CLIENT_CERT_RSA_SIGN,
+ base::Time(),
private_key,
cert));
}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 5483ea3..1e2ecf1 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -3944,7 +3944,6 @@
'../webkit/support/webkit_support.gyp:glue',
],
'sources': [
- 'browser/net/sqlite_origin_bound_cert_store_unittest.cc',
'browser/safe_browsing/filter_false_positive_perftest.cc',
'browser/visitedlink/visitedlink_perftest.cc',
'common/json_value_serializer_perftest.cc',
diff --git a/net/base/default_origin_bound_cert_store.cc b/net/base/default_origin_bound_cert_store.cc
index 8104658..3c311ca 100644
--- a/net/base/default_origin_bound_cert_store.cc
+++ b/net/base/default_origin_bound_cert_store.cc
@@ -30,6 +30,7 @@ void DefaultOriginBoundCertStore::FlushStore(
bool DefaultOriginBoundCertStore::GetOriginBoundCert(
const std::string& origin,
SSLClientCertType* type,
+ base::Time* expiration_time,
std::string* private_key_result,
std::string* cert_result) {
base::AutoLock autolock(lock_);
@@ -42,6 +43,7 @@ bool DefaultOriginBoundCertStore::GetOriginBoundCert(
OriginBoundCert* cert = it->second;
*type = cert->type();
+ *expiration_time = cert->expiration_time();
*private_key_result = cert->private_key();
*cert_result = cert->cert();
@@ -51,6 +53,7 @@ bool DefaultOriginBoundCertStore::GetOriginBoundCert(
void DefaultOriginBoundCertStore::SetOriginBoundCert(
const std::string& origin,
SSLClientCertType type,
+ base::Time expiration_time,
const std::string& private_key,
const std::string& cert) {
base::AutoLock autolock(lock_);
@@ -58,7 +61,8 @@ void DefaultOriginBoundCertStore::SetOriginBoundCert(
InternalDeleteOriginBoundCert(origin);
InternalInsertOriginBoundCert(
- origin, new OriginBoundCert(origin, type, private_key, cert));
+ origin,
+ new OriginBoundCert(origin, type, expiration_time, private_key, cert));
}
void DefaultOriginBoundCertStore::DeleteOriginBoundCert(
diff --git a/net/base/default_origin_bound_cert_store.h b/net/base/default_origin_bound_cert_store.h
index 8f9a3e3..1714248 100644
--- a/net/base/default_origin_bound_cert_store.h
+++ b/net/base/default_origin_bound_cert_store.h
@@ -57,11 +57,13 @@ class NET_EXPORT DefaultOriginBoundCertStore : public OriginBoundCertStore {
virtual bool GetOriginBoundCert(
const std::string& origin,
SSLClientCertType* type,
+ base::Time* expiration_time,
std::string* private_key_result,
std::string* cert_result) OVERRIDE;
virtual void SetOriginBoundCert(
const std::string& origin,
SSLClientCertType type,
+ base::Time expiration_time,
const std::string& private_key,
const std::string& cert) OVERRIDE;
virtual void DeleteOriginBoundCert(const std::string& origin) OVERRIDE;
diff --git a/net/base/default_origin_bound_cert_store_unittest.cc b/net/base/default_origin_bound_cert_store_unittest.cc
index 6b888e0..a62191a 100644
--- a/net/base/default_origin_bound_cert_store_unittest.cc
+++ b/net/base/default_origin_bound_cert_store_unittest.cc
@@ -77,40 +77,59 @@ TEST(DefaultOriginBoundCertStoreTest, TestLoading) {
persistent_store->AddOriginBoundCert(
DefaultOriginBoundCertStore::OriginBoundCert(
- "https://encrypted.google.com/", CLIENT_CERT_RSA_SIGN, "a", "b"));
+ "https://encrypted.google.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "a", "b"));
persistent_store->AddOriginBoundCert(
DefaultOriginBoundCertStore::OriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_ECDSA_SIGN, "c", "d"));
+ "https://www.verisign.com/",
+ CLIENT_CERT_ECDSA_SIGN,
+ base::Time(),
+ "c", "d"));
// Make sure certs load properly.
DefaultOriginBoundCertStore store(persistent_store.get());
EXPECT_EQ(2, store.GetCertCount());
store.SetOriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_RSA_SIGN, "e", "f");
+ "https://www.verisign.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "e", "f");
EXPECT_EQ(2, store.GetCertCount());
store.SetOriginBoundCert(
- "https://www.twitter.com/", CLIENT_CERT_RSA_SIGN, "g", "h");
+ "https://www.twitter.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "g", "h");
EXPECT_EQ(3, store.GetCertCount());
}
TEST(DefaultOriginBoundCertStoreTest, TestSettingAndGetting) {
DefaultOriginBoundCertStore store(NULL);
SSLClientCertType type;
+ base::Time expiration_time;
std::string private_key, cert;
EXPECT_EQ(0, store.GetCertCount());
EXPECT_FALSE(store.GetOriginBoundCert("https://www.verisign.com/",
&type,
+ &expiration_time,
&private_key,
&cert));
EXPECT_TRUE(private_key.empty());
EXPECT_TRUE(cert.empty());
store.SetOriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_RSA_SIGN, "i", "j");
+ "https://www.verisign.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time::FromInternalValue(123),
+ "i", "j");
EXPECT_TRUE(store.GetOriginBoundCert("https://www.verisign.com/",
&type,
+ &expiration_time,
&private_key,
&cert));
EXPECT_EQ(CLIENT_CERT_RSA_SIGN, type);
+ EXPECT_EQ(123, expiration_time.ToInternalValue());
EXPECT_EQ("i", private_key);
EXPECT_EQ("j", cert);
}
@@ -120,19 +139,28 @@ TEST(DefaultOriginBoundCertStoreTest, TestDuplicateCerts) {
DefaultOriginBoundCertStore store(persistent_store.get());
SSLClientCertType type;
+ base::Time expiration_time;
std::string private_key, cert;
EXPECT_EQ(0, store.GetCertCount());
store.SetOriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_RSA_SIGN, "a", "b");
+ "https://www.verisign.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time::FromInternalValue(123),
+ "a", "b");
store.SetOriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_ECDSA_SIGN, "c", "d");
+ "https://www.verisign.com/",
+ CLIENT_CERT_ECDSA_SIGN,
+ base::Time::FromInternalValue(456),
+ "c", "d");
EXPECT_EQ(1, store.GetCertCount());
EXPECT_TRUE(store.GetOriginBoundCert("https://www.verisign.com/",
&type,
+ &expiration_time,
&private_key,
&cert));
EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type);
+ EXPECT_EQ(456, expiration_time.ToInternalValue());
EXPECT_EQ("c", private_key);
EXPECT_EQ("d", cert);
}
@@ -143,11 +171,20 @@ TEST(DefaultOriginBoundCertStoreTest, TestDeleteAll) {
EXPECT_EQ(0, store.GetCertCount());
store.SetOriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_RSA_SIGN, "a", "b");
+ "https://www.verisign.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "a", "b");
store.SetOriginBoundCert(
- "https://www.google.com/", CLIENT_CERT_RSA_SIGN, "c", "d");
+ "https://www.google.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "c", "d");
store.SetOriginBoundCert(
- "https://www.harvard.com/", CLIENT_CERT_RSA_SIGN, "e", "f");
+ "https://www.harvard.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "e", "f");
EXPECT_EQ(3, store.GetCertCount());
store.DeleteAll();
@@ -159,28 +196,38 @@ TEST(DefaultOriginBoundCertStoreTest, TestDelete) {
DefaultOriginBoundCertStore store(persistent_store.get());
SSLClientCertType type;
+ base::Time expiration_time;
std::string private_key, cert;
EXPECT_EQ(0, store.GetCertCount());
store.SetOriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_RSA_SIGN, "a", "b");
+ "https://www.verisign.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "a", "b");
store.SetOriginBoundCert(
- "https://www.google.com/", CLIENT_CERT_ECDSA_SIGN, "c", "d");
+ "https://www.google.com/",
+ CLIENT_CERT_ECDSA_SIGN,
+ base::Time(),
+ "c", "d");
EXPECT_EQ(2, store.GetCertCount());
store.DeleteOriginBoundCert("https://www.verisign.com/");
EXPECT_EQ(1, store.GetCertCount());
EXPECT_FALSE(store.GetOriginBoundCert("https://www.verisign.com/",
&type,
+ &expiration_time,
&private_key,
&cert));
EXPECT_TRUE(store.GetOriginBoundCert("https://www.google.com/",
&type,
+ &expiration_time,
&private_key,
&cert));
store.DeleteOriginBoundCert("https://www.google.com/");
EXPECT_EQ(0, store.GetCertCount());
EXPECT_FALSE(store.GetOriginBoundCert("https://www.google.com/",
&type,
+ &expiration_time,
&private_key,
&cert));
}
@@ -191,13 +238,25 @@ TEST(DefaultOriginBoundCertStoreTest, TestGetAll) {
EXPECT_EQ(0, store.GetCertCount());
store.SetOriginBoundCert(
- "https://www.verisign.com/", CLIENT_CERT_RSA_SIGN, "a", "b");
+ "https://www.verisign.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "a", "b");
store.SetOriginBoundCert(
- "https://www.google.com/", CLIENT_CERT_ECDSA_SIGN, "c", "d");
+ "https://www.google.com/",
+ CLIENT_CERT_ECDSA_SIGN,
+ base::Time(),
+ "c", "d");
store.SetOriginBoundCert(
- "https://www.harvard.com/", CLIENT_CERT_RSA_SIGN, "e", "f");
+ "https://www.harvard.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "e", "f");
store.SetOriginBoundCert(
- "https://www.mit.com/", CLIENT_CERT_RSA_SIGN, "g", "h");
+ "https://www.mit.com/",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time(),
+ "g", "h");
EXPECT_EQ(4, store.GetCertCount());
std::vector<OriginBoundCertStore::OriginBoundCert> certs;
diff --git a/net/base/origin_bound_cert_service.cc b/net/base/origin_bound_cert_service.cc
index 762255f..246383e 100644
--- a/net/base/origin_bound_cert_service.cc
+++ b/net/base/origin_bound_cert_service.cc
@@ -134,6 +134,7 @@ class OriginBoundCertServiceWorker {
error_ = OriginBoundCertService::GenerateCert(origin_,
type_,
serial_number_,
+ &expiration_time_,
&private_key_,
&cert_);
#if defined(USE_NSS)
@@ -159,8 +160,8 @@ class OriginBoundCertServiceWorker {
// memory leaks or worse errors.
base::AutoLock locked(lock_);
if (!canceled_) {
- origin_bound_cert_service_->HandleResult(origin_, error_, type_,
- private_key_, cert_);
+ origin_bound_cert_service_->HandleResult(
+ origin_, error_, type_, expiration_time_, private_key_, cert_);
}
}
delete this;
@@ -208,6 +209,7 @@ class OriginBoundCertServiceWorker {
bool canceled_;
int error_;
+ base::Time expiration_time_;
std::string private_key_;
std::string cert_;
@@ -322,20 +324,26 @@ int OriginBoundCertService::GetOriginBoundCert(
requests_++;
// Check if an origin bound cert of an acceptable type already exists for this
- // origin.
+ // origin, and that it has not expired.
+ base::Time now = base::Time::Now();
+ base::Time expiration_time;
if (origin_bound_cert_store_->GetOriginBoundCert(origin,
type,
+ &expiration_time,
private_key,
cert)) {
- if (IsSupportedCertType(*type) &&
- std::find(requested_types.begin(), requested_types.end(), *type) !=
- requested_types.end()) {
+ if (expiration_time < now) {
+ DVLOG(1) << "Cert store had expired cert for " << origin;
+ } else if (!IsSupportedCertType(*type) ||
+ std::find(requested_types.begin(), requested_types.end(),
+ *type) == requested_types.end()) {
+ DVLOG(1) << "Cert store had cert of wrong type " << *type << " for "
+ << origin;
+ } else {
cert_store_hits_++;
*out_req = NULL;
return OK;
}
- DVLOG(1) << "Cert store had cert of wrong type " << *type << " for "
- << origin;
}
// |origin_bound_cert_store_| has no cert for this origin. See if an
@@ -363,8 +371,10 @@ int OriginBoundCertService::GetOriginBoundCert(
inflight_joins_++;
} else {
// Need to make a new request.
- OriginBoundCertServiceWorker* worker =
- new OriginBoundCertServiceWorker(origin, preferred_type, this);
+ OriginBoundCertServiceWorker* worker = new OriginBoundCertServiceWorker(
+ origin,
+ preferred_type,
+ this);
job = new OriginBoundCertServiceJob(worker, preferred_type);
if (!worker->Start()) {
delete job;
@@ -388,8 +398,12 @@ int OriginBoundCertService::GetOriginBoundCert(
int OriginBoundCertService::GenerateCert(const std::string& origin,
SSLClientCertType type,
uint32 serial_number,
+ base::Time* expiration_time,
std::string* private_key,
std::string* cert) {
+ base::Time now = base::Time::Now();
+ base::Time not_valid_after =
+ now + base::TimeDelta::FromDays(kValidityPeriodInDays);
std::string der_cert;
std::vector<uint8> private_key_info;
switch (type) {
@@ -404,7 +418,8 @@ int OriginBoundCertService::GenerateCert(const std::string& origin,
key.get(),
origin,
serial_number,
- base::TimeDelta::FromDays(kValidityPeriodInDays),
+ now,
+ not_valid_after,
&der_cert)) {
DLOG(ERROR) << "Unable to create x509 cert for client";
return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED;
@@ -426,7 +441,8 @@ int OriginBoundCertService::GenerateCert(const std::string& origin,
key.get(),
origin,
serial_number,
- base::TimeDelta::FromDays(kValidityPeriodInDays),
+ now,
+ not_valid_after,
&der_cert)) {
DLOG(ERROR) << "Unable to create x509 cert for client";
return ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED;
@@ -450,6 +466,7 @@ int OriginBoundCertService::GenerateCert(const std::string& origin,
private_key->swap(key_out);
cert->swap(der_cert);
+ *expiration_time = not_valid_after;
return OK;
}
@@ -465,11 +482,13 @@ void OriginBoundCertService::CancelRequest(RequestHandle req) {
void OriginBoundCertService::HandleResult(const std::string& origin,
int error,
SSLClientCertType type,
+ base::Time expiration_time,
const std::string& private_key,
const std::string& cert) {
DCHECK(CalledOnValidThread());
- origin_bound_cert_store_->SetOriginBoundCert(origin, type, private_key, cert);
+ origin_bound_cert_store_->SetOriginBoundCert(
+ origin, type, expiration_time, private_key, cert);
std::map<std::string, OriginBoundCertServiceJob*>::iterator j;
j = inflight_.find(origin);
diff --git a/net/base/origin_bound_cert_service.h b/net/base/origin_bound_cert_service.h
index c3861e6..0f78260 100644
--- a/net/base/origin_bound_cert_service.h
+++ b/net/base/origin_bound_cert_service.h
@@ -12,6 +12,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "base/time.h"
#include "base/threading/non_thread_safe.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
@@ -86,7 +87,8 @@ class NET_EXPORT OriginBoundCertService
friend class OriginBoundCertServiceWorker; // Calls HandleResult.
// On success, |private_key| stores a DER-encoded PrivateKeyInfo
- // struct, and |cert| stores a DER-encoded certificate. Returns
+ // struct, |cert| stores a DER-encoded certificate, and |expiration_time|
+ // stores the expiration time of the certificate. Returns
// OK if successful and an error code otherwise.
// |serial_number| is passed in because it is created with the function
// base::RandInt, which opens the file /dev/urandom. /dev/urandom is opened
@@ -94,12 +96,14 @@ class NET_EXPORT OriginBoundCertService
static int GenerateCert(const std::string& origin,
SSLClientCertType type,
uint32 serial_number,
+ base::Time* expiration_time,
std::string* private_key,
std::string* cert);
void HandleResult(const std::string& origin,
int error,
SSLClientCertType type,
+ base::Time expiration_time,
const std::string& private_key,
const std::string& cert);
diff --git a/net/base/origin_bound_cert_service_unittest.cc b/net/base/origin_bound_cert_service_unittest.cc
index 1adedfa..65f40a5 100644
--- a/net/base/origin_bound_cert_service_unittest.cc
+++ b/net/base/origin_bound_cert_service_unittest.cc
@@ -457,6 +457,56 @@ TEST(OriginBoundCertServiceTest, CancelRequest) {
EXPECT_EQ(6, service->cert_count());
}
+TEST(OriginBoundCertServiceTest, Expiration) {
+ OriginBoundCertStore* store = new DefaultOriginBoundCertStore(NULL);
+ store->SetOriginBoundCert("https://good",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time::Now() + base::TimeDelta::FromDays(1),
+ "a",
+ "b");
+ store->SetOriginBoundCert("https://expired",
+ CLIENT_CERT_RSA_SIGN,
+ base::Time::Now() - base::TimeDelta::FromDays(1),
+ "c",
+ "d");
+ OriginBoundCertService service(store);
+ EXPECT_EQ(2, service.cert_count());
+
+ int error;
+ std::vector<uint8> types;
+ types.push_back(CLIENT_CERT_RSA_SIGN);
+ TestCompletionCallback callback;
+ OriginBoundCertService::RequestHandle request_handle;
+
+ // Cert still valid - synchronous completion.
+ SSLClientCertType type1;
+ std::string private_key_info1, der_cert1;
+ error = service.GetOriginBoundCert(
+ "https://good", types, &type1, &private_key_info1, &der_cert1,
+ callback.callback(), &request_handle);
+ EXPECT_EQ(OK, error);
+ EXPECT_TRUE(request_handle == NULL);
+ EXPECT_EQ(2, service.cert_count());
+ EXPECT_EQ(CLIENT_CERT_RSA_SIGN, type1);
+ EXPECT_STREQ("a", private_key_info1.c_str());
+ EXPECT_STREQ("b", der_cert1.c_str());
+
+ // Cert expired - New cert will be generated, asynchronous completion.
+ SSLClientCertType type2;
+ std::string private_key_info2, der_cert2;
+ error = service.GetOriginBoundCert(
+ "https://expired", types, &type2, &private_key_info2, &der_cert2,
+ callback.callback(), &request_handle);
+ EXPECT_EQ(ERR_IO_PENDING, error);
+ EXPECT_TRUE(request_handle != NULL);
+ error = callback.WaitForResult();
+ EXPECT_EQ(OK, error);
+ EXPECT_EQ(2, service.cert_count());
+ EXPECT_EQ(CLIENT_CERT_RSA_SIGN, type2);
+ EXPECT_LT(1U, private_key_info2.size());
+ EXPECT_LT(1U, der_cert2.size());
+}
+
#endif // !defined(USE_OPENSSL)
} // namespace
diff --git a/net/base/origin_bound_cert_store.cc b/net/base/origin_bound_cert_store.cc
index fe2b45f..6a31a7e 100644
--- a/net/base/origin_bound_cert_store.cc
+++ b/net/base/origin_bound_cert_store.cc
@@ -13,10 +13,12 @@ OriginBoundCertStore::OriginBoundCert::OriginBoundCert()
OriginBoundCertStore::OriginBoundCert::OriginBoundCert(
const std::string& origin,
SSLClientCertType type,
+ base::Time expiration_time,
const std::string& private_key,
const std::string& cert)
: origin_(origin),
type_(type),
+ expiration_time_(expiration_time),
private_key_(private_key),
cert_(cert) {}
diff --git a/net/base/origin_bound_cert_store.h b/net/base/origin_bound_cert_store.h
index 094839b..1eb8382 100644
--- a/net/base/origin_bound_cert_store.h
+++ b/net/base/origin_bound_cert_store.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/time.h"
#include "net/base/net_export.h"
#include "net/base/ssl_client_cert_type.h"
@@ -30,6 +31,7 @@ class NET_EXPORT OriginBoundCertStore {
OriginBoundCert();
OriginBoundCert(const std::string& origin,
SSLClientCertType type,
+ base::Time expiration_time,
const std::string& private_key,
const std::string& cert);
~OriginBoundCert();
@@ -38,6 +40,8 @@ class NET_EXPORT OriginBoundCertStore {
const std::string& origin() const { return origin_; }
// TLS ClientCertificateType.
SSLClientCertType type() const { return type_; }
+ // The time after which this certificate is no longer valid.
+ base::Time expiration_time() const { return expiration_time_; }
// The encoding of the private key depends on the type.
// rsa_sign: DER-encoded PrivateKeyInfo struct.
// ecdsa_sign: DER-encoded EncryptedPrivateKeyInfo struct.
@@ -48,6 +52,7 @@ class NET_EXPORT OriginBoundCertStore {
private:
std::string origin_;
SSLClientCertType type_;
+ base::Time expiration_time_;
std::string private_key_;
std::string cert_;
};
@@ -57,12 +62,14 @@ class NET_EXPORT OriginBoundCertStore {
// TODO(rkn): File I/O may be required, so this should have an asynchronous
// interface.
// Returns true on success. |private_key_result| stores a DER-encoded
- // PrivateKeyInfo struct and |cert_result| stores a DER-encoded
- // certificate. Returns false if no origin bound cert exists for the
- // specified origin.
+ // PrivateKeyInfo struct, |cert_result| stores a DER-encoded certificate,
+ // |type| is the ClientCertificateType of the returned certificate, and
+ // |expiration_time| is the expiration time of the certificate.
+ // Returns false if no origin bound cert exists for the specified origin.
virtual bool GetOriginBoundCert(
const std::string& origin,
SSLClientCertType* type,
+ base::Time* expiration_time,
std::string* private_key_result,
std::string* cert_result) = 0;
@@ -70,6 +77,7 @@ class NET_EXPORT OriginBoundCertStore {
virtual void SetOriginBoundCert(
const std::string& origin,
SSLClientCertType type,
+ base::Time expiration_time,
const std::string& private_key,
const std::string& cert) = 0;
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index 39f2a94..b4bf88d 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -778,11 +778,14 @@ X509Certificate* X509Certificate::CreateSelfSigned(
base::TimeDelta valid_duration) {
DCHECK(key);
+ base::Time not_valid_before = base::Time::Now();
+ base::Time not_valid_after = not_valid_before + valid_duration;
CERTCertificate* cert = x509_util::CreateSelfSignedCert(key->public_key(),
key->key(),
subject,
serial_number,
- valid_duration);
+ not_valid_before,
+ not_valid_after);
if (!cert)
return NULL;
diff --git a/net/base/x509_util.h b/net/base/x509_util.h
index 1d8c933..b35d274 100644
--- a/net/base/x509_util.h
+++ b/net/base/x509_util.h
@@ -30,12 +30,14 @@ namespace x509_util {
bool NET_EXPORT_PRIVATE CreateOriginBoundCertRSA(crypto::RSAPrivateKey* key,
const std::string& origin,
uint32 serial_number,
- base::TimeDelta valid_duration,
+ base::Time not_valid_before,
+ base::Time not_valid_after,
std::string* der_cert);
bool NET_EXPORT_PRIVATE CreateOriginBoundCertEC(crypto::ECPrivateKey* key,
const std::string& origin,
uint32 serial_number,
- base::TimeDelta valid_duration,
+ base::Time not_valid_before,
+ base::Time not_valid_after,
std::string* der_cert);
} // namespace x509_util
diff --git a/net/base/x509_util_nss.cc b/net/base/x509_util_nss.cc
index 61126af..3f630e2 100644
--- a/net/base/x509_util_nss.cc
+++ b/net/base/x509_util_nss.cc
@@ -78,7 +78,8 @@ CERTCertificate* CreateCertificate(
SECKEYPublicKey* public_key,
const std::string& subject,
uint32 serial_number,
- base::TimeDelta valid_duration) {
+ base::Time not_valid_before,
+ base::Time not_valid_after) {
// Create info about public key.
CERTSubjectPublicKeyInfo* spki =
SECKEY_CreateSubjectPublicKeyInfo(public_key);
@@ -99,11 +100,9 @@ CERTCertificate* CreateCertificate(
return NULL;
}
- PRTime now = PR_Now();
- PRTime not_after = now + valid_duration.InMicroseconds();
-
- // Note that the time is now in micro-second unit.
- CERTValidity* validity = CERT_CreateValidity(now, not_after);
+ CERTValidity* validity = CERT_CreateValidity(
+ crypto::BaseTimeToPRTime(not_valid_before),
+ crypto::BaseTimeToPRTime(not_valid_after));
CERTCertificate* cert = CERT_CreateCertificate(serial_number, subject_name,
validity, cert_request);
if (!cert) {
@@ -176,13 +175,15 @@ bool CreateOriginBoundCertInternal(
SECKEYPrivateKey* private_key,
const std::string& origin,
uint32 serial_number,
- base::TimeDelta valid_duration,
+ base::Time not_valid_before,
+ base::Time not_valid_after,
std::string* der_cert) {
CERTCertificate* cert = CreateCertificate(public_key,
"CN=anonymous.invalid",
serial_number,
- valid_duration);
+ not_valid_before,
+ not_valid_after);
if (!cert)
return false;
@@ -254,11 +255,13 @@ CERTCertificate* CreateSelfSignedCert(
SECKEYPrivateKey* private_key,
const std::string& subject,
uint32 serial_number,
- base::TimeDelta valid_duration) {
+ base::Time not_valid_before,
+ base::Time not_valid_after) {
CERTCertificate* cert = CreateCertificate(public_key,
subject,
serial_number,
- valid_duration);
+ not_valid_before,
+ not_valid_after);
if (!cert)
return NULL;
@@ -274,7 +277,8 @@ bool CreateOriginBoundCertRSA(
crypto::RSAPrivateKey* key,
const std::string& origin,
uint32 serial_number,
- base::TimeDelta valid_duration,
+ base::Time not_valid_before,
+ base::Time not_valid_after,
std::string* der_cert) {
DCHECK(key);
@@ -329,7 +333,8 @@ bool CreateOriginBoundCertRSA(
private_key,
origin,
serial_number,
- valid_duration,
+ not_valid_before,
+ not_valid_after,
der_cert);
}
@@ -337,14 +342,16 @@ bool CreateOriginBoundCertEC(
crypto::ECPrivateKey* key,
const std::string& origin,
uint32 serial_number,
- base::TimeDelta valid_duration,
+ base::Time not_valid_before,
+ base::Time not_valid_after,
std::string* der_cert) {
DCHECK(key);
return CreateOriginBoundCertInternal(key->public_key(),
key->key(),
origin,
serial_number,
- valid_duration,
+ not_valid_before,
+ not_valid_after,
der_cert);
}
diff --git a/net/base/x509_util_nss.h b/net/base/x509_util_nss.h
index 82dd4f9..b5cc503 100644
--- a/net/base/x509_util_nss.h
+++ b/net/base/x509_util_nss.h
@@ -28,7 +28,8 @@ CERTCertificate* CreateSelfSignedCert(
SECKEYPrivateKey* private_key,
const std::string& subject,
uint32 serial_number,
- base::TimeDelta valid_duration);
+ base::Time not_valid_before,
+ base::Time not_valid_after);
} // namespace x509_util
diff --git a/net/base/x509_util_nss_unittest.cc b/net/base/x509_util_nss_unittest.cc
index 7490874..1dc2cd2 100644
--- a/net/base/x509_util_nss_unittest.cc
+++ b/net/base/x509_util_nss_unittest.cc
@@ -145,14 +145,17 @@ void VerifyOriginBoundCert(const std::string& origin,
TEST(X509UtilNSSTest, CreateOriginBoundCertRSA) {
// Create a sample ASCII weborigin.
std::string origin = "http://weborigin.com:443";
+ base::Time now = base::Time::Now();
scoped_ptr<crypto::RSAPrivateKey> private_key(
crypto::RSAPrivateKey::Create(1024));
std::string der_cert;
- ASSERT_TRUE(x509_util::CreateOriginBoundCertRSA(private_key.get(),
- origin, 1,
- base::TimeDelta::FromDays(1),
- &der_cert));
+ ASSERT_TRUE(x509_util::CreateOriginBoundCertRSA(
+ private_key.get(),
+ origin, 1,
+ now,
+ now + base::TimeDelta::FromDays(1),
+ &der_cert));
VerifyOriginBoundCert(origin, der_cert);
@@ -166,14 +169,17 @@ TEST(X509UtilNSSTest, CreateOriginBoundCertRSA) {
TEST(X509UtilNSSTest, CreateOriginBoundCertEC) {
// Create a sample ASCII weborigin.
std::string origin = "http://weborigin.com:443";
+ base::Time now = base::Time::Now();
scoped_ptr<crypto::ECPrivateKey> private_key(
crypto::ECPrivateKey::Create());
std::string der_cert;
- ASSERT_TRUE(x509_util::CreateOriginBoundCertEC(private_key.get(),
- origin, 1,
- base::TimeDelta::FromDays(1),
- &der_cert));
+ ASSERT_TRUE(x509_util::CreateOriginBoundCertEC(
+ private_key.get(),
+ origin, 1,
+ now,
+ now + base::TimeDelta::FromDays(1),
+ &der_cert));
VerifyOriginBoundCert(origin, der_cert);
diff --git a/net/base/x509_util_openssl.cc b/net/base/x509_util_openssl.cc
index e663b95..786dd86 100644
--- a/net/base/x509_util_openssl.cc
+++ b/net/base/x509_util_openssl.cc
@@ -19,7 +19,8 @@ bool CreateOriginBoundCertRSA(
crypto::RSAPrivateKey* key,
const std::string& origin,
uint32 serial_number,
- base::TimeDelta valid_duration,
+ base::Time not_valid_before,
+ base::Time not_valid_after,
std::string* der_cert) {
NOTIMPLEMENTED();
return false;
@@ -29,7 +30,8 @@ bool CreateOriginBoundCertEC(
crypto::ECPrivateKey* key,
const std::string& origin,
uint32 serial_number,
- base::TimeDelta valid_duration,
+ base::Time not_valid_before,
+ base::Time not_valid_after,
std::string* der_cert) {
NOTIMPLEMENTED();
return false;
diff --git a/net/base/x509_util_openssl_unittest.cc b/net/base/x509_util_openssl_unittest.cc
index 23c33a3..5d96dfa 100644
--- a/net/base/x509_util_openssl_unittest.cc
+++ b/net/base/x509_util_openssl_unittest.cc
@@ -15,13 +15,16 @@ namespace net {
// is present.
TEST(X509UtilOpenSSLTest, CreateOriginBoundCertNotImplemented) {
std::string origin = "http://weborigin.com:443";
+ base::Time now = base::Time::Now();
scoped_ptr<crypto::RSAPrivateKey> private_key(
crypto::RSAPrivateKey::Create(1024));
std::string der_cert;
- EXPECT_FALSE(x509_util::CreateOriginBoundCertRSA(private_key.get(),
- origin, 1,
- base::TimeDelta::FromDays(1),
- &der_cert));
+ EXPECT_FALSE(x509_util::CreateOriginBoundCertRSA(
+ private_key.get(),
+ origin, 1,
+ now,
+ now + base::TimeDelta::FromDays(1),
+ &der_cert));
EXPECT_TRUE(der_cert.empty());
}