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:
Jian Cui 2017-11-16 16:58:02 -08:00 committed by Commit Bot
parent e0b2ff5ea4
commit 0a8798b266
8 changed files with 282 additions and 50 deletions

View File

@ -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 {

View File

@ -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_

View File

@ -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.

View File

@ -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_;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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();