blob: 1f0278ac7109da1ca90cc79c91529e55bcc43c2e [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
2 * Copyright 2011 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
Ali Tofigh7fa90572022-03-17 14:47:4911#include "rtc_base/ssl_identity.h"
12
Yves Gerey3e707812018-11-28 15:47:4913#include <string.h>
Ali Tofigh7fa90572022-03-17 14:47:4914
jbauch555604a2016-04-26 10:13:2215#include <memory>
henrike@webrtc.orgf0488722014-05-13 18:00:2616#include <string>
Yves Gerey3e707812018-11-28 15:47:4917#include <vector>
henrike@webrtc.orgf0488722014-05-13 18:00:2618
Steve Anton1c9c9fc2019-02-14 23:13:0919#include "absl/strings/str_replace.h"
Ali Tofigh7fa90572022-03-17 14:47:4920#include "absl/strings/string_view.h"
Yves Gerey3e707812018-11-28 15:47:4921#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 17:11:0022#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3123#include "rtc_base/helpers.h"
Yves Gerey3e707812018-11-28 15:47:4924#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 17:11:0025#include "rtc_base/message_digest.h"
26#include "rtc_base/ssl_fingerprint.h"
Yves Gerey3e707812018-11-28 15:47:4927#include "test/gtest.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2628
29using rtc::SSLIdentity;
30
Yves Gerey665174f2018-06-19 13:03:0531const char kTestCertificate[] =
32 "-----BEGIN CERTIFICATE-----\n"
henrike@webrtc.orgf0488722014-05-13 18:00:2633 "MIIB6TCCAVICAQYwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n"
34 "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n"
35 "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDAxMDE2MjIzMTAzWhcNMDMwMTE0\n"
36 "MjIzMTAzWjBjMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEaMBgG\n"
37 "A1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxIzAhBgNVBAMTGlNlcnZlciB0ZXN0IGNl\n"
38 "cnQgKDUxMiBiaXQpMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+zw4Qnlf8SMVIP\n"
39 "Fe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/7tdkuD8Ey2//\n"
40 "Kv7+ue0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCT0grFQeZaqYb5EYfk20XixZV4\n"
41 "GmyAbXMftG1Eo7qGiMhYzRwGNWxEYojf5PZkYZXvSqZ/ZXHXa4g59jK/rJNnaVGM\n"
42 "k+xIX8mxQvlV0n5O9PIha5BX5teZnkHKgL8aKKLKW1BK7YTngsfSzzaeame5iKfz\n"
43 "itAE+OjGF+PFKbwX8Q==\n"
44 "-----END CERTIFICATE-----\n";
45
Yves Gerey665174f2018-06-19 13:03:0546const unsigned char kTestCertSha1[] = {0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D,
47 0x33, 0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6,
48 0xF6, 0x8A, 0x9E, 0x47, 0xA7, 0xCA};
Torbjorn Granlundb6d4ec42015-08-17 12:08:5949const unsigned char kTestCertSha224[] = {
Yves Gerey665174f2018-06-19 13:03:0550 0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77, 0x38, 0x36,
51 0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd, 0xae, 0x24, 0x21, 0x08,
52 0xcf, 0x6a, 0x44, 0x0d, 0x3f, 0x94, 0x2a, 0x5b};
Torbjorn Granlundb6d4ec42015-08-17 12:08:5953const unsigned char kTestCertSha256[] = {
Yves Gerey665174f2018-06-19 13:03:0554 0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24, 0x77, 0x0b, 0x8b,
55 0x2e, 0xa6, 0x2b, 0xe0, 0xf9, 0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7,
56 0x5c, 0xa1, 0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76};
Torbjorn Granlundb6d4ec42015-08-17 12:08:5957const unsigned char kTestCertSha384[] = {
Yves Gerey665174f2018-06-19 13:03:0558 0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf, 0x3b, 0xba, 0x36, 0xd8,
59 0x37, 0x4a, 0x9a, 0x75, 0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7,
60 0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc, 0x64, 0x47, 0xd6, 0xd8,
61 0xaa, 0xd9, 0x36, 0x60, 0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49};
Torbjorn Granlundb6d4ec42015-08-17 12:08:5962const unsigned char kTestCertSha512[] = {
Yves Gerey665174f2018-06-19 13:03:0563 0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3, 0xd8, 0x1d, 0xa4,
64 0x9d, 0x43, 0xc9, 0xee, 0x32, 0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f,
65 0x25, 0xdf, 0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b, 0x28,
66 0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf, 0x61, 0x33, 0x0e, 0x14,
67 0xc3, 0x04, 0xaa, 0x07, 0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22,
68 0x35, 0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6};
henrike@webrtc.orgf0488722014-05-13 18:00:2669
hbose29352b2016-08-25 10:52:3870// These PEM strings were created by generating an identity with
Artem Titovcfea2182021-08-09 23:22:3171// `SSLIdentity::Create` and invoking `identity->PrivateKeyToPEMString()`,
72// `identity->PublicKeyToPEMString()` and
73// `identity->certificate().ToPEMString()`. If the crypto library is updated,
hbose29352b2016-08-25 10:52:3874// and the update changes the string form of the keys, these will have to be
75// updated too. The fingerprint, fingerprint algorithm and base64 certificate
Artem Titovcfea2182021-08-09 23:22:3176// were created by calling `identity->certificate().GetStats()`.
hbose29352b2016-08-25 10:52:3877static const char kRSA_PRIVATE_KEY_PEM[] =
78 "-----BEGIN PRIVATE KEY-----\n"
79 "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMQPqDStRlYeDpkX\n"
80 "erRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr\n"
81 "4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuFLNEl\n"
82 "7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAECgYA8FWBC5GcNtSBcIinkZyigF0A7\n"
83 "6j081sa+J/uNz4xUuI257ZXM6biygUhhvuXK06/XoIULJfhyN0fAm1yb0HtNhiUs\n"
84 "kMOYeon6b8FqFaPjrQf7Gr9FMiIHXNK19uegTMKztXyPZoUWlX84X0iawY95x0Y3\n"
85 "73f6P2rN2UOjlVVjAQJBAOKy3l2w3Zj2w0oAJox0eMwl+RxBNt1C42SHrob2mFUT\n"
86 "rytpVVYOasr8CoDI0kjacjI94sLum+buJoXXX6YTGO0CQQDdZwlYIEkoS3ftfxPa\n"
87 "Ai0YTBzAWvHJg0r8Gk/TkHo6IM+LSsZ9ZYUv/vBe4BKLw1I4hZ+bQvBiq+f8ROtk\n"
88 "+TDRAkAPL3ghwoU1h+IRBO2QHwUwd6K2N9AbBi4BP+168O3HVSg4ujeTKigRLMzv\n"
89 "T4R2iNt5bhfQgvdCgtVlxcWMdF8JAkBwDCg3eEdt5BuyjwBt8XH+/O4ED0KUWCTH\n"
90 "x00k5dZlupsuhE5Fwe4QpzXg3gekwdnHjyCCQ/NCDHvgOMTkmhQxAkA9V03KRX9b\n"
91 "bhvEzY/fu8gEp+EzsER96/D79az5z1BaMGL5OPM2xHBPJATKlswnAa7Lp3QKGZGk\n"
92 "TxslfL18J71s\n"
93 "-----END PRIVATE KEY-----\n";
94static const char kRSA_PUBLIC_KEY_PEM[] =
95 "-----BEGIN PUBLIC KEY-----\n"
96 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDED6g0rUZWHg6ZF3q0Zr/mtZ2j\n"
97 "PL0lUmNIBtqZZ656H1YlkVtzEalgvtNtDLCI94T2XkgJ7f8vxS/56+BGuzV3MHUa\n"
98 "Nf9cRCu1P3/3I0oNWrp8rxwh8HBXDK99Ryxbx69GYHBcG4CLhSzRJe5CuRzDvQD8\n"
99 "9Z7VI3pPAZgY/MjJfQIDAQAB\n"
100 "-----END PUBLIC KEY-----\n";
101static const char kRSA_CERT_PEM[] =
102 "-----BEGIN CERTIFICATE-----\n"
103 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV\n"
104 "BAMMBXRlc3QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwG\n"
105 "A1UEAwwFdGVzdDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYe\n"
106 "DpkXerRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/F\n"
107 "L/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuF\n"
108 "LNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhvcNAQELBQADgYEA\n"
109 "C3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJi8dx\n"
110 "yTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFq\n"
111 "e3UkexqNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=\n"
112 "-----END CERTIFICATE-----\n";
113static const char kRSA_FINGERPRINT[] =
114 "3C:E8:B2:70:09:CF:A9:09:5A:F4:EF:8F:8D:8A:32:FF:EA:04:91:BA:6E:D4:17:78:16"
115 ":2A:EE:F9:9A:DD:E2:2B";
Yves Gerey665174f2018-06-19 13:03:05116static const char kRSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 10:52:38117static const char kRSA_BASE64_CERTIFICATE[] =
118 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNVBAMMBXRlc3"
119 "QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwGA1UEAwwFdGVzdDEwgZ8w"
120 "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYeDpkXerRmv+a1naM8vSVSY0gG2plnrn"
121 "ofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHw"
122 "cFcMr31HLFvHr0ZgcFwbgIuFLNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhv"
123 "cNAQELBQADgYEAC3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJ"
124 "i8dxyTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFqe3Ukex"
125 "qNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=";
126
127static const char kECDSA_PRIVATE_KEY_PEM[] =
128 "-----BEGIN PRIVATE KEY-----\n"
129 "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/AkEA2hklq7dQ2rN\n"
130 "ZxYL6hOUACL4pn7P4FYlA3ZQhIChRANCAAR7YgdO3utP/8IqVRq8G4VZKreMAxeN\n"
131 "rUa12twthv4uFjuHAHa9D9oyAjncmn+xvZZRyVmKrA56jRzENcEEHoAg\n"
132 "-----END PRIVATE KEY-----\n";
133static const char kECDSA_PUBLIC_KEY_PEM[] =
134 "-----BEGIN PUBLIC KEY-----\n"
135 "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe2IHTt7rT//CKlUavBuFWSq3jAMX\n"
136 "ja1GtdrcLYb+LhY7hwB2vQ/aMgI53Jp/sb2WUclZiqwOeo0cxDXBBB6AIA==\n"
137 "-----END PUBLIC KEY-----\n";
138static const char kECDSA_CERT_PEM[] =
139 "-----BEGIN CERTIFICATE-----\n"
140 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwF\n"
141 "dGVzdDMwHhcNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQD\n"
142 "DAV0ZXN0MzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwb\n"
143 "hVkqt4wDF42tRrXa3C2G/i4WO4cAdr0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQe\n"
144 "gCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuPPpirsd0e/4WGLHou6bIOSQks\n"
145 "DYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99hkekw==\n"
146 "-----END CERTIFICATE-----\n";
147static const char kECDSA_FINGERPRINT[] =
148 "9F:47:FA:88:76:3D:18:B8:00:A0:59:9D:C3:5D:34:0B:1F:B8:99:9E:68:DA:F3:A5:DA"
149 ":50:33:A9:FF:4D:31:89";
Yves Gerey665174f2018-06-19 13:03:05150static const char kECDSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 10:52:38151static const char kECDSA_BASE64_CERTIFICATE[] =
152 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwFdGVzdDMwHh"
153 "cNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQDDAV0ZXN0MzBZMBMGByqG"
154 "SM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwbhVkqt4wDF42tRrXa3C2G/i4WO4cAdr"
155 "0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQegCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuP"
156 "Ppirsd0e/4WGLHou6bIOSQksDYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99h"
157 "kekw==";
158
159struct IdentityAndInfo {
160 std::unique_ptr<rtc::SSLIdentity> identity;
161 std::vector<std::string> ders;
162 std::vector<std::string> pems;
163 std::vector<std::string> fingerprints;
164};
165
166IdentityAndInfo CreateFakeIdentityAndInfoFromDers(
167 const std::vector<std::string>& ders) {
168 RTC_CHECK(!ders.empty());
169 IdentityAndInfo info;
170 info.ders = ders;
171 for (const std::string& der : ders) {
172 info.pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 13:03:05173 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbose29352b2016-08-25 10:52:38174 der.length()));
175 }
Taylor Brandstetterc3928662018-02-23 21:04:51176 info.identity.reset(new rtc::FakeSSLIdentity(info.pems));
hbose29352b2016-08-25 10:52:38177 // Strip header/footer and newline characters of PEM strings.
178 for (size_t i = 0; i < info.pems.size(); ++i) {
Steve Anton1c9c9fc2019-02-14 23:13:09179 absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
180 {"-----END CERTIFICATE-----", ""},
181 {"\n", ""}},
182 &info.pems[i]);
hbose29352b2016-08-25 10:52:38183 }
Taylor Brandstetterc3928662018-02-23 21:04:51184 // Fingerprints for the whole certificate chain, starting with leaf
185 // certificate.
186 const rtc::SSLCertChain& chain = info.identity->cert_chain();
187 std::unique_ptr<rtc::SSLFingerprint> fp;
188 for (size_t i = 0; i < chain.GetSize(); i++) {
Steve Anton4905edb2018-10-16 02:27:44189 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
Taylor Brandstetterc3928662018-02-23 21:04:51190 EXPECT_TRUE(fp);
191 info.fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbose29352b2016-08-25 10:52:38192 }
193 EXPECT_EQ(info.ders.size(), info.fingerprints.size());
194 return info;
195}
196
Mirko Bonadei6a489f22019-04-09 13:11:12197class SSLIdentityTest : public ::testing::Test {
henrike@webrtc.orgf0488722014-05-13 18:00:26198 public:
Steve Anton9de3aac2017-10-24 17:08:26199 void SetUp() override {
Harald Alvestrand8515d5a2020-03-20 21:51:32200 identity_rsa1_ = SSLIdentity::Create("test1", rtc::KT_RSA);
201 identity_rsa2_ = SSLIdentity::Create("test2", rtc::KT_RSA);
202 identity_ecdsa1_ = SSLIdentity::Create("test3", rtc::KT_ECDSA);
203 identity_ecdsa2_ = SSLIdentity::Create("test4", rtc::KT_ECDSA);
henrike@webrtc.orgf0488722014-05-13 18:00:26204
Torbjorn Granlundb6d4ec42015-08-17 12:08:59205 ASSERT_TRUE(identity_rsa1_);
206 ASSERT_TRUE(identity_rsa2_);
207 ASSERT_TRUE(identity_ecdsa1_);
208 ASSERT_TRUE(identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26209
Steve Antonf25303e2018-10-16 22:23:31210 test_cert_ = rtc::SSLCertificate::FromPEMString(kTestCertificate);
henrike@webrtc.orgf0488722014-05-13 18:00:26211 ASSERT_TRUE(test_cert_);
212 }
213
214 void TestGetSignatureDigestAlgorithm() {
215 std::string digest_algorithm;
Torbjorn Granlundb6d4ec42015-08-17 12:08:59216
217 ASSERT_TRUE(identity_rsa1_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26218 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 01:32:11219 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
Torbjorn Granlundb6d4ec42015-08-17 12:08:59220
221 ASSERT_TRUE(identity_rsa2_->certificate().GetSignatureDigestAlgorithm(
222 &digest_algorithm));
223 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
224
225 ASSERT_TRUE(identity_ecdsa1_->certificate().GetSignatureDigestAlgorithm(
226 &digest_algorithm));
227 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
228
229 ASSERT_TRUE(identity_ecdsa2_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26230 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 01:32:11231 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
henrike@webrtc.orgf0488722014-05-13 18:00:26232
233 // The test certificate has an MD5-based signature.
234 ASSERT_TRUE(test_cert_->GetSignatureDigestAlgorithm(&digest_algorithm));
235 ASSERT_EQ(rtc::DIGEST_MD5, digest_algorithm);
236 }
237
Torbjorn Granlundb6d4ec42015-08-17 12:08:59238 typedef unsigned char DigestType[rtc::MessageDigest::kMaxSize];
239
240 void TestDigestHelper(DigestType digest,
241 const SSLIdentity* identity,
Ali Tofigh7fa90572022-03-17 14:47:49242 absl::string_view algorithm,
Torbjorn Granlundb6d4ec42015-08-17 12:08:59243 size_t expected_len) {
244 DigestType digest1;
245 size_t digest_len;
henrike@webrtc.orgf0488722014-05-13 18:00:26246 bool rv;
247
Torbjorn Granlundb6d4ec42015-08-17 12:08:59248 memset(digest, 0, expected_len);
249 rv = identity->certificate().ComputeDigest(algorithm, digest,
250 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26251 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 12:08:59252 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26253
Torbjorn Granlundb6d4ec42015-08-17 12:08:59254 // Repeat digest computation for the identity as a sanity check.
255 memset(digest1, 0xff, expected_len);
256 rv = identity->certificate().ComputeDigest(algorithm, digest1,
257 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26258 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 12:08:59259 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26260
Torbjorn Granlundb6d4ec42015-08-17 12:08:59261 EXPECT_EQ(0, memcmp(digest, digest1, expected_len));
262 }
henrike@webrtc.orgf0488722014-05-13 18:00:26263
Ali Tofigh7fa90572022-03-17 14:47:49264 void TestDigestForGeneratedCert(absl::string_view algorithm,
Torbjorn Granlundb6d4ec42015-08-17 12:08:59265 size_t expected_len) {
266 DigestType digest[4];
henrike@webrtc.orgf0488722014-05-13 18:00:26267
Torbjorn Granlundb6d4ec42015-08-17 12:08:59268 ASSERT_TRUE(expected_len <= sizeof(DigestType));
henrike@webrtc.orgf0488722014-05-13 18:00:26269
Torbjorn Granlundb6d4ec42015-08-17 12:08:59270 TestDigestHelper(digest[0], identity_rsa1_.get(), algorithm, expected_len);
271 TestDigestHelper(digest[1], identity_rsa2_.get(), algorithm, expected_len);
272 TestDigestHelper(digest[2], identity_ecdsa1_.get(), algorithm,
273 expected_len);
274 TestDigestHelper(digest[3], identity_ecdsa2_.get(), algorithm,
275 expected_len);
276
277 // Sanity check that all four digests are unique. This could theoretically
278 // fail, since cryptographic hash collisions have a non-zero probability.
279 for (int i = 0; i < 4; i++) {
280 for (int j = 0; j < 4; j++) {
281 if (i != j)
282 EXPECT_NE(0, memcmp(digest[i], digest[j], expected_len));
283 }
henrike@webrtc.orgf0488722014-05-13 18:00:26284 }
285 }
286
Ali Tofigh7fa90572022-03-17 14:47:49287 void TestDigestForFixedCert(absl::string_view algorithm,
Torbjorn Granlundb6d4ec42015-08-17 12:08:59288 size_t expected_len,
289 const unsigned char* expected_digest) {
290 bool rv;
291 DigestType digest;
292 size_t digest_len;
293
294 ASSERT_TRUE(expected_len <= sizeof(DigestType));
295
296 rv = test_cert_->ComputeDigest(algorithm, digest, sizeof(digest),
297 &digest_len);
298 EXPECT_TRUE(rv);
299 EXPECT_EQ(expected_len, digest_len);
300 EXPECT_EQ(0, memcmp(digest, expected_digest, expected_len));
301 }
302
hbos6b470a92016-04-28 12:14:21303 void TestCloningIdentity(const SSLIdentity& identity) {
Artem Titov96e3b992021-07-26 14:03:14304 // Convert `identity` to PEM strings and create a new identity by converting
hbos6b470a92016-04-28 12:14:21305 // back from the string format.
306 std::string priv_pem = identity.PrivateKeyToPEMString();
307 std::string publ_pem = identity.PublicKeyToPEMString();
308 std::string cert_pem = identity.certificate().ToPEMString();
Harald Alvestrand8515d5a2020-03-20 21:51:32309 std::unique_ptr<SSLIdentity> clone =
310 SSLIdentity::CreateFromPEMStrings(priv_pem, cert_pem);
hbos6b470a92016-04-28 12:14:21311 EXPECT_TRUE(clone);
312
313 // Make sure the clone is identical to the original.
314 EXPECT_TRUE(identity == *clone);
315 ASSERT_EQ(identity.certificate().CertificateExpirationTime(),
316 clone->certificate().CertificateExpirationTime());
317
318 // At this point we are confident that the identities are identical. To be
319 // extra sure, we compare PEM strings of the clone with the original. Note
320 // that the PEM strings of two identities are not strictly guaranteed to be
321 // equal (they describe structs whose members could be listed in a different
322 // order, for example). But because the same function is used to produce
323 // both PEMs, its a good enough bet that this comparison will work. If the
324 // assumption stops holding in the future we can always remove this from the
325 // unittest.
326 std::string clone_priv_pem = clone->PrivateKeyToPEMString();
327 std::string clone_publ_pem = clone->PublicKeyToPEMString();
328 std::string clone_cert_pem = clone->certificate().ToPEMString();
329 ASSERT_EQ(priv_pem, clone_priv_pem);
330 ASSERT_EQ(publ_pem, clone_publ_pem);
331 ASSERT_EQ(cert_pem, clone_cert_pem);
332 }
333
334 protected:
jbauch555604a2016-04-26 10:13:22335 std::unique_ptr<SSLIdentity> identity_rsa1_;
336 std::unique_ptr<SSLIdentity> identity_rsa2_;
337 std::unique_ptr<SSLIdentity> identity_ecdsa1_;
338 std::unique_ptr<SSLIdentity> identity_ecdsa2_;
339 std::unique_ptr<rtc::SSLCertificate> test_cert_;
henrike@webrtc.orgf0488722014-05-13 18:00:26340};
341
Torbjorn Granlundb6d4ec42015-08-17 12:08:59342TEST_F(SSLIdentityTest, FixedDigestSHA1) {
343 TestDigestForFixedCert(rtc::DIGEST_SHA_1, 20, kTestCertSha1);
344}
345
346// HASH_AlgSHA224 is not supported in the chromium linux build.
Torbjorn Granlundb6d4ec42015-08-17 12:08:59347TEST_F(SSLIdentityTest, FixedDigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 12:08:59348 TestDigestForFixedCert(rtc::DIGEST_SHA_224, 28, kTestCertSha224);
349}
350
351TEST_F(SSLIdentityTest, FixedDigestSHA256) {
352 TestDigestForFixedCert(rtc::DIGEST_SHA_256, 32, kTestCertSha256);
353}
354
355TEST_F(SSLIdentityTest, FixedDigestSHA384) {
356 TestDigestForFixedCert(rtc::DIGEST_SHA_384, 48, kTestCertSha384);
357}
358
359TEST_F(SSLIdentityTest, FixedDigestSHA512) {
360 TestDigestForFixedCert(rtc::DIGEST_SHA_512, 64, kTestCertSha512);
henrike@webrtc.orgf0488722014-05-13 18:00:26361}
362
363// HASH_AlgSHA224 is not supported in the chromium linux build.
henrike@webrtc.orgf0488722014-05-13 18:00:26364TEST_F(SSLIdentityTest, DigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 12:08:59365 TestDigestForGeneratedCert(rtc::DIGEST_SHA_224, 28);
henrike@webrtc.orgf0488722014-05-13 18:00:26366}
367
368TEST_F(SSLIdentityTest, DigestSHA256) {
Torbjorn Granlundb6d4ec42015-08-17 12:08:59369 TestDigestForGeneratedCert(rtc::DIGEST_SHA_256, 32);
henrike@webrtc.orgf0488722014-05-13 18:00:26370}
371
372TEST_F(SSLIdentityTest, DigestSHA384) {
Torbjorn Granlundb6d4ec42015-08-17 12:08:59373 TestDigestForGeneratedCert(rtc::DIGEST_SHA_384, 48);
henrike@webrtc.orgf0488722014-05-13 18:00:26374}
375
376TEST_F(SSLIdentityTest, DigestSHA512) {
Torbjorn Granlundb6d4ec42015-08-17 12:08:59377 TestDigestForGeneratedCert(rtc::DIGEST_SHA_512, 64);
henrike@webrtc.orgf0488722014-05-13 18:00:26378}
379
hbos6b470a92016-04-28 12:14:21380TEST_F(SSLIdentityTest, IdentityComparison) {
381 EXPECT_TRUE(*identity_rsa1_ == *identity_rsa1_);
382 EXPECT_FALSE(*identity_rsa1_ == *identity_rsa2_);
383 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa1_);
384 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26385
hbos6b470a92016-04-28 12:14:21386 EXPECT_TRUE(*identity_rsa2_ == *identity_rsa2_);
387 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa1_);
388 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa2_);
389
390 EXPECT_TRUE(*identity_ecdsa1_ == *identity_ecdsa1_);
391 EXPECT_FALSE(*identity_ecdsa1_ == *identity_ecdsa2_);
392}
393
394TEST_F(SSLIdentityTest, FromPEMStringsRSA) {
jbauch555604a2016-04-26 10:13:22395 std::unique_ptr<SSLIdentity> identity(
Harald Alvestrand8515d5a2020-03-20 21:51:32396 SSLIdentity::CreateFromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
henrike@webrtc.orgf0488722014-05-13 18:00:26397 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 12:14:21398 EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
399 EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 10:52:38400 EXPECT_EQ(kRSA_CERT_PEM, identity->certificate().ToPEMString());
henrike@webrtc.orgf0488722014-05-13 18:00:26401}
402
Torbjorn Granlundb6d4ec42015-08-17 12:08:59403TEST_F(SSLIdentityTest, FromPEMStringsEC) {
Harald Alvestrand8515d5a2020-03-20 21:51:32404 std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateFromPEMStrings(
405 kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
Torbjorn Granlundb6d4ec42015-08-17 12:08:59406 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 12:14:21407 EXPECT_EQ(kECDSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
408 EXPECT_EQ(kECDSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 10:52:38409 EXPECT_EQ(kECDSA_CERT_PEM, identity->certificate().ToPEMString());
Torbjorn Granlundb6d4ec42015-08-17 12:08:59410}
Torbjorn Granlundb6d4ec42015-08-17 12:08:59411
Taylor Brandstetter165c6182020-12-11 00:23:03412TEST_F(SSLIdentityTest, FromPEMChainStrings) {
413 // This doesn't form a valid certificate chain, but that doesn't matter for
414 // the purposes of the test
415 std::string chain(kRSA_CERT_PEM);
416 chain.append(kTestCertificate);
417 std::unique_ptr<SSLIdentity> identity(
418 SSLIdentity::CreateFromPEMChainStrings(kRSA_PRIVATE_KEY_PEM, chain));
419 EXPECT_TRUE(identity);
420 EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
421 EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
422 ASSERT_EQ(2u, identity->cert_chain().GetSize());
423 EXPECT_EQ(kRSA_CERT_PEM, identity->cert_chain().Get(0).ToPEMString());
424 EXPECT_EQ(kTestCertificate, identity->cert_chain().Get(1).ToPEMString());
425}
426
hbos6b470a92016-04-28 12:14:21427TEST_F(SSLIdentityTest, CloneIdentityRSA) {
428 TestCloningIdentity(*identity_rsa1_);
429 TestCloningIdentity(*identity_rsa2_);
430}
431
432TEST_F(SSLIdentityTest, CloneIdentityECDSA) {
433 TestCloningIdentity(*identity_ecdsa1_);
434 TestCloningIdentity(*identity_ecdsa2_);
435}
436
henrike@webrtc.orgf0488722014-05-13 18:00:26437TEST_F(SSLIdentityTest, PemDerConversion) {
438 std::string der;
439 EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der));
440
Yves Gerey665174f2018-06-19 13:03:05441 EXPECT_EQ(
442 kTestCertificate,
443 SSLIdentity::DerToPem("CERTIFICATE",
444 reinterpret_cast<const unsigned char*>(der.data()),
445 der.length()));
henrike@webrtc.orgf0488722014-05-13 18:00:26446}
447
448TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) {
449 TestGetSignatureDigestAlgorithm();
450}
Torbjorn Granlund46c9cc02015-12-01 12:06:34451
hbose29352b2016-08-25 10:52:38452TEST_F(SSLIdentityTest, SSLCertificateGetStatsRSA) {
453 std::unique_ptr<SSLIdentity> identity(
Harald Alvestrand8515d5a2020-03-20 21:51:32454 SSLIdentity::CreateFromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
hbose29352b2016-08-25 10:52:38455 std::unique_ptr<rtc::SSLCertificateStats> stats =
456 identity->certificate().GetStats();
457 EXPECT_EQ(stats->fingerprint, kRSA_FINGERPRINT);
458 EXPECT_EQ(stats->fingerprint_algorithm, kRSA_FINGERPRINT_ALGORITHM);
459 EXPECT_EQ(stats->base64_certificate, kRSA_BASE64_CERTIFICATE);
460 EXPECT_FALSE(stats->issuer);
461}
462
463TEST_F(SSLIdentityTest, SSLCertificateGetStatsECDSA) {
Harald Alvestrand8515d5a2020-03-20 21:51:32464 std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateFromPEMStrings(
465 kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
hbose29352b2016-08-25 10:52:38466 std::unique_ptr<rtc::SSLCertificateStats> stats =
467 identity->certificate().GetStats();
468 EXPECT_EQ(stats->fingerprint, kECDSA_FINGERPRINT);
469 EXPECT_EQ(stats->fingerprint_algorithm, kECDSA_FINGERPRINT_ALGORITHM);
470 EXPECT_EQ(stats->base64_certificate, kECDSA_BASE64_CERTIFICATE);
471 EXPECT_FALSE(stats->issuer);
472}
473
474TEST_F(SSLIdentityTest, SSLCertificateGetStatsWithChain) {
475 std::vector<std::string> ders;
476 ders.push_back("every der results in");
477 ders.push_back("an identity + certificate");
478 ders.push_back("in a certificate chain");
479 IdentityAndInfo info = CreateFakeIdentityAndInfoFromDers(ders);
480 EXPECT_TRUE(info.identity);
481 EXPECT_EQ(info.ders, ders);
482 EXPECT_EQ(info.pems.size(), info.ders.size());
483 EXPECT_EQ(info.fingerprints.size(), info.ders.size());
484
485 std::unique_ptr<rtc::SSLCertificateStats> first_stats =
Taylor Brandstetterc3928662018-02-23 21:04:51486 info.identity->cert_chain().GetStats();
hbose29352b2016-08-25 10:52:38487 rtc::SSLCertificateStats* cert_stats = first_stats.get();
488 for (size_t i = 0; i < info.ders.size(); ++i) {
489 EXPECT_EQ(cert_stats->fingerprint, info.fingerprints[i]);
490 EXPECT_EQ(cert_stats->fingerprint_algorithm, "sha-1");
491 EXPECT_EQ(cert_stats->base64_certificate, info.pems[i]);
492 cert_stats = cert_stats->issuer.get();
493 EXPECT_EQ(static_cast<bool>(cert_stats), i + 1 < info.ders.size());
494 }
495}
496
Mirko Bonadei6a489f22019-04-09 13:11:12497class SSLIdentityExpirationTest : public ::testing::Test {
Torbjorn Granlund46c9cc02015-12-01 12:06:34498 public:
499 SSLIdentityExpirationTest() {
500 // Set use of the test RNG to get deterministic expiration timestamp.
501 rtc::SetRandomTestMode(true);
502 }
Steve Anton9de3aac2017-10-24 17:08:26503 ~SSLIdentityExpirationTest() override {
Torbjorn Granlund46c9cc02015-12-01 12:06:34504 // Put it back for the next test.
505 rtc::SetRandomTestMode(false);
506 }
507
508 void TestASN1TimeToSec() {
509 struct asn_example {
510 const char* string;
511 bool long_format;
512 int64_t want;
513 } static const data[] = {
Yves Gerey665174f2018-06-19 13:03:05514 // clang-format off
515 // clang formatting breaks this nice alignment
516
Torbjorn Granlund46c9cc02015-12-01 12:06:34517 // Valid examples.
518 {"19700101000000Z", true, 0},
519 {"700101000000Z", false, 0},
520 {"19700101000001Z", true, 1},
521 {"700101000001Z", false, 1},
522 {"19700101000100Z", true, 60},
523 {"19700101000101Z", true, 61},
524 {"19700101010000Z", true, 3600},
525 {"19700101010001Z", true, 3601},
526 {"19700101010100Z", true, 3660},
527 {"19700101010101Z", true, 3661},
528 {"710911012345Z", false, 53400225},
529 {"20000101000000Z", true, 946684800},
530 {"20000101000000Z", true, 946684800},
531 {"20151130140156Z", true, 1448892116},
532 {"151130140156Z", false, 1448892116},
533 {"20491231235959Z", true, 2524607999},
534 {"491231235959Z", false, 2524607999},
535 {"20500101000000Z", true, 2524607999+1},
536 {"20700101000000Z", true, 3155760000},
537 {"21000101000000Z", true, 4102444800},
538 {"24000101000000Z", true, 13569465600},
539
540 // Invalid examples.
541 {"19700101000000", true, -1}, // missing Z long format
542 {"19700101000000X", true, -1}, // X instead of Z long format
543 {"197001010000000", true, -1}, // 0 instead of Z long format
544 {"1970010100000000Z", true, -1}, // excess digits long format
545 {"700101000000", false, -1}, // missing Z short format
546 {"700101000000X", false, -1}, // X instead of Z short format
547 {"7001010000000", false, -1}, // 0 instead of Z short format
548 {"70010100000000Z", false, -1}, // excess digits short format
549 {":9700101000000Z", true, -1}, // invalid character
550 {"1:700101000001Z", true, -1}, // invalid character
551 {"19:00101000100Z", true, -1}, // invalid character
552 {"197:0101000101Z", true, -1}, // invalid character
553 {"1970:101010000Z", true, -1}, // invalid character
554 {"19700:01010001Z", true, -1}, // invalid character
555 {"197001:1010100Z", true, -1}, // invalid character
556 {"1970010:010101Z", true, -1}, // invalid character
557 {"70010100:000Z", false, -1}, // invalid character
558 {"700101000:01Z", false, -1}, // invalid character
559 {"2000010100:000Z", true, -1}, // invalid character
560 {"21000101000:00Z", true, -1}, // invalid character
561 {"240001010000:0Z", true, -1}, // invalid character
562 {"500101000000Z", false, -1}, // but too old for epoch
563 {"691231235959Z", false, -1}, // too old for epoch
564 {"19611118043000Z", false, -1}, // way too old for epoch
Yves Gerey665174f2018-06-19 13:03:05565
566 // clang-format off
Torbjorn Granlund46c9cc02015-12-01 12:06:34567 };
568
569 unsigned char buf[20];
570
571 // Run all examples and check for the expected result.
572 for (const auto& entry : data) {
573 size_t length = strlen(entry.string);
574 memcpy(buf, entry.string, length); // Copy the ASN1 string...
575 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
576 int64_t res = rtc::ASN1TimeToSec(buf, length, entry.long_format);
Mirko Bonadei675513b2017-11-09 10:09:25577 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 12:06:34578 ASSERT_EQ(entry.want, res);
579 }
580 // Run all examples again, but with an invalid length.
581 for (const auto& entry : data) {
582 size_t length = strlen(entry.string);
583 memcpy(buf, entry.string, length); // Copy the ASN1 string...
584 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
585 int64_t res = rtc::ASN1TimeToSec(buf, length - 1, entry.long_format);
Mirko Bonadei675513b2017-11-09 10:09:25586 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 12:06:34587 ASSERT_EQ(-1, res);
588 }
589 }
590
591 void TestExpireTime(int times) {
torbjornge8dc0812016-02-15 17:35:54592 // We test just ECDSA here since what we're out to exercise is the
593 // interfaces for expiration setting and reading.
Torbjorn Granlund46c9cc02015-12-01 12:06:34594 for (int i = 0; i < times; i++) {
Torbjorn Granlund46c9cc02015-12-01 12:06:34595 // We limit the time to < 2^31 here, i.e., we stay before 2038, since else
596 // we hit time offset limitations in OpenSSL on some 32-bit systems.
Taylor Brandstetter88dec832016-03-15 16:57:55597 time_t time_before_generation = time(nullptr);
598 time_t lifetime =
599 rtc::CreateRandomId() % (0x80000000 - time_before_generation);
torbjornge8dc0812016-02-15 17:35:54600 rtc::KeyParams key_params = rtc::KeyParams::ECDSA(rtc::EC_NIST_P256);
Harald Alvestrand8515d5a2020-03-20 21:51:32601 auto identity =
602 rtc::SSLIdentity::Create("", key_params, lifetime);
Taylor Brandstetter88dec832016-03-15 16:57:55603 time_t time_after_generation = time(nullptr);
604 EXPECT_LE(time_before_generation + lifetime,
605 identity->certificate().CertificateExpirationTime());
606 EXPECT_GE(time_after_generation + lifetime,
Torbjorn Granlund46c9cc02015-12-01 12:06:34607 identity->certificate().CertificateExpirationTime());
Torbjorn Granlund46c9cc02015-12-01 12:06:34608 }
609 }
610};
611
612TEST_F(SSLIdentityExpirationTest, TestASN1TimeToSec) {
613 TestASN1TimeToSec();
614}
615
616TEST_F(SSLIdentityExpirationTest, TestExpireTime) {
617 TestExpireTime(500);
618}