blob: 81831848a9eb6c0c262d560c079cc52db62c8020 [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"
Yves Gerey2e00abc2018-10-05 15:39:24 +020017#include "rtc_base/messagedigest.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/ssladapter.h"
19#include "rtc_base/sslfingerprint.h"
20#include "rtc_base/sslidentity.h"
21#include "rtc_base/stringutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022
23using rtc::SSLIdentity;
24
Yves Gerey665174f2018-06-19 15:03:05 +020025const char kTestCertificate[] =
26 "-----BEGIN CERTIFICATE-----\n"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000027 "MIIB6TCCAVICAQYwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCQVUxEzARBgNV\n"
28 "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMRswGQYD\n"
29 "VQQDExJUZXN0IENBICgxMDI0IGJpdCkwHhcNMDAxMDE2MjIzMTAzWhcNMDMwMTE0\n"
30 "MjIzMTAzWjBjMQswCQYDVQQGEwJBVTETMBEGA1UECBMKUXVlZW5zbGFuZDEaMBgG\n"
31 "A1UEChMRQ3J5cHRTb2Z0IFB0eSBMdGQxIzAhBgNVBAMTGlNlcnZlciB0ZXN0IGNl\n"
32 "cnQgKDUxMiBiaXQpMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+zw4Qnlf8SMVIP\n"
33 "Fe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/7tdkuD8Ey2//\n"
34 "Kv7+ue0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCT0grFQeZaqYb5EYfk20XixZV4\n"
35 "GmyAbXMftG1Eo7qGiMhYzRwGNWxEYojf5PZkYZXvSqZ/ZXHXa4g59jK/rJNnaVGM\n"
36 "k+xIX8mxQvlV0n5O9PIha5BX5teZnkHKgL8aKKLKW1BK7YTngsfSzzaeame5iKfz\n"
37 "itAE+OjGF+PFKbwX8Q==\n"
38 "-----END CERTIFICATE-----\n";
39
Yves Gerey665174f2018-06-19 15:03:05 +020040const unsigned char kTestCertSha1[] = {0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D,
41 0x33, 0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6,
42 0xF6, 0x8A, 0x9E, 0x47, 0xA7, 0xCA};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020043const unsigned char kTestCertSha224[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020044 0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77, 0x38, 0x36,
45 0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd, 0xae, 0x24, 0x21, 0x08,
46 0xcf, 0x6a, 0x44, 0x0d, 0x3f, 0x94, 0x2a, 0x5b};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020047const unsigned char kTestCertSha256[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020048 0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24, 0x77, 0x0b, 0x8b,
49 0x2e, 0xa6, 0x2b, 0xe0, 0xf9, 0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7,
50 0x5c, 0xa1, 0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020051const unsigned char kTestCertSha384[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020052 0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf, 0x3b, 0xba, 0x36, 0xd8,
53 0x37, 0x4a, 0x9a, 0x75, 0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7,
54 0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc, 0x64, 0x47, 0xd6, 0xd8,
55 0xaa, 0xd9, 0x36, 0x60, 0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49};
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +020056const unsigned char kTestCertSha512[] = {
Yves Gerey665174f2018-06-19 15:03:05 +020057 0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3, 0xd8, 0x1d, 0xa4,
58 0x9d, 0x43, 0xc9, 0xee, 0x32, 0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f,
59 0x25, 0xdf, 0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b, 0x28,
60 0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf, 0x61, 0x33, 0x0e, 0x14,
61 0xc3, 0x04, 0xaa, 0x07, 0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22,
62 0x35, 0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000063
hbose29352b2016-08-25 03:52:38 -070064// These PEM strings were created by generating an identity with
65// |SSLIdentity::Generate| and invoking |identity->PrivateKeyToPEMString()|,
66// |identity->PublicKeyToPEMString()| and
67// |identity->certificate().ToPEMString()|. If the crypto library is updated,
68// and the update changes the string form of the keys, these will have to be
69// updated too. The fingerprint, fingerprint algorithm and base64 certificate
70// were created by calling |identity->certificate().GetStats()|.
71static const char kRSA_PRIVATE_KEY_PEM[] =
72 "-----BEGIN PRIVATE KEY-----\n"
73 "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMQPqDStRlYeDpkX\n"
74 "erRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr\n"
75 "4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuFLNEl\n"
76 "7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAECgYA8FWBC5GcNtSBcIinkZyigF0A7\n"
77 "6j081sa+J/uNz4xUuI257ZXM6biygUhhvuXK06/XoIULJfhyN0fAm1yb0HtNhiUs\n"
78 "kMOYeon6b8FqFaPjrQf7Gr9FMiIHXNK19uegTMKztXyPZoUWlX84X0iawY95x0Y3\n"
79 "73f6P2rN2UOjlVVjAQJBAOKy3l2w3Zj2w0oAJox0eMwl+RxBNt1C42SHrob2mFUT\n"
80 "rytpVVYOasr8CoDI0kjacjI94sLum+buJoXXX6YTGO0CQQDdZwlYIEkoS3ftfxPa\n"
81 "Ai0YTBzAWvHJg0r8Gk/TkHo6IM+LSsZ9ZYUv/vBe4BKLw1I4hZ+bQvBiq+f8ROtk\n"
82 "+TDRAkAPL3ghwoU1h+IRBO2QHwUwd6K2N9AbBi4BP+168O3HVSg4ujeTKigRLMzv\n"
83 "T4R2iNt5bhfQgvdCgtVlxcWMdF8JAkBwDCg3eEdt5BuyjwBt8XH+/O4ED0KUWCTH\n"
84 "x00k5dZlupsuhE5Fwe4QpzXg3gekwdnHjyCCQ/NCDHvgOMTkmhQxAkA9V03KRX9b\n"
85 "bhvEzY/fu8gEp+EzsER96/D79az5z1BaMGL5OPM2xHBPJATKlswnAa7Lp3QKGZGk\n"
86 "TxslfL18J71s\n"
87 "-----END PRIVATE KEY-----\n";
88static const char kRSA_PUBLIC_KEY_PEM[] =
89 "-----BEGIN PUBLIC KEY-----\n"
90 "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDED6g0rUZWHg6ZF3q0Zr/mtZ2j\n"
91 "PL0lUmNIBtqZZ656H1YlkVtzEalgvtNtDLCI94T2XkgJ7f8vxS/56+BGuzV3MHUa\n"
92 "Nf9cRCu1P3/3I0oNWrp8rxwh8HBXDK99Ryxbx69GYHBcG4CLhSzRJe5CuRzDvQD8\n"
93 "9Z7VI3pPAZgY/MjJfQIDAQAB\n"
94 "-----END PUBLIC KEY-----\n";
95static const char kRSA_CERT_PEM[] =
96 "-----BEGIN CERTIFICATE-----\n"
97 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV\n"
98 "BAMMBXRlc3QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwG\n"
99 "A1UEAwwFdGVzdDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYe\n"
100 "DpkXerRmv+a1naM8vSVSY0gG2plnrnofViWRW3MRqWC+020MsIj3hPZeSAnt/y/F\n"
101 "L/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHwcFcMr31HLFvHr0ZgcFwbgIuF\n"
102 "LNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhvcNAQELBQADgYEA\n"
103 "C3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJi8dx\n"
104 "yTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFq\n"
105 "e3UkexqNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=\n"
106 "-----END CERTIFICATE-----\n";
107static const char kRSA_FINGERPRINT[] =
108 "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"
109 ":2A:EE:F9:9A:DD:E2:2B";
Yves Gerey665174f2018-06-19 15:03:05 +0200110static const char kRSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 03:52:38 -0700111static const char kRSA_BASE64_CERTIFICATE[] =
112 "MIIBnDCCAQWgAwIBAgIJAOEHLgeWYwrpMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNVBAMMBXRlc3"
113 "QxMB4XDTE2MDQyNDE4MTAyMloXDTE2MDUyNTE4MTAyMlowEDEOMAwGA1UEAwwFdGVzdDEwgZ8w"
114 "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMQPqDStRlYeDpkXerRmv+a1naM8vSVSY0gG2plnrn"
115 "ofViWRW3MRqWC+020MsIj3hPZeSAnt/y/FL/nr4Ea7NXcwdRo1/1xEK7U/f/cjSg1aunyvHCHw"
116 "cFcMr31HLFvHr0ZgcFwbgIuFLNEl7kK5HMO9APz1ntUjek8BmBj8yMl9AgMBAAEwDQYJKoZIhv"
117 "cNAQELBQADgYEAC3ehaZFl+oEYN069C2ht/gMzuC77L854RF/x7xRtNZzkcg9TVgXXdM3auUvJ"
118 "i8dxyTpU3ixErjQvoZew5ngXTEvTY8BSQUijJEaLWh8n6NDKRbEGTdAk8nPAmq9hdCFqe3Ukex"
119 "qNHm3g/VxG4NUC1Y+w29ai0/Rgh+VvgbDwK+Q=";
120
121static const char kECDSA_PRIVATE_KEY_PEM[] =
122 "-----BEGIN PRIVATE KEY-----\n"
123 "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/AkEA2hklq7dQ2rN\n"
124 "ZxYL6hOUACL4pn7P4FYlA3ZQhIChRANCAAR7YgdO3utP/8IqVRq8G4VZKreMAxeN\n"
125 "rUa12twthv4uFjuHAHa9D9oyAjncmn+xvZZRyVmKrA56jRzENcEEHoAg\n"
126 "-----END PRIVATE KEY-----\n";
127static const char kECDSA_PUBLIC_KEY_PEM[] =
128 "-----BEGIN PUBLIC KEY-----\n"
129 "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe2IHTt7rT//CKlUavBuFWSq3jAMX\n"
130 "ja1GtdrcLYb+LhY7hwB2vQ/aMgI53Jp/sb2WUclZiqwOeo0cxDXBBB6AIA==\n"
131 "-----END PUBLIC KEY-----\n";
132static const char kECDSA_CERT_PEM[] =
133 "-----BEGIN CERTIFICATE-----\n"
134 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwF\n"
135 "dGVzdDMwHhcNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQD\n"
136 "DAV0ZXN0MzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwb\n"
137 "hVkqt4wDF42tRrXa3C2G/i4WO4cAdr0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQe\n"
138 "gCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuPPpirsd0e/4WGLHou6bIOSQks\n"
139 "DYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99hkekw==\n"
140 "-----END CERTIFICATE-----\n";
141static const char kECDSA_FINGERPRINT[] =
142 "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"
143 ":50:33:A9:FF:4D:31:89";
Yves Gerey665174f2018-06-19 15:03:05 +0200144static const char kECDSA_FINGERPRINT_ALGORITHM[] = "sha-256";
hbose29352b2016-08-25 03:52:38 -0700145static const char kECDSA_BASE64_CERTIFICATE[] =
146 "MIIBFDCBu6ADAgECAgkArpkxjw62sW4wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwFdGVzdDMwHh"
147 "cNMTYwNDI0MTgxNDM4WhcNMTYwNTI1MTgxNDM4WjAQMQ4wDAYDVQQDDAV0ZXN0MzBZMBMGByqG"
148 "SM49AgEGCCqGSM49AwEHA0IABHtiB07e60//wipVGrwbhVkqt4wDF42tRrXa3C2G/i4WO4cAdr"
149 "0P2jICOdyaf7G9llHJWYqsDnqNHMQ1wQQegCAwCgYIKoZIzj0EAwIDSAAwRQIhANyreQ/K5yuP"
150 "Ppirsd0e/4WGLHou6bIOSQksDYzo56NmAiAKOr3u8ol3LmygbUCwEvtWrS8QcJDygxHPACo99h"
151 "kekw==";
152
153struct IdentityAndInfo {
154 std::unique_ptr<rtc::SSLIdentity> identity;
155 std::vector<std::string> ders;
156 std::vector<std::string> pems;
157 std::vector<std::string> fingerprints;
158};
159
160IdentityAndInfo CreateFakeIdentityAndInfoFromDers(
161 const std::vector<std::string>& ders) {
162 RTC_CHECK(!ders.empty());
163 IdentityAndInfo info;
164 info.ders = ders;
165 for (const std::string& der : ders) {
166 info.pems.push_back(rtc::SSLIdentity::DerToPem(
Yves Gerey665174f2018-06-19 15:03:05 +0200167 "CERTIFICATE", reinterpret_cast<const unsigned char*>(der.c_str()),
hbose29352b2016-08-25 03:52:38 -0700168 der.length()));
169 }
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800170 info.identity.reset(new rtc::FakeSSLIdentity(info.pems));
hbose29352b2016-08-25 03:52:38 -0700171 // Strip header/footer and newline characters of PEM strings.
172 for (size_t i = 0; i < info.pems.size(); ++i) {
Yves Gerey665174f2018-06-19 15:03:05 +0200173 rtc::replace_substrs("-----BEGIN CERTIFICATE-----", 27, "", 0,
174 &info.pems[i]);
175 rtc::replace_substrs("-----END CERTIFICATE-----", 25, "", 0, &info.pems[i]);
176 rtc::replace_substrs("\n", 1, "", 0, &info.pems[i]);
hbose29352b2016-08-25 03:52:38 -0700177 }
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800178 // Fingerprints for the whole certificate chain, starting with leaf
179 // certificate.
180 const rtc::SSLCertChain& chain = info.identity->cert_chain();
181 std::unique_ptr<rtc::SSLFingerprint> fp;
182 for (size_t i = 0; i < chain.GetSize(); i++) {
Steve Anton4905edb2018-10-15 19:27:44 -0700183 fp = rtc::SSLFingerprint::Create("sha-1", chain.Get(i));
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800184 EXPECT_TRUE(fp);
185 info.fingerprints.push_back(fp->GetRfc4572Fingerprint());
hbose29352b2016-08-25 03:52:38 -0700186 }
187 EXPECT_EQ(info.ders.size(), info.fingerprints.size());
188 return info;
189}
190
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000191class SSLIdentityTest : public testing::Test {
192 public:
Steve Anton9de3aac2017-10-24 10:08:26 -0700193 void SetUp() override {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200194 identity_rsa1_.reset(SSLIdentity::Generate("test1", rtc::KT_RSA));
195 identity_rsa2_.reset(SSLIdentity::Generate("test2", rtc::KT_RSA));
196 identity_ecdsa1_.reset(SSLIdentity::Generate("test3", rtc::KT_ECDSA));
197 identity_ecdsa2_.reset(SSLIdentity::Generate("test4", rtc::KT_ECDSA));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000198
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200199 ASSERT_TRUE(identity_rsa1_);
200 ASSERT_TRUE(identity_rsa2_);
201 ASSERT_TRUE(identity_ecdsa1_);
202 ASSERT_TRUE(identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000203
Niklas Enbom82c71af2018-10-15 16:22:55 +0000204 test_cert_.reset(rtc::SSLCertificate::FromPEMString(kTestCertificate));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000205 ASSERT_TRUE(test_cert_);
206 }
207
208 void TestGetSignatureDigestAlgorithm() {
209 std::string digest_algorithm;
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200210
211 ASSERT_TRUE(identity_rsa1_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000212 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 03:32:11 +0200213 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200214
215 ASSERT_TRUE(identity_rsa2_->certificate().GetSignatureDigestAlgorithm(
216 &digest_algorithm));
217 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
218
219 ASSERT_TRUE(identity_ecdsa1_->certificate().GetSignatureDigestAlgorithm(
220 &digest_algorithm));
221 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
222
223 ASSERT_TRUE(identity_ecdsa2_->certificate().GetSignatureDigestAlgorithm(
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000224 &digest_algorithm));
Joachim Bauch1b794d52015-05-12 03:32:11 +0200225 ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000226
227 // The test certificate has an MD5-based signature.
228 ASSERT_TRUE(test_cert_->GetSignatureDigestAlgorithm(&digest_algorithm));
229 ASSERT_EQ(rtc::DIGEST_MD5, digest_algorithm);
230 }
231
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200232 typedef unsigned char DigestType[rtc::MessageDigest::kMaxSize];
233
234 void TestDigestHelper(DigestType digest,
235 const SSLIdentity* identity,
236 const std::string& algorithm,
237 size_t expected_len) {
238 DigestType digest1;
239 size_t digest_len;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240 bool rv;
241
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200242 memset(digest, 0, expected_len);
243 rv = identity->certificate().ComputeDigest(algorithm, digest,
244 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000245 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200246 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000247
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200248 // Repeat digest computation for the identity as a sanity check.
249 memset(digest1, 0xff, expected_len);
250 rv = identity->certificate().ComputeDigest(algorithm, digest1,
251 sizeof(DigestType), &digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000252 EXPECT_TRUE(rv);
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200253 EXPECT_EQ(expected_len, digest_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000254
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200255 EXPECT_EQ(0, memcmp(digest, digest1, expected_len));
256 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000257
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200258 void TestDigestForGeneratedCert(const std::string& algorithm,
259 size_t expected_len) {
260 DigestType digest[4];
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000261
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200262 ASSERT_TRUE(expected_len <= sizeof(DigestType));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000263
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200264 TestDigestHelper(digest[0], identity_rsa1_.get(), algorithm, expected_len);
265 TestDigestHelper(digest[1], identity_rsa2_.get(), algorithm, expected_len);
266 TestDigestHelper(digest[2], identity_ecdsa1_.get(), algorithm,
267 expected_len);
268 TestDigestHelper(digest[3], identity_ecdsa2_.get(), algorithm,
269 expected_len);
270
271 // Sanity check that all four digests are unique. This could theoretically
272 // fail, since cryptographic hash collisions have a non-zero probability.
273 for (int i = 0; i < 4; i++) {
274 for (int j = 0; j < 4; j++) {
275 if (i != j)
276 EXPECT_NE(0, memcmp(digest[i], digest[j], expected_len));
277 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000278 }
279 }
280
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200281 void TestDigestForFixedCert(const std::string& algorithm,
282 size_t expected_len,
283 const unsigned char* expected_digest) {
284 bool rv;
285 DigestType digest;
286 size_t digest_len;
287
288 ASSERT_TRUE(expected_len <= sizeof(DigestType));
289
290 rv = test_cert_->ComputeDigest(algorithm, digest, sizeof(digest),
291 &digest_len);
292 EXPECT_TRUE(rv);
293 EXPECT_EQ(expected_len, digest_len);
294 EXPECT_EQ(0, memcmp(digest, expected_digest, expected_len));
295 }
296
hbos6b470a92016-04-28 05:14:21 -0700297 void TestCloningIdentity(const SSLIdentity& identity) {
298 // Convert |identity| to PEM strings and create a new identity by converting
299 // back from the string format.
300 std::string priv_pem = identity.PrivateKeyToPEMString();
301 std::string publ_pem = identity.PublicKeyToPEMString();
302 std::string cert_pem = identity.certificate().ToPEMString();
303 std::unique_ptr<SSLIdentity> clone(
304 SSLIdentity::FromPEMStrings(priv_pem, cert_pem));
305 EXPECT_TRUE(clone);
306
307 // Make sure the clone is identical to the original.
308 EXPECT_TRUE(identity == *clone);
309 ASSERT_EQ(identity.certificate().CertificateExpirationTime(),
310 clone->certificate().CertificateExpirationTime());
311
312 // At this point we are confident that the identities are identical. To be
313 // extra sure, we compare PEM strings of the clone with the original. Note
314 // that the PEM strings of two identities are not strictly guaranteed to be
315 // equal (they describe structs whose members could be listed in a different
316 // order, for example). But because the same function is used to produce
317 // both PEMs, its a good enough bet that this comparison will work. If the
318 // assumption stops holding in the future we can always remove this from the
319 // unittest.
320 std::string clone_priv_pem = clone->PrivateKeyToPEMString();
321 std::string clone_publ_pem = clone->PublicKeyToPEMString();
322 std::string clone_cert_pem = clone->certificate().ToPEMString();
323 ASSERT_EQ(priv_pem, clone_priv_pem);
324 ASSERT_EQ(publ_pem, clone_publ_pem);
325 ASSERT_EQ(cert_pem, clone_cert_pem);
326 }
327
328 protected:
jbauch555604a2016-04-26 03:13:22 -0700329 std::unique_ptr<SSLIdentity> identity_rsa1_;
330 std::unique_ptr<SSLIdentity> identity_rsa2_;
331 std::unique_ptr<SSLIdentity> identity_ecdsa1_;
332 std::unique_ptr<SSLIdentity> identity_ecdsa2_;
333 std::unique_ptr<rtc::SSLCertificate> test_cert_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000334};
335
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200336TEST_F(SSLIdentityTest, FixedDigestSHA1) {
337 TestDigestForFixedCert(rtc::DIGEST_SHA_1, 20, kTestCertSha1);
338}
339
340// HASH_AlgSHA224 is not supported in the chromium linux build.
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200341TEST_F(SSLIdentityTest, FixedDigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200342 TestDigestForFixedCert(rtc::DIGEST_SHA_224, 28, kTestCertSha224);
343}
344
345TEST_F(SSLIdentityTest, FixedDigestSHA256) {
346 TestDigestForFixedCert(rtc::DIGEST_SHA_256, 32, kTestCertSha256);
347}
348
349TEST_F(SSLIdentityTest, FixedDigestSHA384) {
350 TestDigestForFixedCert(rtc::DIGEST_SHA_384, 48, kTestCertSha384);
351}
352
353TEST_F(SSLIdentityTest, FixedDigestSHA512) {
354 TestDigestForFixedCert(rtc::DIGEST_SHA_512, 64, kTestCertSha512);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000355}
356
357// HASH_AlgSHA224 is not supported in the chromium linux build.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000358TEST_F(SSLIdentityTest, DigestSHA224) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200359 TestDigestForGeneratedCert(rtc::DIGEST_SHA_224, 28);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000360}
361
362TEST_F(SSLIdentityTest, DigestSHA256) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200363 TestDigestForGeneratedCert(rtc::DIGEST_SHA_256, 32);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000364}
365
366TEST_F(SSLIdentityTest, DigestSHA384) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200367 TestDigestForGeneratedCert(rtc::DIGEST_SHA_384, 48);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000368}
369
370TEST_F(SSLIdentityTest, DigestSHA512) {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200371 TestDigestForGeneratedCert(rtc::DIGEST_SHA_512, 64);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000372}
373
hbos6b470a92016-04-28 05:14:21 -0700374TEST_F(SSLIdentityTest, IdentityComparison) {
375 EXPECT_TRUE(*identity_rsa1_ == *identity_rsa1_);
376 EXPECT_FALSE(*identity_rsa1_ == *identity_rsa2_);
377 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa1_);
378 EXPECT_FALSE(*identity_rsa1_ == *identity_ecdsa2_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000379
hbos6b470a92016-04-28 05:14:21 -0700380 EXPECT_TRUE(*identity_rsa2_ == *identity_rsa2_);
381 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa1_);
382 EXPECT_FALSE(*identity_rsa2_ == *identity_ecdsa2_);
383
384 EXPECT_TRUE(*identity_ecdsa1_ == *identity_ecdsa1_);
385 EXPECT_FALSE(*identity_ecdsa1_ == *identity_ecdsa2_);
386}
387
388TEST_F(SSLIdentityTest, FromPEMStringsRSA) {
jbauch555604a2016-04-26 03:13:22 -0700389 std::unique_ptr<SSLIdentity> identity(
hbose29352b2016-08-25 03:52:38 -0700390 SSLIdentity::FromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000391 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 05:14:21 -0700392 EXPECT_EQ(kRSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
393 EXPECT_EQ(kRSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 03:52:38 -0700394 EXPECT_EQ(kRSA_CERT_PEM, identity->certificate().ToPEMString());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000395}
396
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200397TEST_F(SSLIdentityTest, FromPEMStringsEC) {
jbauch555604a2016-04-26 03:13:22 -0700398 std::unique_ptr<SSLIdentity> identity(
hbose29352b2016-08-25 03:52:38 -0700399 SSLIdentity::FromPEMStrings(kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200400 EXPECT_TRUE(identity);
hbos6b470a92016-04-28 05:14:21 -0700401 EXPECT_EQ(kECDSA_PRIVATE_KEY_PEM, identity->PrivateKeyToPEMString());
402 EXPECT_EQ(kECDSA_PUBLIC_KEY_PEM, identity->PublicKeyToPEMString());
hbose29352b2016-08-25 03:52:38 -0700403 EXPECT_EQ(kECDSA_CERT_PEM, identity->certificate().ToPEMString());
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200404}
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200405
hbos6b470a92016-04-28 05:14:21 -0700406TEST_F(SSLIdentityTest, CloneIdentityRSA) {
407 TestCloningIdentity(*identity_rsa1_);
408 TestCloningIdentity(*identity_rsa2_);
409}
410
411TEST_F(SSLIdentityTest, CloneIdentityECDSA) {
412 TestCloningIdentity(*identity_ecdsa1_);
413 TestCloningIdentity(*identity_ecdsa2_);
414}
415
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000416TEST_F(SSLIdentityTest, PemDerConversion) {
417 std::string der;
418 EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der));
419
Yves Gerey665174f2018-06-19 15:03:05 +0200420 EXPECT_EQ(
421 kTestCertificate,
422 SSLIdentity::DerToPem("CERTIFICATE",
423 reinterpret_cast<const unsigned char*>(der.data()),
424 der.length()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000425}
426
427TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) {
428 TestGetSignatureDigestAlgorithm();
429}
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100430
hbose29352b2016-08-25 03:52:38 -0700431TEST_F(SSLIdentityTest, SSLCertificateGetStatsRSA) {
432 std::unique_ptr<SSLIdentity> identity(
433 SSLIdentity::FromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
434 std::unique_ptr<rtc::SSLCertificateStats> stats =
435 identity->certificate().GetStats();
436 EXPECT_EQ(stats->fingerprint, kRSA_FINGERPRINT);
437 EXPECT_EQ(stats->fingerprint_algorithm, kRSA_FINGERPRINT_ALGORITHM);
438 EXPECT_EQ(stats->base64_certificate, kRSA_BASE64_CERTIFICATE);
439 EXPECT_FALSE(stats->issuer);
440}
441
442TEST_F(SSLIdentityTest, SSLCertificateGetStatsECDSA) {
443 std::unique_ptr<SSLIdentity> identity(
444 SSLIdentity::FromPEMStrings(kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
445 std::unique_ptr<rtc::SSLCertificateStats> stats =
446 identity->certificate().GetStats();
447 EXPECT_EQ(stats->fingerprint, kECDSA_FINGERPRINT);
448 EXPECT_EQ(stats->fingerprint_algorithm, kECDSA_FINGERPRINT_ALGORITHM);
449 EXPECT_EQ(stats->base64_certificate, kECDSA_BASE64_CERTIFICATE);
450 EXPECT_FALSE(stats->issuer);
451}
452
453TEST_F(SSLIdentityTest, SSLCertificateGetStatsWithChain) {
454 std::vector<std::string> ders;
455 ders.push_back("every der results in");
456 ders.push_back("an identity + certificate");
457 ders.push_back("in a certificate chain");
458 IdentityAndInfo info = CreateFakeIdentityAndInfoFromDers(ders);
459 EXPECT_TRUE(info.identity);
460 EXPECT_EQ(info.ders, ders);
461 EXPECT_EQ(info.pems.size(), info.ders.size());
462 EXPECT_EQ(info.fingerprints.size(), info.ders.size());
463
464 std::unique_ptr<rtc::SSLCertificateStats> first_stats =
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800465 info.identity->cert_chain().GetStats();
hbose29352b2016-08-25 03:52:38 -0700466 rtc::SSLCertificateStats* cert_stats = first_stats.get();
467 for (size_t i = 0; i < info.ders.size(); ++i) {
468 EXPECT_EQ(cert_stats->fingerprint, info.fingerprints[i]);
469 EXPECT_EQ(cert_stats->fingerprint_algorithm, "sha-1");
470 EXPECT_EQ(cert_stats->base64_certificate, info.pems[i]);
471 cert_stats = cert_stats->issuer.get();
472 EXPECT_EQ(static_cast<bool>(cert_stats), i + 1 < info.ders.size());
473 }
474}
475
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100476class SSLIdentityExpirationTest : public testing::Test {
477 public:
478 SSLIdentityExpirationTest() {
479 // Set use of the test RNG to get deterministic expiration timestamp.
480 rtc::SetRandomTestMode(true);
481 }
Steve Anton9de3aac2017-10-24 10:08:26 -0700482 ~SSLIdentityExpirationTest() override {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100483 // Put it back for the next test.
484 rtc::SetRandomTestMode(false);
485 }
486
487 void TestASN1TimeToSec() {
488 struct asn_example {
489 const char* string;
490 bool long_format;
491 int64_t want;
492 } static const data[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200493 // clang-format off
494 // clang formatting breaks this nice alignment
495
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100496 // Valid examples.
497 {"19700101000000Z", true, 0},
498 {"700101000000Z", false, 0},
499 {"19700101000001Z", true, 1},
500 {"700101000001Z", false, 1},
501 {"19700101000100Z", true, 60},
502 {"19700101000101Z", true, 61},
503 {"19700101010000Z", true, 3600},
504 {"19700101010001Z", true, 3601},
505 {"19700101010100Z", true, 3660},
506 {"19700101010101Z", true, 3661},
507 {"710911012345Z", false, 53400225},
508 {"20000101000000Z", true, 946684800},
509 {"20000101000000Z", true, 946684800},
510 {"20151130140156Z", true, 1448892116},
511 {"151130140156Z", false, 1448892116},
512 {"20491231235959Z", true, 2524607999},
513 {"491231235959Z", false, 2524607999},
514 {"20500101000000Z", true, 2524607999+1},
515 {"20700101000000Z", true, 3155760000},
516 {"21000101000000Z", true, 4102444800},
517 {"24000101000000Z", true, 13569465600},
518
519 // Invalid examples.
520 {"19700101000000", true, -1}, // missing Z long format
521 {"19700101000000X", true, -1}, // X instead of Z long format
522 {"197001010000000", true, -1}, // 0 instead of Z long format
523 {"1970010100000000Z", true, -1}, // excess digits long format
524 {"700101000000", false, -1}, // missing Z short format
525 {"700101000000X", false, -1}, // X instead of Z short format
526 {"7001010000000", false, -1}, // 0 instead of Z short format
527 {"70010100000000Z", false, -1}, // excess digits short format
528 {":9700101000000Z", true, -1}, // invalid character
529 {"1:700101000001Z", true, -1}, // invalid character
530 {"19:00101000100Z", true, -1}, // invalid character
531 {"197:0101000101Z", true, -1}, // invalid character
532 {"1970:101010000Z", true, -1}, // invalid character
533 {"19700:01010001Z", true, -1}, // invalid character
534 {"197001:1010100Z", true, -1}, // invalid character
535 {"1970010:010101Z", true, -1}, // invalid character
536 {"70010100:000Z", false, -1}, // invalid character
537 {"700101000:01Z", false, -1}, // invalid character
538 {"2000010100:000Z", true, -1}, // invalid character
539 {"21000101000:00Z", true, -1}, // invalid character
540 {"240001010000:0Z", true, -1}, // invalid character
541 {"500101000000Z", false, -1}, // but too old for epoch
542 {"691231235959Z", false, -1}, // too old for epoch
543 {"19611118043000Z", false, -1}, // way too old for epoch
Yves Gerey665174f2018-06-19 15:03:05 +0200544
545 // clang-format off
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100546 };
547
548 unsigned char buf[20];
549
550 // Run all examples and check for the expected result.
551 for (const auto& entry : data) {
552 size_t length = strlen(entry.string);
553 memcpy(buf, entry.string, length); // Copy the ASN1 string...
554 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
555 int64_t res = rtc::ASN1TimeToSec(buf, length, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100556 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100557 ASSERT_EQ(entry.want, res);
558 }
559 // Run all examples again, but with an invalid length.
560 for (const auto& entry : data) {
561 size_t length = strlen(entry.string);
562 memcpy(buf, entry.string, length); // Copy the ASN1 string...
563 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
564 int64_t res = rtc::ASN1TimeToSec(buf, length - 1, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100565 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100566 ASSERT_EQ(-1, res);
567 }
568 }
569
570 void TestExpireTime(int times) {
torbjornge8dc0812016-02-15 09:35:54 -0800571 // We test just ECDSA here since what we're out to exercise is the
572 // interfaces for expiration setting and reading.
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100573 for (int i = 0; i < times; i++) {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100574 // We limit the time to < 2^31 here, i.e., we stay before 2038, since else
575 // we hit time offset limitations in OpenSSL on some 32-bit systems.
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700576 time_t time_before_generation = time(nullptr);
577 time_t lifetime =
578 rtc::CreateRandomId() % (0x80000000 - time_before_generation);
torbjornge8dc0812016-02-15 09:35:54 -0800579 rtc::KeyParams key_params = rtc::KeyParams::ECDSA(rtc::EC_NIST_P256);
580 SSLIdentity* identity =
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200581 rtc::SSLIdentity::GenerateWithExpiration("", key_params, lifetime);
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700582 time_t time_after_generation = time(nullptr);
583 EXPECT_LE(time_before_generation + lifetime,
584 identity->certificate().CertificateExpirationTime());
585 EXPECT_GE(time_after_generation + lifetime,
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100586 identity->certificate().CertificateExpirationTime());
587 delete identity;
588 }
589 }
590};
591
592TEST_F(SSLIdentityExpirationTest, TestASN1TimeToSec) {
593 TestASN1TimeToSec();
594}
595
596TEST_F(SSLIdentityExpirationTest, TestExpireTime) {
597 TestExpireTime(500);
598}