blob: a8be7963b59b5093b54d66b7ba7fbb49a5fdc0e5 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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
Yves Gerey3e707812018-11-28 16:47:49 +010011#include <string.h>
jbauch555604a2016-04-26 03:13:22 -070012#include <memory>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#include <string>
Yves Gerey3e707812018-11-28 16:47:49 +010014#include <vector>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015
Steve Anton1c9c9fc2019-02-14 15:13:09 -080016#include "absl/strings/str_replace.h"
Yves Gerey3e707812018-11-28 16:47:49 +010017#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080018#include "rtc_base/fake_ssl_identity.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/helpers.h"
Yves Gerey3e707812018-11-28 16:47:49 +010020#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080021#include "rtc_base/message_digest.h"
22#include "rtc_base/ssl_fingerprint.h"
23#include "rtc_base/ssl_identity.h"
Yves Gerey3e707812018-11-28 16:47:49 +010024#include "test/gtest.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025
26using rtc::SSLIdentity;
27
Yves Gerey665174f2018-06-19 15:03:05 +020028const char kTestCertificate[] =
29 "-----BEGIN CERTIFICATE-----\n"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000030 "MIIB6TCCAVICAQYwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n"
31 "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n"
32 "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDAxMDE2MjIzMTAzWhcNMDMwMTE0\n"
33 "MjIzMTAzWjBjMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEaMBgG\n"
34 "A1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxIzAhBgNVBAMTGlNlcnZlciB0ZXN0IGNl\n"
35 "cnQgKDUxMiBiaXQpMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+zw4Qnlf8SMVIP\n"
36 "Fe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/7tdkuD8Ey2//\n"
37 "Kv7+ue0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCT0grFQeZaqYb5EYfk20XixZV4\n"
38 "GmyAbXMftG1Eo7qGiMhYzRwGNWxEYojf5PZkYZXvSqZ/ZXHXa4g59jK/rJNnaVGM\n"
39 "k+xIX8mxQvlV0n5O9PIha5BX5teZnkHKgL8aKKLKW1BK7YTngsfSzzaeame5iKfz\n"
40 "itAE+OjGF+PFKbwX8Q==\n"
41 "-----END CERTIFICATE-----\n";
42
Yves Gerey665174f2018-06-19 15:03:05 +020043const unsigned char kTestCertSha1[] = {0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D,
44 0x33, 0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6,
45 0xF6, 0x8A, 0x9E, 0x47, 0xA7, 0xCA};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020046const unsigned char kTestCertSha224[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020047 0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77, 0x38, 0x36,
48 0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd, 0xae, 0x24, 0x21, 0x08,
49 0xcf, 0x6a, 0x44, 0x0d, 0x3f, 0x94, 0x2a, 0x5b};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020050const unsigned char kTestCertSha256[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020051 0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24, 0x77, 0x0b, 0x8b,
52 0x2e, 0xa6, 0x2b, 0xe0, 0xf9, 0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7,
53 0x5c, 0xa1, 0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020054const unsigned char kTestCertSha384[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020055 0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf, 0x3b, 0xba, 0x36, 0xd8,
56 0x37, 0x4a, 0x9a, 0x75, 0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7,
57 0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc, 0x64, 0x47, 0xd6, 0xd8,
58 0xaa, 0xd9, 0x36, 0x60, 0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020059const unsigned char kTestCertSha512[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020060 0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3, 0xd8, 0x1d, 0xa4,
61 0x9d, 0x43, 0xc9, 0xee, 0x32, 0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f,
62 0x25, 0xdf, 0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b, 0x28,
63 0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf, 0x61, 0x33, 0x0e, 0x14,
64 0xc3, 0x04, 0xaa, 0x07, 0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22,
65 0x35, 0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066
hbose29352b2016-08-25 03:52:38 -070067// These PEM strings were created by generating an identity with
Taylor Brandstetter165c6182020-12-10 16:23:03 -080068// |SSLIdentity::Create| and invoking |identity->PrivateKeyToPEMString()|,
hbose29352b2016-08-25 03:52:38 -070069// |identity->PublicKeyToPEMString()| and
70// |identity->certificate().ToPEMString()|. If the crypto library is updated,
71// and the update changes the string form of the keys, these will have to be
72// updated too. The fingerprint, fingerprint algorithm and base64 certificate
73// were created by calling |identity->certificate().GetStats()|.
74static const char kRSA_PRIVATE_KEY_PEM[] =
75 "-----BEGIN PRIVATE KEY-----\n"
76 "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMQPqDStRlYeDpkX\n"
77 "erRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr\n"
78 "4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuFLNEl\n"
79 "7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAECgYA8FWBC5GcNtSBcIinkZyigF0A7\n"
80 "6j081sa+J/uNz4xUuI257ZXM6biygUhhvuXK06/XoIULJfhyN0fAm1yb0HtNhiUs\n"
81 "kMOYeon6b8FqFaPjrQf7Gr9FMiIHXNK19uegTMKztXyPZoUWlX84X0iawY95x0Y3\n"
82 "73f6P2rN2UOjlVVjAQJBAOKy3l2w3Zj2w0oAJox0eMwl+RxBNt1C42SHrob2mFUT\n"
83 "rytpVVYOasr8CoDI0kjacjI94sLum+buJoXXX6YTGO0CQQDdZwlYIEkoS3ftfxPa\n"
84 "Ai0YTBzAWvHJg0r8Gk/TkHo6IM+LSsZ9ZYUv/vBe4BKLw1I4hZ+bQvBiq+f8ROtk\n"
85 "+TDRAkAPL3ghwoU1h+IRBO2QHwUwd6K2N9AbBi4BP+168O3HVSg4ujeTKigRLMzv\n"
86 "T4R2iNt5bhfQgvdCgtVlxcWMdF8JAkBwDCg3eEdt5BuyjwBt8XH+/O4ED0KUWCTH\n"
87 "x00k5dZlupsuhE5Fwe4QpzXg3gekwdnHjyCCQ/NCDHvgOMTkmhQxAkA9V03KRX9b\n"
88 "bhvEzY/fu8gEp+EzsER96/D79az5z1BaMGL5OPM2xHBPJATKlswnAa7Lp3QKGZGk\n"
89 "TxslfL18J71s\n"
90 "-----END PRIVATE KEY-----\n";
91static const char kRSA_PUBLIC_KEY_PEM[] =
92 "-----BEGIN PUBLIC KEY-----\n"
93 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDED6g0rUZWHg6ZF3q0Zr/mtZ2j\n"
94 "PL0lUmNIBtqZZ656H1YlkVtzEalgvtNtDLCI94T2XkgJ7f8vxS/56+BGuzV3MHUa\n"
95 "Nf9cRCu1P3/3I0oNWrp8rxwh8HBXDK99Ryxbx69GYHBcG4CLhSzRJe5CuRzDvQD8\n"
96 "9Z7VI3pPAZgY/MjJfQIDAQAB\n"
97 "-----END PUBLIC KEY-----\n";
98static const char kRSA_CERT_PEM[] =
99 "-----BEGIN CERTIFICATE-----\n"
100 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV\n"
101 "BAMMBXRlc3QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwG\n"
102 "A1UEAwwFdGVzdDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYe\n"
103 "DpkXerRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/F\n"
104 "L/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuF\n"
105 "LNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhvcNAQELBQADgYEA\n"
106 "C3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJi8dx\n"
107 "yTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFq\n"
108 "e3UkexqNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=\n"
109 "-----END CERTIFICATE-----\n";
110static const char kRSA_FINGERPRINT[] =
111 "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"
112 ":2A:EE:F9:9A:DD:E2:2B";
Yves Gerey665174f2018-06-19 15:03:05 +0200113static const char kRSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 03:52:38 -0700114static const char kRSA_BASE64_CERTIFICATE[] =
115 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNVBAMMBXRlc3"
116 "QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwGA1UEAwwFdGVzdDEwgZ8w"
117 "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYeDpkXerRmv+a1naM8vSVSY0gG2plnrn"
118 "ofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHw"
119 "cFcMr31HLFvHr0ZgcFwbgIuFLNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhv"
120 "cNAQELBQADgYEAC3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJ"
121 "i8dxyTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFqe3Ukex"
122 "qNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=";
123
124static const char kECDSA_PRIVATE_KEY_PEM[] =
125 "-----BEGIN PRIVATE KEY-----\n"
126 "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/AkEA2hklq7dQ2rN\n"
127 "ZxYL6hOUACL4pn7P4FYlA3ZQhIChRANCAAR7YgdO3utP/8IqVRq8G4VZKreMAxeN\n"
128 "rUa12twthv4uFjuHAHa9D9oyAjncmn+xvZZRyVmKrA56jRzENcEEHoAg\n"
129 "-----END PRIVATE KEY-----\n";
130static const char kECDSA_PUBLIC_KEY_PEM[] =
131 "-----BEGIN PUBLIC KEY-----\n"
132 "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe2IHTt7rT//CKlUavBuFWSq3jAMX\n"
133 "ja1GtdrcLYb+LhY7hwB2vQ/aMgI53Jp/sb2WUclZiqwOeo0cxDXBBB6AIA==\n"
134 "-----END PUBLIC KEY-----\n";
135static const char kECDSA_CERT_PEM[] =
136 "-----BEGIN CERTIFICATE-----\n"
137 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwF\n"
138 "dGVzdDMwHhcNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQD\n"
139 "DAV0ZXN0MzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwb\n"
140 "hVkqt4wDF42tRrXa3C2G/i4WO4cAdr0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQe\n"
141 "gCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuPPpirsd0e/4WGLHou6bIOSQks\n"
142 "DYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99hkekw==\n"
143 "-----END CERTIFICATE-----\n";
144static const char kECDSA_FINGERPRINT[] =
145 "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"
146 ":50:33:A9:FF:4D:31:89";
Yves Gerey665174f2018-06-19 15:03:05 +0200147static const char kECDSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 03:52:38 -0700148static const char kECDSA_BASE64_CERTIFICATE[] =
149 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwFdGVzdDMwHh"
150 "cNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQDDAV0ZXN0MzBZMBMGByqG"
151 "SM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwbhVkqt4wDF42tRrXa3C2G/i4WO4cAdr"
152 "0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQegCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuP"
153 "Ppirsd0e/4WGLHou6bIOSQksDYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99h"
154 "kekw==";
155
156struct IdentityAndInfo {
157 std::unique_ptr<rtc::SSLIdentity> identity;
158 std::vector<std::string> ders;
159 std::vector<std::string> pems;
160 std::vector<std::string> fingerprints;
161};
162
163IdentityAndInfo CreateFakeIdentityAndInfoFromDers(
164 const std::vector<std::string>& ders) {
165 RTC_CHECK(!ders.empty());
166 IdentityAndInfo info;
167 info.ders = ders;
168 for (const std::string& der : ders) {
169 info.pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 15:03:05 +0200170 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbose29352b2016-08-25 03:52:38 -0700171 der.length()));
172 }
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800173 info.identity.reset(new rtc::FakeSSLIdentity(info.pems));
hbose29352b2016-08-25 03:52:38 -0700174 // Strip header/footer and newline characters of PEM strings.
175 for (size_t i = 0; i < info.pems.size(); ++i) {
Steve Anton1c9c9fc2019-02-14 15:13:09 -0800176 absl::StrReplaceAll({{"-----BEGIN CERTIFICATE-----", ""},
177 {"-----END CERTIFICATE-----", ""},
178 {"\n", ""}},
179 &info.pems[i]);
hbose29352b2016-08-25 03:52:38 -0700180 }
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800181 // Fingerprints for the whole certificate chain, starting with leaf
182 // certificate.
183 const rtc::SSLCertChain& chain = info.identity->cert_chain();
184 std::unique_ptr<rtc::SSLFingerprint> fp;
185 for (size_t i = 0; i < chain.GetSize(); i++) {
Steve Anton4905edb2018-10-15 19:27:44 -0700186 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800187 EXPECT_TRUE(fp);
188 info.fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbose29352b2016-08-25 03:52:38 -0700189 }
190 EXPECT_EQ(info.ders.size(), info.fingerprints.size());
191 return info;
192}
193
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200194class SSLIdentityTest : public ::testing::Test {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000195 public:
Steve Anton9de3aac2017-10-24 10:08:26 -0700196 void SetUp() override {
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100197 identity_rsa1_ = SSLIdentity::Create("test1", rtc::KT_RSA);
198 identity_rsa2_ = SSLIdentity::Create("test2", rtc::KT_RSA);
199 identity_ecdsa1_ = SSLIdentity::Create("test3", rtc::KT_ECDSA);
200 identity_ecdsa2_ = SSLIdentity::Create("test4", rtc::KT_ECDSA);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000201
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200202 ASSERT_TRUE(identity_rsa1_);
203 ASSERT_TRUE(identity_rsa2_);
204 ASSERT_TRUE(identity_ecdsa1_);
205 ASSERT_TRUE(identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000206
Steve Antonf25303e2018-10-16 15:23:31 -0700207 test_cert_ = rtc::SSLCertificate::FromPEMString(kTestCertificate);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000208 ASSERT_TRUE(test_cert_);
209 }
210
211 void TestGetSignatureDigestAlgorithm() {
212 std::string digest_algorithm;
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200213
214 ASSERT_TRUE(identity_rsa1_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000215 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 03:32:11 +0200216 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200217
218 ASSERT_TRUE(identity_rsa2_->certificate().GetSignatureDigestAlgorithm(
219 &digest_algorithm));
220 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
221
222 ASSERT_TRUE(identity_ecdsa1_->certificate().GetSignatureDigestAlgorithm(
223 &digest_algorithm));
224 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
225
226 ASSERT_TRUE(identity_ecdsa2_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 03:32:11 +0200228 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000229
230 // The test certificate has an MD5-based signature.
231 ASSERT_TRUE(test_cert_->GetSignatureDigestAlgorithm(&digest_algorithm));
232 ASSERT_EQ(rtc::DIGEST_MD5, digest_algorithm);
233 }
234
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200235 typedef unsigned char DigestType[rtc::MessageDigest::kMaxSize];
236
237 void TestDigestHelper(DigestType digest,
238 const SSLIdentity* identity,
239 const std::string& algorithm,
240 size_t expected_len) {
241 DigestType digest1;
242 size_t digest_len;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000243 bool rv;
244
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200245 memset(digest, 0, expected_len);
246 rv = identity->certificate().ComputeDigest(algorithm, digest,
247 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000248 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200249 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000250
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200251 // Repeat digest computation for the identity as a sanity check.
252 memset(digest1, 0xff, expected_len);
253 rv = identity->certificate().ComputeDigest(algorithm, digest1,
254 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000255 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200256 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000257
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200258 EXPECT_EQ(0, memcmp(digest, digest1, expected_len));
259 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000260
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200261 void TestDigestForGeneratedCert(const std::string& algorithm,
262 size_t expected_len) {
263 DigestType digest[4];
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000264
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200265 ASSERT_TRUE(expected_len <= sizeof(DigestType));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000266
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200267 TestDigestHelper(digest[0], identity_rsa1_.get(), algorithm, expected_len);
268 TestDigestHelper(digest[1], identity_rsa2_.get(), algorithm, expected_len);
269 TestDigestHelper(digest[2], identity_ecdsa1_.get(), algorithm,
270 expected_len);
271 TestDigestHelper(digest[3], identity_ecdsa2_.get(), algorithm,
272 expected_len);
273
274 // Sanity check that all four digests are unique. This could theoretically
275 // fail, since cryptographic hash collisions have a non-zero probability.
276 for (int i = 0; i < 4; i++) {
277 for (int j = 0; j < 4; j++) {
278 if (i != j)
279 EXPECT_NE(0, memcmp(digest[i], digest[j], expected_len));
280 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000281 }
282 }
283
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200284 void TestDigestForFixedCert(const std::string& algorithm,
285 size_t expected_len,
286 const unsigned char* expected_digest) {
287 bool rv;
288 DigestType digest;
289 size_t digest_len;
290
291 ASSERT_TRUE(expected_len <= sizeof(DigestType));
292
293 rv = test_cert_->ComputeDigest(algorithm, digest, sizeof(digest),
294 &digest_len);
295 EXPECT_TRUE(rv);
296 EXPECT_EQ(expected_len, digest_len);
297 EXPECT_EQ(0, memcmp(digest, expected_digest, expected_len));
298 }
299
hbos6b470a92016-04-28 05:14:21 -0700300 void TestCloningIdentity(const SSLIdentity& identity) {
Artem Titov96e3b992021-07-26 16:03:14 +0200301 // Convert `identity` to PEM strings and create a new identity by converting
hbos6b470a92016-04-28 05:14:21 -0700302 // back from the string format.
303 std::string priv_pem = identity.PrivateKeyToPEMString();
304 std::string publ_pem = identity.PublicKeyToPEMString();
305 std::string cert_pem = identity.certificate().ToPEMString();
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100306 std::unique_ptr<SSLIdentity> clone =
307 SSLIdentity::CreateFromPEMStrings(priv_pem, cert_pem);
hbos6b470a92016-04-28 05:14:21 -0700308 EXPECT_TRUE(clone);
309
310 // Make sure the clone is identical to the original.
311 EXPECT_TRUE(identity == *clone);
312 ASSERT_EQ(identity.certificate().CertificateExpirationTime(),
313 clone->certificate().CertificateExpirationTime());
314
315 // At this point we are confident that the identities are identical. To be
316 // extra sure, we compare PEM strings of the clone with the original. Note
317 // that the PEM strings of two identities are not strictly guaranteed to be
318 // equal (they describe structs whose members could be listed in a different
319 // order, for example). But because the same function is used to produce
320 // both PEMs, its a good enough bet that this comparison will work. If the
321 // assumption stops holding in the future we can always remove this from the
322 // unittest.
323 std::string clone_priv_pem = clone->PrivateKeyToPEMString();
324 std::string clone_publ_pem = clone->PublicKeyToPEMString();
325 std::string clone_cert_pem = clone->certificate().ToPEMString();
326 ASSERT_EQ(priv_pem, clone_priv_pem);
327 ASSERT_EQ(publ_pem, clone_publ_pem);
328 ASSERT_EQ(cert_pem, clone_cert_pem);
329 }
330
331 protected:
jbauch555604a2016-04-26 03:13:22 -0700332 std::unique_ptr<SSLIdentity> identity_rsa1_;
333 std::unique_ptr<SSLIdentity> identity_rsa2_;
334 std::unique_ptr<SSLIdentity> identity_ecdsa1_;
335 std::unique_ptr<SSLIdentity> identity_ecdsa2_;
336 std::unique_ptr<rtc::SSLCertificate> test_cert_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000337};
338
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200339TEST_F(SSLIdentityTest, FixedDigestSHA1) {
340 TestDigestForFixedCert(rtc::DIGEST_SHA_1, 20, kTestCertSha1);
341}
342
343// HASH_AlgSHA224 is not supported in the chromium linux build.
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200344TEST_F(SSLIdentityTest, FixedDigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200345 TestDigestForFixedCert(rtc::DIGEST_SHA_224, 28, kTestCertSha224);
346}
347
348TEST_F(SSLIdentityTest, FixedDigestSHA256) {
349 TestDigestForFixedCert(rtc::DIGEST_SHA_256, 32, kTestCertSha256);
350}
351
352TEST_F(SSLIdentityTest, FixedDigestSHA384) {
353 TestDigestForFixedCert(rtc::DIGEST_SHA_384, 48, kTestCertSha384);
354}
355
356TEST_F(SSLIdentityTest, FixedDigestSHA512) {
357 TestDigestForFixedCert(rtc::DIGEST_SHA_512, 64, kTestCertSha512);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358}
359
360// HASH_AlgSHA224 is not supported in the chromium linux build.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000361TEST_F(SSLIdentityTest, DigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200362 TestDigestForGeneratedCert(rtc::DIGEST_SHA_224, 28);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363}
364
365TEST_F(SSLIdentityTest, DigestSHA256) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200366 TestDigestForGeneratedCert(rtc::DIGEST_SHA_256, 32);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367}
368
369TEST_F(SSLIdentityTest, DigestSHA384) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200370 TestDigestForGeneratedCert(rtc::DIGEST_SHA_384, 48);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000371}
372
373TEST_F(SSLIdentityTest, DigestSHA512) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200374 TestDigestForGeneratedCert(rtc::DIGEST_SHA_512, 64);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000375}
376
hbos6b470a92016-04-28 05:14:21 -0700377TEST_F(SSLIdentityTest, IdentityComparison) {
378 EXPECT_TRUE(*identity_rsa1_ == *identity_rsa1_);
379 EXPECT_FALSE(*identity_rsa1_ == *identity_rsa2_);
380 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa1_);
381 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000382
hbos6b470a92016-04-28 05:14:21 -0700383 EXPECT_TRUE(*identity_rsa2_ == *identity_rsa2_);
384 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa1_);
385 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa2_);
386
387 EXPECT_TRUE(*identity_ecdsa1_ == *identity_ecdsa1_);
388 EXPECT_FALSE(*identity_ecdsa1_ == *identity_ecdsa2_);
389}
390
391TEST_F(SSLIdentityTest, FromPEMStringsRSA) {
jbauch555604a2016-04-26 03:13:22 -0700392 std::unique_ptr<SSLIdentity> identity(
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100393 SSLIdentity::CreateFromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000394 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 05:14:21 -0700395 EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
396 EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 03:52:38 -0700397 EXPECT_EQ(kRSA_CERT_PEM, identity->certificate().ToPEMString());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000398}
399
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200400TEST_F(SSLIdentityTest, FromPEMStringsEC) {
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100401 std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateFromPEMStrings(
402 kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200403 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 05:14:21 -0700404 EXPECT_EQ(kECDSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
405 EXPECT_EQ(kECDSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 03:52:38 -0700406 EXPECT_EQ(kECDSA_CERT_PEM, identity->certificate().ToPEMString());
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200407}
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200408
Taylor Brandstetter165c6182020-12-10 16:23:03 -0800409TEST_F(SSLIdentityTest, FromPEMChainStrings) {
410 // This doesn't form a valid certificate chain, but that doesn't matter for
411 // the purposes of the test
412 std::string chain(kRSA_CERT_PEM);
413 chain.append(kTestCertificate);
414 std::unique_ptr<SSLIdentity> identity(
415 SSLIdentity::CreateFromPEMChainStrings(kRSA_PRIVATE_KEY_PEM, chain));
416 EXPECT_TRUE(identity);
417 EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
418 EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
419 ASSERT_EQ(2u, identity->cert_chain().GetSize());
420 EXPECT_EQ(kRSA_CERT_PEM, identity->cert_chain().Get(0).ToPEMString());
421 EXPECT_EQ(kTestCertificate, identity->cert_chain().Get(1).ToPEMString());
422}
423
hbos6b470a92016-04-28 05:14:21 -0700424TEST_F(SSLIdentityTest, CloneIdentityRSA) {
425 TestCloningIdentity(*identity_rsa1_);
426 TestCloningIdentity(*identity_rsa2_);
427}
428
429TEST_F(SSLIdentityTest, CloneIdentityECDSA) {
430 TestCloningIdentity(*identity_ecdsa1_);
431 TestCloningIdentity(*identity_ecdsa2_);
432}
433
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000434TEST_F(SSLIdentityTest, PemDerConversion) {
435 std::string der;
436 EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der));
437
Yves Gerey665174f2018-06-19 15:03:05 +0200438 EXPECT_EQ(
439 kTestCertificate,
440 SSLIdentity::DerToPem("CERTIFICATE",
441 reinterpret_cast<const unsigned char*>(der.data()),
442 der.length()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000443}
444
445TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) {
446 TestGetSignatureDigestAlgorithm();
447}
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100448
hbose29352b2016-08-25 03:52:38 -0700449TEST_F(SSLIdentityTest, SSLCertificateGetStatsRSA) {
450 std::unique_ptr<SSLIdentity> identity(
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100451 SSLIdentity::CreateFromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
hbose29352b2016-08-25 03:52:38 -0700452 std::unique_ptr<rtc::SSLCertificateStats> stats =
453 identity->certificate().GetStats();
454 EXPECT_EQ(stats->fingerprint, kRSA_FINGERPRINT);
455 EXPECT_EQ(stats->fingerprint_algorithm, kRSA_FINGERPRINT_ALGORITHM);
456 EXPECT_EQ(stats->base64_certificate, kRSA_BASE64_CERTIFICATE);
457 EXPECT_FALSE(stats->issuer);
458}
459
460TEST_F(SSLIdentityTest, SSLCertificateGetStatsECDSA) {
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100461 std::unique_ptr<SSLIdentity> identity(SSLIdentity::CreateFromPEMStrings(
462 kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
hbose29352b2016-08-25 03:52:38 -0700463 std::unique_ptr<rtc::SSLCertificateStats> stats =
464 identity->certificate().GetStats();
465 EXPECT_EQ(stats->fingerprint, kECDSA_FINGERPRINT);
466 EXPECT_EQ(stats->fingerprint_algorithm, kECDSA_FINGERPRINT_ALGORITHM);
467 EXPECT_EQ(stats->base64_certificate, kECDSA_BASE64_CERTIFICATE);
468 EXPECT_FALSE(stats->issuer);
469}
470
471TEST_F(SSLIdentityTest, SSLCertificateGetStatsWithChain) {
472 std::vector<std::string> ders;
473 ders.push_back("every der results in");
474 ders.push_back("an identity + certificate");
475 ders.push_back("in a certificate chain");
476 IdentityAndInfo info = CreateFakeIdentityAndInfoFromDers(ders);
477 EXPECT_TRUE(info.identity);
478 EXPECT_EQ(info.ders, ders);
479 EXPECT_EQ(info.pems.size(), info.ders.size());
480 EXPECT_EQ(info.fingerprints.size(), info.ders.size());
481
482 std::unique_ptr<rtc::SSLCertificateStats> first_stats =
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800483 info.identity->cert_chain().GetStats();
hbose29352b2016-08-25 03:52:38 -0700484 rtc::SSLCertificateStats* cert_stats = first_stats.get();
485 for (size_t i = 0; i < info.ders.size(); ++i) {
486 EXPECT_EQ(cert_stats->fingerprint, info.fingerprints[i]);
487 EXPECT_EQ(cert_stats->fingerprint_algorithm, "sha-1");
488 EXPECT_EQ(cert_stats->base64_certificate, info.pems[i]);
489 cert_stats = cert_stats->issuer.get();
490 EXPECT_EQ(static_cast<bool>(cert_stats), i + 1 < info.ders.size());
491 }
492}
493
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200494class SSLIdentityExpirationTest : public ::testing::Test {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100495 public:
496 SSLIdentityExpirationTest() {
497 // Set use of the test RNG to get deterministic expiration timestamp.
498 rtc::SetRandomTestMode(true);
499 }
Steve Anton9de3aac2017-10-24 10:08:26 -0700500 ~SSLIdentityExpirationTest() override {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100501 // Put it back for the next test.
502 rtc::SetRandomTestMode(false);
503 }
504
505 void TestASN1TimeToSec() {
506 struct asn_example {
507 const char* string;
508 bool long_format;
509 int64_t want;
510 } static const data[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200511 // clang-format off
512 // clang formatting breaks this nice alignment
513
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100514 // Valid examples.
515 {"19700101000000Z", true, 0},
516 {"700101000000Z", false, 0},
517 {"19700101000001Z", true, 1},
518 {"700101000001Z", false, 1},
519 {"19700101000100Z", true, 60},
520 {"19700101000101Z", true, 61},
521 {"19700101010000Z", true, 3600},
522 {"19700101010001Z", true, 3601},
523 {"19700101010100Z", true, 3660},
524 {"19700101010101Z", true, 3661},
525 {"710911012345Z", false, 53400225},
526 {"20000101000000Z", true, 946684800},
527 {"20000101000000Z", true, 946684800},
528 {"20151130140156Z", true, 1448892116},
529 {"151130140156Z", false, 1448892116},
530 {"20491231235959Z", true, 2524607999},
531 {"491231235959Z", false, 2524607999},
532 {"20500101000000Z", true, 2524607999+1},
533 {"20700101000000Z", true, 3155760000},
534 {"21000101000000Z", true, 4102444800},
535 {"24000101000000Z", true, 13569465600},
536
537 // Invalid examples.
538 {"19700101000000", true, -1}, // missing Z long format
539 {"19700101000000X", true, -1}, // X instead of Z long format
540 {"197001010000000", true, -1}, // 0 instead of Z long format
541 {"1970010100000000Z", true, -1}, // excess digits long format
542 {"700101000000", false, -1}, // missing Z short format
543 {"700101000000X", false, -1}, // X instead of Z short format
544 {"7001010000000", false, -1}, // 0 instead of Z short format
545 {"70010100000000Z", false, -1}, // excess digits short format
546 {":9700101000000Z", true, -1}, // invalid character
547 {"1:700101000001Z", true, -1}, // invalid character
548 {"19:00101000100Z", true, -1}, // invalid character
549 {"197:0101000101Z", true, -1}, // invalid character
550 {"1970:101010000Z", true, -1}, // invalid character
551 {"19700:01010001Z", true, -1}, // invalid character
552 {"197001:1010100Z", true, -1}, // invalid character
553 {"1970010:010101Z", true, -1}, // invalid character
554 {"70010100:000Z", false, -1}, // invalid character
555 {"700101000:01Z", false, -1}, // invalid character
556 {"2000010100:000Z", true, -1}, // invalid character
557 {"21000101000:00Z", true, -1}, // invalid character
558 {"240001010000:0Z", true, -1}, // invalid character
559 {"500101000000Z", false, -1}, // but too old for epoch
560 {"691231235959Z", false, -1}, // too old for epoch
561 {"19611118043000Z", false, -1}, // way too old for epoch
Yves Gerey665174f2018-06-19 15:03:05 +0200562
563 // clang-format off
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100564 };
565
566 unsigned char buf[20];
567
568 // Run all examples and check for the expected result.
569 for (const auto& entry : data) {
570 size_t length = strlen(entry.string);
571 memcpy(buf, entry.string, length); // Copy the ASN1 string...
572 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
573 int64_t res = rtc::ASN1TimeToSec(buf, length, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100574 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100575 ASSERT_EQ(entry.want, res);
576 }
577 // Run all examples again, but with an invalid length.
578 for (const auto& entry : data) {
579 size_t length = strlen(entry.string);
580 memcpy(buf, entry.string, length); // Copy the ASN1 string...
581 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
582 int64_t res = rtc::ASN1TimeToSec(buf, length - 1, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100583 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100584 ASSERT_EQ(-1, res);
585 }
586 }
587
588 void TestExpireTime(int times) {
torbjornge8dc0812016-02-15 09:35:54 -0800589 // We test just ECDSA here since what we're out to exercise is the
590 // interfaces for expiration setting and reading.
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100591 for (int i = 0; i < times; i++) {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100592 // We limit the time to < 2^31 here, i.e., we stay before 2038, since else
593 // we hit time offset limitations in OpenSSL on some 32-bit systems.
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700594 time_t time_before_generation = time(nullptr);
595 time_t lifetime =
596 rtc::CreateRandomId() % (0x80000000 - time_before_generation);
torbjornge8dc0812016-02-15 09:35:54 -0800597 rtc::KeyParams key_params = rtc::KeyParams::ECDSA(rtc::EC_NIST_P256);
Harald Alvestrand8515d5a2020-03-20 22:51:32 +0100598 auto identity =
599 rtc::SSLIdentity::Create("", key_params, lifetime);
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700600 time_t time_after_generation = time(nullptr);
601 EXPECT_LE(time_before_generation + lifetime,
602 identity->certificate().CertificateExpirationTime());
603 EXPECT_GE(time_after_generation + lifetime,
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100604 identity->certificate().CertificateExpirationTime());
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100605 }
606 }
607};
608
609TEST_F(SSLIdentityExpirationTest, TestASN1TimeToSec) {
610 TestASN1TimeToSec();
611}
612
613TEST_F(SSLIdentityExpirationTest, TestExpireTime) {
614 TestExpireTime(500);
615}