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