blob: 8e4d02db415217d4c964eb94d039452e57205133 [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
68// |SSLIdentity::Generate| and invoking |identity->PrivateKeyToPEMString()|,
69// |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 {
Torbjorn Granlundb6d4ec42015-08-17 14:08:59 +0200197 identity_rsa1_.reset(SSLIdentity::Generate("test1", rtc::KT_RSA));
198 identity_rsa2_.reset(SSLIdentity::Generate("test2", rtc::KT_RSA));
199 identity_ecdsa1_.reset(SSLIdentity::Generate("test3", rtc::KT_ECDSA));
200 identity_ecdsa2_.reset(SSLIdentity::Generate("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) {
301 // Convert |identity| to PEM strings and create a new identity by converting
302 // 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();
306 std::unique_ptr<SSLIdentity> clone(
307 SSLIdentity::FromPEMStrings(priv_pem, cert_pem));
308 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(
hbose29352b2016-08-25 03:52:38 -0700393 SSLIdentity::FromPEMStrings(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) {
jbauch555604a2016-04-26 03:13:22 -0700401 std::unique_ptr<SSLIdentity> identity(
hbose29352b2016-08-25 03:52:38 -0700402 SSLIdentity::FromPEMStrings(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
hbos6b470a92016-04-28 05:14:21 -0700409TEST_F(SSLIdentityTest, CloneIdentityRSA) {
410 TestCloningIdentity(*identity_rsa1_);
411 TestCloningIdentity(*identity_rsa2_);
412}
413
414TEST_F(SSLIdentityTest, CloneIdentityECDSA) {
415 TestCloningIdentity(*identity_ecdsa1_);
416 TestCloningIdentity(*identity_ecdsa2_);
417}
418
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000419TEST_F(SSLIdentityTest, PemDerConversion) {
420 std::string der;
421 EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der));
422
Yves Gerey665174f2018-06-19 15:03:05 +0200423 EXPECT_EQ(
424 kTestCertificate,
425 SSLIdentity::DerToPem("CERTIFICATE",
426 reinterpret_cast<const unsigned char*>(der.data()),
427 der.length()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000428}
429
430TEST_F(SSLIdentityTest, GetSignatureDigestAlgorithm) {
431 TestGetSignatureDigestAlgorithm();
432}
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100433
hbose29352b2016-08-25 03:52:38 -0700434TEST_F(SSLIdentityTest, SSLCertificateGetStatsRSA) {
435 std::unique_ptr<SSLIdentity> identity(
436 SSLIdentity::FromPEMStrings(kRSA_PRIVATE_KEY_PEM, kRSA_CERT_PEM));
437 std::unique_ptr<rtc::SSLCertificateStats> stats =
438 identity->certificate().GetStats();
439 EXPECT_EQ(stats->fingerprint, kRSA_FINGERPRINT);
440 EXPECT_EQ(stats->fingerprint_algorithm, kRSA_FINGERPRINT_ALGORITHM);
441 EXPECT_EQ(stats->base64_certificate, kRSA_BASE64_CERTIFICATE);
442 EXPECT_FALSE(stats->issuer);
443}
444
445TEST_F(SSLIdentityTest, SSLCertificateGetStatsECDSA) {
446 std::unique_ptr<SSLIdentity> identity(
447 SSLIdentity::FromPEMStrings(kECDSA_PRIVATE_KEY_PEM, kECDSA_CERT_PEM));
448 std::unique_ptr<rtc::SSLCertificateStats> stats =
449 identity->certificate().GetStats();
450 EXPECT_EQ(stats->fingerprint, kECDSA_FINGERPRINT);
451 EXPECT_EQ(stats->fingerprint_algorithm, kECDSA_FINGERPRINT_ALGORITHM);
452 EXPECT_EQ(stats->base64_certificate, kECDSA_BASE64_CERTIFICATE);
453 EXPECT_FALSE(stats->issuer);
454}
455
456TEST_F(SSLIdentityTest, SSLCertificateGetStatsWithChain) {
457 std::vector<std::string> ders;
458 ders.push_back("every der results in");
459 ders.push_back("an identity + certificate");
460 ders.push_back("in a certificate chain");
461 IdentityAndInfo info = CreateFakeIdentityAndInfoFromDers(ders);
462 EXPECT_TRUE(info.identity);
463 EXPECT_EQ(info.ders, ders);
464 EXPECT_EQ(info.pems.size(), info.ders.size());
465 EXPECT_EQ(info.fingerprints.size(), info.ders.size());
466
467 std::unique_ptr<rtc::SSLCertificateStats> first_stats =
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800468 info.identity->cert_chain().GetStats();
hbose29352b2016-08-25 03:52:38 -0700469 rtc::SSLCertificateStats* cert_stats = first_stats.get();
470 for (size_t i = 0; i < info.ders.size(); ++i) {
471 EXPECT_EQ(cert_stats->fingerprint, info.fingerprints[i]);
472 EXPECT_EQ(cert_stats->fingerprint_algorithm, "sha-1");
473 EXPECT_EQ(cert_stats->base64_certificate, info.pems[i]);
474 cert_stats = cert_stats->issuer.get();
475 EXPECT_EQ(static_cast<bool>(cert_stats), i + 1 < info.ders.size());
476 }
477}
478
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200479class SSLIdentityExpirationTest : public ::testing::Test {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100480 public:
481 SSLIdentityExpirationTest() {
482 // Set use of the test RNG to get deterministic expiration timestamp.
483 rtc::SetRandomTestMode(true);
484 }
Steve Anton9de3aac2017-10-24 10:08:26 -0700485 ~SSLIdentityExpirationTest() override {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100486 // Put it back for the next test.
487 rtc::SetRandomTestMode(false);
488 }
489
490 void TestASN1TimeToSec() {
491 struct asn_example {
492 const char* string;
493 bool long_format;
494 int64_t want;
495 } static const data[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200496 // clang-format off
497 // clang formatting breaks this nice alignment
498
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100499 // Valid examples.
500 {"19700101000000Z", true, 0},
501 {"700101000000Z", false, 0},
502 {"19700101000001Z", true, 1},
503 {"700101000001Z", false, 1},
504 {"19700101000100Z", true, 60},
505 {"19700101000101Z", true, 61},
506 {"19700101010000Z", true, 3600},
507 {"19700101010001Z", true, 3601},
508 {"19700101010100Z", true, 3660},
509 {"19700101010101Z", true, 3661},
510 {"710911012345Z", false, 53400225},
511 {"20000101000000Z", true, 946684800},
512 {"20000101000000Z", true, 946684800},
513 {"20151130140156Z", true, 1448892116},
514 {"151130140156Z", false, 1448892116},
515 {"20491231235959Z", true, 2524607999},
516 {"491231235959Z", false, 2524607999},
517 {"20500101000000Z", true, 2524607999+1},
518 {"20700101000000Z", true, 3155760000},
519 {"21000101000000Z", true, 4102444800},
520 {"24000101000000Z", true, 13569465600},
521
522 // Invalid examples.
523 {"19700101000000", true, -1}, // missing Z long format
524 {"19700101000000X", true, -1}, // X instead of Z long format
525 {"197001010000000", true, -1}, // 0 instead of Z long format
526 {"1970010100000000Z", true, -1}, // excess digits long format
527 {"700101000000", false, -1}, // missing Z short format
528 {"700101000000X", false, -1}, // X instead of Z short format
529 {"7001010000000", false, -1}, // 0 instead of Z short format
530 {"70010100000000Z", false, -1}, // excess digits short format
531 {":9700101000000Z", true, -1}, // invalid character
532 {"1:700101000001Z", true, -1}, // invalid character
533 {"19:00101000100Z", true, -1}, // invalid character
534 {"197:0101000101Z", true, -1}, // invalid character
535 {"1970:101010000Z", true, -1}, // invalid character
536 {"19700:01010001Z", true, -1}, // invalid character
537 {"197001:1010100Z", true, -1}, // invalid character
538 {"1970010:010101Z", true, -1}, // invalid character
539 {"70010100:000Z", false, -1}, // invalid character
540 {"700101000:01Z", false, -1}, // invalid character
541 {"2000010100:000Z", true, -1}, // invalid character
542 {"21000101000:00Z", true, -1}, // invalid character
543 {"240001010000:0Z", true, -1}, // invalid character
544 {"500101000000Z", false, -1}, // but too old for epoch
545 {"691231235959Z", false, -1}, // too old for epoch
546 {"19611118043000Z", false, -1}, // way too old for epoch
Yves Gerey665174f2018-06-19 15:03:05 +0200547
548 // clang-format off
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100549 };
550
551 unsigned char buf[20];
552
553 // Run all examples and check for the expected result.
554 for (const auto& entry : data) {
555 size_t length = strlen(entry.string);
556 memcpy(buf, entry.string, length); // Copy the ASN1 string...
557 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
558 int64_t res = rtc::ASN1TimeToSec(buf, length, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100559 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100560 ASSERT_EQ(entry.want, res);
561 }
562 // Run all examples again, but with an invalid length.
563 for (const auto& entry : data) {
564 size_t length = strlen(entry.string);
565 memcpy(buf, entry.string, length); // Copy the ASN1 string...
566 buf[length] = rtc::CreateRandomId(); // ...and terminate it with junk.
567 int64_t res = rtc::ASN1TimeToSec(buf, length - 1, entry.long_format);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100568 RTC_LOG(LS_VERBOSE) << entry.string;
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100569 ASSERT_EQ(-1, res);
570 }
571 }
572
573 void TestExpireTime(int times) {
torbjornge8dc0812016-02-15 09:35:54 -0800574 // We test just ECDSA here since what we're out to exercise is the
575 // interfaces for expiration setting and reading.
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100576 for (int i = 0; i < times; i++) {
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100577 // We limit the time to < 2^31 here, i.e., we stay before 2038, since else
578 // we hit time offset limitations in OpenSSL on some 32-bit systems.
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700579 time_t time_before_generation = time(nullptr);
580 time_t lifetime =
581 rtc::CreateRandomId() % (0x80000000 - time_before_generation);
torbjornge8dc0812016-02-15 09:35:54 -0800582 rtc::KeyParams key_params = rtc::KeyParams::ECDSA(rtc::EC_NIST_P256);
583 SSLIdentity* identity =
Torbjorn Granlund1d846b22016-03-31 16:21:04 +0200584 rtc::SSLIdentity::GenerateWithExpiration("", key_params, lifetime);
Taylor Brandstetter88dec832016-03-15 09:57:55 -0700585 time_t time_after_generation = time(nullptr);
586 EXPECT_LE(time_before_generation + lifetime,
587 identity->certificate().CertificateExpirationTime());
588 EXPECT_GE(time_after_generation + lifetime,
Torbjorn Granlund46c9cc02015-12-01 13:06:34 +0100589 identity->certificate().CertificateExpirationTime());
590 delete identity;
591 }
592 }
593};
594
595TEST_F(SSLIdentityExpirationTest, TestASN1TimeToSec) {
596 TestASN1TimeToSec();
597}
598
599TEST_F(SSLIdentityExpirationTest, TestExpireTime) {
600 TestExpireTime(500);
601}