mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
dtls环境自动初始化,支持多线程
This commit is contained in:
parent
0d4cc2fc65
commit
d0a1c72fda
@ -10,6 +10,7 @@
|
||||
#include <openssl/rsa.h>
|
||||
#include <cstdio> // std::sprintf(), std::fopen()
|
||||
#include <cstring> // std::memcpy(), std::strcmp()
|
||||
#include "Util/util.h"
|
||||
|
||||
#define LOG_OPENSSL_ERROR(desc) \
|
||||
do \
|
||||
@ -53,7 +54,6 @@ namespace RTC
|
||||
|
||||
// clang-format off
|
||||
static constexpr int DtlsMtu{ 1350 };
|
||||
static constexpr int SslReadBufferSize{ 65536 };
|
||||
// AES-HMAC: http://tools.ietf.org/html/rfc3711
|
||||
static constexpr size_t SrtpMasterKeyLength{ 16 };
|
||||
static constexpr size_t SrtpMasterSaltLength{ 14 };
|
||||
@ -68,11 +68,6 @@ namespace RTC
|
||||
// clang-format on
|
||||
|
||||
/* Class variables. */
|
||||
|
||||
X509* DtlsTransport::certificate{ nullptr };
|
||||
EVP_PKEY* DtlsTransport::privateKey{ nullptr };
|
||||
SSL_CTX* DtlsTransport::sslCtx{ nullptr };
|
||||
uint8_t DtlsTransport::sslReadBuffer[SslReadBufferSize];
|
||||
// clang-format off
|
||||
std::map<std::string, DtlsTransport::FingerprintAlgorithm> DtlsTransport::string2FingerprintAlgorithm =
|
||||
{
|
||||
@ -96,7 +91,6 @@ namespace RTC
|
||||
{ "client", DtlsTransport::Role::CLIENT },
|
||||
{ "server", DtlsTransport::Role::SERVER }
|
||||
};
|
||||
std::vector<DtlsTransport::Fingerprint> DtlsTransport::localFingerprints;
|
||||
std::vector<DtlsTransport::SrtpCryptoSuiteMapEntry> DtlsTransport::srtpCryptoSuites =
|
||||
{
|
||||
{ RTC::SrtpSession::CryptoSuite::AEAD_AES_256_GCM, "SRTP_AEAD_AES_256_GCM" },
|
||||
@ -106,13 +100,14 @@ namespace RTC
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
INSTANCE_IMP(DtlsTransport::DtlsEnvironment);
|
||||
|
||||
/* Class methods. */
|
||||
|
||||
void DtlsTransport::ClassInit()
|
||||
DtlsTransport::DtlsEnvironment::DtlsEnvironment()
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
|
||||
// Generate a X509 certificate and private key (unless PEM files are provided).
|
||||
if (true /*
|
||||
Settings::configuration.dtlsCertificateFile.empty() ||
|
||||
@ -132,19 +127,19 @@ namespace RTC
|
||||
GenerateFingerprints();
|
||||
}
|
||||
|
||||
void DtlsTransport::ClassDestroy()
|
||||
DtlsTransport::DtlsEnvironment::~DtlsEnvironment()
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
if (DtlsTransport::privateKey)
|
||||
EVP_PKEY_free(DtlsTransport::privateKey);
|
||||
if (DtlsTransport::certificate)
|
||||
X509_free(DtlsTransport::certificate);
|
||||
if (DtlsTransport::sslCtx)
|
||||
SSL_CTX_free(DtlsTransport::sslCtx);
|
||||
if (privateKey)
|
||||
EVP_PKEY_free(privateKey);
|
||||
if (certificate)
|
||||
X509_free(certificate);
|
||||
if (sslCtx)
|
||||
SSL_CTX_free(sslCtx);
|
||||
}
|
||||
|
||||
void DtlsTransport::GenerateCertificateAndPrivateKey()
|
||||
void DtlsTransport::DtlsEnvironment::GenerateCertificateAndPrivateKey()
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
@ -177,9 +172,9 @@ namespace RTC
|
||||
}
|
||||
|
||||
// Create a private key object.
|
||||
DtlsTransport::privateKey = EVP_PKEY_new();
|
||||
privateKey = EVP_PKEY_new();
|
||||
|
||||
if (!DtlsTransport::privateKey)
|
||||
if (!privateKey)
|
||||
{
|
||||
LOG_OPENSSL_ERROR("EVP_PKEY_new() failed");
|
||||
|
||||
@ -187,7 +182,7 @@ namespace RTC
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||
ret = EVP_PKEY_assign_EC_KEY(DtlsTransport::privateKey, ecKey);
|
||||
ret = EVP_PKEY_assign_EC_KEY(privateKey, ecKey);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -200,9 +195,9 @@ namespace RTC
|
||||
ecKey = nullptr;
|
||||
|
||||
// Create the X509 certificate.
|
||||
DtlsTransport::certificate = X509_new();
|
||||
certificate = X509_new();
|
||||
|
||||
if (!DtlsTransport::certificate)
|
||||
if (!certificate)
|
||||
{
|
||||
LOG_OPENSSL_ERROR("X509_new() failed");
|
||||
|
||||
@ -210,19 +205,19 @@ namespace RTC
|
||||
}
|
||||
|
||||
// Set version 3 (note that 0 means version 1).
|
||||
X509_set_version(DtlsTransport::certificate, 2);
|
||||
X509_set_version(certificate, 2);
|
||||
|
||||
// Set serial number (avoid default 0).
|
||||
ASN1_INTEGER_set(
|
||||
X509_get_serialNumber(DtlsTransport::certificate),
|
||||
X509_get_serialNumber(certificate),
|
||||
static_cast<uint64_t>(rand() % 999999 + 100000));
|
||||
|
||||
// Set valid period.
|
||||
X509_gmtime_adj(X509_get_notBefore(DtlsTransport::certificate), -315360000); // -10 years.
|
||||
X509_gmtime_adj(X509_get_notAfter(DtlsTransport::certificate), 315360000); // 10 years.
|
||||
X509_gmtime_adj(X509_get_notBefore(certificate), -315360000); // -10 years.
|
||||
X509_gmtime_adj(X509_get_notAfter(certificate), 315360000); // 10 years.
|
||||
|
||||
// Set the public key for the certificate using the key.
|
||||
ret = X509_set_pubkey(DtlsTransport::certificate, DtlsTransport::privateKey);
|
||||
ret = X509_set_pubkey(certificate, privateKey);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -232,7 +227,7 @@ namespace RTC
|
||||
}
|
||||
|
||||
// Set certificate fields.
|
||||
certName = X509_get_subject_name(DtlsTransport::certificate);
|
||||
certName = X509_get_subject_name(certificate);
|
||||
|
||||
if (!certName)
|
||||
{
|
||||
@ -247,7 +242,7 @@ namespace RTC
|
||||
certName, "CN", MBSTRING_ASC, reinterpret_cast<const uint8_t*>(subject.c_str()), -1, -1, 0);
|
||||
|
||||
// It is self-signed so set the issuer name to be the same as the subject.
|
||||
ret = X509_set_issuer_name(DtlsTransport::certificate, certName);
|
||||
ret = X509_set_issuer_name(certificate, certName);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -257,7 +252,7 @@ namespace RTC
|
||||
}
|
||||
|
||||
// Sign the certificate with its own private key.
|
||||
ret = X509_sign(DtlsTransport::certificate, DtlsTransport::privateKey, EVP_sha1());
|
||||
ret = X509_sign(certificate, privateKey, EVP_sha1());
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -273,16 +268,16 @@ namespace RTC
|
||||
if (ecKey)
|
||||
EC_KEY_free(ecKey);
|
||||
|
||||
if (DtlsTransport::privateKey)
|
||||
EVP_PKEY_free(DtlsTransport::privateKey); // NOTE: This also frees the EC key.
|
||||
if (privateKey)
|
||||
EVP_PKEY_free(privateKey); // NOTE: This also frees the EC key.
|
||||
|
||||
if (DtlsTransport::certificate)
|
||||
X509_free(DtlsTransport::certificate);
|
||||
if (certificate)
|
||||
X509_free(certificate);
|
||||
|
||||
MS_THROW_ERROR("DTLS certificate and private key generation failed");
|
||||
}
|
||||
|
||||
void DtlsTransport::ReadCertificateAndPrivateKeyFromFiles()
|
||||
void DtlsTransport::DtlsEnvironment::ReadCertificateAndPrivateKeyFromFiles()
|
||||
{
|
||||
#if 0
|
||||
MS_TRACE();
|
||||
@ -298,9 +293,9 @@ namespace RTC
|
||||
goto error;
|
||||
}
|
||||
|
||||
DtlsTransport::certificate = PEM_read_X509(file, nullptr, nullptr, nullptr);
|
||||
certificate = PEM_read_X509(file, nullptr, nullptr, nullptr);
|
||||
|
||||
if (!DtlsTransport::certificate)
|
||||
if (!certificate)
|
||||
{
|
||||
LOG_OPENSSL_ERROR("PEM_read_X509() failed");
|
||||
|
||||
@ -318,9 +313,9 @@ namespace RTC
|
||||
goto error;
|
||||
}
|
||||
|
||||
DtlsTransport::privateKey = PEM_read_PrivateKey(file, nullptr, nullptr, nullptr);
|
||||
privateKey = PEM_read_PrivateKey(file, nullptr, nullptr, nullptr);
|
||||
|
||||
if (!DtlsTransport::privateKey)
|
||||
if (!privateKey)
|
||||
{
|
||||
LOG_OPENSSL_ERROR("PEM_read_PrivateKey() failed");
|
||||
|
||||
@ -337,7 +332,7 @@ namespace RTC
|
||||
#endif
|
||||
}
|
||||
|
||||
void DtlsTransport::CreateSslCtx()
|
||||
void DtlsTransport::DtlsEnvironment::CreateSslCtx()
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
@ -347,16 +342,16 @@ namespace RTC
|
||||
/* Set the global DTLS context. */
|
||||
|
||||
// Both DTLS 1.0 and 1.2 (requires OpenSSL >= 1.1.0).
|
||||
DtlsTransport::sslCtx = SSL_CTX_new(DTLS_method());
|
||||
sslCtx = SSL_CTX_new(DTLS_method());
|
||||
|
||||
if (!DtlsTransport::sslCtx)
|
||||
if (!sslCtx)
|
||||
{
|
||||
LOG_OPENSSL_ERROR("SSL_CTX_new() failed");
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = SSL_CTX_use_certificate(DtlsTransport::sslCtx, DtlsTransport::certificate);
|
||||
ret = SSL_CTX_use_certificate(sslCtx, certificate);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -365,7 +360,7 @@ namespace RTC
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = SSL_CTX_use_PrivateKey(DtlsTransport::sslCtx, DtlsTransport::privateKey);
|
||||
ret = SSL_CTX_use_PrivateKey(sslCtx, privateKey);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -374,7 +369,7 @@ namespace RTC
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = SSL_CTX_check_private_key(DtlsTransport::sslCtx);
|
||||
ret = SSL_CTX_check_private_key(sslCtx);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -385,31 +380,31 @@ namespace RTC
|
||||
|
||||
// Set options.
|
||||
SSL_CTX_set_options(
|
||||
DtlsTransport::sslCtx,
|
||||
sslCtx,
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_NO_TICKET | SSL_OP_SINGLE_ECDH_USE |
|
||||
SSL_OP_NO_QUERY_MTU);
|
||||
|
||||
// Don't use sessions cache.
|
||||
SSL_CTX_set_session_cache_mode(DtlsTransport::sslCtx, SSL_SESS_CACHE_OFF);
|
||||
SSL_CTX_set_session_cache_mode(sslCtx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
// Read always as much into the buffer as possible.
|
||||
// NOTE: This is the default for DTLS, but a bug in non latest OpenSSL
|
||||
// versions makes this call required.
|
||||
SSL_CTX_set_read_ahead(DtlsTransport::sslCtx, 1);
|
||||
SSL_CTX_set_read_ahead(sslCtx, 1);
|
||||
|
||||
SSL_CTX_set_verify_depth(DtlsTransport::sslCtx, 4);
|
||||
SSL_CTX_set_verify_depth(sslCtx, 4);
|
||||
|
||||
// Require certificate from peer.
|
||||
SSL_CTX_set_verify(
|
||||
DtlsTransport::sslCtx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, onSslCertificateVerify);
|
||||
sslCtx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, onSslCertificateVerify);
|
||||
|
||||
// Set SSL info callback.
|
||||
SSL_CTX_set_info_callback(DtlsTransport::sslCtx, [](const SSL* ssl, int where, int ret){
|
||||
SSL_CTX_set_info_callback(sslCtx, [](const SSL* ssl, int where, int ret){
|
||||
static_cast<RTC::DtlsTransport*>(SSL_get_ex_data(ssl, 0))->OnSslInfo(where, ret);
|
||||
});
|
||||
// Set ciphers.
|
||||
ret = SSL_CTX_set_cipher_list(
|
||||
DtlsTransport::sslCtx, "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK");
|
||||
sslCtx, "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK");
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -424,7 +419,7 @@ namespace RTC
|
||||
// NOTE: https://bugs.ruby-lang.org/issues/12324
|
||||
|
||||
// For OpenSSL >= 1.0.2.
|
||||
SSL_CTX_set_ecdh_auto(DtlsTransport::sslCtx, 1);
|
||||
SSL_CTX_set_ecdh_auto(sslCtx, 1);
|
||||
|
||||
// Set the "use_srtp" DTLS extension.
|
||||
for (auto it = DtlsTransport::srtpCryptoSuites.begin();
|
||||
@ -441,7 +436,7 @@ namespace RTC
|
||||
MS_DEBUG_2TAGS(dtls, srtp, "setting SRTP cryptoSuites for DTLS: %s", dtlsSrtpCryptoSuites.c_str());
|
||||
|
||||
// NOTE: This function returns 0 on success.
|
||||
ret = SSL_CTX_set_tlsext_use_srtp(DtlsTransport::sslCtx, dtlsSrtpCryptoSuites.c_str());
|
||||
ret = SSL_CTX_set_tlsext_use_srtp(sslCtx, dtlsSrtpCryptoSuites.c_str());
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
@ -456,16 +451,16 @@ namespace RTC
|
||||
|
||||
error:
|
||||
|
||||
if (DtlsTransport::sslCtx)
|
||||
if (sslCtx)
|
||||
{
|
||||
SSL_CTX_free(DtlsTransport::sslCtx);
|
||||
DtlsTransport::sslCtx = nullptr;
|
||||
SSL_CTX_free(sslCtx);
|
||||
sslCtx = nullptr;
|
||||
}
|
||||
|
||||
MS_THROW_ERROR("SSL context creation failed");
|
||||
}
|
||||
|
||||
void DtlsTransport::GenerateFingerprints()
|
||||
void DtlsTransport::DtlsEnvironment::GenerateFingerprints()
|
||||
{
|
||||
MS_TRACE();
|
||||
|
||||
@ -505,7 +500,7 @@ namespace RTC
|
||||
MS_THROW_ERROR("unknown algorithm");
|
||||
}
|
||||
|
||||
ret = X509_digest(DtlsTransport::certificate, hashFunction, binaryFingerprint, &size);
|
||||
ret = X509_digest(certificate, hashFunction, binaryFingerprint, &size);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
@ -528,7 +523,7 @@ namespace RTC
|
||||
fingerprint.algorithm = DtlsTransport::GetFingerprintAlgorithm(algorithmString);
|
||||
fingerprint.value = hexFingerprint;
|
||||
|
||||
DtlsTransport::localFingerprints.push_back(fingerprint);
|
||||
localFingerprints.push_back(fingerprint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,10 +532,11 @@ namespace RTC
|
||||
DtlsTransport::DtlsTransport(EventPoller::Ptr poller,Listener* listener) : poller(std::move(poller)), listener(listener)
|
||||
{
|
||||
MS_TRACE();
|
||||
env = DtlsEnvironment::Instance().shared_from_this();
|
||||
|
||||
/* Set SSL. */
|
||||
|
||||
this->ssl = SSL_new(DtlsTransport::sslCtx);
|
||||
this->ssl = SSL_new(env->sslCtx);
|
||||
|
||||
if (!this->ssl)
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ using namespace toolkit;
|
||||
|
||||
namespace RTC
|
||||
{
|
||||
class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
{
|
||||
public:
|
||||
enum class DtlsState
|
||||
@ -60,6 +60,27 @@ class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
const char* name;
|
||||
};
|
||||
|
||||
class DtlsEnvironment : public std::enable_shared_from_this<DtlsEnvironment>
|
||||
{
|
||||
public:
|
||||
using Ptr = std::shared_ptr<DtlsEnvironment>;
|
||||
~DtlsEnvironment();
|
||||
static DtlsEnvironment& Instance();
|
||||
|
||||
private:
|
||||
DtlsEnvironment();
|
||||
void GenerateCertificateAndPrivateKey();
|
||||
void ReadCertificateAndPrivateKeyFromFiles();
|
||||
void CreateSslCtx();
|
||||
void GenerateFingerprints();
|
||||
|
||||
public:
|
||||
X509* certificate{ nullptr };
|
||||
EVP_PKEY* privateKey{ nullptr };
|
||||
SSL_CTX* sslCtx{ nullptr };
|
||||
std::vector<Fingerprint> localFingerprints;
|
||||
};
|
||||
|
||||
public:
|
||||
class Listener
|
||||
{
|
||||
@ -93,8 +114,6 @@ class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
};
|
||||
|
||||
public:
|
||||
static void ClassInit();
|
||||
static void ClassDestroy();
|
||||
static Role StringToRole(const std::string& role)
|
||||
{
|
||||
auto it = DtlsTransport::string2Role.find(role);
|
||||
@ -132,20 +151,9 @@ class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
}
|
||||
|
||||
private:
|
||||
static void GenerateCertificateAndPrivateKey();
|
||||
static void ReadCertificateAndPrivateKeyFromFiles();
|
||||
static void CreateSslCtx();
|
||||
static void GenerateFingerprints();
|
||||
|
||||
private:
|
||||
static X509* certificate;
|
||||
static EVP_PKEY* privateKey;
|
||||
static SSL_CTX* sslCtx;
|
||||
static uint8_t sslReadBuffer[];
|
||||
static std::map<std::string, Role> string2Role;
|
||||
static std::map<std::string, FingerprintAlgorithm> string2FingerprintAlgorithm;
|
||||
static std::map<FingerprintAlgorithm, std::string> fingerprintAlgorithm2String;
|
||||
static std::vector<Fingerprint> localFingerprints;
|
||||
static std::vector<SrtpCryptoSuiteMapEntry> srtpCryptoSuites;
|
||||
|
||||
public:
|
||||
@ -157,7 +165,7 @@ class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
void Run(Role localRole);
|
||||
std::vector<Fingerprint>& GetLocalFingerprints() const
|
||||
{
|
||||
return DtlsTransport::localFingerprints;
|
||||
return env->localFingerprints;
|
||||
}
|
||||
bool SetRemoteFingerprint(Fingerprint fingerprint);
|
||||
void ProcessDtlsData(const uint8_t* data, size_t len);
|
||||
@ -203,6 +211,7 @@ class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
void OnTimer();
|
||||
|
||||
private:
|
||||
DtlsEnvironment::Ptr env;
|
||||
EventPoller::Ptr poller;
|
||||
// Passed by argument.
|
||||
Listener* listener{ nullptr };
|
||||
@ -218,7 +227,9 @@ class DtlsTransport : public std::enable_shared_from_this<DtlsTransport>
|
||||
bool handshakeDone{ false };
|
||||
bool handshakeDoneNow{ false };
|
||||
std::string remoteCert;
|
||||
};
|
||||
static constexpr int SslReadBufferSize{ 65536 };
|
||||
uint8_t sslReadBuffer[SslReadBufferSize];
|
||||
};
|
||||
} // namespace RTC
|
||||
|
||||
#endif
|
||||
|
@ -3,10 +3,6 @@
|
||||
#include "Rtcp/Rtcp.h"
|
||||
|
||||
WebRtcTransport::WebRtcTransport() {
|
||||
static onceToken token([](){
|
||||
RTC::DtlsTransport::ClassInit();
|
||||
});
|
||||
|
||||
dtls_transport_ = std::make_shared<RTC::DtlsTransport>(EventPollerPool::Instance().getFirstPoller(), this);
|
||||
ice_server_ = std::make_shared<RTC::IceServer>(this, makeRandStr(4), makeRandStr(24));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user