|  | /* | 
|  | *  Copyright 2004 The WebRTC Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "rtc_base/ssl_certificate.h" | 
|  |  | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | #include "absl/algorithm/container.h" | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "api/array_view.h" | 
|  | #include "rtc_base/base64.h" | 
|  | #include "rtc_base/buffer.h" | 
|  | #include "rtc_base/openssl.h" | 
|  | #include "rtc_base/ssl_fingerprint.h" | 
|  |  | 
|  | // IWYU pragma: begin_keep | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | #include "rtc_base/boringssl_certificate.h" | 
|  | #include "rtc_base/boringssl_identity.h" | 
|  | #else | 
|  | #include "rtc_base/openssl_certificate.h" | 
|  | #include "rtc_base/openssl_identity.h" | 
|  | #endif | 
|  | // IWYU pragma: end_keep | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////// | 
|  | // SSLCertificateStats | 
|  | ////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | SSLCertificateStats::SSLCertificateStats( | 
|  | std::string&& fingerprint, | 
|  | std::string&& fingerprint_algorithm, | 
|  | std::string&& base64_certificate, | 
|  | std::unique_ptr<SSLCertificateStats> issuer) | 
|  | : fingerprint(std::move(fingerprint)), | 
|  | fingerprint_algorithm(std::move(fingerprint_algorithm)), | 
|  | base64_certificate(std::move(base64_certificate)), | 
|  | issuer(std::move(issuer)) {} | 
|  |  | 
|  | SSLCertificateStats::~SSLCertificateStats() {} | 
|  |  | 
|  | std::unique_ptr<SSLCertificateStats> SSLCertificateStats::Copy() const { | 
|  | return std::make_unique<SSLCertificateStats>( | 
|  | std::string(fingerprint), std::string(fingerprint_algorithm), | 
|  | std::string(base64_certificate), issuer ? issuer->Copy() : nullptr); | 
|  | } | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////// | 
|  | // SSLCertificate | 
|  | ////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | std::unique_ptr<SSLCertificateStats> SSLCertificate::GetStats() const { | 
|  | // TODO(bemasc): Move this computation to a helper class that caches these | 
|  | // values to reduce CPU use in `StatsCollector::GetStats`. This will require | 
|  | // adding a fast `SSLCertificate::Equals` to detect certificate changes. | 
|  | std::string digest_algorithm; | 
|  | if (!GetSignatureDigestAlgorithm(&digest_algorithm)) | 
|  | return nullptr; | 
|  |  | 
|  | // `SSLFingerprint::Create` can fail if the algorithm returned by | 
|  | // `SSLCertificate::GetSignatureDigestAlgorithm` is not supported by the | 
|  | // implementation of `SSLCertificate::ComputeDigest`. This currently happens | 
|  | // with MD5- and SHA-224-signed certificates when linked to libNSS. | 
|  | std::unique_ptr<SSLFingerprint> ssl_fingerprint = | 
|  | SSLFingerprint::Create(digest_algorithm, *this); | 
|  | if (!ssl_fingerprint) | 
|  | return nullptr; | 
|  | std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint(); | 
|  |  | 
|  | Buffer der_buffer; | 
|  | ToDER(&der_buffer); | 
|  | ArrayView<const uint8_t> der_view(der_buffer); | 
|  | std::string der_base64 = Base64Encode(der_view); | 
|  |  | 
|  | return std::make_unique<SSLCertificateStats>(std::move(fingerprint), | 
|  | std::move(digest_algorithm), | 
|  | std::move(der_base64), nullptr); | 
|  | } | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////// | 
|  | // SSLCertChain | 
|  | ////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | SSLCertChain::SSLCertChain(std::unique_ptr<SSLCertificate> single_cert) { | 
|  | certs_.push_back(std::move(single_cert)); | 
|  | } | 
|  |  | 
|  | SSLCertChain::SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs) | 
|  | : certs_(std::move(certs)) {} | 
|  |  | 
|  | SSLCertChain::SSLCertChain(SSLCertChain&& rhs) = default; | 
|  |  | 
|  | SSLCertChain& SSLCertChain::operator=(SSLCertChain&&) = default; | 
|  |  | 
|  | SSLCertChain::~SSLCertChain() = default; | 
|  |  | 
|  | std::unique_ptr<SSLCertChain> SSLCertChain::Clone() const { | 
|  | std::vector<std::unique_ptr<SSLCertificate>> new_certs(certs_.size()); | 
|  | absl::c_transform( | 
|  | certs_, new_certs.begin(), | 
|  | [](const std::unique_ptr<SSLCertificate>& cert) | 
|  | -> std::unique_ptr<SSLCertificate> { return cert->Clone(); }); | 
|  | return std::make_unique<SSLCertChain>(std::move(new_certs)); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<SSLCertificateStats> SSLCertChain::GetStats() const { | 
|  | // We have a linked list of certificates, starting with the first element of | 
|  | // `certs_` and ending with the last element of `certs_`. The "issuer" of a | 
|  | // certificate is the next certificate in the chain. Stats are produced for | 
|  | // each certificate in the list. Here, the "issuer" is the issuer's stats. | 
|  | std::unique_ptr<SSLCertificateStats> issuer; | 
|  | // The loop runs in reverse so that the `issuer` is known before the | 
|  | // certificate issued by `issuer`. | 
|  | for (ptrdiff_t i = certs_.size() - 1; i >= 0; --i) { | 
|  | std::unique_ptr<SSLCertificateStats> new_stats = certs_[i]->GetStats(); | 
|  | if (new_stats) { | 
|  | new_stats->issuer = std::move(issuer); | 
|  | } | 
|  | issuer = std::move(new_stats); | 
|  | } | 
|  | return issuer; | 
|  | } | 
|  |  | 
|  | // static | 
|  | std::unique_ptr<SSLCertificate> SSLCertificate::FromPEMString( | 
|  | absl::string_view pem_string) { | 
|  | #ifdef OPENSSL_IS_BORINGSSL | 
|  | return BoringSSLCertificate::FromPEMString(pem_string); | 
|  | #else | 
|  | return OpenSSLCertificate::FromPEMString(pem_string); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |