Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  boringssl_certificate.cc

  Sprache: C
 

/*
 *  Copyright 2020 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/boringssl_certificate.h"

#include <openssl/asn1.h>
#include <openssl/base.h>
#include <openssl/bytestring.h>
#include <openssl/digest.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/pool.h>
#include <openssl/rand.h>

#include <cstdint>
#include <cstring>
#include <ctime>
#include <memory>
#include <string>
#include <utility>

#include "absl/strings/string_view.h"
#include "rtc_base/buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/crypto_random.h"
#include "rtc_base/logging.h"
#include "rtc_base/message_digest.h"
#include "rtc_base/openssl_digest.h"
#include "rtc_base/openssl_key_pair.h"
#include "rtc_base/openssl_utility.h"
#include "rtc_base/ssl_certificate.h"
#include "rtc_base/ssl_identity.h"

namespace webrtc {
namespace {

// List of OIDs of signature algorithms accepted by WebRTC.
// Taken from openssl/nid.h.
const uint8_t kMD5WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x03};
const uint8_t kMD5WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                         0x0d, 0x01, 0x01, 0x04};
const uint8_t kECDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01};
const uint8_t kDSAWithSHA1[] = {0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x03};
const uint8_t kDSAWithSHA1_2[] = {0x2b, 0x0e, 0x03, 0x02, 0x1b};
const uint8_t kSHA1WithRSA[] = {0x2b, 0x0e, 0x03, 0x02, 0x1d};
const uint8_t kSHA1WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                          0x0d, 0x01, 0x01, 0x05};
const uint8_t kECDSAWithSHA224[] = {0x2a, 0x86, 0x48, 0xce,
                                    0x3d, 0x04, 0x03, 0x01};
const uint8_t kSHA224WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                            0x0d, 0x01, 0x01, 0x0e};
const uint8_t kDSAWithSHA224[] = {0x60, 0x86, 0x48, 0x01, 0x65,
                                  0x03, 0x04, 0x03, 0x01};
const uint8_t kECDSAWithSHA256[] = {0x2a, 0x86, 0x48, 0xce,
                                    0x3d, 0x04, 0x03, 0x02};
const uint8_t kSHA256WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                            0x0d, 0x01, 0x01, 0x0b};
const uint8_t kDSAWithSHA256[] = {0x60, 0x86, 0x48, 0x01, 0x65,
                                  0x03, 0x04, 0x03, 0x02};
const uint8_t kECDSAWithSHA384[] = {0x2a, 0x86, 0x48, 0xce,
                                    0x3d, 0x04, 0x03, 0x03};
const uint8_t kSHA384WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                            0x0d, 0x01, 0x01, 0x0c};
const uint8_t kECDSAWithSHA512[] = {0x2a, 0x86, 0x48, 0xce,
                                    0x3d, 0x04, 0x03, 0x04};
const uint8_t kSHA512WithRSAEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                            0x0d, 0x01, 0x01, 0x0d};

#if !defined(NDEBUG)
// Print a certificate to the log, for debugging.
void PrintCert(BoringSSLCertificate* cert) {
  // Since we're using CRYPTO_BUFFER, we can't use X509_print_ex, so we'll just
  // print the PEM string.
  RTC_DLOG(LS_VERBOSE) << "PEM representation of certificate:\n"
                       << cert->ToPEMString();
}
#endif

bool AddSHA256SignatureAlgorithm(CBB* cbb, KeyType key_type) {
  // An AlgorithmIdentifier is described in RFC 5280, 4.1.1.2.
  CBB sequence, oid, params;
  if (!CBB_add_asn1(cbb, &sequence, CBS_ASN1_SEQUENCE) ||
      !CBB_add_asn1(&sequence, &oid, CBS_ASN1_OBJECT)) {
    return false;
  }

  switch (key_type) {
    case KT_RSA:
      if (!CBB_add_bytes(&oid, kSHA256WithRSAEncryption,
                         sizeof(kSHA256WithRSAEncryption)) ||
          !CBB_add_asn1(&sequence, ¶ms, CBS_ASN1_NULL)) {
        return false;
      }
      break;
    case KT_ECDSA:
      if (!CBB_add_bytes(&oid, kECDSAWithSHA256, sizeof(kECDSAWithSHA256))) {
        return false;
      }
      break;
    default:
      RTC_DCHECK_NOTREACHED();
      return false;
  }
  if (!CBB_flush(cbb)) {
    return false;
  }
  return true;
}

// Adds an X.509 Common Name to `cbb`.
bool AddCommonName(CBB* cbb, absl::string_view common_name) {
  // See RFC 4519.
  static const uint8_t kCommonName[] = {0x55, 0x04, 0x03};

  if (common_name.empty()) {
    RTC_LOG(LS_ERROR) << "Common name cannot be empty.";
    return false;
  }

  // See RFC 5280, section 4.1.2.4.
  CBB rdns;
  if (!CBB_add_asn1(cbb, &rdns, CBS_ASN1_SEQUENCE)) {
    return false;
  }

  CBB rdn, attr, type, value;
  if (!CBB_add_asn1(&rdns, &rdn, CBS_ASN1_SET) ||
      !CBB_add_asn1(&rdn, &attr, CBS_ASN1_SEQUENCE) ||
      !CBB_add_asn1(&attr, &type, CBS_ASN1_OBJECT) ||
      !CBB_add_bytes(&type, kCommonName, sizeof(kCommonName)) ||
      !CBB_add_asn1(&attr, &value, CBS_ASN1_UTF8STRING) ||
      !CBB_add_bytes(&value,
                     reinterpret_cast<const uint8_t*>(common_name.data()),
                     common_name.size()) ||
      !CBB_flush(cbb)) {
    return false;
  }

  return true;
}

bool AddTime(CBB* cbb, time_t time) {
  bssl::UniquePtr<ASN1_TIME> asn1_time(ASN1_TIME_new());
  if (!asn1_time) {
    return false;
  }

  if (!ASN1_TIME_set(asn1_time.get(), time)) {
    return false;
  }

  unsigned tag;
  switch (asn1_time->type) {
    case V_ASN1_UTCTIME:
      tag = CBS_ASN1_UTCTIME;
      break;
    case V_ASN1_GENERALIZEDTIME:
      tag = CBS_ASN1_GENERALIZEDTIME;
      break;
    default:
      return false;
  }

  CBB child;
  if (!CBB_add_asn1(cbb, &child, tag) ||
      !CBB_add_bytes(&child, asn1_time->data, asn1_time->length) ||
      !CBB_flush(cbb)) {
    return false;
  }

  return true;
}

// Generate a self-signed certificate, with the public key from the
// given key pair. Caller is responsible for freeing the returned object.
bssl::UniquePtr<CRYPTO_BUFFER> MakeCertificate(
    EVP_PKEY* pkey,
    const SSLIdentityParams& params) {
  RTC_LOG(LS_INFO) << "Making certificate for " << params.common_name;

  // See RFC 5280, section 4.1. First, construct the TBSCertificate.
  bssl::ScopedCBB cbb;
  CBB tbs_cert, version, validity;
  uint8_t* tbs_cert_bytes;
  size_t tbs_cert_len;
  uint64_t serial_number;
  if (!CBB_init(cbb.get(), 64) ||
      !CBB_add_asn1(cbb.get(), &tbs_cert, CBS_ASN1_SEQUENCE) ||
      !CBB_add_asn1(&tbs_cert, &version,
                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
      !CBB_add_asn1_uint64(&version, 2) ||
      !RAND_bytes(reinterpret_cast<uint8_t*>(&serial_number),
                  sizeof(serial_number)) ||
      !CBB_add_asn1_uint64(&tbs_cert, serial_number) ||
      !AddSHA256SignatureAlgorithm(&tbs_cert, params.key_params.type()) ||
      !AddCommonName(&tbs_cert, params.common_name) ||  // issuer
      !CBB_add_asn1(&tbs_cert, &validity, CBS_ASN1_SEQUENCE) ||
      !AddTime(&validity, params.not_before) ||
      !AddTime(&validity, params.not_after) ||
      !AddCommonName(&tbs_cert, params.common_name) ||  // subject
      !EVP_marshal_public_key(&tbs_cert, pkey) ||       // subjectPublicKeyInfo
      !CBB_finish(cbb.get(), &tbs_cert_bytes, &tbs_cert_len)) {
    return nullptr;
  }

  bssl::UniquePtr<uint8_t> delete_tbs_cert_bytes(tbs_cert_bytes);

  // Sign the TBSCertificate and write the entire certificate.
  CBB cert, signature;
  bssl::ScopedEVP_MD_CTX ctx;
  uint8_t* sig_out;
  size_t sig_len;
  uint8_t* cert_bytes;
  size_t cert_len;
  if (!CBB_init(cbb.get(), tbs_cert_len) ||
      !CBB_add_asn1(cbb.get(), &cert, CBS_ASN1_SEQUENCE) ||
      !CBB_add_bytes(&cert, tbs_cert_bytes, tbs_cert_len) ||
      !AddSHA256SignatureAlgorithm(&cert, params.key_params.type()) ||
      !CBB_add_asn1(&cert, &signature, CBS_ASN1_BITSTRING) ||
      !CBB_add_u8(&signature, 0 /* no unused bits */) ||
      !EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, pkey) ||
      // Compute the maximum signature length.
      !EVP_DigestSign(ctx.get(), nullptr, &sig_len, tbs_cert_bytes,
                      tbs_cert_len) ||
      !CBB_reserve(&signature, &sig_out, sig_len) ||
      // Actually sign the TBSCertificate.
      !EVP_DigestSign(ctx.get(), sig_out, &sig_len, tbs_cert_bytes,
                      tbs_cert_len) ||
      !CBB_did_write(&signature, sig_len) ||
      !CBB_finish(cbb.get(), &cert_bytes, &cert_len)) {
    return nullptr;
  }
  bssl::UniquePtr<uint8_t> delete_cert_bytes(cert_bytes);

  RTC_LOG(LS_INFO) << "Returning certificate";
  return bssl::UniquePtr<CRYPTO_BUFFER>(
      CRYPTO_BUFFER_new(cert_bytes, cert_len, openssl::GetBufferPool()));
}

}  // namespace

BoringSSLCertificate::BoringSSLCertificate(
    bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer)
    : cert_buffer_(std::move(cert_buffer)) {
  RTC_DCHECK(cert_buffer_ != nullptr);
}

std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::Generate(
    OpenSSLKeyPair* key_pair,
    const SSLIdentityParams& params) {
  SSLIdentityParams actual_params(params);
  if (actual_params.common_name.empty()) {
    // Use a random string, arbitrarily 8 chars long.
    actual_params.common_name = CreateRandomString(8);
  }
  bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer =
      MakeCertificate(key_pair->pkey(), actual_params);
  if (!cert_buffer) {
    openssl::LogSSLErrors("Generating certificate");
    return nullptr;
  }
  auto ret = std::make_unique<BoringSSLCertificate>(std::move(cert_buffer));
#if !defined(NDEBUG)
  PrintCert(ret.get());
#endif
  return ret;
}

std::unique_ptr<BoringSSLCertificate> BoringSSLCertificate::FromPEMString(
    absl::string_view pem_string) {
  std::string der;
  if (!SSLIdentity::PemToDer(kPemTypeCertificate, pem_string, &der)) {
    return nullptr;
  }
  bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer(
      CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(der.c_str()),
                        der.length(), openssl::GetBufferPool()));
  if (!cert_buffer) {
    return nullptr;
  }
  return std::make_unique<BoringSSLCertificate>(std::move(cert_buffer));
}

#define OID_MATCHES(oid, oid_other)      \
  (CBS_len(&oid) == sizeof(oid_other) && \
   0 == memcmp(CBS_data(&oid), oid_other, sizeof(oid_other)))

bool BoringSSLCertificate::GetSignatureDigestAlgorithm(
    std::string* algorithm) const {
  CBS oid;
  if (!openssl::ParseCertificate(cert_buffer_.get(), &oid, nullptr)) {
    RTC_LOG(LS_ERROR) << "Failed to parse certificate.";
    return false;
  }
  if (OID_MATCHES(oid, kMD5WithRSA) ||
      OID_MATCHES(oid, kMD5WithRSAEncryption)) {
    *algorithm = DIGEST_MD5;
    return true;
  }
  if (OID_MATCHES(oid, kECDSAWithSHA1) || OID_MATCHES(oid, kDSAWithSHA1) ||
      OID_MATCHES(oid, kDSAWithSHA1_2) || OID_MATCHES(oid, kSHA1WithRSA) ||
      OID_MATCHES(oid, kSHA1WithRSAEncryption)) {
    *algorithm = DIGEST_SHA_1;
    return true;
  }
  if (OID_MATCHES(oid, kECDSAWithSHA224) ||
      OID_MATCHES(oid, kSHA224WithRSAEncryption) ||
      OID_MATCHES(oid, kDSAWithSHA224)) {
    *algorithm = DIGEST_SHA_224;
    return true;
  }
  if (OID_MATCHES(oid, kECDSAWithSHA256) ||
      OID_MATCHES(oid, kSHA256WithRSAEncryption) ||
      OID_MATCHES(oid, kDSAWithSHA256)) {
    *algorithm = DIGEST_SHA_256;
    return true;
  }
  if (OID_MATCHES(oid, kECDSAWithSHA384) ||
      OID_MATCHES(oid, kSHA384WithRSAEncryption)) {
    *algorithm = DIGEST_SHA_384;
    return true;
  }
  if (OID_MATCHES(oid, kECDSAWithSHA512) ||
      OID_MATCHES(oid, kSHA512WithRSAEncryption)) {
    *algorithm = DIGEST_SHA_512;
    return true;
  }
  // Unknown algorithm.  There are several unhandled options that are less
  // common and more complex.
  RTC_LOG(LS_ERROR) << "Unknown signature algorithm.";
  algorithm->clear();
  return false;
}

bool BoringSSLCertificate::ComputeDigest(absl::string_view algorithm,
                                         Buffer& digest) const {
  RTC_DCHECK_GT(digest.capacity(), 0);

  const EVP_MD* md = nullptr;
  unsigned int n = 0;
  if (!OpenSSLDigest::GetDigestEVP(algorithm, &md)) {
    return false;
  }
  if (digest.capacity() < static_cast<size_t>(EVP_MD_size(md))) {
    return false;
  }
  if (!EVP_Digest(CRYPTO_BUFFER_data(cert_buffer_.get()),
                  CRYPTO_BUFFER_len(cert_buffer_.get()), digest.data(), &n, md,
                  nullptr)) {
    return false;
  }
  digest.SetSize(n);
  return true;
}

BoringSSLCertificate::~BoringSSLCertificate() {}

std::unique_ptr<SSLCertificate> BoringSSLCertificate::Clone() const {
  return std::make_unique<BoringSSLCertificate>(
      bssl::UpRef(cert_buffer_.get()));
}

std::string BoringSSLCertificate::ToPEMString() const {
  return SSLIdentity::DerToPem(kPemTypeCertificate,
                               CRYPTO_BUFFER_data(cert_buffer_.get()),
                               CRYPTO_BUFFER_len(cert_buffer_.get()));
}

void BoringSSLCertificate::ToDER(Buffer* der_buffer) const {
  der_buffer->SetData(CRYPTO_BUFFER_data(cert_buffer_.get()),
                      CRYPTO_BUFFER_len(cert_buffer_.get()));
}

bool BoringSSLCertificate::operator==(const BoringSSLCertificate& other) const {
  return CRYPTO_BUFFER_len(cert_buffer_.get()) ==
             CRYPTO_BUFFER_len(other.cert_buffer_.get()) &&
         0 == memcmp(CRYPTO_BUFFER_data(cert_buffer_.get()),
                     CRYPTO_BUFFER_data(other.cert_buffer_.get()),
                     CRYPTO_BUFFER_len(cert_buffer_.get()));
}

bool BoringSSLCertificate::operator!=(const BoringSSLCertificate& other) const {
  return !(*this == other);
}

int64_t BoringSSLCertificate::CertificateExpirationTime() const {
  int64_t ret;
  if (!openssl::ParseCertificate(cert_buffer_.get(), nullptr, &ret)) {
    RTC_LOG(LS_ERROR) << "Failed to parse certificate.";
    return -1;
  }
  return ret;
}

}  // namespace webrtc

Messung V0.5 in Prozent
C=94 H=100 G=96

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-08-24) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

letze Version des Elbe Quellennavigators


Jenseits des Üblichen ....

Besucher

Besucher

Statistik
#Sources=434850
#Domains=655579