RTCCertificate::Expires() and ::HasExpired() implemented using SSLCertificate::CertificateExpirationTime().
NOPRESUBMIT=true BUG=chromium:544894 Review URL: https://codereview.webrtc.org/1494103003 Cr-Commit-Position: refs/heads/master@{#10930}
This commit is contained in:
@ -88,6 +88,7 @@
|
|||||||
'ratetracker_unittest.cc',
|
'ratetracker_unittest.cc',
|
||||||
'referencecountedsingletonfactory_unittest.cc',
|
'referencecountedsingletonfactory_unittest.cc',
|
||||||
'rollingaccumulator_unittest.cc',
|
'rollingaccumulator_unittest.cc',
|
||||||
|
'rtccertificate_unittests.cc',
|
||||||
'scopedptrcollection_unittest.cc',
|
'scopedptrcollection_unittest.cc',
|
||||||
'sha1digest_unittest.cc',
|
'sha1digest_unittest.cc',
|
||||||
'sharedexclusivelock_unittest.cc',
|
'sharedexclusivelock_unittest.cc',
|
||||||
|
@ -25,9 +25,11 @@ class FakeSSLCertificate : public rtc::SSLCertificate {
|
|||||||
// SHA-1 is the default digest algorithm because it is available in all build
|
// SHA-1 is the default digest algorithm because it is available in all build
|
||||||
// configurations used for unit testing.
|
// configurations used for unit testing.
|
||||||
explicit FakeSSLCertificate(const std::string& data)
|
explicit FakeSSLCertificate(const std::string& data)
|
||||||
: data_(data), digest_algorithm_(DIGEST_SHA_1) {}
|
: data_(data), digest_algorithm_(DIGEST_SHA_1), expiration_time_(-1) {}
|
||||||
explicit FakeSSLCertificate(const std::vector<std::string>& certs)
|
explicit FakeSSLCertificate(const std::vector<std::string>& certs)
|
||||||
: data_(certs.front()), digest_algorithm_(DIGEST_SHA_1) {
|
: data_(certs.front()),
|
||||||
|
digest_algorithm_(DIGEST_SHA_1),
|
||||||
|
expiration_time_(-1) {
|
||||||
std::vector<std::string>::const_iterator it;
|
std::vector<std::string>::const_iterator it;
|
||||||
// Skip certs[0].
|
// Skip certs[0].
|
||||||
for (it = certs.begin() + 1; it != certs.end(); ++it) {
|
for (it = certs.begin() + 1; it != certs.end(); ++it) {
|
||||||
@ -45,7 +47,12 @@ class FakeSSLCertificate : public rtc::SSLCertificate {
|
|||||||
VERIFY(SSLIdentity::PemToDer(kPemTypeCertificate, data_, &der_string));
|
VERIFY(SSLIdentity::PemToDer(kPemTypeCertificate, data_, &der_string));
|
||||||
der_buffer->SetData(der_string.c_str(), der_string.size());
|
der_buffer->SetData(der_string.c_str(), der_string.size());
|
||||||
}
|
}
|
||||||
int64_t CertificateExpirationTime() const override { return -1; }
|
int64_t CertificateExpirationTime() const override {
|
||||||
|
return expiration_time_;
|
||||||
|
}
|
||||||
|
void SetCertificateExpirationTime(int64_t expiration_time) {
|
||||||
|
expiration_time_ = expiration_time;
|
||||||
|
}
|
||||||
void set_digest_algorithm(const std::string& algorithm) {
|
void set_digest_algorithm(const std::string& algorithm) {
|
||||||
digest_algorithm_ = algorithm;
|
digest_algorithm_ = algorithm;
|
||||||
}
|
}
|
||||||
@ -79,6 +86,8 @@ class FakeSSLCertificate : public rtc::SSLCertificate {
|
|||||||
std::string data_;
|
std::string data_;
|
||||||
std::vector<FakeSSLCertificate> certs_;
|
std::vector<FakeSSLCertificate> certs_;
|
||||||
std::string digest_algorithm_;
|
std::string digest_algorithm_;
|
||||||
|
// Expiration time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC).
|
||||||
|
int64_t expiration_time_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FakeSSLIdentity : public rtc::SSLIdentity {
|
class FakeSSLIdentity : public rtc::SSLIdentity {
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "webrtc/base/rtccertificate.h"
|
#include "webrtc/base/rtccertificate.h"
|
||||||
|
|
||||||
#include "webrtc/base/checks.h"
|
#include "webrtc/base/checks.h"
|
||||||
#include "webrtc/base/timeutils.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
@ -28,13 +27,16 @@ RTCCertificate::RTCCertificate(SSLIdentity* identity)
|
|||||||
RTCCertificate::~RTCCertificate() {
|
RTCCertificate::~RTCCertificate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t RTCCertificate::expires_timestamp_ns() const {
|
uint64_t RTCCertificate::Expires() const {
|
||||||
// TODO(hbos): Update once SSLIdentity/SSLCertificate supports expires field.
|
int64_t expires = ssl_certificate().CertificateExpirationTime();
|
||||||
return 0;
|
if (expires != -1)
|
||||||
|
return static_cast<uint64_t>(expires) * kNumMillisecsPerSec;
|
||||||
|
// If the expiration time could not be retrieved return an expired timestamp.
|
||||||
|
return 0; // = 1970-01-01
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RTCCertificate::HasExpired() const {
|
bool RTCCertificate::HasExpired(uint64_t now) const {
|
||||||
return expires_timestamp_ns() <= TimeNanos();
|
return Expires() <= now;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SSLCertificate& RTCCertificate::ssl_certificate() const {
|
const SSLCertificate& RTCCertificate::ssl_certificate() const {
|
||||||
|
@ -27,8 +27,11 @@ class RTCCertificate : public RefCountInterface {
|
|||||||
// Takes ownership of |identity|.
|
// Takes ownership of |identity|.
|
||||||
static scoped_refptr<RTCCertificate> Create(scoped_ptr<SSLIdentity> identity);
|
static scoped_refptr<RTCCertificate> Create(scoped_ptr<SSLIdentity> identity);
|
||||||
|
|
||||||
uint64_t expires_timestamp_ns() const;
|
// Returns the expiration time in ms relative to epoch, 1970-01-01T00:00:00Z.
|
||||||
bool HasExpired() const;
|
uint64_t Expires() const;
|
||||||
|
// Checks if the certificate has expired, where |now| is expressed in ms
|
||||||
|
// relative to epoch, 1970-01-01T00:00:00Z.
|
||||||
|
bool HasExpired(uint64_t now) const;
|
||||||
const SSLCertificate& ssl_certificate() const;
|
const SSLCertificate& ssl_certificate() const;
|
||||||
|
|
||||||
// TODO(hbos): If possible, remove once RTCCertificate and its
|
// TODO(hbos): If possible, remove once RTCCertificate and its
|
||||||
|
116
webrtc/base/rtccertificate_unittests.cc
Normal file
116
webrtc/base/rtccertificate_unittests.cc
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The WebRTC Project Authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "webrtc/base/checks.h"
|
||||||
|
#include "webrtc/base/fakesslidentity.h"
|
||||||
|
#include "webrtc/base/gunit.h"
|
||||||
|
#include "webrtc/base/logging.h"
|
||||||
|
#include "webrtc/base/rtccertificate.h"
|
||||||
|
#include "webrtc/base/safe_conversions.h"
|
||||||
|
#include "webrtc/base/scoped_ptr.h"
|
||||||
|
#include "webrtc/base/sslidentity.h"
|
||||||
|
#include "webrtc/base/thread.h"
|
||||||
|
#include "webrtc/base/timeutils.h"
|
||||||
|
|
||||||
|
namespace rtc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static const char* kTestCertCommonName = "RTCCertificateTest's certificate";
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class RTCCertificateTest : public testing::Test {
|
||||||
|
public:
|
||||||
|
RTCCertificateTest() {}
|
||||||
|
~RTCCertificateTest() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Timestamp note:
|
||||||
|
// All timestamps in this unittest are expressed in number of seconds since
|
||||||
|
// epoch, 1970-01-01T00:00:00Z (UTC). The RTCCertificate interface uses ms,
|
||||||
|
// but only seconds-precision is supported by SSLCertificate. To make the
|
||||||
|
// tests clearer we convert everything to seconds since the precision matters
|
||||||
|
// when generating certificates or comparing timestamps.
|
||||||
|
// As a result, ExpiresSeconds and HasExpiredSeconds are used instead of
|
||||||
|
// RTCCertificate::Expires and ::HasExpired for ms -> s conversion.
|
||||||
|
|
||||||
|
uint64_t NowSeconds() const {
|
||||||
|
return TimeNanos() / kNumNanosecsPerSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ExpiresSeconds(const scoped_refptr<RTCCertificate>& cert) const {
|
||||||
|
uint64_t exp_ms = cert->Expires();
|
||||||
|
uint64_t exp_s = exp_ms / kNumMillisecsPerSec;
|
||||||
|
// Make sure this did not result in loss of precision.
|
||||||
|
RTC_CHECK_EQ(exp_s * kNumMillisecsPerSec, exp_ms);
|
||||||
|
return exp_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasExpiredSeconds(const scoped_refptr<RTCCertificate>& cert,
|
||||||
|
uint64_t now_s) const {
|
||||||
|
return cert->HasExpired(now_s * kNumMillisecsPerSec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// An RTC_CHECK ensures that |expires_s| this is in valid range of time_t as
|
||||||
|
// is required by SSLIdentityParams. On some 32-bit systems time_t is limited
|
||||||
|
// to < 2^31. On such systems this will fail for expiration times of year 2038
|
||||||
|
// or later.
|
||||||
|
scoped_refptr<RTCCertificate> GenerateCertificateWithExpires(
|
||||||
|
uint64_t expires_s) const {
|
||||||
|
RTC_CHECK(IsValueInRangeForNumericType<time_t>(expires_s));
|
||||||
|
|
||||||
|
SSLIdentityParams params;
|
||||||
|
params.common_name = kTestCertCommonName;
|
||||||
|
params.not_before = 0;
|
||||||
|
params.not_after = static_cast<time_t>(expires_s);
|
||||||
|
// Certificate type does not matter for our purposes, using ECDSA because it
|
||||||
|
// is fast to generate.
|
||||||
|
params.key_params = KeyParams::ECDSA();
|
||||||
|
|
||||||
|
scoped_ptr<SSLIdentity> identity(SSLIdentity::GenerateForTest(params));
|
||||||
|
return RTCCertificate::Create(identity.Pass());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(RTCCertificateTest, NewCertificateNotExpired) {
|
||||||
|
// Generate a real certificate without specifying the expiration time.
|
||||||
|
// Certificate type doesn't matter, using ECDSA because it's fast to generate.
|
||||||
|
scoped_ptr<SSLIdentity> identity(
|
||||||
|
SSLIdentity::Generate(kTestCertCommonName, KeyParams::ECDSA()));
|
||||||
|
scoped_refptr<RTCCertificate> certificate =
|
||||||
|
RTCCertificate::Create(identity.Pass());
|
||||||
|
|
||||||
|
uint64_t now = NowSeconds();
|
||||||
|
EXPECT_FALSE(HasExpiredSeconds(certificate, now));
|
||||||
|
// Even without specifying the expiration time we would expect it to be valid
|
||||||
|
// for at least half an hour.
|
||||||
|
EXPECT_FALSE(HasExpiredSeconds(certificate, now + 30*60));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RTCCertificateTest, UsesExpiresAskedFor) {
|
||||||
|
uint64_t now = NowSeconds();
|
||||||
|
scoped_refptr<RTCCertificate> certificate =
|
||||||
|
GenerateCertificateWithExpires(now);
|
||||||
|
EXPECT_EQ(now, ExpiresSeconds(certificate));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(RTCCertificateTest, ExpiresInOneSecond) {
|
||||||
|
// Generate a certificate that expires in 1s.
|
||||||
|
uint64_t now = NowSeconds();
|
||||||
|
scoped_refptr<RTCCertificate> certificate =
|
||||||
|
GenerateCertificateWithExpires(now + 1);
|
||||||
|
// Now it should not have expired.
|
||||||
|
EXPECT_FALSE(HasExpiredSeconds(certificate, now));
|
||||||
|
// In 2s it should have expired.
|
||||||
|
EXPECT_TRUE(HasExpiredSeconds(certificate, now + 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rtc
|
@ -70,7 +70,8 @@ class SSLCertificate {
|
|||||||
size_t size,
|
size_t size,
|
||||||
size_t* length) const = 0;
|
size_t* length) const = 0;
|
||||||
|
|
||||||
// Returns the time in seconds relative to epoch.
|
// Returns the time in seconds relative to epoch, 1970-01-01T00:00:00Z (UTC),
|
||||||
|
// or -1 if an expiration time could not be retrieved.
|
||||||
virtual int64_t CertificateExpirationTime() const = 0;
|
virtual int64_t CertificateExpirationTime() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user