xref: /aosp_15_r20/external/webrtc/rtc_base/openssl_identity.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
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 #include "rtc_base/openssl_identity.h"
12 
13 #include <memory>
14 #include <utility>
15 #include <vector>
16 
17 #if defined(WEBRTC_WIN)
18 // Must be included first before openssl headers.
19 #include "rtc_base/win32.h"  // NOLINT
20 #endif                       // WEBRTC_WIN
21 
22 #include <openssl/bio.h>
23 #include <openssl/err.h>
24 #include <openssl/pem.h>
25 #include <stdint.h>
26 
27 #include "absl/memory/memory.h"
28 #include "rtc_base/checks.h"
29 #include "rtc_base/logging.h"
30 #include "rtc_base/numerics/safe_conversions.h"
31 #include "rtc_base/openssl.h"
32 #include "rtc_base/openssl_utility.h"
33 
34 namespace rtc {
35 
OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,std::unique_ptr<OpenSSLCertificate> certificate)36 OpenSSLIdentity::OpenSSLIdentity(
37     std::unique_ptr<OpenSSLKeyPair> key_pair,
38     std::unique_ptr<OpenSSLCertificate> certificate)
39     : key_pair_(std::move(key_pair)) {
40   RTC_DCHECK(key_pair_ != nullptr);
41   RTC_DCHECK(certificate != nullptr);
42   std::vector<std::unique_ptr<SSLCertificate>> certs;
43   certs.push_back(std::move(certificate));
44   cert_chain_.reset(new SSLCertChain(std::move(certs)));
45 }
46 
OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,std::unique_ptr<SSLCertChain> cert_chain)47 OpenSSLIdentity::OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
48                                  std::unique_ptr<SSLCertChain> cert_chain)
49     : key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
50   RTC_DCHECK(key_pair_ != nullptr);
51   RTC_DCHECK(cert_chain_ != nullptr);
52 }
53 
54 OpenSSLIdentity::~OpenSSLIdentity() = default;
55 
CreateInternal(const SSLIdentityParams & params)56 std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateInternal(
57     const SSLIdentityParams& params) {
58   auto key_pair = OpenSSLKeyPair::Generate(params.key_params);
59   if (key_pair) {
60     std::unique_ptr<OpenSSLCertificate> certificate(
61         OpenSSLCertificate::Generate(key_pair.get(), params));
62     if (certificate != nullptr) {
63       return absl::WrapUnique(
64           new OpenSSLIdentity(std::move(key_pair), std::move(certificate)));
65     }
66   }
67   RTC_LOG(LS_ERROR) << "Identity generation failed";
68   return nullptr;
69 }
70 
71 // static
CreateWithExpiration(absl::string_view common_name,const KeyParams & key_params,time_t certificate_lifetime)72 std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateWithExpiration(
73     absl::string_view common_name,
74     const KeyParams& key_params,
75     time_t certificate_lifetime) {
76   SSLIdentityParams params;
77   params.key_params = key_params;
78   params.common_name = std::string(common_name);
79   time_t now = time(nullptr);
80   params.not_before = now + kCertificateWindowInSeconds;
81   params.not_after = now + certificate_lifetime;
82   if (params.not_before > params.not_after)
83     return nullptr;
84   return CreateInternal(params);
85 }
86 
CreateForTest(const SSLIdentityParams & params)87 std::unique_ptr<OpenSSLIdentity> OpenSSLIdentity::CreateForTest(
88     const SSLIdentityParams& params) {
89   return CreateInternal(params);
90 }
91 
CreateFromPEMStrings(absl::string_view private_key,absl::string_view certificate)92 std::unique_ptr<SSLIdentity> OpenSSLIdentity::CreateFromPEMStrings(
93     absl::string_view private_key,
94     absl::string_view certificate) {
95   std::unique_ptr<OpenSSLCertificate> cert(
96       OpenSSLCertificate::FromPEMString(certificate));
97   if (!cert) {
98     RTC_LOG(LS_ERROR) << "Failed to create OpenSSLCertificate from PEM string.";
99     return nullptr;
100   }
101 
102   auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
103   if (!key_pair) {
104     RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
105     return nullptr;
106   }
107 
108   return absl::WrapUnique(
109       new OpenSSLIdentity(std::move(key_pair), std::move(cert)));
110 }
111 
CreateFromPEMChainStrings(absl::string_view private_key,absl::string_view certificate_chain)112 std::unique_ptr<SSLIdentity> OpenSSLIdentity::CreateFromPEMChainStrings(
113     absl::string_view private_key,
114     absl::string_view certificate_chain) {
115   BIO* bio = BIO_new_mem_buf(certificate_chain.data(),
116                              rtc::dchecked_cast<int>(certificate_chain.size()));
117   if (!bio)
118     return nullptr;
119   BIO_set_mem_eof_return(bio, 0);
120   std::vector<std::unique_ptr<SSLCertificate>> certs;
121   while (true) {
122     X509* x509 =
123         PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
124     if (x509 == nullptr) {
125       uint32_t err = ERR_peek_error();
126       if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
127           ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
128         break;
129       }
130       RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string.";
131       BIO_free(bio);
132       return nullptr;
133     }
134     certs.emplace_back(new OpenSSLCertificate(x509));
135     X509_free(x509);
136   }
137   BIO_free(bio);
138   if (certs.empty()) {
139     RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
140     return nullptr;
141   }
142 
143   auto key_pair = OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
144   if (!key_pair) {
145     RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
146     return nullptr;
147   }
148 
149   return absl::WrapUnique(new OpenSSLIdentity(
150       std::move(key_pair), std::make_unique<SSLCertChain>(std::move(certs))));
151 }
152 
certificate() const153 const OpenSSLCertificate& OpenSSLIdentity::certificate() const {
154   return *static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(0));
155 }
156 
cert_chain() const157 const SSLCertChain& OpenSSLIdentity::cert_chain() const {
158   return *cert_chain_.get();
159 }
160 
CloneInternal() const161 std::unique_ptr<SSLIdentity> OpenSSLIdentity::CloneInternal() const {
162   // We cannot use std::make_unique here because the referenced OpenSSLIdentity
163   // constructor is private.
164   return absl::WrapUnique(
165       new OpenSSLIdentity(key_pair_->Clone(), cert_chain_->Clone()));
166 }
167 
ConfigureIdentity(SSL_CTX * ctx)168 bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
169   // 1 is the documented success return code.
170   const OpenSSLCertificate* cert = &certificate();
171   if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 ||
172       SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
173     openssl::LogSSLErrors("Configuring key and certificate");
174     return false;
175   }
176   // If a chain is available, use it.
177   for (size_t i = 1; i < cert_chain_->GetSize(); ++i) {
178     cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i));
179     if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) {
180       openssl::LogSSLErrors("Configuring intermediate certificate");
181       return false;
182     }
183   }
184 
185   return true;
186 }
187 
PrivateKeyToPEMString() const188 std::string OpenSSLIdentity::PrivateKeyToPEMString() const {
189   return key_pair_->PrivateKeyToPEMString();
190 }
191 
PublicKeyToPEMString() const192 std::string OpenSSLIdentity::PublicKeyToPEMString() const {
193   return key_pair_->PublicKeyToPEMString();
194 }
195 
operator ==(const OpenSSLIdentity & other) const196 bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const {
197   return *this->key_pair_ == *other.key_pair_ &&
198          this->certificate() == other.certificate();
199 }
200 
operator !=(const OpenSSLIdentity & other) const201 bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const {
202   return !(*this == other);
203 }
204 
205 }  // namespace rtc
206