Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 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/sslcertificate.h" |
| 12 | |
Yves Gerey | 988cc08 | 2018-10-23 12:03:01 +0200 | [diff] [blame] | 13 | #include <algorithm> |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 14 | #include <string> |
| 15 | #include <utility> |
| 16 | |
Yves Gerey | 988cc08 | 2018-10-23 12:03:01 +0200 | [diff] [blame] | 17 | #include "absl/memory/memory.h" |
| 18 | #include "rtc_base/checks.h" |
| 19 | #include "rtc_base/opensslcertificate.h" |
| 20 | #include "rtc_base/sslfingerprint.h" |
| 21 | #include "rtc_base/third_party/base64/base64.h" |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 22 | |
| 23 | namespace rtc { |
| 24 | |
| 25 | ////////////////////////////////////////////////////////////////////// |
| 26 | // SSLCertificateStats |
| 27 | ////////////////////////////////////////////////////////////////////// |
| 28 | |
| 29 | SSLCertificateStats::SSLCertificateStats( |
| 30 | std::string&& fingerprint, |
| 31 | std::string&& fingerprint_algorithm, |
| 32 | std::string&& base64_certificate, |
Steve Anton | f25303e | 2018-10-16 15:23:31 -0700 | [diff] [blame] | 33 | std::unique_ptr<SSLCertificateStats> issuer) |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 34 | : fingerprint(std::move(fingerprint)), |
| 35 | fingerprint_algorithm(std::move(fingerprint_algorithm)), |
| 36 | base64_certificate(std::move(base64_certificate)), |
| 37 | issuer(std::move(issuer)) {} |
| 38 | |
| 39 | SSLCertificateStats::~SSLCertificateStats() {} |
| 40 | |
| 41 | ////////////////////////////////////////////////////////////////////// |
| 42 | // SSLCertificate |
| 43 | ////////////////////////////////////////////////////////////////////// |
| 44 | |
| 45 | std::unique_ptr<SSLCertificateStats> SSLCertificate::GetStats() const { |
| 46 | // TODO(bemasc): Move this computation to a helper class that caches these |
| 47 | // values to reduce CPU use in |StatsCollector::GetStats|. This will require |
| 48 | // adding a fast |SSLCertificate::Equals| to detect certificate changes. |
| 49 | std::string digest_algorithm; |
| 50 | if (!GetSignatureDigestAlgorithm(&digest_algorithm)) |
| 51 | return nullptr; |
| 52 | |
| 53 | // |SSLFingerprint::Create| can fail if the algorithm returned by |
| 54 | // |SSLCertificate::GetSignatureDigestAlgorithm| is not supported by the |
| 55 | // implementation of |SSLCertificate::ComputeDigest|. This currently happens |
| 56 | // with MD5- and SHA-224-signed certificates when linked to libNSS. |
Steve Anton | 4905edb | 2018-10-15 19:27:44 -0700 | [diff] [blame] | 57 | std::unique_ptr<SSLFingerprint> ssl_fingerprint = |
| 58 | SSLFingerprint::Create(digest_algorithm, *this); |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 59 | if (!ssl_fingerprint) |
| 60 | return nullptr; |
| 61 | std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint(); |
| 62 | |
| 63 | Buffer der_buffer; |
| 64 | ToDER(&der_buffer); |
| 65 | std::string der_base64; |
| 66 | Base64::EncodeFromArray(der_buffer.data(), der_buffer.size(), &der_base64); |
| 67 | |
Karl Wiberg | 918f50c | 2018-07-05 11:40:33 +0200 | [diff] [blame] | 68 | return absl::make_unique<SSLCertificateStats>(std::move(fingerprint), |
| 69 | std::move(digest_algorithm), |
| 70 | std::move(der_base64), nullptr); |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 71 | } |
| 72 | |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 73 | ////////////////////////////////////////////////////////////////////// |
| 74 | // SSLCertChain |
| 75 | ////////////////////////////////////////////////////////////////////// |
| 76 | |
Steve Anton | f25303e | 2018-10-16 15:23:31 -0700 | [diff] [blame] | 77 | SSLCertChain::SSLCertChain(std::unique_ptr<SSLCertificate> single_cert) { |
| 78 | certs_.push_back(std::move(single_cert)); |
| 79 | } |
| 80 | |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 81 | SSLCertChain::SSLCertChain(std::vector<std::unique_ptr<SSLCertificate>> certs) |
| 82 | : certs_(std::move(certs)) {} |
| 83 | |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 84 | SSLCertChain::SSLCertChain(SSLCertChain&& rhs) = default; |
| 85 | |
| 86 | SSLCertChain& SSLCertChain::operator=(SSLCertChain&&) = default; |
| 87 | |
Steve Anton | f25303e | 2018-10-16 15:23:31 -0700 | [diff] [blame] | 88 | SSLCertChain::~SSLCertChain() = default; |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 89 | |
Steve Anton | f25303e | 2018-10-16 15:23:31 -0700 | [diff] [blame] | 90 | std::unique_ptr<SSLCertChain> SSLCertChain::Clone() const { |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 91 | std::vector<std::unique_ptr<SSLCertificate>> new_certs(certs_.size()); |
Steve Anton | f25303e | 2018-10-16 15:23:31 -0700 | [diff] [blame] | 92 | std::transform( |
| 93 | certs_.begin(), certs_.end(), new_certs.begin(), |
| 94 | [](const std::unique_ptr<SSLCertificate>& cert) |
| 95 | -> std::unique_ptr<SSLCertificate> { return cert->Clone(); }); |
| 96 | return absl::make_unique<SSLCertChain>(std::move(new_certs)); |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | std::unique_ptr<SSLCertificateStats> SSLCertChain::GetStats() const { |
| 100 | // We have a linked list of certificates, starting with the first element of |
| 101 | // |certs_| and ending with the last element of |certs_|. The "issuer" of a |
| 102 | // certificate is the next certificate in the chain. Stats are produced for |
| 103 | // each certificate in the list. Here, the "issuer" is the issuer's stats. |
| 104 | std::unique_ptr<SSLCertificateStats> issuer; |
| 105 | // The loop runs in reverse so that the |issuer| is known before the |
| 106 | // certificate issued by |issuer|. |
| 107 | for (ptrdiff_t i = certs_.size() - 1; i >= 0; --i) { |
| 108 | std::unique_ptr<SSLCertificateStats> new_stats = certs_[i]->GetStats(); |
| 109 | if (new_stats) { |
| 110 | new_stats->issuer = std::move(issuer); |
| 111 | } |
| 112 | issuer = std::move(new_stats); |
| 113 | } |
| 114 | return issuer; |
| 115 | } |
| 116 | |
| 117 | // static |
Steve Anton | f25303e | 2018-10-16 15:23:31 -0700 | [diff] [blame] | 118 | std::unique_ptr<SSLCertificate> SSLCertificate::FromPEMString( |
| 119 | const std::string& pem_string) { |
Benjamin Wright | d6f86e8 | 2018-05-08 13:12:25 -0700 | [diff] [blame] | 120 | return OpenSSLCertificate::FromPEMString(pem_string); |
| 121 | } |
| 122 | |
| 123 | } // namespace rtc |