blob: 8d93ecfe2376b65bb0990c10151cb05a98654cc3 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
2 * Copyright 2004 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
11// Handling of certificates and keypairs for SSLStreamAdapter's peer mode.
Steve Anton10542f22019-01-11 17:11:0012#include "rtc_base/ssl_identity.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2613
Taylor Brandstetter165c6182020-12-11 00:23:0314#include <openssl/ossl_typ.h>
Yves Gerey988cc082018-10-23 10:03:0115#include <string.h>
16#include <time.h>
henrike@webrtc.orgf0488722014-05-13 18:00:2617
Yves Gerey988cc082018-10-23 10:03:0118#include "rtc_base/checks.h"
Taylor Brandstetter165c6182020-12-11 00:23:0319#ifdef OPENSSL_IS_BORINGSSL
20#include "rtc_base/boringssl_identity.h"
21#else
Steve Anton10542f22019-01-11 17:11:0022#include "rtc_base/openssl_identity.h"
Taylor Brandstetter165c6182020-12-11 00:23:0323#endif
Steve Anton10542f22019-01-11 17:11:0024#include "rtc_base/ssl_certificate.h"
Yves Gerey988cc082018-10-23 10:03:0125#include "rtc_base/strings/string_builder.h"
26#include "rtc_base/third_party/base64/base64.h"
Steve Anton10542f22019-01-11 17:11:0027#include "rtc_base/time_utils.h"
deadbeeff33491e2017-01-21 01:01:4528
henrike@webrtc.orgf0488722014-05-13 18:00:2629namespace rtc {
30
Benjamin Wrightd6f86e82018-05-08 20:12:2531//////////////////////////////////////////////////////////////////////
Benjamin Wright22a8f982018-10-29 01:39:0032// Helper Functions
33//////////////////////////////////////////////////////////////////////
34
35namespace {
36// Read |n| bytes from ASN1 number string at *|pp| and return the numeric value.
37// Update *|pp| and *|np| to reflect number of read bytes.
38// TODO(bugs.webrtc.org/9860) - Remove this code.
39inline int ASN1ReadInt(const unsigned char** pp, size_t* np, size_t n) {
40 const unsigned char* p = *pp;
41 int x = 0;
42 for (size_t i = 0; i < n; i++) {
43 x = 10 * x + p[i] - '0';
44 }
45 *pp = p + n;
46 *np = *np - n;
47 return x;
48}
49
50} // namespace
51
52// TODO(bugs.webrtc.org/9860) - Remove this code.
53int64_t ASN1TimeToSec(const unsigned char* s, size_t length, bool long_format) {
54 size_t bytes_left = length;
55 // Make sure the string ends with Z. Doing it here protects the strspn call
56 // from running off the end of the string in Z's absense.
57 if (length == 0 || s[length - 1] != 'Z') {
58 return -1;
59 }
60 // Make sure we only have ASCII digits so that we don't need to clutter the
61 // code below and ASN1ReadInt with error checking.
62 size_t n = strspn(reinterpret_cast<const char*>(s), "0123456789");
63 if (n + 1 != length) {
64 return -1;
65 }
66 // Read out ASN1 year, in either 2-char "UTCTIME" or 4-char "GENERALIZEDTIME"
67 // format. Both format use UTC in this context.
68 int year = 0;
69 if (long_format) {
70 // ASN1 format: yyyymmddhh[mm[ss[.fff]]]Z where the Z is literal, but
71 // RFC 5280 requires us to only support exactly yyyymmddhhmmssZ.
72 if (bytes_left < 11) {
73 return -1;
74 }
75 year = ASN1ReadInt(&s, &bytes_left, 4);
76 year -= 1900;
77 } else {
78 // ASN1 format: yymmddhhmm[ss]Z where the Z is literal, but RFC 5280
79 // requires us to only support exactly yymmddhhmmssZ.
80 if (bytes_left < 9) {
81 return -1;
82 }
83 year = ASN1ReadInt(&s, &bytes_left, 2);
84 // Per RFC 5280 4.1.2.5.1
85 if (year < 50) {
86 year += 100;
87 }
88 }
89
90 // Read out remaining ASN1 time data and store it in |tm| in documented
91 // std::tm format.
92 tm tm;
93 tm.tm_year = year;
94 tm.tm_mon = ASN1ReadInt(&s, &bytes_left, 2) - 1;
95 tm.tm_mday = ASN1ReadInt(&s, &bytes_left, 2);
96 tm.tm_hour = ASN1ReadInt(&s, &bytes_left, 2);
97 tm.tm_min = ASN1ReadInt(&s, &bytes_left, 2);
98 tm.tm_sec = ASN1ReadInt(&s, &bytes_left, 2);
99
100 // Now just Z should remain. Its existence was asserted above.
101 if (bytes_left != 1) {
102 return -1;
103 }
104 return TmToSeconds(tm);
105}
106
107//////////////////////////////////////////////////////////////////////
Benjamin Wrightd6f86e82018-05-08 20:12:25108// KeyParams
109//////////////////////////////////////////////////////////////////////
110
henrike@webrtc.orgf0488722014-05-13 18:00:26111const char kPemTypeCertificate[] = "CERTIFICATE";
112const char kPemTypeRsaPrivateKey[] = "RSA PRIVATE KEY";
Torbjorn Granlundb6d4ec42015-08-17 12:08:59113const char kPemTypeEcPrivateKey[] = "EC PRIVATE KEY";
henrike@webrtc.orgf0488722014-05-13 18:00:26114
torbjorng4e572472015-10-08 16:42:49115KeyParams::KeyParams(KeyType key_type) {
116 if (key_type == KT_ECDSA) {
117 type_ = KT_ECDSA;
118 params_.curve = EC_NIST_P256;
119 } else if (key_type == KT_RSA) {
120 type_ = KT_RSA;
121 params_.rsa.mod_size = kRsaDefaultModSize;
122 params_.rsa.pub_exp = kRsaDefaultExponent;
123 } else {
124 RTC_NOTREACHED();
125 }
126}
127
128// static
129KeyParams KeyParams::RSA(int mod_size, int pub_exp) {
130 KeyParams kt(KT_RSA);
131 kt.params_.rsa.mod_size = mod_size;
132 kt.params_.rsa.pub_exp = pub_exp;
133 return kt;
134}
135
136// static
137KeyParams KeyParams::ECDSA(ECCurve curve) {
138 KeyParams kt(KT_ECDSA);
139 kt.params_.curve = curve;
140 return kt;
141}
142
143bool KeyParams::IsValid() const {
144 if (type_ == KT_RSA) {
145 return (params_.rsa.mod_size >= kRsaMinModSize &&
146 params_.rsa.mod_size <= kRsaMaxModSize &&
147 params_.rsa.pub_exp > params_.rsa.mod_size);
148 } else if (type_ == KT_ECDSA) {
149 return (params_.curve == EC_NIST_P256);
150 }
151 return false;
152}
153
154RSAParams KeyParams::rsa_params() const {
155 RTC_DCHECK(type_ == KT_RSA);
156 return params_.rsa;
157}
158
159ECCurve KeyParams::ec_curve() const {
160 RTC_DCHECK(type_ == KT_ECDSA);
161 return params_.curve;
162}
163
Henrik Boström9b5476d2015-09-22 12:12:57164KeyType IntKeyTypeFamilyToKeyType(int key_type_family) {
165 return static_cast<KeyType>(key_type_family);
166}
167
Benjamin Wrightd6f86e82018-05-08 20:12:25168//////////////////////////////////////////////////////////////////////
169// SSLIdentity
170//////////////////////////////////////////////////////////////////////
171
henrike@webrtc.orgf0488722014-05-13 18:00:26172bool SSLIdentity::PemToDer(const std::string& pem_type,
173 const std::string& pem_string,
174 std::string* der) {
Benjamin Wright22a8f982018-10-29 01:39:00175 // Find the inner body. We need this to fulfill the contract of returning
176 // pem_length.
henrike@webrtc.orgf0488722014-05-13 18:00:26177 size_t header = pem_string.find("-----BEGIN " + pem_type + "-----");
Benjamin Wright22a8f982018-10-29 01:39:00178 if (header == std::string::npos) {
henrike@webrtc.orgf0488722014-05-13 18:00:26179 return false;
Benjamin Wright22a8f982018-10-29 01:39:00180 }
Mirko Bonadei37ec55e2019-01-28 10:43:52181 size_t body = pem_string.find('\n', header);
Benjamin Wright22a8f982018-10-29 01:39:00182 if (body == std::string::npos) {
henrike@webrtc.orgf0488722014-05-13 18:00:26183 return false;
Benjamin Wright22a8f982018-10-29 01:39:00184 }
henrike@webrtc.orgf0488722014-05-13 18:00:26185 size_t trailer = pem_string.find("-----END " + pem_type + "-----");
Benjamin Wright22a8f982018-10-29 01:39:00186 if (trailer == std::string::npos) {
henrike@webrtc.orgf0488722014-05-13 18:00:26187 return false;
Benjamin Wright22a8f982018-10-29 01:39:00188 }
henrike@webrtc.orgf0488722014-05-13 18:00:26189 std::string inner = pem_string.substr(body + 1, trailer - (body + 1));
Yves Gerey665174f2018-06-19 13:03:05190 *der = Base64::Decode(inner, Base64::DO_PARSE_WHITE | Base64::DO_PAD_ANY |
191 Base64::DO_TERM_BUFFER);
henrike@webrtc.orgf0488722014-05-13 18:00:26192 return true;
193}
194
195std::string SSLIdentity::DerToPem(const std::string& pem_type,
196 const unsigned char* data,
197 size_t length) {
Jonas Olsson366a50c2018-09-06 11:41:30198 rtc::StringBuilder result;
henrike@webrtc.orgf0488722014-05-13 18:00:26199 result << "-----BEGIN " << pem_type << "-----\n";
200
201 std::string b64_encoded;
202 Base64::EncodeFromArray(data, length, &b64_encoded);
Benjamin Wright22a8f982018-10-29 01:39:00203 // Divide the Base-64 encoded data into 64-character chunks, as per 4.3.2.4
204 // of RFC 1421.
henrike@webrtc.orgf0488722014-05-13 18:00:26205 static const size_t kChunkSize = 64;
206 size_t chunks = (b64_encoded.size() + (kChunkSize - 1)) / kChunkSize;
207 for (size_t i = 0, chunk_offset = 0; i < chunks;
208 ++i, chunk_offset += kChunkSize) {
209 result << b64_encoded.substr(chunk_offset, kChunkSize);
210 result << "\n";
211 }
henrike@webrtc.orgf0488722014-05-13 18:00:26212 result << "-----END " << pem_type << "-----\n";
Jonas Olsson84df1c72018-09-14 14:59:32213 return result.Release();
henrike@webrtc.orgf0488722014-05-13 18:00:26214}
215
Torbjorn Granlunda3dc79e2016-02-16 12:33:53216// static
Harald Alvestrand8515d5a2020-03-20 21:51:32217std::unique_ptr<SSLIdentity> SSLIdentity::Create(const std::string& common_name,
218 const KeyParams& key_param,
219 time_t certificate_lifetime) {
Taylor Brandstetter165c6182020-12-11 00:23:03220#ifdef OPENSSL_IS_BORINGSSL
221 return BoringSSLIdentity::CreateWithExpiration(common_name, key_param,
222 certificate_lifetime);
223#else
Harald Alvestrand8515d5a2020-03-20 21:51:32224 return OpenSSLIdentity::CreateWithExpiration(common_name, key_param,
225 certificate_lifetime);
Taylor Brandstetter165c6182020-12-11 00:23:03226#endif
Harald Alvestrand8515d5a2020-03-20 21:51:32227}
228
229// static
230std::unique_ptr<SSLIdentity> SSLIdentity::Create(const std::string& common_name,
231 const KeyParams& key_param) {
Taylor Brandstetter165c6182020-12-11 00:23:03232 return Create(common_name, key_param, kDefaultCertificateLifetimeInSeconds);
Harald Alvestrand8515d5a2020-03-20 21:51:32233}
234
235// static
236std::unique_ptr<SSLIdentity> SSLIdentity::Create(const std::string& common_name,
237 KeyType key_type) {
Taylor Brandstetter165c6182020-12-11 00:23:03238 return Create(common_name, KeyParams(key_type),
239 kDefaultCertificateLifetimeInSeconds);
Harald Alvestrand8515d5a2020-03-20 21:51:32240}
241
242// static
243std::unique_ptr<SSLIdentity> SSLIdentity::CreateForTest(
244 const SSLIdentityParams& params) {
Taylor Brandstetter165c6182020-12-11 00:23:03245#ifdef OPENSSL_IS_BORINGSSL
246 return BoringSSLIdentity::CreateForTest(params);
247#else
Harald Alvestrand8515d5a2020-03-20 21:51:32248 return OpenSSLIdentity::CreateForTest(params);
Taylor Brandstetter165c6182020-12-11 00:23:03249#endif
Harald Alvestrand8515d5a2020-03-20 21:51:32250}
251
252// Construct an identity from a private key and a certificate.
253// static
254std::unique_ptr<SSLIdentity> SSLIdentity::CreateFromPEMStrings(
255 const std::string& private_key,
256 const std::string& certificate) {
Taylor Brandstetter165c6182020-12-11 00:23:03257#ifdef OPENSSL_IS_BORINGSSL
258 return BoringSSLIdentity::CreateFromPEMStrings(private_key, certificate);
259#else
Harald Alvestrand8515d5a2020-03-20 21:51:32260 return OpenSSLIdentity::CreateFromPEMStrings(private_key, certificate);
Taylor Brandstetter165c6182020-12-11 00:23:03261#endif
Harald Alvestrand8515d5a2020-03-20 21:51:32262}
263
264// Construct an identity from a private key and a certificate chain.
265// static
266std::unique_ptr<SSLIdentity> SSLIdentity::CreateFromPEMChainStrings(
267 const std::string& private_key,
268 const std::string& certificate_chain) {
Taylor Brandstetter165c6182020-12-11 00:23:03269#ifdef OPENSSL_IS_BORINGSSL
270 return BoringSSLIdentity::CreateFromPEMChainStrings(private_key,
271 certificate_chain);
272#else
Harald Alvestrand8515d5a2020-03-20 21:51:32273 return OpenSSLIdentity::CreateFromPEMChainStrings(private_key,
274 certificate_chain);
Taylor Brandstetter165c6182020-12-11 00:23:03275#endif
Harald Alvestrand8515d5a2020-03-20 21:51:32276}
277
hbos6b470a92016-04-28 12:14:21278bool operator==(const SSLIdentity& a, const SSLIdentity& b) {
Taylor Brandstetter165c6182020-12-11 00:23:03279#ifdef OPENSSL_IS_BORINGSSL
280 return static_cast<const BoringSSLIdentity&>(a) ==
281 static_cast<const BoringSSLIdentity&>(b);
282#else
hbos6b470a92016-04-28 12:14:21283 return static_cast<const OpenSSLIdentity&>(a) ==
284 static_cast<const OpenSSLIdentity&>(b);
Taylor Brandstetter165c6182020-12-11 00:23:03285#endif
hbos6b470a92016-04-28 12:14:21286}
287bool operator!=(const SSLIdentity& a, const SSLIdentity& b) {
288 return !(a == b);
289}
290
henrike@webrtc.orgf0488722014-05-13 18:00:26291} // namespace rtc