|
@@ -360,7 +360,302 @@ int DtlsTransport::TimeoutCallback(gnutls_transport_ptr_t ptr, unsigned int /* m
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-#else // USE_GNUTLS==0
|
|
|
|
|
|
+#elif USE_MBEDTLS
|
|
|
|
+
|
|
|
|
+mbedtls_ssl_srtp_profile srtpSupportedProtectionProfiles[] = {
|
|
|
|
+ MBEDTLS_TLS_SRTP_AES128_CM_HMAC_SHA1_80,
|
|
|
|
+ MBEDTLS_TLS_SRTP_UNSET,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr certificate,
|
|
|
|
+ optional<size_t> mtu, verifier_callback verifierCallback,
|
|
|
|
+ state_callback stateChangeCallback)
|
|
|
|
+ : Transport(lower, std::move(stateChangeCallback)), mMtu(mtu), mCertificate(certificate),
|
|
|
|
+ mVerifierCallback(std::move(verifierCallback)),
|
|
|
|
+ mIsClient(lower->role() == Description::Role::Active) {
|
|
|
|
+
|
|
|
|
+ PLOG_DEBUG << "Initializing DTLS transport (MbedTLS)";
|
|
|
|
+
|
|
|
|
+ if (!mCertificate)
|
|
|
|
+ throw std::invalid_argument("DTLS certificate is null");
|
|
|
|
+
|
|
|
|
+ mbedtls_entropy_init(&mEntropy);
|
|
|
|
+ mbedtls_ctr_drbg_init(&mDrbg);
|
|
|
|
+ mbedtls_ssl_init(&mSsl);
|
|
|
|
+ mbedtls_ssl_config_init(&mConf);
|
|
|
|
+ mbedtls_ctr_drbg_set_prediction_resistance(&mDrbg, MBEDTLS_CTR_DRBG_PR_ON);
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ mbedtls::check(mbedtls_ctr_drbg_seed(&mDrbg, mbedtls_entropy_func, &mEntropy, NULL, 0),
|
|
|
|
+ "Failed creating Mbed TLS Context");
|
|
|
|
+
|
|
|
|
+ mbedtls::check(mbedtls_ssl_config_defaults(
|
|
|
|
+ &mConf, mIsClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
|
|
|
|
+ MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT),
|
|
|
|
+ "Failed creating Mbed TLS Context");
|
|
|
|
+
|
|
|
|
+ mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
|
|
|
+ mbedtls_ssl_conf_rng(&mConf, mbedtls_ctr_drbg_random, &mDrbg);
|
|
|
|
+
|
|
|
|
+ auto [crt, pk] = mCertificate->credentials();
|
|
|
|
+ mbedtls::check(mbedtls_ssl_conf_own_cert(&mConf, crt.get(), pk.get()),
|
|
|
|
+ "Failed creating Mbed TLS Context");
|
|
|
|
+
|
|
|
|
+ mbedtls_ssl_conf_dtls_cookies(&mConf, NULL, NULL, NULL);
|
|
|
|
+ mbedtls_ssl_conf_dtls_srtp_protection_profiles(&mConf, srtpSupportedProtectionProfiles);
|
|
|
|
+
|
|
|
|
+ mbedtls::check(mbedtls_ssl_setup(&mSsl, &mConf), "Failed creating Mbed TLS Context");
|
|
|
|
+
|
|
|
|
+ size_t mtu = mMtu.value_or(DEFAULT_MTU) - 8 - 40; // UDP/IPv6
|
|
|
|
+ mbedtls_ssl_set_mtu(&mSsl, static_cast<unsigned int>(mtu));
|
|
|
|
+ PLOG_VERBOSE << "DTLS MTU set to " << mtu;
|
|
|
|
+
|
|
|
|
+ mbedtls_ssl_set_export_keys_cb(&mSsl, DtlsTransport::ExportKeysCallback, this);
|
|
|
|
+ mbedtls_ssl_set_bio(&mSsl, this, WriteCallback, ReadCallback, NULL);
|
|
|
|
+ mbedtls_ssl_set_timer_cb(&mSsl, this, SetTimerCallback, GetTimerCallback);
|
|
|
|
+ } catch (...) {
|
|
|
|
+ mbedtls_entropy_free(&mEntropy);
|
|
|
|
+ mbedtls_ctr_drbg_free(&mDrbg);
|
|
|
|
+ mbedtls_ssl_free(&mSsl);
|
|
|
|
+ mbedtls_ssl_config_free(&mConf);
|
|
|
|
+ throw;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Set recommended medium-priority DSCP value for handshake
|
|
|
|
+ // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5
|
|
|
|
+ mCurrentDscp = 10; // AF11: Assured Forwarding class 1, low drop probability
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+DtlsTransport::~DtlsTransport() {
|
|
|
|
+ stop();
|
|
|
|
+
|
|
|
|
+ PLOG_DEBUG << "Destroying DTLS transport";
|
|
|
|
+ mbedtls_entropy_free(&mEntropy);
|
|
|
|
+ mbedtls_ctr_drbg_free(&mDrbg);
|
|
|
|
+ mbedtls_ssl_free(&mSsl);
|
|
|
|
+ mbedtls_ssl_config_free(&mConf);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::Init() {
|
|
|
|
+ // Nothing to do
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::Cleanup() {
|
|
|
|
+ // Nothing to do
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::start() {
|
|
|
|
+ PLOG_DEBUG << "Starting DTLS transport";
|
|
|
|
+ registerIncoming();
|
|
|
|
+ changeState(State::Connecting);
|
|
|
|
+
|
|
|
|
+ enqueueRecv(); // to initiate the handshake
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::stop() {
|
|
|
|
+ PLOG_DEBUG << "Stopping DTLS transport";
|
|
|
|
+ unregisterIncoming();
|
|
|
|
+ mIncomingQueue.stop();
|
|
|
|
+ enqueueRecv();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool DtlsTransport::send(message_ptr message) {
|
|
|
|
+ if (!message || state() != State::Connected)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ PLOG_VERBOSE << "Send size=" << message->size();
|
|
|
|
+
|
|
|
|
+ int ret;
|
|
|
|
+ do {
|
|
|
|
+ std::lock_guard lock(mMutex);
|
|
|
|
+ mCurrentDscp = message->dscp;
|
|
|
|
+
|
|
|
|
+ if (message->size() > size_t(mbedtls_ssl_get_max_out_record_payload(&mSsl)))
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ ret = mbedtls_ssl_write(&mSsl, reinterpret_cast<const unsigned char *>(message->data()),
|
|
|
|
+ message->size());
|
|
|
|
+ } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE);
|
|
|
|
+ mbedtls::check(ret);
|
|
|
|
+
|
|
|
|
+ return mOutgoingResult;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::incoming(message_ptr message) {
|
|
|
|
+ if (!message) {
|
|
|
|
+ mIncomingQueue.stop();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ PLOG_VERBOSE << "Incoming size=" << message->size();
|
|
|
|
+ mIncomingQueue.push(message);
|
|
|
|
+ enqueueRecv();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool DtlsTransport::outgoing(message_ptr message) {
|
|
|
|
+ message->dscp = mCurrentDscp;
|
|
|
|
+
|
|
|
|
+ bool result = Transport::outgoing(std::move(message));
|
|
|
|
+ mOutgoingResult = result;
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool DtlsTransport::demuxMessage(message_ptr) {
|
|
|
|
+ // Dummy
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::postHandshake() {
|
|
|
|
+ // Dummy
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::doRecv() {
|
|
|
|
+ std::lock_guard lock(mRecvMutex);
|
|
|
|
+ --mPendingRecvCount;
|
|
|
|
+
|
|
|
|
+ if (state() != State::Connecting && state() != State::Connected)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ const size_t bufferSize = 4096;
|
|
|
|
+ char buffer[bufferSize];
|
|
|
|
+
|
|
|
|
+ // Handle handshake if connecting
|
|
|
|
+ if (state() == State::Connecting) {
|
|
|
|
+ while (true) {
|
|
|
|
+ auto ret = mbedtls_ssl_handshake(&mSsl);
|
|
|
|
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
|
|
|
+ ThreadPool::Instance().schedule(mTimerSetAt + milliseconds(mFinMs), [weak_this = weak_from_this()]() {
|
|
|
|
+ if (auto locked = weak_this.lock())
|
|
|
|
+ locked->doRecv();
|
|
|
|
+ });
|
|
|
|
+ return;
|
|
|
|
+ } else if ( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS || ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mbedtls::check(ret);
|
|
|
|
+ PLOG_INFO << "DTLS handshake finished";
|
|
|
|
+ changeState(State::Connected);
|
|
|
|
+ postHandshake();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (state() == State::Connected) {
|
|
|
|
+ while (true) {
|
|
|
|
+ mMutex.lock();
|
|
|
|
+ auto ret =
|
|
|
|
+ mbedtls_ssl_read(&mSsl, reinterpret_cast<unsigned char *>(buffer), bufferSize);
|
|
|
|
+ mMutex.unlock();
|
|
|
|
+
|
|
|
|
+ if (ret == 0 || ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
|
|
|
|
+ // Closed
|
|
|
|
+ PLOG_DEBUG << "DTLS connection cleanly closed";
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
|
|
|
|
+ ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ||
|
|
|
|
+ ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ mbedtls::check(ret);
|
|
|
|
+
|
|
|
|
+ auto *b = reinterpret_cast<byte *>(buffer);
|
|
|
|
+ recv(make_message(b, b + ret));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } catch (const std::exception &e) {
|
|
|
|
+ PLOG_ERROR << "DTLS recv: " << e.what();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ PLOG_INFO << "DTLS closed";
|
|
|
|
+ changeState(State::Disconnected);
|
|
|
|
+ recv(nullptr);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::ExportKeysCallback(void *ctx, mbedtls_ssl_key_export_type /*type*/,
|
|
|
|
+ const unsigned char *secret, size_t secret_len,
|
|
|
|
+ const unsigned char client_random[32],
|
|
|
|
+ const unsigned char server_random[32],
|
|
|
|
+ mbedtls_tls_prf_types tls_prf_type) {
|
|
|
|
+ auto dtlsTransport = static_cast<DtlsTransport *>(ctx);
|
|
|
|
+ std::memcpy(dtlsTransport->mMasterSecret, secret, secret_len);
|
|
|
|
+ std::memcpy(dtlsTransport->mRandBytes, client_random, 32);
|
|
|
|
+ std::memcpy(dtlsTransport->mRandBytes + 32, server_random, 32);
|
|
|
|
+ dtlsTransport->mTlsProfile = tls_prf_type;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int DtlsTransport::WriteCallback(void *ctx, const unsigned char *buf, size_t len) {
|
|
|
|
+ auto *t = static_cast<DtlsTransport *>(ctx);
|
|
|
|
+ try {
|
|
|
|
+ if (len > 0) {
|
|
|
|
+ auto b = reinterpret_cast<const byte *>(buf);
|
|
|
|
+ t->outgoing(make_message(b, b + len));
|
|
|
|
+ }
|
|
|
|
+ return int(len);
|
|
|
|
+
|
|
|
|
+ } catch (const std::exception &e) {
|
|
|
|
+ PLOG_WARNING << e.what();
|
|
|
|
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int DtlsTransport::ReadCallback(void *ctx, unsigned char *buf, size_t len) {
|
|
|
|
+ auto *t = static_cast<DtlsTransport *>(ctx);
|
|
|
|
+ try {
|
|
|
|
+ while (t->mIncomingQueue.running()) {
|
|
|
|
+ auto next = t->mIncomingQueue.pop();
|
|
|
|
+ if (!next) {
|
|
|
|
+ return MBEDTLS_ERR_SSL_WANT_READ;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ message_ptr message = std::move(*next);
|
|
|
|
+ if (t->demuxMessage(message))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ auto bufMin = std::min(len, size_t(message->size()));
|
|
|
|
+ std::memcpy(buf, message->data(), bufMin);
|
|
|
|
+ return int(len);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Closed
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ } catch (const std::exception &e) {
|
|
|
|
+ PLOG_WARNING << e.what();
|
|
|
|
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
|
|
|
|
+ ;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void DtlsTransport::SetTimerCallback(void *ctx, uint32_t int_ms, uint32_t fin_ms) {
|
|
|
|
+ auto dtlsTransport = static_cast<DtlsTransport *>(ctx);
|
|
|
|
+ dtlsTransport->mIntMs = int_ms;
|
|
|
|
+ dtlsTransport->mFinMs = fin_ms;
|
|
|
|
+
|
|
|
|
+ if (fin_ms != 0) {
|
|
|
|
+ dtlsTransport->mTimerSetAt = std::chrono::steady_clock::now();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int DtlsTransport::GetTimerCallback(void *ctx) {
|
|
|
|
+ auto dtlsTransport = static_cast<DtlsTransport *>(ctx);
|
|
|
|
+ auto now = std::chrono::steady_clock::now();
|
|
|
|
+
|
|
|
|
+ if (dtlsTransport->mFinMs == 0) {
|
|
|
|
+ return -1;
|
|
|
|
+ } else if (now >= dtlsTransport->mTimerSetAt + milliseconds(dtlsTransport->mFinMs)) {
|
|
|
|
+ return 2;
|
|
|
|
+ } else if (now >= dtlsTransport->mTimerSetAt + milliseconds(dtlsTransport->mIntMs)) {
|
|
|
|
+ return 1;
|
|
|
|
+ } else {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#else // OPENSSL
|
|
|
|
|
|
BIO_METHOD *DtlsTransport::BioMethods = NULL;
|
|
BIO_METHOD *DtlsTransport::BioMethods = NULL;
|
|
int DtlsTransport::TransportExIndex = -1;
|
|
int DtlsTransport::TransportExIndex = -1;
|
|
@@ -415,8 +710,8 @@ DtlsTransport::DtlsTransport(shared_ptr<IceTransport> lower, certificate_ptr cer
|
|
|
|
|
|
SSL_CTX_set_min_proto_version(mCtx, DTLS1_VERSION);
|
|
SSL_CTX_set_min_proto_version(mCtx, DTLS1_VERSION);
|
|
SSL_CTX_set_read_ahead(mCtx, 1);
|
|
SSL_CTX_set_read_ahead(mCtx, 1);
|
|
- //sent the dtls close_notify alert
|
|
|
|
- //SSL_CTX_set_quiet_shutdown(mCtx, 1);
|
|
|
|
|
|
+ // sent the dtls close_notify alert
|
|
|
|
+ // SSL_CTX_set_quiet_shutdown(mCtx, 1);
|
|
SSL_CTX_set_info_callback(mCtx, InfoCallback);
|
|
SSL_CTX_set_info_callback(mCtx, InfoCallback);
|
|
|
|
|
|
SSL_CTX_set_verify(mCtx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
|
SSL_CTX_set_verify(mCtx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|