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