Implement OpenSSLCertificate::GetChain
Continue from https://codereview.webrtc.org/3010363002/ BUG=webrtc:8289 Change-Id: I8d14ba7974b654387f63ff30dee822b3045edcc7 Reviewed-on: https://webrtc-review.googlesource.com/6500 Commit-Queue: Jian Cui <jiancui@google.com> Reviewed-by: David Benjamin <davidben@webrtc.org> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20723}
This commit is contained in:
parent
e0b2ff5ea4
commit
0a8798b266
@ -16,17 +16,18 @@
|
||||
#include "rtc_base/win32.h" // NOLINT
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/helpers.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/openssl.h"
|
||||
#include "rtc_base/openssldigest.h"
|
||||
#include "rtc_base/ptr_util.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
@ -143,7 +144,7 @@ static X509* MakeCertificate(EVP_PKEY* pkey, const SSLIdentityParams& params) {
|
||||
RTC_LOG(LS_INFO) << "Returning certificate";
|
||||
return x509;
|
||||
|
||||
error:
|
||||
error:
|
||||
BN_free(serial_number);
|
||||
X509_NAME_free(name);
|
||||
X509_free(x509);
|
||||
@ -218,8 +219,8 @@ std::string OpenSSLKeyPair::PrivateKeyToPEMString() const {
|
||||
RTC_NOTREACHED();
|
||||
return "";
|
||||
}
|
||||
if (!PEM_write_bio_PrivateKey(
|
||||
temp_memory_bio, pkey_, nullptr, nullptr, 0, nullptr, nullptr)) {
|
||||
if (!PEM_write_bio_PrivateKey(temp_memory_bio, pkey_, nullptr, nullptr, 0,
|
||||
nullptr, nullptr)) {
|
||||
RTC_LOG_F(LS_ERROR) << "Failed to write private key";
|
||||
BIO_free(temp_memory_bio);
|
||||
RTC_NOTREACHED();
|
||||
@ -279,8 +280,13 @@ static void PrintCert(X509* x509) {
|
||||
}
|
||||
#endif
|
||||
|
||||
OpenSSLCertificate::OpenSSLCertificate(X509* x509) : x509_(x509) {
|
||||
AddReference();
|
||||
}
|
||||
|
||||
OpenSSLCertificate* OpenSSLCertificate::Generate(
|
||||
OpenSSLKeyPair* key_pair, const SSLIdentityParams& params) {
|
||||
OpenSSLKeyPair* key_pair,
|
||||
const SSLIdentityParams& params) {
|
||||
SSLIdentityParams actual_params(params);
|
||||
if (actual_params.common_name.empty()) {
|
||||
// Use a random string, arbitrarily 8chars long.
|
||||
@ -363,9 +369,6 @@ bool OpenSSLCertificate::GetSignatureDigestAlgorithm(
|
||||
}
|
||||
|
||||
std::unique_ptr<SSLCertChain> OpenSSLCertificate::GetChain() const {
|
||||
// Chains are not yet supported when using OpenSSL.
|
||||
// OpenSSLStreamAdapter::SSLVerifyCallback currently requires the remote
|
||||
// certificate to be self-signed.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -451,7 +454,7 @@ void OpenSSLCertificate::AddReference() const {
|
||||
}
|
||||
|
||||
bool OpenSSLCertificate::operator==(const OpenSSLCertificate& other) const {
|
||||
return X509_cmp(this->x509_, other.x509_) == 0;
|
||||
return X509_cmp(x509_, other.x509_) == 0;
|
||||
}
|
||||
|
||||
bool OpenSSLCertificate::operator!=(const OpenSSLCertificate& other) const {
|
||||
@ -474,24 +477,35 @@ int64_t OpenSSLCertificate::CertificateExpirationTime() const {
|
||||
return ASN1TimeToSec(expire_time->data, expire_time->length, long_format);
|
||||
}
|
||||
|
||||
OpenSSLIdentity::OpenSSLIdentity(OpenSSLKeyPair* key_pair,
|
||||
OpenSSLCertificate* certificate)
|
||||
: key_pair_(key_pair), certificate_(certificate) {
|
||||
RTC_DCHECK(key_pair != nullptr);
|
||||
OpenSSLIdentity::OpenSSLIdentity(
|
||||
std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<OpenSSLCertificate> certificate)
|
||||
: key_pair_(std::move(key_pair)) {
|
||||
RTC_DCHECK(key_pair_ != nullptr);
|
||||
RTC_DCHECK(certificate != nullptr);
|
||||
std::vector<std::unique_ptr<SSLCertificate>> certs;
|
||||
certs.push_back(std::move(certificate));
|
||||
cert_chain_.reset(new SSLCertChain(std::move(certs)));
|
||||
}
|
||||
|
||||
OpenSSLIdentity::OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<SSLCertChain> cert_chain)
|
||||
: key_pair_(std::move(key_pair)), cert_chain_(std::move(cert_chain)) {
|
||||
RTC_DCHECK(key_pair_ != nullptr);
|
||||
RTC_DCHECK(cert_chain_ != nullptr);
|
||||
}
|
||||
|
||||
OpenSSLIdentity::~OpenSSLIdentity() = default;
|
||||
|
||||
OpenSSLIdentity* OpenSSLIdentity::GenerateInternal(
|
||||
const SSLIdentityParams& params) {
|
||||
OpenSSLKeyPair* key_pair = OpenSSLKeyPair::Generate(params.key_params);
|
||||
std::unique_ptr<OpenSSLKeyPair> key_pair(
|
||||
OpenSSLKeyPair::Generate(params.key_params));
|
||||
if (key_pair) {
|
||||
OpenSSLCertificate* certificate =
|
||||
OpenSSLCertificate::Generate(key_pair, params);
|
||||
if (certificate)
|
||||
return new OpenSSLIdentity(key_pair, certificate);
|
||||
delete key_pair;
|
||||
std::unique_ptr<OpenSSLCertificate> certificate(
|
||||
OpenSSLCertificate::Generate(key_pair.get(), params));
|
||||
if (certificate != nullptr)
|
||||
return new OpenSSLIdentity(std::move(key_pair), std::move(certificate));
|
||||
}
|
||||
RTC_LOG(LS_INFO) << "Identity generation failed";
|
||||
return nullptr;
|
||||
@ -517,9 +531,8 @@ OpenSSLIdentity* OpenSSLIdentity::GenerateForTest(
|
||||
return GenerateInternal(params);
|
||||
}
|
||||
|
||||
SSLIdentity* OpenSSLIdentity::FromPEMStrings(
|
||||
const std::string& private_key,
|
||||
const std::string& certificate) {
|
||||
SSLIdentity* OpenSSLIdentity::FromPEMStrings(const std::string& private_key,
|
||||
const std::string& certificate) {
|
||||
std::unique_ptr<OpenSSLCertificate> cert(
|
||||
OpenSSLCertificate::FromPEMString(certificate));
|
||||
if (!cert) {
|
||||
@ -527,33 +540,84 @@ SSLIdentity* OpenSSLIdentity::FromPEMStrings(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OpenSSLKeyPair* key_pair =
|
||||
OpenSSLKeyPair::FromPrivateKeyPEMString(private_key);
|
||||
std::unique_ptr<OpenSSLKeyPair> key_pair(
|
||||
OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
|
||||
if (!key_pair) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new OpenSSLIdentity(key_pair,
|
||||
cert.release());
|
||||
return new OpenSSLIdentity(std::move(key_pair), std::move(cert));
|
||||
}
|
||||
|
||||
SSLIdentity* OpenSSLIdentity::FromPEMChainStrings(
|
||||
const std::string& private_key,
|
||||
const std::string& certificate_chain) {
|
||||
BIO* bio =
|
||||
BIO_new_mem_buf(certificate_chain.data(), certificate_chain.size());
|
||||
if (!bio)
|
||||
return nullptr;
|
||||
BIO_set_mem_eof_return(bio, 0);
|
||||
std::vector<std::unique_ptr<SSLCertificate>> certs;
|
||||
while (true) {
|
||||
X509* x509 =
|
||||
PEM_read_bio_X509(bio, nullptr, nullptr, const_cast<char*>("\0"));
|
||||
if (x509 == nullptr) {
|
||||
uint32_t err = ERR_peek_error();
|
||||
if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
|
||||
ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
|
||||
break;
|
||||
}
|
||||
RTC_LOG(LS_ERROR) << "Failed to parse certificate from PEM string.";
|
||||
BIO_free(bio);
|
||||
return nullptr;
|
||||
}
|
||||
certs.emplace_back(new OpenSSLCertificate(x509));
|
||||
X509_free(x509);
|
||||
}
|
||||
BIO_free(bio);
|
||||
if (certs.empty()) {
|
||||
RTC_LOG(LS_ERROR) << "Found no certificates in PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<OpenSSLKeyPair> key_pair(
|
||||
OpenSSLKeyPair::FromPrivateKeyPEMString(private_key));
|
||||
if (!key_pair) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to create key pair from PEM string.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new OpenSSLIdentity(std::move(key_pair),
|
||||
MakeUnique<SSLCertChain>(std::move(certs)));
|
||||
}
|
||||
|
||||
const OpenSSLCertificate& OpenSSLIdentity::certificate() const {
|
||||
return *certificate_;
|
||||
return *static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(0));
|
||||
}
|
||||
|
||||
OpenSSLIdentity* OpenSSLIdentity::GetReference() const {
|
||||
return new OpenSSLIdentity(key_pair_->GetReference(),
|
||||
certificate_->GetReference());
|
||||
return new OpenSSLIdentity(WrapUnique(key_pair_->GetReference()),
|
||||
WrapUnique(certificate().GetReference()));
|
||||
}
|
||||
|
||||
bool OpenSSLIdentity::ConfigureIdentity(SSL_CTX* ctx) {
|
||||
// 1 is the documented success return code.
|
||||
if (SSL_CTX_use_certificate(ctx, certificate_->x509()) != 1 ||
|
||||
SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
|
||||
const OpenSSLCertificate* cert = &certificate();
|
||||
if (SSL_CTX_use_certificate(ctx, cert->x509()) != 1 ||
|
||||
SSL_CTX_use_PrivateKey(ctx, key_pair_->pkey()) != 1) {
|
||||
LogSSLErrors("Configuring key and certificate");
|
||||
return false;
|
||||
}
|
||||
// If a chain is available, use it.
|
||||
for (size_t i = 1; i < cert_chain_->GetSize(); ++i) {
|
||||
cert = static_cast<const OpenSSLCertificate*>(&cert_chain_->Get(i));
|
||||
if (SSL_CTX_add1_chain_cert(ctx, cert->x509()) != 1) {
|
||||
LogSSLErrors("Configuring intermediate certificate");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -567,7 +631,7 @@ std::string OpenSSLIdentity::PublicKeyToPEMString() const {
|
||||
|
||||
bool OpenSSLIdentity::operator==(const OpenSSLIdentity& other) const {
|
||||
return *this->key_pair_ == *other.key_pair_ &&
|
||||
*this->certificate_ == *other.certificate_;
|
||||
this->certificate() == other.certificate();
|
||||
}
|
||||
|
||||
bool OpenSSLIdentity::operator!=(const OpenSSLIdentity& other) const {
|
||||
|
||||
@ -36,8 +36,7 @@ class OpenSSLKeyPair {
|
||||
static OpenSSLKeyPair* Generate(const KeyParams& key_params);
|
||||
// Constructs a key pair from the private key PEM string. This must not result
|
||||
// in missing public key parameters. Returns null on error.
|
||||
static OpenSSLKeyPair* FromPrivateKeyPEMString(
|
||||
const std::string& pem_string);
|
||||
static OpenSSLKeyPair* FromPrivateKeyPEMString(const std::string& pem_string);
|
||||
|
||||
virtual ~OpenSSLKeyPair();
|
||||
|
||||
@ -62,9 +61,7 @@ class OpenSSLKeyPair {
|
||||
class OpenSSLCertificate : public SSLCertificate {
|
||||
public:
|
||||
// Caller retains ownership of the X509 object.
|
||||
explicit OpenSSLCertificate(X509* x509) : x509_(x509) {
|
||||
AddReference();
|
||||
}
|
||||
explicit OpenSSLCertificate(X509* x509);
|
||||
|
||||
static OpenSSLCertificate* Generate(OpenSSLKeyPair* key_pair,
|
||||
const SSLIdentityParams& params);
|
||||
@ -103,7 +100,6 @@ class OpenSSLCertificate : public SSLCertificate {
|
||||
void AddReference() const;
|
||||
|
||||
X509* x509_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(OpenSSLCertificate);
|
||||
};
|
||||
|
||||
@ -117,6 +113,8 @@ class OpenSSLIdentity : public SSLIdentity {
|
||||
static OpenSSLIdentity* GenerateForTest(const SSLIdentityParams& params);
|
||||
static SSLIdentity* FromPEMStrings(const std::string& private_key,
|
||||
const std::string& certificate);
|
||||
static SSLIdentity* FromPEMChainStrings(const std::string& private_key,
|
||||
const std::string& certificate_chain);
|
||||
~OpenSSLIdentity() override;
|
||||
|
||||
const OpenSSLCertificate& certificate() const override;
|
||||
@ -131,17 +129,19 @@ class OpenSSLIdentity : public SSLIdentity {
|
||||
bool operator!=(const OpenSSLIdentity& other) const;
|
||||
|
||||
private:
|
||||
OpenSSLIdentity(OpenSSLKeyPair* key_pair, OpenSSLCertificate* certificate);
|
||||
OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<OpenSSLCertificate> certificate);
|
||||
OpenSSLIdentity(std::unique_ptr<OpenSSLKeyPair> key_pair,
|
||||
std::unique_ptr<SSLCertChain> cert_chain);
|
||||
|
||||
static OpenSSLIdentity* GenerateInternal(const SSLIdentityParams& params);
|
||||
|
||||
std::unique_ptr<OpenSSLKeyPair> key_pair_;
|
||||
std::unique_ptr<OpenSSLCertificate> certificate_;
|
||||
std::unique_ptr<SSLCertChain> cert_chain_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(OpenSSLIdentity);
|
||||
};
|
||||
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_OPENSSLIDENTITY_H_
|
||||
|
||||
@ -1104,6 +1104,11 @@ bool OpenSSLStreamAdapter::VerifyPeerCertificate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<SSLCertChain> OpenSSLStreamAdapter::GetPeerSSLCertChain()
|
||||
const {
|
||||
return std::unique_ptr<SSLCertChain>(peer_cert_chain_->Copy());
|
||||
}
|
||||
|
||||
int OpenSSLStreamAdapter::SSLVerifyCallback(X509_STORE_CTX* store, void* arg) {
|
||||
// Get our SSL structure and OpenSSLStreamAdapter from the store.
|
||||
SSL* ssl = reinterpret_cast<SSL*>(
|
||||
@ -1111,10 +1116,23 @@ int OpenSSLStreamAdapter::SSLVerifyCallback(X509_STORE_CTX* store, void* arg) {
|
||||
OpenSSLStreamAdapter* stream =
|
||||
reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl));
|
||||
|
||||
#if defined(OPENSSL_IS_BORINGSSL)
|
||||
STACK_OF(X509)* chain = SSL_get_peer_full_cert_chain(ssl);
|
||||
// Creates certificate.
|
||||
stream->peer_certificate_.reset(
|
||||
new OpenSSLCertificate(sk_X509_value(chain, 0)));
|
||||
// Creates certificate chain.
|
||||
std::vector<std::unique_ptr<SSLCertificate>> cert_chain;
|
||||
for (X509* cert : chain) {
|
||||
cert_chain.emplace_back(new OpenSSLCertificate(cert));
|
||||
}
|
||||
stream->peer_cert_chain_.reset(new SSLCertChain(std::move(cert_chain)));
|
||||
#else
|
||||
// Record the peer's certificate.
|
||||
X509* cert = SSL_get_peer_certificate(ssl);
|
||||
stream->peer_certificate_.reset(new OpenSSLCertificate(cert));
|
||||
X509_free(cert);
|
||||
#endif
|
||||
|
||||
// If the peer certificate digest isn't known yet, we'll wait to verify
|
||||
// until it's known, and for now just return a success status.
|
||||
|
||||
@ -71,6 +71,8 @@ class OpenSSLStreamAdapter : public SSLStreamAdapter {
|
||||
|
||||
std::unique_ptr<SSLCertificate> GetPeerCertificate() const override;
|
||||
|
||||
std::unique_ptr<SSLCertChain> GetPeerSSLCertChain() const override;
|
||||
|
||||
// Goes from state SSL_NONE to either SSL_CONNECTING or SSL_WAIT, depending
|
||||
// on whether the underlying stream is already open or not.
|
||||
int StartSSL() override;
|
||||
@ -198,6 +200,7 @@ class OpenSSLStreamAdapter : public SSLStreamAdapter {
|
||||
// The certificate that the peer presented. Initially null, until the
|
||||
// connection is established.
|
||||
std::unique_ptr<OpenSSLCertificate> peer_certificate_;
|
||||
std::unique_ptr<SSLCertChain> peer_cert_chain_;
|
||||
bool peer_certificate_verified_ = false;
|
||||
// The digest of the certificate that the peer must present.
|
||||
Buffer peer_certificate_digest_value_;
|
||||
|
||||
@ -265,6 +265,13 @@ SSLIdentity* SSLIdentity::FromPEMStrings(const std::string& private_key,
|
||||
return OpenSSLIdentity::FromPEMStrings(private_key, certificate);
|
||||
}
|
||||
|
||||
// static
|
||||
SSLIdentity* SSLIdentity::FromPEMChainStrings(
|
||||
const std::string& private_key,
|
||||
const std::string& certificate_chain) {
|
||||
return OpenSSLIdentity::FromPEMChainStrings(private_key, certificate_chain);
|
||||
}
|
||||
|
||||
bool operator==(const SSLIdentity& a, const SSLIdentity& b) {
|
||||
return static_cast<const OpenSSLIdentity&>(a) ==
|
||||
static_cast<const OpenSSLIdentity&>(b);
|
||||
|
||||
@ -67,8 +67,8 @@ class SSLCertificate {
|
||||
|
||||
std::unique_ptr<SSLCertificate> GetUniqueReference() const;
|
||||
|
||||
// Provides the cert chain, or null. The chain includes a copy of each
|
||||
// certificate, excluding the leaf.
|
||||
// Returns null. This is deprecated. Please use
|
||||
// SSLStreamAdapter::GetPeerSSLCertChain
|
||||
virtual std::unique_ptr<SSLCertChain> GetChain() const = 0;
|
||||
|
||||
// Returns a PEM encoded string representation of the certificate.
|
||||
@ -98,7 +98,7 @@ class SSLCertificate {
|
||||
|
||||
private:
|
||||
std::unique_ptr<SSLCertificateStats> GetStats(
|
||||
std::unique_ptr<SSLCertificateStats> issuer) const;
|
||||
std::unique_ptr<SSLCertificateStats> issuer) const;
|
||||
};
|
||||
|
||||
// SSLCertChain is a simple wrapper for a vector of SSLCertificates. It serves
|
||||
@ -229,6 +229,10 @@ class SSLIdentity {
|
||||
static SSLIdentity* FromPEMStrings(const std::string& private_key,
|
||||
const std::string& certificate);
|
||||
|
||||
// Construct an identity from a private key and a certificate chain.
|
||||
static SSLIdentity* FromPEMChainStrings(const std::string& private_key,
|
||||
const std::string& certificate_chain);
|
||||
|
||||
virtual ~SSLIdentity() {}
|
||||
|
||||
// Returns a new SSLIdentity object instance wrapping the same
|
||||
|
||||
@ -58,8 +58,9 @@ int SrtpCryptoSuiteFromName(const std::string& crypto_suite);
|
||||
|
||||
// Get key length and salt length for given crypto suite. Returns true for
|
||||
// valid suites, otherwise false.
|
||||
bool GetSrtpKeyAndSaltLengths(int crypto_suite, int *key_length,
|
||||
int *salt_length);
|
||||
bool GetSrtpKeyAndSaltLengths(int crypto_suite,
|
||||
int* key_length,
|
||||
int* salt_length);
|
||||
|
||||
// Returns true if the given crypto suite id uses a GCM cipher.
|
||||
bool IsGcmCryptoSuite(int crypto_suite);
|
||||
@ -103,7 +104,6 @@ std::vector<int> GetSupportedDtlsSrtpCryptoSuites(
|
||||
// for doing this are in SSLAdapter. They should possibly be moved out
|
||||
// to a neutral class.
|
||||
|
||||
|
||||
enum SSLRole { SSL_CLIENT, SSL_SERVER };
|
||||
enum SSLMode { SSL_MODE_TLS, SSL_MODE_DTLS };
|
||||
enum SSLProtocolVersion {
|
||||
@ -202,10 +202,13 @@ class SSLStreamAdapter : public StreamAdapterInterface {
|
||||
SSLPeerCertificateDigestError* error = nullptr) = 0;
|
||||
|
||||
// Retrieves the peer's X.509 certificate, if a connection has been
|
||||
// established. It returns the transmitted over SSL, including the entire
|
||||
// chain.
|
||||
// established.
|
||||
virtual std::unique_ptr<SSLCertificate> GetPeerCertificate() const = 0;
|
||||
|
||||
// Retrieves the peer's certificate chain including leaf, if a
|
||||
// connection has been established.
|
||||
virtual std::unique_ptr<SSLCertChain> GetPeerSSLCertChain() const = 0;
|
||||
|
||||
// Retrieves the IANA registration id of the cipher suite used for the
|
||||
// connection (e.g. 0x2F for "TLS_RSA_WITH_AES_128_CBC_SHA").
|
||||
virtual bool GetSslCipherSuite(int* cipher_suite);
|
||||
|
||||
@ -64,6 +64,71 @@ static const char kCERT_PEM[] =
|
||||
"UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
static const char kIntCert1[] =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIEUjCCAjqgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBljELMAkGA1UEBhMCVVMx\n"
|
||||
"EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS\n"
|
||||
"BgNVBAoMC0dvb2dsZSwgSW5jMQwwCgYDVQQLDANHVFAxFzAVBgNVBAMMDnRlbGVw\n"
|
||||
"aG9ueS5nb29nMR0wGwYJKoZIhvcNAQkBFg5ndHBAZ29vZ2xlLmNvbTAeFw0xNzA5\n"
|
||||
"MjYwNDA5MDNaFw0yMDA2MjIwNDA5MDNaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI\n"
|
||||
"DAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEXMBUGA1UECgwOdGVsZXBob255\n"
|
||||
"Lmdvb2cxFzAVBgNVBAMMDnRlbGVwaG9ueS5nb29nMIGfMA0GCSqGSIb3DQEBAQUA\n"
|
||||
"A4GNADCBiQKBgQDJXWeeU1v1+wlqkVobzI3aN7Uh2iVQA9YCdq5suuabtiD/qoOD\n"
|
||||
"NKpmQqsx7WZGGWSZTDFEBaUpvIK7Hb+nzRqk6iioPCFOFuarm6GxO1xVneImMuE6\n"
|
||||
"tuWb3YZPr+ikChJbl11y5UcSbg0QsbeUc+jHl5umNvrL85Y+z8SP0rxbBwIDAQAB\n"
|
||||
"o2AwXjAdBgNVHQ4EFgQU7tdZobqlN8R8V72FQnRxmqq8tKswHwYDVR0jBBgwFoAU\n"
|
||||
"5GgKMUtcxkQ2dJrtNR5YOlIAPDswDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMC\n"
|
||||
"AQYwDQYJKoZIhvcNAQELBQADggIBADObh9Z+z14FmP9zSenhFtq7hFnmNrSkklk8\n"
|
||||
"eyYWXKfOuIriEQQBZsz76ZcnzStih8Rj+yQ0AXydk4fJ5LOwC2cUqQBar17g6Pd2\n"
|
||||
"8g4SIL4azR9WvtiSvpuGlwp25b+yunaacDne6ebnf/MUiiKT5w61Xo3cEPVfl38e\n"
|
||||
"/Up2l0bioid5enUTmg6LY6RxDO6tnZQkz3XD+nNSwT4ehtkqFpHYWjErj0BbkDM2\n"
|
||||
"hiVc/JsYOZn3DmuOlHVHU6sKwqh3JEyvHO/d7DGzMGWHpHwv2mCTJq6l/sR95Tc2\n"
|
||||
"GaQZgGDVNs9pdEouJCDm9e/PbQWRYhnat82PTkXx/6mDAAwdZlIi/pACzq8K4p7e\n"
|
||||
"6hF0t8uKGnXJubHPXxlnJU6yxZ0yWmivAGjwWK4ur832gKlho4jeMDhiI/T3QPpl\n"
|
||||
"iMNsIvxRhdD+GxJkQP1ezayw8s+Uc9KwKglrkBSRRDLCJUfPOvMmXLUDSTMX7kp4\n"
|
||||
"/Ak1CA8dVLJIlfEjLBUuvAttlP7+7lsKNgxAjCxZkWLXIyGULzNPQwVWkGfCbrQs\n"
|
||||
"XyMvSbFsSIb7blV7eLlmf9a+2RprUUkc2ALXLLCI9YQXmxm2beBfMyNmmebwBJzT\n"
|
||||
"B0OR+5pFFNTJPoNlqpdrDsGrDu7JlUtk0ZLZzYyKXbgy2qXxfd4OWzXXjxpLMszZ\n"
|
||||
"LDIpOAkj\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
static const char kCACert[] =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"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\n"
|
||||
"dGaXBy+qbVXVyGXaeEbIRjtJ6m92\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
class SSLStreamAdapterTestBase;
|
||||
|
||||
class SSLDummyStreamBase : public rtc::StreamInterface,
|
||||
@ -865,6 +930,36 @@ class SSLStreamAdapterTestDTLSFromPEMStrings : public SSLStreamAdapterTestDTLS {
|
||||
}
|
||||
};
|
||||
|
||||
// Test fixture for certificate chaining. Server will push more than one
|
||||
// certificate.
|
||||
class SSLStreamAdapterTestDTLSCertChain : public SSLStreamAdapterTestDTLS {
|
||||
public:
|
||||
SSLStreamAdapterTestDTLSCertChain() : SSLStreamAdapterTestDTLS("", ""){};
|
||||
void SetUp() override {
|
||||
CreateStreams();
|
||||
|
||||
client_ssl_.reset(rtc::SSLStreamAdapter::Create(client_stream_));
|
||||
server_ssl_.reset(rtc::SSLStreamAdapter::Create(server_stream_));
|
||||
|
||||
// Set up the slots
|
||||
client_ssl_->SignalEvent.connect(
|
||||
reinterpret_cast<SSLStreamAdapterTestBase*>(this),
|
||||
&SSLStreamAdapterTestBase::OnEvent);
|
||||
server_ssl_->SignalEvent.connect(
|
||||
reinterpret_cast<SSLStreamAdapterTestBase*>(this),
|
||||
&SSLStreamAdapterTestBase::OnEvent);
|
||||
|
||||
if (!client_cert_pem_.empty() && !client_private_key_pem_.empty()) {
|
||||
client_identity_ = rtc::SSLIdentity::FromPEMStrings(
|
||||
client_private_key_pem_, client_cert_pem_);
|
||||
} else {
|
||||
client_identity_ = rtc::SSLIdentity::Generate("client", client_key_type_);
|
||||
}
|
||||
|
||||
client_ssl_->SetIdentity(client_identity_);
|
||||
}
|
||||
};
|
||||
|
||||
// Basic tests: TLS
|
||||
|
||||
// Test that we can make a handshake work
|
||||
@ -872,6 +967,44 @@ TEST_P(SSLStreamAdapterTestTLS, TestTLSConnect) {
|
||||
TestHandshake();
|
||||
};
|
||||
|
||||
TEST_P(SSLStreamAdapterTestTLS, GetPeerCertChainWithOneCertificate) {
|
||||
TestHandshake();
|
||||
std::unique_ptr<rtc::SSLCertChain> cert_chain =
|
||||
client_ssl_->GetPeerSSLCertChain();
|
||||
std::unique_ptr<rtc::SSLCertificate> certificate =
|
||||
client_ssl_->GetPeerCertificate();
|
||||
ASSERT_NE(nullptr, cert_chain);
|
||||
EXPECT_EQ(1u, cert_chain->GetSize());
|
||||
EXPECT_EQ(cert_chain->Get(0).ToPEMString(), certificate->ToPEMString());
|
||||
}
|
||||
|
||||
TEST_F(SSLStreamAdapterTestDTLSCertChain, TwoCertHandshake) {
|
||||
server_identity_ = rtc::SSLIdentity::FromPEMChainStrings(
|
||||
kRSA_PRIVATE_KEY_PEM, std::string(kCERT_PEM) + kCACert);
|
||||
server_ssl_->SetIdentity(server_identity_);
|
||||
TestHandshake();
|
||||
std::unique_ptr<rtc::SSLCertChain> peer_cert_chain =
|
||||
client_ssl_->GetPeerSSLCertChain();
|
||||
ASSERT_NE(nullptr, peer_cert_chain);
|
||||
ASSERT_EQ(2u, peer_cert_chain->GetSize());
|
||||
EXPECT_EQ(kCERT_PEM, peer_cert_chain->Get(0).ToPEMString());
|
||||
EXPECT_EQ(kCACert, peer_cert_chain->Get(1).ToPEMString());
|
||||
}
|
||||
|
||||
TEST_F(SSLStreamAdapterTestDTLSCertChain, ThreeCertHandshake) {
|
||||
server_identity_ = rtc::SSLIdentity::FromPEMChainStrings(
|
||||
kRSA_PRIVATE_KEY_PEM, std::string(kCERT_PEM) + kIntCert1 + kCACert);
|
||||
server_ssl_->SetIdentity(server_identity_);
|
||||
TestHandshake();
|
||||
std::unique_ptr<rtc::SSLCertChain> peer_cert_chain =
|
||||
client_ssl_->GetPeerSSLCertChain();
|
||||
ASSERT_NE(nullptr, peer_cert_chain);
|
||||
ASSERT_EQ(3u, peer_cert_chain->GetSize());
|
||||
EXPECT_EQ(kCERT_PEM, peer_cert_chain->Get(0).ToPEMString());
|
||||
EXPECT_EQ(kIntCert1, peer_cert_chain->Get(1).ToPEMString());
|
||||
EXPECT_EQ(kCACert, peer_cert_chain->Get(2).ToPEMString());
|
||||
}
|
||||
|
||||
// Test that closing the connection on one side updates the other side.
|
||||
TEST_P(SSLStreamAdapterTestTLS, TestTLSClose) {
|
||||
TestHandshake();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user