blob: c22e5fbb9d9667b7e5bffee838e320976811e5d8 [file] [log] [blame]
Benjamin Wrightd6f86e82018-05-08 13:12:25 -07001/*
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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "rtc_base/openssl_certificate.h"
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070012
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070013#if defined(WEBRTC_WIN)
14// Must be included first before openssl headers.
15#include "rtc_base/win32.h" // NOLINT
16#endif // WEBRTC_WIN
17
18#include <openssl/bio.h>
19#include <openssl/bn.h>
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070020#include <openssl/pem.h>
Yves Gerey988cc082018-10-23 12:03:01 +020021#include <time.h>
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070022
Karl Wiberg918f50c2018-07-05 11:40:33 +020023#include "absl/memory/memory.h"
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070024#include "rtc_base/checks.h"
25#include "rtc_base/helpers.h"
26#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080027#include "rtc_base/message_digest.h"
28#include "rtc_base/openssl_digest.h"
29#include "rtc_base/openssl_identity.h"
30#include "rtc_base/openssl_utility.h"
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070031
32namespace rtc {
Benjamin Wright428320c2018-10-28 18:22:53 -070033namespace {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070034
35// Random bits for certificate serial number
36static const int SERIAL_RAND_BITS = 64;
37
Benjamin Wrightd6f86e82018-05-08 13:12:25 -070038#if !defined(NDEBUG)
39// Print a certificate to the log, for debugging.
40static void PrintCert(X509* x509) {
41 BIO* temp_memory_bio = BIO_new(BIO_s_mem());
42 if (!temp_memory_bio) {
43 RTC_DLOG_F(LS_ERROR) << "Failed to allocate temporary memory bio";
44 return;
45 }
46 X509_print_ex(temp_memory_bio, x509, XN_FLAG_SEP_CPLUS_SPC, 0);
47 BIO_write(temp_memory_bio, "\0", 1);
48 char* buffer;
49 BIO_get_mem_data(temp_memory_bio, &buffer);
50 RTC_DLOG(LS_VERBOSE) << buffer;
51 BIO_free(temp_memory_bio);
52}
53#endif
54
Benjamin Wright428320c2018-10-28 18:22:53 -070055// Generate a self-signed certificate, with the public key from the
56// given key pair. Caller is responsible for freeing the returned object.
57static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) {
58 RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name;
59
60 ASN1_INTEGER* asn1_serial_number = nullptr;
61 BIGNUM* serial_number = nullptr;
62 X509* x509 = nullptr;
63 X509_NAME* name = nullptr;
64 time_t epoch_off = 0; // Time offset since epoch.
65
66 if ((x509 = X509_new()) == nullptr) {
67 goto error;
68 }
69 if (!X509_set_pubkey(x509, pkey)) {
70 goto error;
71 }
72 // serial number - temporary reference to serial number inside x509 struct
73 if ((serial_number = BN_new()) == nullptr ||
74 !BN_pseudo_rand(serial_number, SERIAL_RAND_BITS, 0, 0) ||
75 (asn1_serial_number = X509_get_serialNumber(x509)) == nullptr ||
76 !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number)) {
77 goto error;
78 }
79 // Set version to X509.V3
80 if (!X509_set_version(x509, 2L)) {
81 goto error;
82 }
83
84 // There are a lot of possible components for the name entries. In
85 // our P2P SSL mode however, the certificates are pre-exchanged
86 // (through the secure XMPP channel), and so the certificate
87 // identification is arbitrary. It can't be empty, so we set some
88 // arbitrary common_name. Note that this certificate goes out in
89 // clear during SSL negotiation, so there may be a privacy issue in
90 // putting anything recognizable here.
91 if ((name = X509_NAME_new()) == nullptr ||
92 !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_UTF8,
93 (unsigned char*)params.common_name.c_str(),
94 -1, -1, 0) ||
95 !X509_set_subject_name(x509, name) || !X509_set_issuer_name(x509, name)) {
96 goto error;
97 }
98 if (!X509_time_adj(X509_get_notBefore(x509), params.not_before, &epoch_off) ||
99 !X509_time_adj(X509_get_notAfter(x509), params.not_after, &epoch_off)) {
100 goto error;
101 }
102 if (!X509_sign(x509, pkey, EVP_sha256())) {
103 goto error;
104 }
105
106 BN_free(serial_number);
107 X509_NAME_free(name);
108 RTC_LOG(LS_INFO) << "Returning certificate";
109 return x509;
110
111error:
112 BN_free(serial_number);
113 X509_NAME_free(name);
114 X509_free(x509);
115 return nullptr;
116}
117
118} // namespace
119
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700120OpenSSLCertificate::OpenSSLCertificate(X509* x509) : x509_(x509) {
Steve Antonf25303e2018-10-16 15:23:31 -0700121 RTC_DCHECK(x509_ != nullptr);
122 X509_up_ref(x509_);
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700123}
124
Steve Antonf25303e2018-10-16 15:23:31 -0700125std::unique_ptr<OpenSSLCertificate> OpenSSLCertificate::Generate(
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700126 OpenSSLKeyPair* key_pair,
127 const SSLIdentityParams& params) {
128 SSLIdentityParams actual_params(params);
129 if (actual_params.common_name.empty()) {
130 // Use a random string, arbitrarily 8chars long.
131 actual_params.common_name = CreateRandomString(8);
132 }
133 X509* x509 = MakeCertificate(key_pair->pkey(), actual_params);
134 if (!x509) {
135 openssl::LogSSLErrors("Generating certificate");
136 return nullptr;
137 }
138#if !defined(NDEBUG)
139 PrintCert(x509);
140#endif
Steve Antonf25303e2018-10-16 15:23:31 -0700141 auto ret = absl::make_unique<OpenSSLCertificate>(x509);
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700142 X509_free(x509);
143 return ret;
144}
145
Steve Antonf25303e2018-10-16 15:23:31 -0700146std::unique_ptr<OpenSSLCertificate> OpenSSLCertificate::FromPEMString(
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700147 const std::string& pem_string) {
148 BIO* bio = BIO_new_mem_buf(const_cast<char*>(pem_string.c_str()), -1);
Benjamin Wright428320c2018-10-28 18:22:53 -0700149 if (!bio) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700150 return nullptr;
Benjamin Wright428320c2018-10-28 18:22:53 -0700151 }
152
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700153 BIO_set_mem_eof_return(bio, 0);
154 X509* x509 =
155 PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
156 BIO_free(bio); // Frees the BIO, but not the pointed-to string.
157
Benjamin Wright428320c2018-10-28 18:22:53 -0700158 if (!x509) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700159 return nullptr;
Benjamin Wright428320c2018-10-28 18:22:53 -0700160 }
Steve Antonf25303e2018-10-16 15:23:31 -0700161 auto ret = absl::make_unique<OpenSSLCertificate>(x509);
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700162 X509_free(x509);
163 return ret;
164}
165
166// NOTE: This implementation only functions correctly after InitializeSSL
167// and before CleanupSSL.
168bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
169 std::string* algorithm) const {
170 int nid = X509_get_signature_nid(x509_);
171 switch (nid) {
172 case NID_md5WithRSA:
173 case NID_md5WithRSAEncryption:
174 *algorithm = DIGEST_MD5;
175 break;
176 case NID_ecdsa_with_SHA1:
177 case NID_dsaWithSHA1:
178 case NID_dsaWithSHA1_2:
179 case NID_sha1WithRSA:
180 case NID_sha1WithRSAEncryption:
181 *algorithm = DIGEST_SHA_1;
182 break;
183 case NID_ecdsa_with_SHA224:
184 case NID_sha224WithRSAEncryption:
185 case NID_dsa_with_SHA224:
186 *algorithm = DIGEST_SHA_224;
187 break;
188 case NID_ecdsa_with_SHA256:
189 case NID_sha256WithRSAEncryption:
190 case NID_dsa_with_SHA256:
191 *algorithm = DIGEST_SHA_256;
192 break;
193 case NID_ecdsa_with_SHA384:
194 case NID_sha384WithRSAEncryption:
195 *algorithm = DIGEST_SHA_384;
196 break;
197 case NID_ecdsa_with_SHA512:
198 case NID_sha512WithRSAEncryption:
199 *algorithm = DIGEST_SHA_512;
200 break;
201 default:
202 // Unknown algorithm. There are several unhandled options that are less
203 // common and more complex.
204 RTC_LOG(LS_ERROR) << "Unknown signature algorithm NID: " << nid;
205 algorithm->clear();
206 return false;
207 }
208 return true;
209}
210
211bool OpenSSLCertificate::ComputeDigest(const std::string& algorithm,
212 unsigned char* digest,
213 size_t size,
214 size_t* length) const {
215 return ComputeDigest(x509_, algorithm, digest, size, length);
216}
217
218bool OpenSSLCertificate::ComputeDigest(const X509* x509,
219 const std::string& algorithm,
220 unsigned char* digest,
221 size_t size,
222 size_t* length) {
Benjamin Wright428320c2018-10-28 18:22:53 -0700223 const EVP_MD* md = nullptr;
224 unsigned int n = 0;
225 if (!OpenSSLDigest::GetDigestEVP(algorithm, &md)) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700226 return false;
Benjamin Wright428320c2018-10-28 18:22:53 -0700227 }
228 if (size < static_cast<size_t>(EVP_MD_size(md))) {
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700229 return false;
Benjamin Wright428320c2018-10-28 18:22:53 -0700230 }
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700231 X509_digest(x509, md, digest, &n);
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700232 *length = n;
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700233 return true;
234}
235
236OpenSSLCertificate::~OpenSSLCertificate() {
237 X509_free(x509_);
238}
239
Steve Antonf25303e2018-10-16 15:23:31 -0700240std::unique_ptr<SSLCertificate> OpenSSLCertificate::Clone() const {
241 return absl::make_unique<OpenSSLCertificate>(x509_);
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700242}
243
244std::string OpenSSLCertificate::ToPEMString() const {
245 BIO* bio = BIO_new(BIO_s_mem());
246 if (!bio) {
Benjamin Wright428320c2018-10-28 18:22:53 -0700247 FATAL() << "Unreachable code.";
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700248 }
249 if (!PEM_write_bio_X509(bio, x509_)) {
250 BIO_free(bio);
Benjamin Wright428320c2018-10-28 18:22:53 -0700251 FATAL() << "Unreachable code.";
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700252 }
253 BIO_write(bio, "\0", 1);
254 char* buffer;
255 BIO_get_mem_data(bio, &buffer);
256 std::string ret(buffer);
257 BIO_free(bio);
258 return ret;
259}
260
261void OpenSSLCertificate::ToDER(Buffer* der_buffer) const {
262 // In case of failure, make sure to leave the buffer empty.
263 der_buffer->SetSize(0);
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700264 // Calculates the DER representation of the certificate, from scratch.
265 BIO* bio = BIO_new(BIO_s_mem());
266 if (!bio) {
Benjamin Wright428320c2018-10-28 18:22:53 -0700267 FATAL() << "Unreachable code.";
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700268 }
269 if (!i2d_X509_bio(bio, x509_)) {
270 BIO_free(bio);
Benjamin Wright428320c2018-10-28 18:22:53 -0700271 FATAL() << "Unreachable code.";
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700272 }
Benjamin Wright428320c2018-10-28 18:22:53 -0700273 char* data = nullptr;
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700274 size_t length = BIO_get_mem_data(bio, &data);
275 der_buffer->SetData(data, length);
276 BIO_free(bio);
277}
278
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700279bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const {
280 return X509_cmp(x509_, other.x509_) == 0;
281}
282
283bool OpenSSLCertificate::operator!=(const OpenSSLCertificate& other) const {
284 return !(*this == other);
285}
286
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700287int64_t OpenSSLCertificate::CertificateExpirationTime() const {
288 ASN1_TIME* expire_time = X509_get_notAfter(x509_);
289 bool long_format;
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700290 if (expire_time->type == V_ASN1_UTCTIME) {
291 long_format = false;
292 } else if (expire_time->type == V_ASN1_GENERALIZEDTIME) {
293 long_format = true;
294 } else {
295 return -1;
296 }
Benjamin Wrightd6f86e82018-05-08 13:12:25 -0700297 return ASN1TimeToSec(expire_time->data, expire_time->length, long_format);
298}
299
300} // namespace rtc