blob: 132e240c2f5a5c0dc48c77ac88e75e86a3ac28c0 [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
jbauch555604a2016-04-26 03:13:22 -070011#include <memory>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012#include <string>
13
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "rtc_base/fakesslidentity.h"
15#include "rtc_base/gunit.h"
16#include "rtc_base/helpers.h"
17#include "rtc_base/ssladapter.h"
18#include "rtc_base/sslfingerprint.h"
19#include "rtc_base/sslidentity.h"
20#include "rtc_base/stringutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000021
22using rtc::SSLIdentity;
23
Yves Gerey665174f2018-06-19 15:03:05 +020024const char kTestCertificate[] =
25 "-----BEGIN CERTIFICATE-----\n"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026 "MIIB6TCCAVICAQYwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n"
27 "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n"
28 "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDAxMDE2MjIzMTAzWhcNMDMwMTE0\n"
29 "MjIzMTAzWjBjMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEaMBgG\n"
30 "A1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxIzAhBgNVBAMTGlNlcnZlciB0ZXN0IGNl\n"
31 "cnQgKDUxMiBiaXQpMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+zw4Qnlf8SMVIP\n"
32 "Fe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/7tdkuD8Ey2//\n"
33 "Kv7+ue0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCT0grFQeZaqYb5EYfk20XixZV4\n"
34 "GmyAbXMftG1Eo7qGiMhYzRwGNWxEYojf5PZkYZXvSqZ/ZXHXa4g59jK/rJNnaVGM\n"
35 "k+xIX8mxQvlV0n5O9PIha5BX5teZnkHKgL8aKKLKW1BK7YTngsfSzzaeame5iKfz\n"
36 "itAE+OjGF+PFKbwX8Q==\n"
37 "-----END CERTIFICATE-----\n";
38
Yves Gerey665174f2018-06-19 15:03:05 +020039const unsigned char kTestCertSha1[] = {0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D,
40 0x33, 0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6,
41 0xF6, 0x8A, 0x9E, 0x47, 0xA7, 0xCA};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020042const unsigned char kTestCertSha224[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020043 0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77, 0x38, 0x36,
44 0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd, 0xae, 0x24, 0x21, 0x08,
45 0xcf, 0x6a, 0x44, 0x0d, 0x3f, 0x94, 0x2a, 0x5b};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020046const unsigned char kTestCertSha256[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020047 0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24, 0x77, 0x0b, 0x8b,
48 0x2e, 0xa6, 0x2b, 0xe0, 0xf9, 0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7,
49 0x5c, 0xa1, 0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020050const unsigned char kTestCertSha384[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020051 0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf, 0x3b, 0xba, 0x36, 0xd8,
52 0x37, 0x4a, 0x9a, 0x75, 0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7,
53 0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc, 0x64, 0x47, 0xd6, 0xd8,
54 0xaa, 0xd9, 0x36, 0x60, 0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020055const unsigned char kTestCertSha512[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020056 0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3, 0xd8, 0x1d, 0xa4,
57 0x9d, 0x43, 0xc9, 0xee, 0x32, 0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f,
58 0x25, 0xdf, 0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b, 0x28,
59 0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf, 0x61, 0x33, 0x0e, 0x14,
60 0xc3, 0x04, 0xaa, 0x07, 0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22,
61 0x35, 0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000062
hbose29352b2016-08-25 03:52:38 -070063// These PEM strings were created by generating an identity with
64// |SSLIdentity::Generate| and invoking |identity->PrivateKeyToPEMString()|,
65// |identity->PublicKeyToPEMString()| and
66// |identity->certificate().ToPEMString()|. If the crypto library is updated,
67// and the update changes the string form of the keys, these will have to be
68// updated too. The fingerprint, fingerprint algorithm and base64 certificate
69// were created by calling |identity->certificate().GetStats()|.
70static const char kRSA_PRIVATE_KEY_PEM[] =
71 "-----BEGIN PRIVATE KEY-----\n"
72 "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMQPqDStRlYeDpkX\n"
73 "erRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr\n"
74 "4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuFLNEl\n"
75 "7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAECgYA8FWBC5GcNtSBcIinkZyigF0A7\n"
76 "6j081sa+J/uNz4xUuI257ZXM6biygUhhvuXK06/XoIULJfhyN0fAm1yb0HtNhiUs\n"
77 "kMOYeon6b8FqFaPjrQf7Gr9FMiIHXNK19uegTMKztXyPZoUWlX84X0iawY95x0Y3\n"
78 "73f6P2rN2UOjlVVjAQJBAOKy3l2w3Zj2w0oAJox0eMwl+RxBNt1C42SHrob2mFUT\n"
79 "rytpVVYOasr8CoDI0kjacjI94sLum+buJoXXX6YTGO0CQQDdZwlYIEkoS3ftfxPa\n"
80 "Ai0YTBzAWvHJg0r8Gk/TkHo6IM+LSsZ9ZYUv/vBe4BKLw1I4hZ+bQvBiq+f8ROtk\n"
81 "+TDRAkAPL3ghwoU1h+IRBO2QHwUwd6K2N9AbBi4BP+168O3HVSg4ujeTKigRLMzv\n"
82 "T4R2iNt5bhfQgvdCgtVlxcWMdF8JAkBwDCg3eEdt5BuyjwBt8XH+/O4ED0KUWCTH\n"
83 "x00k5dZlupsuhE5Fwe4QpzXg3gekwdnHjyCCQ/NCDHvgOMTkmhQxAkA9V03KRX9b\n"
84 "bhvEzY/fu8gEp+EzsER96/D79az5z1BaMGL5OPM2xHBPJATKlswnAa7Lp3QKGZGk\n"
85 "TxslfL18J71s\n"
86 "-----END PRIVATE KEY-----\n";
87static const char kRSA_PUBLIC_KEY_PEM[] =
88 "-----BEGIN PUBLIC KEY-----\n"
89 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDED6g0rUZWHg6ZF3q0Zr/mtZ2j\n"
90 "PL0lUmNIBtqZZ656H1YlkVtzEalgvtNtDLCI94T2XkgJ7f8vxS/56+BGuzV3MHUa\n"
91 "Nf9cRCu1P3/3I0oNWrp8rxwh8HBXDK99Ryxbx69GYHBcG4CLhSzRJe5CuRzDvQD8\n"
92 "9Z7VI3pPAZgY/MjJfQIDAQAB\n"
93 "-----END PUBLIC KEY-----\n";
94static const char kRSA_CERT_PEM[] =
95 "-----BEGIN CERTIFICATE-----\n"
96 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV\n"
97 "BAMMBXRlc3QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwG\n"
98 "A1UEAwwFdGVzdDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYe\n"
99 "DpkXerRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/F\n"
100 "L/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuF\n"
101 "LNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhvcNAQELBQADgYEA\n"
102 "C3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJi8dx\n"
103 "yTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFq\n"
104 "e3UkexqNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=\n"
105 "-----END CERTIFICATE-----\n";
106static const char kRSA_FINGERPRINT[] =
107 "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"
108 ":2A:EE:F9:9A:DD:E2:2B";
Yves Gerey665174f2018-06-19 15:03:05 +0200109static const char kRSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 03:52:38 -0700110static const char kRSA_BASE64_CERTIFICATE[] =
111 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNVBAMMBXRlc3"
112 "QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwGA1UEAwwFdGVzdDEwgZ8w"
113 "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYeDpkXerRmv+a1naM8vSVSY0gG2plnrn"
114 "ofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHw"
115 "cFcMr31HLFvHr0ZgcFwbgIuFLNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhv"
116 "cNAQELBQADgYEAC3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJ"
117 "i8dxyTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFqe3Ukex"
118 "qNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=";
119
120static const char kECDSA_PRIVATE_KEY_PEM[] =
121 "-----BEGIN PRIVATE KEY-----\n"
122 "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/AkEA2hklq7dQ2rN\n"
123 "ZxYL6hOUACL4pn7P4FYlA3ZQhIChRANCAAR7YgdO3utP/8IqVRq8G4VZKreMAxeN\n"
124 "rUa12twthv4uFjuHAHa9D9oyAjncmn+xvZZRyVmKrA56jRzENcEEHoAg\n"
125 "-----END PRIVATE KEY-----\n";
126static const char kECDSA_PUBLIC_KEY_PEM[] =
127 "-----BEGIN PUBLIC KEY-----\n"
128 "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe2IHTt7rT//CKlUavBuFWSq3jAMX\n"
129 "ja1GtdrcLYb+LhY7hwB2vQ/aMgI53Jp/sb2WUclZiqwOeo0cxDXBBB6AIA==\n"
130 "-----END PUBLIC KEY-----\n";
131static const char kECDSA_CERT_PEM[] =
132 "-----BEGIN CERTIFICATE-----\n"
133 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwF\n"
134 "dGVzdDMwHhcNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQD\n"
135 "DAV0ZXN0MzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwb\n"
136 "hVkqt4wDF42tRrXa3C2G/i4WO4cAdr0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQe\n"
137 "gCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuPPpirsd0e/4WGLHou6bIOSQks\n"
138 "DYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99hkekw==\n"
139 "-----END CERTIFICATE-----\n";
140static const char kECDSA_FINGERPRINT[] =
141 "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"
142 ":50:33:A9:FF:4D:31:89";
Yves Gerey665174f2018-06-19 15:03:05 +0200143static const char kECDSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 03:52:38 -0700144static const char kECDSA_BASE64_CERTIFICATE[] =
145 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwFdGVzdDMwHh"
146 "cNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQDDAV0ZXN0MzBZMBMGByqG"
147 "SM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwbhVkqt4wDF42tRrXa3C2G/i4WO4cAdr"
148 "0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQegCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuP"
149 "Ppirsd0e/4WGLHou6bIOSQksDYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99h"
150 "kekw==";
151
152struct IdentityAndInfo {
153 std::unique_ptr<rtc::SSLIdentity> identity;
154 std::vector<std::string> ders;
155 std::vector<std::string> pems;
156 std::vector<std::string> fingerprints;
157};
158
159IdentityAndInfo CreateFakeIdentityAndInfoFromDers(
160 const std::vector<std::string>& ders) {
161 RTC_CHECK(!ders.empty());
162 IdentityAndInfo info;
163 info.ders = ders;
164 for (const std::string& der : ders) {
165 info.pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 15:03:05 +0200166 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbose29352b2016-08-25 03:52:38 -0700167 der.length()));
168 }
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800169 info.identity.reset(new rtc::FakeSSLIdentity(info.pems));
hbose29352b2016-08-25 03:52:38 -0700170 // Strip header/footer and newline characters of PEM strings.
171 for (size_t i = 0; i < info.pems.size(); ++i) {
Yves Gerey665174f2018-06-19 15:03:05 +0200172 rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27, "", 0,
173 &info.pems[i]);
174 rtc::replace_substrs("-----END CERTIFICATE-----", 25, "", 0, &info.pems[i]);
175 rtc::replace_substrs("\n", 1, "", 0, &info.pems[i]);
hbose29352b2016-08-25 03:52:38 -0700176 }
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800177 // Fingerprints for the whole certificate chain, starting with leaf
178 // certificate.
179 const rtc::SSLCertChain& chain = info.identity->cert_chain();
180 std::unique_ptr<rtc::SSLFingerprint> fp;
181 for (size_t i = 0; i < chain.GetSize(); i++) {
182 fp.reset(rtc::SSLFingerprint::Create("sha-1", &chain.Get(i)));
183 EXPECT_TRUE(fp);
184 info.fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbose29352b2016-08-25 03:52:38 -0700185 }
186 EXPECT_EQ(info.ders.size(), info.fingerprints.size());
187 return info;
188}
189
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000190class SSLIdentityTest : public testing::Test {
191 public:
Steve Anton9de3aac2017-10-24 10:08:26 -0700192 void SetUp() override {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200193 identity_rsa1_.reset(SSLIdentity::Generate("test1", rtc::KT_RSA));
194 identity_rsa2_.reset(SSLIdentity::Generate("test2", rtc::KT_RSA));
195 identity_ecdsa1_.reset(SSLIdentity::Generate("test3", rtc::KT_ECDSA));
196 identity_ecdsa2_.reset(SSLIdentity::Generate("test4", rtc::KT_ECDSA));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000197
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200198 ASSERT_TRUE(identity_rsa1_);
199 ASSERT_TRUE(identity_rsa2_);
200 ASSERT_TRUE(identity_ecdsa1_);
201 ASSERT_TRUE(identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000202
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200203 test_cert_.reset(rtc::SSLCertificate::FromPEMString(kTestCertificate));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000204 ASSERT_TRUE(test_cert_);
205 }
206
207 void TestGetSignatureDigestAlgorithm() {
208 std::string digest_algorithm;
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200209
210 ASSERT_TRUE(identity_rsa1_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 03:32:11 +0200212 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200213
214 ASSERT_TRUE(identity_rsa2_->certificate().GetSignatureDigestAlgorithm(
215 &digest_algorithm));
216 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
217
218 ASSERT_TRUE(identity_ecdsa1_->certificate().GetSignatureDigestAlgorithm(
219 &digest_algorithm));
220 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
221
222 ASSERT_TRUE(identity_ecdsa2_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 03:32:11 +0200224 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225
226 // The test certificate has an MD5-based signature.
227 ASSERT_TRUE(test_cert_->GetSignatureDigestAlgorithm(&digest_algorithm));
228 ASSERT_EQ(rtc::DIGEST_MD5, digest_algorithm);
229 }
230
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200231 typedef unsigned char DigestType[rtc::MessageDigest::kMaxSize];
232
233 void TestDigestHelper(DigestType digest,
234 const SSLIdentity* identity,
235 const std::string& algorithm,
236 size_t expected_len) {
237 DigestType digest1;
238 size_t digest_len;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239 bool rv;
240
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200241 memset(digest, 0, expected_len);
242 rv = identity->certificate().ComputeDigest(algorithm, digest,
243 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000244 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200245 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000246
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200247 // Repeat digest computation for the identity as a sanity check.
248 memset(digest1, 0xff, expected_len);
249 rv = identity->certificate().ComputeDigest(algorithm, digest1,
250 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000251 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200252 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000253
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200254 EXPECT_EQ(0, memcmp(digest, digest1, expected_len));
255 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000256
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200257 void TestDigestForGeneratedCert(const std::string& algorithm,
258 size_t expected_len) {
259 DigestType digest[4];
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000260
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200261 ASSERT_TRUE(expected_len <= sizeof(DigestType));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000262
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200263 TestDigestHelper(digest[0], identity_rsa1_.get(), algorithm, expected_len);
264 TestDigestHelper(digest[1], identity_rsa2_.get(), algorithm, expected_len);
265 TestDigestHelper(digest[2], identity_ecdsa1_.get(), algorithm,
266 expected_len);
267 TestDigestHelper(digest[3], identity_ecdsa2_.get(), algorithm,
268 expected_len);
269
270 // Sanity check that all four digests are unique. This could theoretically
271 // fail, since cryptographic hash collisions have a non-zero probability.
272 for (int i = 0; i < 4; i++) {
273 for (int j = 0; j < 4; j++) {
274 if (i != j)
275 EXPECT_NE(0, memcmp(digest[i], digest[j], expected_len));
276 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000277 }
278 }
279
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200280 void TestDigestForFixedCert(const std::string& algorithm,
281 size_t expected_len,
282 const unsigned char* expected_digest) {
283 bool rv;
284 DigestType digest;
285 size_t digest_len;
286
287 ASSERT_TRUE(expected_len <= sizeof(DigestType));
288
289 rv = test_cert_->ComputeDigest(algorithm, digest, sizeof(digest),
290 &digest_len);
291 EXPECT_TRUE(rv);
292 EXPECT_EQ(expected_len, digest_len);
293 EXPECT_EQ(0, memcmp(digest, expected_digest, expected_len));
294 }
295
hbos6b470a92016-04-28 05:14:21 -0700296 void TestCloningIdentity(const SSLIdentity& identity) {
297 // Convert |identity| to PEM strings and create a new identity by converting
298 // back from the string format.
299 std::string priv_pem = identity.PrivateKeyToPEMString();
300 std::string publ_pem = identity.PublicKeyToPEMString();
301 std::string cert_pem = identity.certificate().ToPEMString();
302 std::unique_ptr<SSLIdentity> clone(
303 SSLIdentity::FromPEMStrings(priv_pem, cert_pem));
304 EXPECT_TRUE(clone);
305
306 // Make sure the clone is identical to the original.
307 EXPECT_TRUE(identity == *clone);
308 ASSERT_EQ(identity.certificate().CertificateExpirationTime(),
309 clone->certificate().CertificateExpirationTime());
310
311 // At this point we are confident that the identities are identical. To be
312 // extra sure, we compare PEM strings of the clone with the original. Note
313 // that the PEM strings of two identities are not strictly guaranteed to be
314 // equal (they describe structs whose members could be listed in a different
315 // order, for example). But because the same function is used to produce
316 // both PEMs, its a good enough bet that this comparison will work. If the
317 // assumption stops holding in the future we can always remove this from the
318 // unittest.
319 std::string clone_priv_pem = clone->PrivateKeyToPEMString();
320 std::string clone_publ_pem = clone->PublicKeyToPEMString();
321 std::string clone_cert_pem = clone->certificate().ToPEMString();
322 ASSERT_EQ(priv_pem, clone_priv_pem);
323 ASSERT_EQ(publ_pem, clone_publ_pem);
324 ASSERT_EQ(cert_pem, clone_cert_pem);
325 }
326
327 protected:
jbauch555604a2016-04-26 03:13:22 -0700328 std::unique_ptr<SSLIdentity> identity_rsa1_;
329 std::unique_ptr<SSLIdentity> identity_rsa2_;
330 std::unique_ptr<SSLIdentity> identity_ecdsa1_;
331 std::unique_ptr<SSLIdentity> identity_ecdsa2_;
332 std::unique_ptr<rtc::SSLCertificate> test_cert_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000333};
334
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200335TEST_F(SSLIdentityTest, FixedDigestSHA1) {
336 TestDigestForFixedCert(rtc::DIGEST_SHA_1, 20, kTestCertSha1);
337}
338
339// HASH_AlgSHA224 is not supported in the chromium linux build.
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200340TEST_F(SSLIdentityTest, FixedDigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200341 TestDigestForFixedCert(rtc::DIGEST_SHA_224, 28, kTestCertSha224);
342}
343
344TEST_F(SSLIdentityTest, FixedDigestSHA256) {
345 TestDigestForFixedCert(rtc::DIGEST_SHA_256, 32, kTestCertSha256);
346}
347
348TEST_F(SSLIdentityTest, FixedDigestSHA384) {
349 TestDigestForFixedCert(rtc::DIGEST_SHA_384, 48, kTestCertSha384);
350}
351
352TEST_F(SSLIdentityTest, FixedDigestSHA512) {
353 TestDigestForFixedCert(rtc::DIGEST_SHA_512, 64, kTestCertSha512);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000354}
355
356// HASH_AlgSHA224 is not supported in the chromium linux build.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000357TEST_F(SSLIdentityTest, DigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200358 TestDigestForGeneratedCert(rtc::DIGEST_SHA_224, 28);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000359}
360
361TEST_F(SSLIdentityTest, DigestSHA256) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200362 TestDigestForGeneratedCert(rtc::DIGEST_SHA_256, 32);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363}
364
365TEST_F(SSLIdentityTest, DigestSHA384) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200366 TestDigestForGeneratedCert(rtc::DIGEST_SHA_384, 48);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000367}
368
369TEST_F(SSLIdentityTest, DigestSHA512) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200370 TestDigestForGeneratedCert(rtc::DIGEST_SHA_512, 64);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000371}
372
hbos6b470a92016-04-28 05:14:21 -0700373TEST_F(SSLIdentityTest, IdentityComparison) {
374 EXPECT_TRUE(*identity_rsa1_ == *identity_rsa1_);
375 EXPECT_FALSE(*identity_rsa1_ == *identity_rsa2_);
376 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa1_);
377 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000378
hbos6b470a92016-04-28 05:14:21 -0700379 EXPECT_TRUE(*identity_rsa2_ == *identity_rsa2_);
380 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa1_);
381 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa2_);
382
383 EXPECT_TRUE(*identity_ecdsa1_ == *identity_ecdsa1_);
384 EXPECT_FALSE(*identity_ecdsa1_ == *identity_ecdsa2_);
385}
386
387TEST_F(SSLIdentityTest, FromPEMStringsRSA) {
jbauch555604a2016-04-26 03:13:22 -0700388 std::unique_ptr<SSLIdentity> identity(
hbose29352b2016-08-25 03:52:38 -0700389 SSLIdentity::FromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000390 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 05:14:21 -0700391 EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
392 EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 03:52:38 -0700393 EXPECT_EQ(kRSA_CERT_PEM, identity->certificate().ToPEMString());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000394}
395
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200396TEST_F(SSLIdentityTest, FromPEMStringsEC) {
jbauch555604a2016-04-26 03:13:22 -0700397 std::unique_ptr<SSLIdentity> identity(
hbose29352b2016-08-25 03:52:38 -0700398 SSLIdentity::FromPEMStrings(kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200399 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 05:14:21 -0700400 EXPECT_EQ(kECDSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
401 EXPECT_EQ(kECDSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 03:52:38 -0700402 EXPECT_EQ(kECDSA_CERT_PEM, identity->certificate().ToPEMString());
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200403}
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200404
hbos6b470a92016-04-28 05:14:21 -0700405TEST_F(SSLIdentityTest, CloneIdentityRSA) {
406 TestCloningIdentity(*identity_rsa1_);
407 TestCloningIdentity(*identity_rsa2_);
408}
409
410TEST_F(SSLIdentityTest, CloneIdentityECDSA) {
411 TestCloningIdentity(*identity_ecdsa1_);
412 TestCloningIdentity(*identity_ecdsa2_);
413}
414
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000415TEST_F(SSLIdentityTest, PemDerConversion) {
416 std::string der;
417 EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der));
418
Yves Gerey665174f2018-06-19 15:03:05 +0200419 EXPECT_EQ(
420 kTestCertificate,
421 SSLIdentity::DerToPem("CERTIFICATE",
422 reinterpret_cast<const unsigned char*>(der.data()),
423 der.length()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000424}
425
426TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) {
427 TestGetSignatureDigestAlgorithm();
428}
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100429
hbose29352b2016-08-25 03:52:38 -0700430TEST_F(SSLIdentityTest, SSLCertificateGetStatsRSA) {
431 std::unique_ptr<SSLIdentity> identity(
432 SSLIdentity::FromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
433 std::unique_ptr<rtc::SSLCertificateStats> stats =
434 identity->certificate().GetStats();
435 EXPECT_EQ(stats->fingerprint, kRSA_FINGERPRINT);
436 EXPECT_EQ(stats->fingerprint_algorithm, kRSA_FINGERPRINT_ALGORITHM);
437 EXPECT_EQ(stats->base64_certificate, kRSA_BASE64_CERTIFICATE);
438 EXPECT_FALSE(stats->issuer);
439}
440
441TEST_F(SSLIdentityTest, SSLCertificateGetStatsECDSA) {
442 std::unique_ptr<SSLIdentity> identity(
443 SSLIdentity::FromPEMStrings(kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
444 std::unique_ptr<rtc::SSLCertificateStats> stats =
445 identity->certificate().GetStats();
446 EXPECT_EQ(stats->fingerprint, kECDSA_FINGERPRINT);
447 EXPECT_EQ(stats->fingerprint_algorithm, kECDSA_FINGERPRINT_ALGORITHM);
448 EXPECT_EQ(stats->base64_certificate, kECDSA_BASE64_CERTIFICATE);
449 EXPECT_FALSE(stats->issuer);
450}
451
452TEST_F(SSLIdentityTest, SSLCertificateGetStatsWithChain) {
453 std::vector<std::string> ders;
454 ders.push_back("every der results in");
455 ders.push_back("an identity + certificate");
456 ders.push_back("in a certificate chain");
457 IdentityAndInfo info = CreateFakeIdentityAndInfoFromDers(ders);
458 EXPECT_TRUE(info.identity);
459 EXPECT_EQ(info.ders, ders);
460 EXPECT_EQ(info.pems.size(), info.ders.size());
461 EXPECT_EQ(info.fingerprints.size(), info.ders.size());
462
463 std::unique_ptr<rtc::SSLCertificateStats> first_stats =
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800464 info.identity->cert_chain().GetStats();
hbose29352b2016-08-25 03:52:38 -0700465 rtc::SSLCertificateStats* cert_stats = first_stats.get();
466 for (size_t i = 0; i < info.ders.size(); ++i) {
467 EXPECT_EQ(cert_stats->fingerprint, info.fingerprints[i]);
468 EXPECT_EQ(cert_stats->fingerprint_algorithm, "sha-1");
469 EXPECT_EQ(cert_stats->base64_certificate, info.pems[i]);
470 cert_stats = cert_stats->issuer.get();
471 EXPECT_EQ(static_cast<bool>(cert_stats), i + 1 < info.ders.size());
472 }
473}
474
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100475class SSLIdentityExpirationTest : public testing::Test {
476 public:
477 SSLIdentityExpirationTest() {
478 // Set use of the test RNG to get deterministic expiration timestamp.
479 rtc::SetRandomTestMode(true);
480 }
Steve Anton9de3aac2017-10-24 10:08:26 -0700481 ~SSLIdentityExpirationTest() override {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100482 // Put it back for the next test.
483 rtc::SetRandomTestMode(false);
484 }
485
486 void TestASN1TimeToSec() {
487 struct asn_example {
488 const char* string;
489 bool long_format;
490 int64_t want;
491 } static const data[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200492 // clang-format off
493 // clang formatting breaks this nice alignment
494
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100495 // Valid examples.
496 {"19700101000000Z", true, 0},
497 {"700101000000Z", false, 0},
498 {"19700101000001Z", true, 1},
499 {"700101000001Z", false, 1},
500 {"19700101000100Z", true, 60},
501 {"19700101000101Z", true, 61},
502 {"19700101010000Z", true, 3600},
503 {"19700101010001Z", true, 3601},
504 {"19700101010100Z", true, 3660},
505 {"19700101010101Z", true, 3661},
506 {"710911012345Z", false, 53400225},
507 {"20000101000000Z", true, 946684800},
508 {"20000101000000Z", true, 946684800},
509 {"20151130140156Z", true, 1448892116},
510 {"151130140156Z", false, 1448892116},
511 {"20491231235959Z", true, 2524607999},
512 {"491231235959Z", false, 2524607999},
513 {"20500101000000Z", true, 2524607999+1},
514 {"20700101000000Z", true, 3155760000},
515 {"21000101000000Z", true, 4102444800},
516 {"24000101000000Z", true, 13569465600},
517
518 // Invalid examples.
519 {"19700101000000", true, -1}, // missing Z long format
520 {"19700101000000X", true, -1}, // X instead of Z long format
521 {"197001010000000", true, -1}, // 0 instead of Z long format
522 {"1970010100000000Z", true, -1}, // excess digits long format
523 {"700101000000", false, -1}, // missing Z short format
524 {"700101000000X", false, -1}, // X instead of Z short format
525 {"7001010000000", false, -1}, // 0 instead of Z short format
526 {"70010100000000Z", false, -1}, // excess digits short format
527 {":9700101000000Z", true, -1}, // invalid character
528 {"1:700101000001Z", true, -1}, // invalid character
529 {"19:00101000100Z", true, -1}, // invalid character
530 {"197:0101000101Z", true, -1}, // invalid character
531 {"1970:101010000Z", true, -1}, // invalid character
532 {"19700:01010001Z", true, -1}, // invalid character
533 {"197001:1010100Z", true, -1}, // invalid character
534 {"1970010:010101Z", true, -1}, // invalid character
535 {"70010100:000Z", false, -1}, // invalid character
536 {"700101000:01Z", false, -1}, // invalid character
537 {"2000010100:000Z", true, -1}, // invalid character
538 {"21000101000:00Z", true, -1}, // invalid character
539 {"240001010000:0Z", true, -1}, // invalid character
540 {"500101000000Z", false, -1}, // but too old for epoch
541 {"691231235959Z", false, -1}, // too old for epoch
542 {"19611118043000Z", false, -1}, // way too old for epoch
Yves Gerey665174f2018-06-19 15:03:05 +0200543
544 // clang-format off
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100545 };
546
547 unsigned char buf[20];
548
549 // Run all examples and check for the expected result.
550 for (const auto& entry : data) {
551 size_t length = strlen(entry.string);
552 memcpy(buf, entry.string, length); // Copy the ASN1 string...
553 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
554 int64_t res = rtc::ASN1TimeToSec(buf, length, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100555 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100556 ASSERT_EQ(entry.want, res);
557 }
558 // Run all examples again, but with an invalid length.
559 for (const auto& entry : data) {
560 size_t length = strlen(entry.string);
561 memcpy(buf, entry.string, length); // Copy the ASN1 string...
562 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
563 int64_t res = rtc::ASN1TimeToSec(buf, length - 1, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100564 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100565 ASSERT_EQ(-1, res);
566 }
567 }
568
569 void TestExpireTime(int times) {
torbjornge8dc0812016-02-15 09:35:54 -0800570 // We test just ECDSA here since what we're out to exercise is the
571 // interfaces for expiration setting and reading.
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100572 for (int i = 0; i < times; i++) {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100573 // We limit the time to < 2^31 here, i.e., we stay before 2038, since else
574 // we hit time offset limitations in OpenSSL on some 32-bit systems.
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700575 time_t time_before_generation = time(nullptr);
576 time_t lifetime =
577 rtc::CreateRandomId() % (0x80000000 - time_before_generation);
torbjornge8dc0812016-02-15 09:35:54 -0800578 rtc::KeyParams key_params = rtc::KeyParams::ECDSA(rtc::EC_NIST_P256);
579 SSLIdentity* identity =
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200580 rtc::SSLIdentity::GenerateWithExpiration("", key_params, lifetime);
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700581 time_t time_after_generation = time(nullptr);
582 EXPECT_LE(time_before_generation + lifetime,
583 identity->certificate().CertificateExpirationTime());
584 EXPECT_GE(time_after_generation + lifetime,
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100585 identity->certificate().CertificateExpirationTime());
586 delete identity;
587 }
588 }
589};
590
591TEST_F(SSLIdentityExpirationTest, TestASN1TimeToSec) {
592 TestASN1TimeToSec();
593}
594
595TEST_F(SSLIdentityExpirationTest, TestExpireTime) {
596 TestExpireTime(500);
597}