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