1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2015 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/rtc_certificate.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <time.h>
14*d9f75844SAndroid Build Coastguard Worker
15*d9f75844SAndroid Build Coastguard Worker #include <memory>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
19*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/ssl_identity.h"
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/time_utils.h"
22*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
23*d9f75844SAndroid Build Coastguard Worker
24*d9f75844SAndroid Build Coastguard Worker namespace rtc {
25*d9f75844SAndroid Build Coastguard Worker
26*d9f75844SAndroid Build Coastguard Worker namespace {
27*d9f75844SAndroid Build Coastguard Worker
28*d9f75844SAndroid Build Coastguard Worker static const char* kTestCertCommonName = "RTCCertificateTest's certificate";
29*d9f75844SAndroid Build Coastguard Worker
30*d9f75844SAndroid Build Coastguard Worker } // namespace
31*d9f75844SAndroid Build Coastguard Worker
32*d9f75844SAndroid Build Coastguard Worker class RTCCertificateTest : public ::testing::Test {
33*d9f75844SAndroid Build Coastguard Worker protected:
GenerateECDSA()34*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> GenerateECDSA() {
35*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<SSLIdentity> identity(
36*d9f75844SAndroid Build Coastguard Worker SSLIdentity::Create(kTestCertCommonName, KeyParams::ECDSA()));
37*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(identity);
38*d9f75844SAndroid Build Coastguard Worker return RTCCertificate::Create(std::move(identity));
39*d9f75844SAndroid Build Coastguard Worker }
40*d9f75844SAndroid Build Coastguard Worker
41*d9f75844SAndroid Build Coastguard Worker // Timestamp note:
42*d9f75844SAndroid Build Coastguard Worker // All timestamps in this unittest are expressed in number of seconds since
43*d9f75844SAndroid Build Coastguard Worker // epoch, 1970-01-01T00:00:00Z (UTC). The RTCCertificate interface uses ms,
44*d9f75844SAndroid Build Coastguard Worker // but only seconds-precision is supported by SSLCertificate. To make the
45*d9f75844SAndroid Build Coastguard Worker // tests clearer we convert everything to seconds since the precision matters
46*d9f75844SAndroid Build Coastguard Worker // when generating certificates or comparing timestamps.
47*d9f75844SAndroid Build Coastguard Worker // As a result, ExpiresSeconds and HasExpiredSeconds are used instead of
48*d9f75844SAndroid Build Coastguard Worker // RTCCertificate::Expires and ::HasExpired for ms -> s conversion.
49*d9f75844SAndroid Build Coastguard Worker
NowSeconds() const50*d9f75844SAndroid Build Coastguard Worker uint64_t NowSeconds() const { return TimeNanos() / kNumNanosecsPerSec; }
51*d9f75844SAndroid Build Coastguard Worker
ExpiresSeconds(const scoped_refptr<RTCCertificate> & cert) const52*d9f75844SAndroid Build Coastguard Worker uint64_t ExpiresSeconds(const scoped_refptr<RTCCertificate>& cert) const {
53*d9f75844SAndroid Build Coastguard Worker uint64_t exp_ms = cert->Expires();
54*d9f75844SAndroid Build Coastguard Worker uint64_t exp_s = exp_ms / kNumMillisecsPerSec;
55*d9f75844SAndroid Build Coastguard Worker // Make sure this did not result in loss of precision.
56*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(exp_s * kNumMillisecsPerSec, exp_ms);
57*d9f75844SAndroid Build Coastguard Worker return exp_s;
58*d9f75844SAndroid Build Coastguard Worker }
59*d9f75844SAndroid Build Coastguard Worker
HasExpiredSeconds(const scoped_refptr<RTCCertificate> & cert,uint64_t now_s) const60*d9f75844SAndroid Build Coastguard Worker bool HasExpiredSeconds(const scoped_refptr<RTCCertificate>& cert,
61*d9f75844SAndroid Build Coastguard Worker uint64_t now_s) const {
62*d9f75844SAndroid Build Coastguard Worker return cert->HasExpired(now_s * kNumMillisecsPerSec);
63*d9f75844SAndroid Build Coastguard Worker }
64*d9f75844SAndroid Build Coastguard Worker
65*d9f75844SAndroid Build Coastguard Worker // An RTC_CHECK ensures that `expires_s` this is in valid range of time_t as
66*d9f75844SAndroid Build Coastguard Worker // is required by SSLIdentityParams. On some 32-bit systems time_t is limited
67*d9f75844SAndroid Build Coastguard Worker // to < 2^31. On such systems this will fail for expiration times of year 2038
68*d9f75844SAndroid Build Coastguard Worker // or later.
GenerateCertificateWithExpires(uint64_t expires_s) const69*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> GenerateCertificateWithExpires(
70*d9f75844SAndroid Build Coastguard Worker uint64_t expires_s) const {
71*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(IsValueInRangeForNumericType<time_t>(expires_s));
72*d9f75844SAndroid Build Coastguard Worker
73*d9f75844SAndroid Build Coastguard Worker SSLIdentityParams params;
74*d9f75844SAndroid Build Coastguard Worker params.common_name = kTestCertCommonName;
75*d9f75844SAndroid Build Coastguard Worker params.not_before = 0;
76*d9f75844SAndroid Build Coastguard Worker params.not_after = static_cast<time_t>(expires_s);
77*d9f75844SAndroid Build Coastguard Worker // Certificate type does not matter for our purposes, using ECDSA because it
78*d9f75844SAndroid Build Coastguard Worker // is fast to generate.
79*d9f75844SAndroid Build Coastguard Worker params.key_params = KeyParams::ECDSA();
80*d9f75844SAndroid Build Coastguard Worker
81*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateForTest(params));
82*d9f75844SAndroid Build Coastguard Worker return RTCCertificate::Create(std::move(identity));
83*d9f75844SAndroid Build Coastguard Worker }
84*d9f75844SAndroid Build Coastguard Worker };
85*d9f75844SAndroid Build Coastguard Worker
TEST_F(RTCCertificateTest,NewCertificateNotExpired)86*d9f75844SAndroid Build Coastguard Worker TEST_F(RTCCertificateTest, NewCertificateNotExpired) {
87*d9f75844SAndroid Build Coastguard Worker // Generate a real certificate without specifying the expiration time.
88*d9f75844SAndroid Build Coastguard Worker // Certificate type doesn't matter, using ECDSA because it's fast to generate.
89*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> certificate = GenerateECDSA();
90*d9f75844SAndroid Build Coastguard Worker
91*d9f75844SAndroid Build Coastguard Worker uint64_t now = NowSeconds();
92*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(HasExpiredSeconds(certificate, now));
93*d9f75844SAndroid Build Coastguard Worker // Even without specifying the expiration time we would expect it to be valid
94*d9f75844SAndroid Build Coastguard Worker // for at least half an hour.
95*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(HasExpiredSeconds(certificate, now + 30 * 60));
96*d9f75844SAndroid Build Coastguard Worker }
97*d9f75844SAndroid Build Coastguard Worker
TEST_F(RTCCertificateTest,UsesExpiresAskedFor)98*d9f75844SAndroid Build Coastguard Worker TEST_F(RTCCertificateTest, UsesExpiresAskedFor) {
99*d9f75844SAndroid Build Coastguard Worker uint64_t now = NowSeconds();
100*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> certificate =
101*d9f75844SAndroid Build Coastguard Worker GenerateCertificateWithExpires(now);
102*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(now, ExpiresSeconds(certificate));
103*d9f75844SAndroid Build Coastguard Worker }
104*d9f75844SAndroid Build Coastguard Worker
TEST_F(RTCCertificateTest,ExpiresInOneSecond)105*d9f75844SAndroid Build Coastguard Worker TEST_F(RTCCertificateTest, ExpiresInOneSecond) {
106*d9f75844SAndroid Build Coastguard Worker // Generate a certificate that expires in 1s.
107*d9f75844SAndroid Build Coastguard Worker uint64_t now = NowSeconds();
108*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> certificate =
109*d9f75844SAndroid Build Coastguard Worker GenerateCertificateWithExpires(now + 1);
110*d9f75844SAndroid Build Coastguard Worker // Now it should not have expired.
111*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(HasExpiredSeconds(certificate, now));
112*d9f75844SAndroid Build Coastguard Worker // In 2s it should have expired.
113*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(HasExpiredSeconds(certificate, now + 2));
114*d9f75844SAndroid Build Coastguard Worker }
115*d9f75844SAndroid Build Coastguard Worker
TEST_F(RTCCertificateTest,DifferentCertificatesNotEqual)116*d9f75844SAndroid Build Coastguard Worker TEST_F(RTCCertificateTest, DifferentCertificatesNotEqual) {
117*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> a = GenerateECDSA();
118*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> b = GenerateECDSA();
119*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(*a != *b);
120*d9f75844SAndroid Build Coastguard Worker }
121*d9f75844SAndroid Build Coastguard Worker
TEST_F(RTCCertificateTest,CloneWithPEMSerialization)122*d9f75844SAndroid Build Coastguard Worker TEST_F(RTCCertificateTest, CloneWithPEMSerialization) {
123*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> orig = GenerateECDSA();
124*d9f75844SAndroid Build Coastguard Worker
125*d9f75844SAndroid Build Coastguard Worker // To PEM.
126*d9f75844SAndroid Build Coastguard Worker RTCCertificatePEM orig_pem = orig->ToPEM();
127*d9f75844SAndroid Build Coastguard Worker // Clone from PEM.
128*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> clone = RTCCertificate::FromPEM(orig_pem);
129*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(clone);
130*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(*orig == *clone);
131*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(orig->Expires(), clone->Expires());
132*d9f75844SAndroid Build Coastguard Worker }
133*d9f75844SAndroid Build Coastguard Worker
TEST_F(RTCCertificateTest,FromPEMWithInvalidPEM)134*d9f75844SAndroid Build Coastguard Worker TEST_F(RTCCertificateTest, FromPEMWithInvalidPEM) {
135*d9f75844SAndroid Build Coastguard Worker RTCCertificatePEM pem("not a valid PEM", "not a valid PEM");
136*d9f75844SAndroid Build Coastguard Worker scoped_refptr<RTCCertificate> certificate = RTCCertificate::FromPEM(pem);
137*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(certificate);
138*d9f75844SAndroid Build Coastguard Worker }
139*d9f75844SAndroid Build Coastguard Worker
140*d9f75844SAndroid Build Coastguard Worker } // namespace rtc
141