2020-03-06 15:01:48 +00:00
|
|
|
/**
|
|
|
|
* The MIT License (MIT)
|
|
|
|
*
|
|
|
|
* Copyright (c) 2013-2020 Winlin
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
|
|
* the Software without restriction, including without limitation the rights to
|
|
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
* subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
* copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2020-05-11 04:07:55 +00:00
|
|
|
#include <srs_app_rtc_dtls.hpp>
|
2020-03-06 15:01:48 +00:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <srs_kernel_log.hpp>
|
2020-04-03 07:03:09 +00:00
|
|
|
#include <srs_kernel_error.hpp>
|
|
|
|
#include <srs_app_config.hpp>
|
2020-06-25 12:47:17 +00:00
|
|
|
#include <srs_core_autofree.hpp>
|
2020-06-27 03:13:53 +00:00
|
|
|
#include <srs_rtmp_stack.hpp>
|
2020-08-13 04:33:43 +00:00
|
|
|
#include <srs_app_utility.hpp>
|
2020-08-13 06:41:11 +00:00
|
|
|
#include <srs_kernel_rtc_rtp.hpp>
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-03-12 16:24:56 +00:00
|
|
|
#include <srtp2/srtp.h>
|
2020-04-03 05:43:13 +00:00
|
|
|
#include <openssl/ssl.h>
|
2020-08-04 12:08:21 +00:00
|
|
|
#include <openssl/err.h>
|
2020-03-12 16:24:56 +00:00
|
|
|
|
2020-06-24 12:21:36 +00:00
|
|
|
// The return value of verify_callback controls the strategy of the further verification process. If verify_callback
|
|
|
|
// returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is
|
|
|
|
// set, a verification failure alert is sent to the peer and the TLS/SSL handshake is terminated. If verify_callback
|
|
|
|
// returns 1, the verification process is continued. If verify_callback always returns 1, the TLS/SSL handshake will
|
|
|
|
// not be terminated with respect to verification failures and the connection will be established. The calling process
|
|
|
|
// can however retrieve the error code of the last verification error using SSL_get_verify_result(3) or by maintaining
|
|
|
|
// its own error storage managed by verify_callback.
|
|
|
|
// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
|
2020-08-18 11:20:07 +00:00
|
|
|
int srs_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
2020-06-24 12:21:36 +00:00
|
|
|
{
|
|
|
|
// Always OK, we don't check the certificate of client,
|
|
|
|
// because we allow client self-sign certificate.
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-08-18 11:20:07 +00:00
|
|
|
SSL_CTX* srs_build_dtls_ctx(SrsDtlsVersion version)
|
|
|
|
{
|
|
|
|
SSL_CTX* dtls_ctx;
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2
|
|
|
|
dtls_ctx = SSL_CTX_new(DTLSv1_method());
|
|
|
|
#else
|
|
|
|
if (version == SrsDtlsVersion1_0) {
|
|
|
|
dtls_ctx = SSL_CTX_new(DTLSv1_method());
|
|
|
|
} else if (version == SrsDtlsVersion1_2) {
|
|
|
|
dtls_ctx = SSL_CTX_new(DTLSv1_2_method());
|
|
|
|
} else {
|
|
|
|
// SrsDtlsVersionAuto, use version-flexible DTLS methods
|
|
|
|
dtls_ctx = SSL_CTX_new(DTLS_method());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (_srs_rtc_dtls_certificate->is_ecdsa()) { // By ECDSA, https://stackoverflow.com/a/6006898
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L // v1.0.2
|
|
|
|
// For ECDSA, we could set the curves list.
|
|
|
|
// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set1_curves_list.html
|
|
|
|
SSL_CTX_set1_curves_list(dtls_ctx, "P-521:P-384:P-256");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// For openssl <1.1, we must set the ECDH manually.
|
|
|
|
// @see https://stackoverrun.com/cn/q/10791887
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L // v1.1.x
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2
|
|
|
|
SSL_CTX_set_tmp_ecdh(dtls_ctx, _srs_rtc_dtls_certificate->get_ecdsa_key());
|
|
|
|
#else
|
|
|
|
SSL_CTX_set_ecdh_auto(dtls_ctx, 1);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup DTLS context.
|
|
|
|
if (true) {
|
|
|
|
// We use "ALL", while you can use "DEFAULT" means "ALL:!EXPORT:!LOW:!aNULL:!eNULL:!SSLv2"
|
|
|
|
// @see https://www.openssl.org/docs/man1.0.2/man1/ciphers.html
|
|
|
|
srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL") == 1);
|
|
|
|
|
|
|
|
// Setup the certificate.
|
|
|
|
srs_assert(SSL_CTX_use_certificate(dtls_ctx, _srs_rtc_dtls_certificate->get_cert()) == 1);
|
|
|
|
srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, _srs_rtc_dtls_certificate->get_public_key()) == 1);
|
|
|
|
|
|
|
|
// Server will send Certificate Request.
|
|
|
|
// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
|
|
|
|
// TODO: FIXME: Config it, default to off to make the packet smaller.
|
|
|
|
SSL_CTX_set_verify(dtls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, srs_verify_callback);
|
|
|
|
// The depth count is "level 0:peer certificate", "level 1: CA certificate",
|
|
|
|
// "level 2: higher level CA certificate", and so on.
|
|
|
|
// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_verify.html
|
|
|
|
SSL_CTX_set_verify_depth(dtls_ctx, 4);
|
|
|
|
|
|
|
|
// Whether we should read as many input bytes as possible (for non-blocking reads) or not.
|
|
|
|
// @see https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_read_ahead.html
|
|
|
|
SSL_CTX_set_read_ahead(dtls_ctx, 1);
|
|
|
|
|
|
|
|
// TODO: Maybe we can use SRTP-GCM in future.
|
|
|
|
// @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701
|
|
|
|
// @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ
|
|
|
|
// @remark Only support SRTP_AES128_CM_SHA1_80, please read ssl/d1_srtp.c
|
|
|
|
srs_assert(SSL_CTX_set_tlsext_use_srtp(dtls_ctx, "SRTP_AES128_CM_SHA1_80") == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return dtls_ctx;
|
|
|
|
}
|
|
|
|
|
2020-06-24 12:03:21 +00:00
|
|
|
SrsDtlsCertificate::SrsDtlsCertificate()
|
2020-03-06 15:01:48 +00:00
|
|
|
{
|
2020-08-18 11:20:07 +00:00
|
|
|
ecdsa_mode = true;
|
2020-06-24 09:09:26 +00:00
|
|
|
dtls_cert = NULL;
|
|
|
|
dtls_pkey = NULL;
|
|
|
|
eckey = NULL;
|
2020-03-06 15:01:48 +00:00
|
|
|
}
|
|
|
|
|
2020-06-24 12:03:21 +00:00
|
|
|
SrsDtlsCertificate::~SrsDtlsCertificate()
|
2020-03-06 15:01:48 +00:00
|
|
|
{
|
2020-06-24 09:09:26 +00:00
|
|
|
if (eckey) {
|
|
|
|
EC_KEY_free(eckey);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dtls_pkey) {
|
|
|
|
EVP_PKEY_free(dtls_pkey);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dtls_cert) {
|
|
|
|
X509_free(dtls_cert);
|
|
|
|
}
|
2020-03-06 15:01:48 +00:00
|
|
|
}
|
|
|
|
|
2020-06-24 12:03:21 +00:00
|
|
|
srs_error_t SrsDtlsCertificate::initialize()
|
2020-03-06 15:01:48 +00:00
|
|
|
{
|
2020-04-03 07:03:09 +00:00
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-04-03 07:05:04 +00:00
|
|
|
// Initialize once.
|
2020-06-24 09:09:26 +00:00
|
|
|
if (dtls_cert) {
|
2020-04-03 07:05:04 +00:00
|
|
|
return err;
|
|
|
|
}
|
2020-03-12 16:24:56 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L // v1.1.x
|
|
|
|
// Initialize SSL library by registering algorithms
|
|
|
|
// The SSL_library_init() and OpenSSL_add_ssl_algorithms() functions were deprecated in OpenSSL 1.1.0 by OPENSSL_init_ssl().
|
|
|
|
// @see https://www.openssl.org/docs/man1.1.0/man3/OpenSSL_add_ssl_algorithms.html
|
|
|
|
// @see https://web.archive.org/web/20150806185102/http://sctp.fh-muenster.de:80/dtls/dtls_udp_echo.c
|
|
|
|
OpenSSL_add_ssl_algorithms();
|
|
|
|
#endif
|
|
|
|
|
2020-04-03 07:05:04 +00:00
|
|
|
// Initialize SRTP first.
|
|
|
|
srs_assert(srtp_init() == 0);
|
|
|
|
|
2020-04-03 07:03:09 +00:00
|
|
|
// Whether use ECDSA certificate.
|
2020-06-24 12:03:21 +00:00
|
|
|
ecdsa_mode = _srs_config->get_rtc_server_ecdsa();
|
2020-04-03 07:03:09 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
// Create keys by RSA or ECDSA.
|
2020-06-24 09:09:26 +00:00
|
|
|
dtls_pkey = EVP_PKEY_new();
|
2020-04-03 05:43:13 +00:00
|
|
|
srs_assert(dtls_pkey);
|
2020-06-24 12:03:21 +00:00
|
|
|
if (!ecdsa_mode) { // By RSA
|
2020-04-03 05:43:13 +00:00
|
|
|
RSA* rsa = RSA_new();
|
|
|
|
srs_assert(rsa);
|
|
|
|
|
|
|
|
// Initialize the big-number for private key.
|
|
|
|
BIGNUM* exponent = BN_new();
|
|
|
|
srs_assert(exponent);
|
|
|
|
BN_set_word(exponent, RSA_F4);
|
|
|
|
|
|
|
|
// Generates a key pair and stores it in the RSA structure provided in rsa.
|
|
|
|
// @see https://www.openssl.org/docs/man1.0.2/man3/RSA_generate_key_ex.html
|
|
|
|
int key_bits = 1024;
|
|
|
|
RSA_generate_key_ex(rsa, key_bits, exponent, NULL);
|
|
|
|
|
|
|
|
// @see https://www.openssl.org/docs/man1.1.0/man3/EVP_PKEY_type.html
|
|
|
|
srs_assert(EVP_PKEY_set1_RSA(dtls_pkey, rsa) == 1);
|
|
|
|
|
|
|
|
RSA_free(rsa);
|
|
|
|
BN_free(exponent);
|
|
|
|
}
|
2020-06-24 12:03:21 +00:00
|
|
|
if (ecdsa_mode) { // By ECDSA, https://stackoverflow.com/a/6006898
|
2020-06-24 09:09:26 +00:00
|
|
|
eckey = EC_KEY_new();
|
2020-04-03 05:43:13 +00:00
|
|
|
srs_assert(eckey);
|
|
|
|
|
|
|
|
// Should use the curves in ClientHello.supported_groups
|
|
|
|
// For example:
|
|
|
|
// Supported Group: x25519 (0x001d)
|
|
|
|
// Supported Group: secp256r1 (0x0017)
|
|
|
|
// Supported Group: secp384r1 (0x0018)
|
|
|
|
// @remark The curve NID_secp256k1 is not secp256r1, k1 != r1.
|
|
|
|
// TODO: FIXME: Parse ClientHello and choose the curve.
|
|
|
|
// Note that secp256r1 in openssl is called NID_X9_62_prime256v1, not NID_secp256k1
|
|
|
|
// @see https://stackoverflow.com/questions/41950056/openssl1-1-0-b-is-not-support-secp256r1openssl-ecparam-list-curves
|
|
|
|
EC_GROUP* ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
|
|
|
|
//EC_GROUP* ecgroup = EC_GROUP_new_by_curve_name(NID_secp384r1);
|
|
|
|
srs_assert(ecgroup);
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L // v1.1.x
|
|
|
|
// For openssl 1.0, we must set the group parameters, so that cert is ok.
|
|
|
|
// @see https://github.com/monero-project/monero/blob/master/contrib/epee/src/net_ssl.cpp#L225
|
|
|
|
EC_GROUP_set_asn1_flag(ecgroup, OPENSSL_EC_NAMED_CURVE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
srs_assert(EC_KEY_set_group(eckey, ecgroup) == 1);
|
|
|
|
srs_assert(EC_KEY_generate_key(eckey) == 1);
|
|
|
|
|
|
|
|
// @see https://www.openssl.org/docs/man1.1.0/man3/EVP_PKEY_type.html
|
|
|
|
srs_assert(EVP_PKEY_set1_EC_KEY(dtls_pkey, eckey) == 1);
|
|
|
|
|
|
|
|
EC_GROUP_free(ecgroup);
|
|
|
|
}
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
// Create certificate, from previous generated pkey.
|
|
|
|
// TODO: Support ECDSA certificate.
|
2020-06-24 09:09:26 +00:00
|
|
|
dtls_cert = X509_new();
|
2020-03-06 15:01:48 +00:00
|
|
|
srs_assert(dtls_cert);
|
2020-04-03 05:43:13 +00:00
|
|
|
if (true) {
|
|
|
|
X509_NAME* subject = X509_NAME_new();
|
|
|
|
srs_assert(subject);
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
int serial = rand();
|
|
|
|
ASN1_INTEGER_set(X509_get_serialNumber(dtls_cert), serial);
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
const std::string& aor = RTMP_SIG_SRS_DOMAIN;
|
2020-04-03 05:43:13 +00:00
|
|
|
X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *) aor.data(), aor.size(), -1, 0);
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
X509_set_issuer_name(dtls_cert, subject);
|
|
|
|
X509_set_subject_name(dtls_cert, subject);
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
int expire_day = 365;
|
|
|
|
const long cert_duration = 60*60*24*expire_day;
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
X509_gmtime_adj(X509_get_notBefore(dtls_cert), 0);
|
|
|
|
X509_gmtime_adj(X509_get_notAfter(dtls_cert), cert_duration);
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
X509_set_version(dtls_cert, 2);
|
|
|
|
srs_assert(X509_set_pubkey(dtls_cert, dtls_pkey) == 1);
|
|
|
|
srs_assert(X509_sign(dtls_cert, dtls_pkey, EVP_sha1()) != 0);
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
X509_NAME_free(subject);
|
|
|
|
}
|
2020-03-06 15:01:48 +00:00
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
// Show DTLS fingerprint
|
|
|
|
if (true) {
|
|
|
|
char fp[100] = {0};
|
|
|
|
char *p = fp;
|
|
|
|
unsigned char md[EVP_MAX_MD_SIZE];
|
|
|
|
unsigned int n = 0;
|
|
|
|
|
|
|
|
// TODO: FIXME: Unused variable.
|
|
|
|
/*int r = */X509_digest(dtls_cert, EVP_sha256(), md, &n);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < n; i++, ++p) {
|
|
|
|
sprintf(p, "%02X", md[i]);
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
if(i < (n-1)) {
|
|
|
|
*p = ':';
|
|
|
|
} else {
|
|
|
|
*p = '\0';
|
|
|
|
}
|
2020-03-06 15:01:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 05:43:13 +00:00
|
|
|
fingerprint.assign(fp, strlen(fp));
|
|
|
|
srs_trace("fingerprint=%s", fingerprint.c_str());
|
|
|
|
}
|
2020-04-03 07:03:09 +00:00
|
|
|
|
|
|
|
return err;
|
2020-03-06 15:01:48 +00:00
|
|
|
}
|
2020-05-02 01:48:04 +00:00
|
|
|
|
2020-06-24 12:03:21 +00:00
|
|
|
X509* SrsDtlsCertificate::get_cert()
|
|
|
|
{
|
|
|
|
return dtls_cert;
|
|
|
|
}
|
|
|
|
|
|
|
|
EVP_PKEY* SrsDtlsCertificate::get_public_key()
|
|
|
|
{
|
|
|
|
return dtls_pkey;
|
|
|
|
}
|
|
|
|
|
|
|
|
EC_KEY* SrsDtlsCertificate::get_ecdsa_key()
|
|
|
|
{
|
|
|
|
return eckey;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string SrsDtlsCertificate::get_fingerprint()
|
|
|
|
{
|
|
|
|
return fingerprint;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsDtlsCertificate::is_ecdsa()
|
|
|
|
{
|
|
|
|
return ecdsa_mode;
|
|
|
|
}
|
|
|
|
|
2020-06-25 04:03:21 +00:00
|
|
|
ISrsDtlsCallback::ISrsDtlsCallback()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ISrsDtlsCallback::~ISrsDtlsCallback()
|
|
|
|
{
|
|
|
|
}
|
2020-06-24 12:03:21 +00:00
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
SrsDtlsImpl::SrsDtlsImpl(ISrsDtlsCallback* callback)
|
2020-06-24 12:03:21 +00:00
|
|
|
{
|
2020-07-15 05:11:35 +00:00
|
|
|
dtls_ctx = NULL;
|
|
|
|
dtls = NULL;
|
2020-08-21 13:14:18 +00:00
|
|
|
bio_in = NULL;
|
|
|
|
bio_out = NULL;
|
2020-07-15 05:11:35 +00:00
|
|
|
|
2020-08-18 11:20:07 +00:00
|
|
|
callback_ = callback;
|
2020-08-13 06:22:43 +00:00
|
|
|
handshake_done_for_us = false;
|
2020-06-27 03:13:53 +00:00
|
|
|
|
2020-08-13 06:41:11 +00:00
|
|
|
last_outgoing_packet_cache = new uint8_t[kRtpPacketSize];
|
|
|
|
nn_last_outgoing_packet = 0;
|
|
|
|
|
2020-06-27 03:13:53 +00:00
|
|
|
version_ = SrsDtlsVersionAuto;
|
2020-06-24 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
SrsDtlsImpl::~SrsDtlsImpl()
|
2020-06-24 12:03:21 +00:00
|
|
|
{
|
2020-06-25 04:03:21 +00:00
|
|
|
if (dtls_ctx) {
|
|
|
|
SSL_CTX_free(dtls_ctx);
|
|
|
|
dtls_ctx = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dtls) {
|
|
|
|
// this function will free bio_in and bio_out
|
|
|
|
SSL_free(dtls);
|
|
|
|
dtls = NULL;
|
|
|
|
}
|
2020-08-13 06:41:11 +00:00
|
|
|
|
|
|
|
srs_freepa(last_outgoing_packet_cache);
|
2020-06-24 12:03:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
srs_error_t SrsDtlsImpl::initialize(std::string version)
|
2020-06-25 04:03:21 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-06-27 03:13:53 +00:00
|
|
|
if (version == "dtls1.0") {
|
|
|
|
version_ = SrsDtlsVersion1_0;
|
|
|
|
} else if (version == "dtls1.2") {
|
|
|
|
version_ = SrsDtlsVersion1_2;
|
|
|
|
} else {
|
|
|
|
version_ = SrsDtlsVersionAuto;
|
|
|
|
}
|
|
|
|
|
2020-08-18 11:20:07 +00:00
|
|
|
dtls_ctx = srs_build_dtls_ctx(version_);
|
2020-06-27 03:13:53 +00:00
|
|
|
|
2020-06-25 04:03:21 +00:00
|
|
|
if ((dtls = SSL_new(dtls_ctx)) == NULL) {
|
|
|
|
return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((bio_in = BIO_new(BIO_s_mem())) == NULL) {
|
|
|
|
return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((bio_out = BIO_new(BIO_s_mem())) == NULL) {
|
|
|
|
BIO_free(bio_in);
|
|
|
|
return srs_error_new(ERROR_OpenSslBIONew, "BIO_new out");
|
|
|
|
}
|
|
|
|
|
|
|
|
SSL_set_bio(dtls, bio_in, bio_out);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
srs_error_t SrsDtlsImpl::on_dtls(char* data, int nb_data)
|
2020-06-25 04:03:21 +00:00
|
|
|
{
|
2020-08-13 08:21:01 +00:00
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
if ((err = do_on_dtls(data, nb_data)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "on_dtls size=%u, data=[%s]", nb_data,
|
|
|
|
srs_string_dumps_hex(data, nb_data, 32).c_str());
|
2020-06-25 04:03:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 08:21:01 +00:00
|
|
|
return err;
|
2020-06-25 04:03:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
srs_error_t SrsDtlsImpl::do_on_dtls(char* data, int nb_data)
|
2020-08-13 04:33:43 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
int r0 = 0;
|
|
|
|
if ((r0 = BIO_reset(bio_in)) != 1) {
|
|
|
|
return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset r0=%d", r0);
|
2020-06-25 04:03:21 +00:00
|
|
|
}
|
2020-08-13 04:33:43 +00:00
|
|
|
if ((r0 = BIO_reset(bio_out)) != 1) {
|
|
|
|
return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset r0=%d", r0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trace the detail of DTLS packet.
|
2020-08-18 11:20:07 +00:00
|
|
|
state_trace((uint8_t*)data, nb_data, true, r0, SSL_ERROR_NONE, false, false);
|
2020-06-25 04:03:21 +00:00
|
|
|
|
2020-08-13 04:33:43 +00:00
|
|
|
if ((r0 = BIO_write(bio_in, data, nb_data)) <= 0) {
|
2020-06-25 04:03:21 +00:00
|
|
|
// TODO: 0 or -1 maybe block, use BIO_should_retry to check.
|
2020-08-13 04:33:43 +00:00
|
|
|
return srs_error_new(ERROR_OpenSslBIOWrite, "BIO_write r0=%d", r0);
|
2020-06-25 04:03:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 06:22:43 +00:00
|
|
|
// Always do handshake, even the handshake is done, because the last DTLS packet maybe dropped,
|
|
|
|
// so we thought the DTLS is done, but client need us to retransmit the last packet.
|
|
|
|
if ((err = do_handshake()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "do handshake");
|
2020-08-13 04:36:04 +00:00
|
|
|
}
|
2020-08-13 05:38:55 +00:00
|
|
|
|
2020-08-13 04:36:04 +00:00
|
|
|
while (BIO_ctrl_pending(bio_in) > 0) {
|
2020-08-13 06:22:43 +00:00
|
|
|
char buf[8092];
|
|
|
|
int nb = SSL_read(dtls, buf, sizeof(buf));
|
2020-08-18 11:20:07 +00:00
|
|
|
if (nb <= 0) {
|
2020-08-13 04:36:04 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-08-13 06:22:43 +00:00
|
|
|
srs_trace("DTLS: read nb=%d, data=[%s]", nb, srs_string_dumps_hex(buf, nb, 32).c_str());
|
2020-08-13 04:36:04 +00:00
|
|
|
|
2020-08-18 11:20:07 +00:00
|
|
|
if ((err = callback_->on_dtls_application_data(buf, nb)) != srs_success) {
|
2020-08-13 04:36:04 +00:00
|
|
|
return srs_error_wrap(err, "on DTLS data, size=%u, data=[%s]", nb,
|
2020-08-13 06:22:43 +00:00
|
|
|
srs_string_dumps_hex(buf, nb, 32).c_str());
|
2020-06-25 04:03:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
srs_error_t SrsDtlsImpl::do_handshake()
|
2020-08-13 05:38:55 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-18 06:45:30 +00:00
|
|
|
// Do handshake and get the result.
|
|
|
|
int r0 = SSL_do_handshake(dtls);
|
|
|
|
int r1 = SSL_get_error(dtls, r0);
|
2020-08-13 05:38:55 +00:00
|
|
|
|
2020-08-18 11:20:07 +00:00
|
|
|
// Fatal SSL error, for example, no available suite when peer is DTLS 1.0 while we are DTLS 1.2.
|
|
|
|
if (r0 < 0 && (r1 != SSL_ERROR_NONE && r1 != SSL_ERROR_WANT_READ && r1 != SSL_ERROR_WANT_WRITE)) {
|
2020-08-18 11:29:35 +00:00
|
|
|
return srs_error_new(ERROR_RTC_DTLS, "handshake r0=%d, r1=%d", r0, r1);
|
2020-08-18 11:20:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// OK, Handshake is done, note that it maybe done many times.
|
2020-08-18 06:45:30 +00:00
|
|
|
if (r1 == SSL_ERROR_NONE) {
|
|
|
|
handshake_done_for_us = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The data to send out to peer.
|
2020-08-13 06:22:43 +00:00
|
|
|
uint8_t* data = NULL;
|
|
|
|
int size = BIO_get_mem_data(bio_out, &data);
|
2020-08-13 05:38:55 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
// Callback when got SSL original data.
|
2020-08-13 06:41:11 +00:00
|
|
|
bool cache = false;
|
2020-08-19 11:06:00 +00:00
|
|
|
on_ssl_out_data(data, size, cache);
|
2020-08-18 11:20:07 +00:00
|
|
|
state_trace((uint8_t*)data, size, false, r0, r1, cache, false);
|
2020-08-13 06:41:11 +00:00
|
|
|
|
|
|
|
// Update the packet cache.
|
|
|
|
if (size > 0 && data != last_outgoing_packet_cache && size < kRtpPacketSize) {
|
|
|
|
memcpy(last_outgoing_packet_cache, data, size);
|
|
|
|
nn_last_outgoing_packet = size;
|
|
|
|
}
|
2020-08-13 05:38:55 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
// Callback for the final output data, before send-out.
|
|
|
|
if ((err = on_final_out_data(data, size)) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "handle");
|
2020-08-13 08:21:01 +00:00
|
|
|
}
|
|
|
|
|
2020-08-18 11:20:07 +00:00
|
|
|
if (size > 0 && (err = callback_->write_dtls_data(data, size)) != srs_success) {
|
2020-08-13 06:22:43 +00:00
|
|
|
return srs_error_wrap(err, "dtls send size=%u, data=[%s]", size,
|
|
|
|
srs_string_dumps_hex((char*)data, size, 32).c_str());
|
2020-08-13 05:43:23 +00:00
|
|
|
}
|
|
|
|
|
2020-08-13 06:22:43 +00:00
|
|
|
if (handshake_done_for_us) {
|
2020-08-19 11:06:00 +00:00
|
|
|
if (((err = on_handshake_done()) != srs_success)) {
|
|
|
|
return srs_error_wrap(err, "done");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
void SrsDtlsImpl::state_trace(uint8_t* data, int length, bool incoming, int r0, int r1, bool cache, bool arq)
|
2020-08-19 11:06:00 +00:00
|
|
|
{
|
|
|
|
uint8_t content_type = 0;
|
|
|
|
if (length >= 1) {
|
|
|
|
content_type = (uint8_t)data[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t size = 0;
|
|
|
|
if (length >= 13) {
|
|
|
|
size = uint16_t(data[11])<<8 | uint16_t(data[12]);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t handshake_type = 0;
|
|
|
|
if (length >= 14) {
|
|
|
|
handshake_type = (uint8_t)data[13];
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_trace("DTLS: %s %s, done=%u, cache=%u, arq=%u, r0=%d, r1=%d, len=%u, cnt=%u, size=%u, hs=%u",
|
|
|
|
(is_dtls_client()? "Active":"Passive"), (incoming? "RECV":"SEND"), handshake_done_for_us, cache, arq,
|
|
|
|
r0, r1, length, content_type, size, handshake_type);
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:09:31 +00:00
|
|
|
const int SRTP_MASTER_KEY_KEY_LEN = 16;
|
|
|
|
const int SRTP_MASTER_KEY_SALT_LEN = 14;
|
2020-08-19 11:11:42 +00:00
|
|
|
srs_error_t SrsDtlsImpl::get_srtp_key(std::string& recv_key, std::string& send_key)
|
2020-08-19 11:09:31 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server
|
|
|
|
static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp";
|
|
|
|
if (!SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) {
|
2020-08-20 10:46:11 +00:00
|
|
|
return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL export key r0=%lu", ERR_get_error());
|
2020-08-19 11:09:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t offset = 0;
|
|
|
|
|
|
|
|
std::string client_master_key(reinterpret_cast<char*>(material), SRTP_MASTER_KEY_KEY_LEN);
|
|
|
|
offset += SRTP_MASTER_KEY_KEY_LEN;
|
|
|
|
std::string server_master_key(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_KEY_LEN);
|
|
|
|
offset += SRTP_MASTER_KEY_KEY_LEN;
|
|
|
|
std::string client_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
|
|
|
offset += SRTP_MASTER_KEY_SALT_LEN;
|
|
|
|
std::string server_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
|
|
|
|
|
|
|
if (is_dtls_client()) {
|
|
|
|
recv_key = server_master_key + server_master_salt;
|
|
|
|
send_key = client_master_key + client_master_salt;
|
|
|
|
} else {
|
|
|
|
recv_key = client_master_key + client_master_salt;
|
|
|
|
send_key = server_master_key + server_master_salt;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
SrsDtlsClientImpl::SrsDtlsClientImpl(ISrsDtlsCallback* callback) : SrsDtlsImpl(callback)
|
2020-08-19 11:06:00 +00:00
|
|
|
{
|
|
|
|
trd = NULL;
|
|
|
|
state_ = SrsDtlsStateInit;
|
|
|
|
arq_first = 50 * SRS_UTIME_MILLISECONDS;
|
|
|
|
arq_interval = 100 * SRS_UTIME_MILLISECONDS;
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsDtlsClientImpl::~SrsDtlsClientImpl()
|
|
|
|
{
|
|
|
|
srs_freep(trd);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtlsClientImpl::initialize(std::string version)
|
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
if ((err = SrsDtlsImpl::initialize(version)) != srs_success) {
|
2020-08-19 11:06:00 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dtls setup active, as client role.
|
|
|
|
SSL_set_connect_state(dtls);
|
|
|
|
SSL_set_max_send_fragment(dtls, kRtpPacketSize);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtlsClientImpl::start_active_handshake()
|
|
|
|
{
|
|
|
|
return do_handshake();
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtlsClientImpl::on_dtls(char* data, int nb_data)
|
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
// When got packet, stop the ARQ if server in the first ARQ state SrsDtlsStateServerHello.
|
|
|
|
// @note But for ARQ state, we should never stop the ARQ, for example, we are in the second ARQ sate
|
|
|
|
// SrsDtlsStateServerDone, but we got previous late wrong packet ServeHello, which is not the expect
|
|
|
|
// packet SessionNewTicket, we should never stop the ARQ thread.
|
|
|
|
if (state_ == SrsDtlsStateServerHello) {
|
|
|
|
stop_arq();
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
if ((err = SrsDtlsImpl::on_dtls(data, nb_data)) != srs_success) {
|
2020-08-19 11:06:00 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsDtlsClientImpl::on_ssl_out_data(uint8_t*& data, int& size, bool& cached)
|
|
|
|
{
|
|
|
|
// DTLS client use ARQ thread to send cached packet.
|
|
|
|
cached = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtlsClientImpl::on_final_out_data(uint8_t* data, int size)
|
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
// Driven ARQ and state for DTLS client.
|
|
|
|
// If we are sending client hello, change from init to new state.
|
|
|
|
if (state_ == SrsDtlsStateInit && size > 14 && data[13] == 1) {
|
|
|
|
state_ = SrsDtlsStateClientHello;
|
|
|
|
}
|
|
|
|
// If we are sending certificate, change from SrsDtlsStateServerHello to new state.
|
|
|
|
if (state_ == SrsDtlsStateServerHello && size > 14 && data[13] == 11) {
|
|
|
|
state_ = SrsDtlsStateClientCertificate;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to start the ARQ for client.
|
|
|
|
if ((state_ == SrsDtlsStateClientHello || state_ == SrsDtlsStateClientCertificate)) {
|
|
|
|
if (state_ == SrsDtlsStateClientHello) {
|
|
|
|
state_ = SrsDtlsStateServerHello;
|
|
|
|
} else if (state_ == SrsDtlsStateClientCertificate) {
|
|
|
|
state_ = SrsDtlsStateServerDone;
|
2020-08-13 08:21:01 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
if ((err = start_arq()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "start arq");
|
2020-08-13 05:38:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
srs_error_t SrsDtlsClientImpl::on_handshake_done()
|
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
// When handshake done, stop the ARQ.
|
|
|
|
state_ = SrsDtlsStateClientDone;
|
|
|
|
stop_arq();
|
|
|
|
|
|
|
|
// Notify connection the DTLS is done.
|
|
|
|
if (((err = callback_->on_dtls_handshake_done()) != srs_success)) {
|
|
|
|
return srs_error_wrap(err, "dtls done");
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SrsDtlsClientImpl::is_dtls_client()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtlsClientImpl::start_arq()
|
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
srs_info("start arq, state=%u", state_);
|
|
|
|
|
|
|
|
// Dispose the previous ARQ thread.
|
|
|
|
srs_freep(trd);
|
|
|
|
trd = new SrsSTCoroutine("dtls", this, _srs_context->get_id());
|
|
|
|
|
|
|
|
// We should start the ARQ thread for DTLS client.
|
|
|
|
if ((err = trd->start()) != srs_success) {
|
|
|
|
return srs_error_wrap(err, "arq start");
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SrsDtlsClientImpl::stop_arq()
|
|
|
|
{
|
|
|
|
srs_info("stop arq, state=%u", state_);
|
|
|
|
srs_freep(trd);
|
|
|
|
srs_info("stop arq, done");
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtlsClientImpl::cycle()
|
2020-08-13 08:21:01 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
// The first ARQ delay.
|
2020-08-19 09:22:34 +00:00
|
|
|
srs_usleep(arq_first);
|
2020-08-13 08:21:01 +00:00
|
|
|
|
2020-08-19 13:28:06 +00:00
|
|
|
// Limit the max retry for ARQ.
|
|
|
|
for (int arq_retry_left = 7; arq_retry_left > 0; arq_retry_left--) {
|
|
|
|
srs_info("arq cycle, state=%u, retry=%d", state_, arq_retry_left);
|
2020-08-13 08:21:01 +00:00
|
|
|
|
|
|
|
// We ignore any error for ARQ thread.
|
|
|
|
if ((err = trd->pull()) != srs_success) {
|
|
|
|
srs_freep(err);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If done, should stop ARQ.
|
|
|
|
if (handshake_done_for_us) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For DTLS client ARQ, the state should be specified.
|
2020-08-13 08:27:50 +00:00
|
|
|
if (state_ != SrsDtlsStateServerHello && state_ != SrsDtlsStateServerDone) {
|
2020-08-13 08:21:01 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to retransmit the packet.
|
|
|
|
uint8_t* data = last_outgoing_packet_cache;
|
|
|
|
int size = nn_last_outgoing_packet;
|
|
|
|
|
|
|
|
if (size) {
|
|
|
|
// Trace the detail of DTLS packet.
|
2020-08-18 11:20:07 +00:00
|
|
|
state_trace((uint8_t*)data, size, false, 1, SSL_ERROR_NONE, true, true);
|
2020-08-13 08:21:01 +00:00
|
|
|
|
2020-08-18 11:20:07 +00:00
|
|
|
if ((err = callback_->write_dtls_data(data, size)) != srs_success) {
|
2020-08-13 08:21:01 +00:00
|
|
|
return srs_error_wrap(err, "dtls send size=%u, data=[%s]", size,
|
|
|
|
srs_string_dumps_hex((char*)data, size, 32).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Use ARQ step timeouts.
|
2020-08-19 09:22:34 +00:00
|
|
|
srs_usleep(arq_interval);
|
2020-08-13 08:21:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
SrsDtlsServerImpl::SrsDtlsServerImpl(ISrsDtlsCallback* callback) : SrsDtlsImpl(callback)
|
2020-08-13 04:33:43 +00:00
|
|
|
{
|
2020-08-19 11:06:00 +00:00
|
|
|
}
|
2020-08-13 05:23:45 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
SrsDtlsServerImpl::~SrsDtlsServerImpl()
|
|
|
|
{
|
2020-08-13 08:21:01 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
srs_error_t SrsDtlsServerImpl::initialize(std::string version)
|
2020-08-13 08:21:01 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-19 11:11:42 +00:00
|
|
|
if ((err = SrsDtlsImpl::initialize(version)) != srs_success) {
|
2020-08-13 08:21:01 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
// Dtls setup passive, as server role.
|
|
|
|
SSL_set_accept_state(dtls);
|
2020-08-13 08:21:01 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
return err;
|
|
|
|
}
|
2020-08-13 08:21:01 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
srs_error_t SrsDtlsServerImpl::start_active_handshake()
|
|
|
|
{
|
|
|
|
return srs_success;
|
|
|
|
}
|
2020-08-13 08:21:01 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
void SrsDtlsServerImpl::on_ssl_out_data(uint8_t*& data, int& size, bool& cached)
|
|
|
|
{
|
|
|
|
// If outgoing packet is empty, we use the last cache.
|
|
|
|
// @remark Only for DTLS server, because DTLS client use ARQ thread to send cached packet.
|
|
|
|
if (size <= 0 && nn_last_outgoing_packet) {
|
|
|
|
size = nn_last_outgoing_packet;
|
|
|
|
data = last_outgoing_packet_cache;
|
|
|
|
cached = true;
|
|
|
|
}
|
2020-08-13 08:21:01 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
srs_error_t SrsDtlsServerImpl::on_final_out_data(uint8_t* data, int size)
|
2020-08-13 08:21:01 +00:00
|
|
|
{
|
2020-08-19 11:06:00 +00:00
|
|
|
return srs_success;
|
2020-08-13 04:33:43 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
srs_error_t SrsDtlsServerImpl::on_handshake_done()
|
2020-06-25 04:03:21 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
// Notify connection the DTLS is done.
|
|
|
|
if (((err = callback_->on_dtls_handshake_done()) != srs_success)) {
|
|
|
|
return srs_error_wrap(err, "dtls done");
|
2020-06-25 04:03:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
return err;
|
|
|
|
}
|
2020-06-25 06:50:14 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
bool SrsDtlsServerImpl::is_dtls_client()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2020-06-25 06:50:14 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
SrsDtls::SrsDtls(ISrsDtlsCallback* callback)
|
|
|
|
{
|
|
|
|
callback_ = callback;
|
|
|
|
impl = new SrsDtlsServerImpl(callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsDtls::~SrsDtls()
|
|
|
|
{
|
|
|
|
srs_freep(impl);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtls::initialize(std::string role, std::string version)
|
|
|
|
{
|
|
|
|
srs_freep(impl);
|
|
|
|
if (role == "active") {
|
|
|
|
impl = new SrsDtlsClientImpl(callback_);
|
2020-06-27 03:13:53 +00:00
|
|
|
} else {
|
2020-08-19 11:06:00 +00:00
|
|
|
impl = new SrsDtlsServerImpl(callback_);
|
2020-06-27 03:13:53 +00:00
|
|
|
}
|
2020-06-25 06:50:14 +00:00
|
|
|
|
2020-08-19 11:06:00 +00:00
|
|
|
return impl->initialize(version);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtls::start_active_handshake()
|
|
|
|
{
|
|
|
|
return impl->start_active_handshake();
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtls::on_dtls(char* data, int nb_data)
|
|
|
|
{
|
|
|
|
return impl->on_dtls(data, nb_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key)
|
|
|
|
{
|
|
|
|
return impl->get_srtp_key(recv_key, send_key);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSRTP::SrsSRTP()
|
|
|
|
{
|
2020-06-25 12:47:17 +00:00
|
|
|
recv_ctx_ = NULL;
|
|
|
|
send_ctx_ = NULL;
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SrsSRTP::~SrsSRTP()
|
|
|
|
{
|
2020-06-25 12:47:17 +00:00
|
|
|
if (recv_ctx_) {
|
|
|
|
srtp_dealloc(recv_ctx_);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (send_ctx_) {
|
|
|
|
srtp_dealloc(send_ctx_);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
srs_error_t SrsSRTP::initialize(string recv_key, std::string send_key)
|
2020-06-25 06:50:14 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
|
|
|
srtp_policy_t policy;
|
|
|
|
bzero(&policy, sizeof(policy));
|
|
|
|
|
|
|
|
// TODO: Maybe we can use SRTP-GCM in future.
|
|
|
|
// @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701
|
|
|
|
// @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ
|
|
|
|
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
|
|
|
|
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
|
|
|
|
|
|
|
|
policy.ssrc.value = 0;
|
|
|
|
// TODO: adjust window_size
|
|
|
|
policy.window_size = 8192;
|
|
|
|
policy.allow_repeat_tx = 1;
|
|
|
|
policy.next = NULL;
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
// init recv context
|
|
|
|
policy.ssrc.type = ssrc_any_inbound;
|
|
|
|
uint8_t *rkey = new uint8_t[recv_key.size()];
|
|
|
|
SrsAutoFreeA(uint8_t, rkey);
|
|
|
|
memcpy(rkey, recv_key.data(), recv_key.size());
|
|
|
|
policy.key = rkey;
|
2020-06-25 06:50:14 +00:00
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
srtp_err_status_t r0 = srtp_err_status_ok;
|
|
|
|
if ((r0 = srtp_create(&recv_ctx_, &policy)) != srtp_err_status_ok) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp create r0=%u", r0);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
policy.ssrc.type = ssrc_any_outbound;
|
|
|
|
uint8_t *skey = new uint8_t[send_key.size()];
|
|
|
|
SrsAutoFreeA(uint8_t, skey);
|
|
|
|
memcpy(skey, send_key.data(), send_key.size());
|
|
|
|
policy.key = skey;
|
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
if ((r0 = srtp_create(&send_ctx_, &policy)) != srtp_err_status_ok) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp create r0=%u", r0);
|
2020-06-25 12:47:17 +00:00
|
|
|
}
|
2020-06-25 06:50:14 +00:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
srs_error_t SrsSRTP::protect_rtp(const char* plaintext, char* cipher, int& nb_cipher)
|
2020-06-25 06:50:14 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
// If DTLS/SRTP is not ready, fail.
|
|
|
|
if (!send_ctx_) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "not ready");
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
memcpy(cipher, plaintext, nb_cipher);
|
2020-08-04 12:08:21 +00:00
|
|
|
|
|
|
|
srtp_err_status_t r0 = srtp_err_status_ok;
|
|
|
|
if ((r0 = srtp_protect(send_ctx_, cipher, &nb_cipher)) != srtp_err_status_ok) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect r0=%u", r0);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
srs_error_t SrsSRTP::protect_rtcp(const char* plaintext, char* cipher, int& nb_cipher)
|
2020-06-25 06:50:14 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
// If DTLS/SRTP is not ready, fail.
|
|
|
|
if (!send_ctx_) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "not ready");
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
memcpy(cipher, plaintext, nb_cipher);
|
2020-08-04 12:08:21 +00:00
|
|
|
|
|
|
|
srtp_err_status_t r0 = srtp_err_status_ok;
|
|
|
|
if ((r0 = srtp_protect_rtcp(send_ctx_, cipher, &nb_cipher)) != srtp_err_status_ok) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect r0=%u", r0);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
srs_error_t SrsSRTP::protect_rtp2(void* rtp_hdr, int* len_ptr)
|
2020-06-25 06:50:14 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
// If DTLS/SRTP is not ready, fail.
|
|
|
|
if (!send_ctx_) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "not ready");
|
|
|
|
}
|
|
|
|
|
|
|
|
srtp_err_status_t r0 = srtp_err_status_ok;
|
|
|
|
if ((r0 = srtp_protect(send_ctx_, rtp_hdr, len_ptr)) != srtp_err_status_ok) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect r0=%u", r0);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
srs_error_t SrsSRTP::unprotect_rtp(const char* cipher, char* plaintext, int& nb_plaintext)
|
2020-06-25 06:50:14 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
// If DTLS/SRTP is not ready, fail.
|
|
|
|
if (!recv_ctx_) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "not ready");
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
memcpy(plaintext, cipher, nb_plaintext);
|
2020-08-04 12:08:21 +00:00
|
|
|
|
|
|
|
srtp_err_status_t r0 = srtp_err_status_ok;
|
|
|
|
if ((r0 = srtp_unprotect(recv_ctx_, plaintext, &nb_plaintext)) != srtp_err_status_ok) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect r0=%u", r0);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
srs_error_t SrsSRTP::unprotect_rtcp(const char* cipher, char* plaintext, int& nb_plaintext)
|
2020-06-25 06:50:14 +00:00
|
|
|
{
|
|
|
|
srs_error_t err = srs_success;
|
|
|
|
|
2020-08-04 12:08:21 +00:00
|
|
|
// If DTLS/SRTP is not ready, fail.
|
|
|
|
if (!recv_ctx_) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "not ready");
|
|
|
|
}
|
|
|
|
|
2020-06-25 12:47:17 +00:00
|
|
|
memcpy(plaintext, cipher, nb_plaintext);
|
2020-08-04 12:08:21 +00:00
|
|
|
|
|
|
|
srtp_err_status_t r0 = srtp_err_status_ok;
|
|
|
|
if ((r0 = srtp_unprotect_rtcp(recv_ctx_, plaintext, &nb_plaintext)) != srtp_err_status_ok) {
|
|
|
|
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect r0=%u", r0);
|
2020-06-25 06:50:14 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 04:03:21 +00:00
|
|
|
return err;
|
2020-08-04 12:08:21 +00:00
|
|
|
}
|
|
|
|
|