Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panic due to improper handling of use_srtp extension #649

Open
Deluvi opened this issue Jan 23, 2025 · 2 comments
Open

Panic due to improper handling of use_srtp extension #649

Deluvi opened this issue Jan 23, 2025 · 2 comments

Comments

@Deluvi
Copy link

Deluvi commented Jan 23, 2025

Hello everyone !

For a project, I wanted to integrate OpenAI's Realtime API using the WebRTC method.

However, upon connecting using this webrtc-rs library, I encountered a panic:

Panic in webrtc-srtp-0.14.0/src/key_derivation.rs

[2025-01-23T08:38:38Z INFO  webrtc::peer_connection] ICE connection state changed: connected
Connection State has changed connected
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 0: Preparing
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 0: Sending
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 0: Waiting
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Recv [handshake:server] -> ClientHello (epoch: 0, seq: 0)
[2025-01-23T08:38:38Z DEBUG webrtc_dtls::flight::flight0] [handshake:server] use cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 0 -> Flight 2
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 2: Preparing
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 2: Sending
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Send [handshake:server] -> HelloVerifyRequest (epoch: 0, seq: 0)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 2: Waiting
[2025-01-23T08:38:38Z TRACE webrtc_ice::agent::agent_selector] inbound STUN (SuccessResponse) from udp4 host 40.84.168.209:3478 to udp4 host 192.168.1.52:52612
[2025-01-23T08:38:38Z TRACE webrtc_ice::agent::agent_selector] Found valid candidate pair: prio 9151314440652587007 (local, prio 2130706431) udp4 host 192.168.1.52:52612 <-> udp4 host 40.84.168.209:3478 (remote, prio 2130706431), p.state: 4, isUseCandidate: true, false
[2025-01-23T08:38:38Z TRACE webrtc_ice::agent::agent_internal] [controlling]: inbound STUN (Request) from 40.84.168.209:3478 to udp4 host 192.168.1.52:52612
[2025-01-23T08:38:38Z TRACE webrtc_ice::agent::agent_selector] controllingSelector: sendBindingSuccess
[2025-01-23T08:38:38Z TRACE webrtc_ice::agent::agent_selector] controllingSelector: after findPair prio 9151314440652587007 (local, prio 2130706431) udp4 host 192.168.1.52:52612 <-> udp4 host 40.84.168.209:3478 (remote, prio 2130706431), p.state: 4, false
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Recv [handshake:server] -> ClientHello (epoch: 0, seq: 1)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 2 -> Flight 4
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 4: Preparing
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 4: Sending
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Send [handshake:server] -> ServerHello (epoch: 0, seq: 1)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Send [handshake:server] -> Certificate (epoch: 0, seq: 2)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Send [handshake:server] -> ServerKeyExchange (epoch: 0, seq: 3)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Send [handshake:server] -> CertificateRequest (epoch: 0, seq: 4)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Send [handshake:server] -> ServerHelloDone (epoch: 0, seq: 5)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 4: Waiting
[2025-01-23T08:38:38Z TRACE webrtc_ice::agent::agent_selector] [controlling]: checking keepalive
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Recv [handshake:server] -> Certificate (epoch: 0, seq: 2)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Recv [handshake:server] -> ClientKeyExchange (epoch: 0, seq: 3)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Recv [handshake:server] -> CertificateVerify (epoch: 0, seq: 4)
[2025-01-23T08:38:38Z DEBUG webrtc_dtls::conn] server: CipherSuite not initialized, queuing packet
[2025-01-23T08:38:38Z DEBUG webrtc_dtls::conn] server: received packet of next epoch, queuing packet
[2025-01-23T08:38:38Z TRACE webrtc_dtls::flight::flight4] [handshake] PeerCertificates4 1
[2025-01-23T08:38:38Z TRACE webrtc_dtls::crypto] Picked an algorithm ECDSA_P256_SHA256_ASN1
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] server: <- ChangeCipherSpec (epoch: 1)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Recv [handshake:server] -> Finished (epoch: 1, seq: 5)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::flight::flight4] server peer_certificates.len() 1
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 4 -> Flight 6
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 6: Preparing
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] -> changeCipherSpec (epoch: 1)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 6: Sending
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Send [handshake:server] -> Finished (epoch: 1, seq: 6)
[2025-01-23T08:38:38Z TRACE webrtc_dtls::handshaker] [handshake:server] Flight 6: Finished
[2025-01-23T08:38:38Z TRACE webrtc_dtls::conn] Handshake Completed
thread 'tokio-runtime-worker' panicked at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/generic-array-0.14.7/src/lib.rs:572:9:
assertion `left == right` failed
  left: 32
 right: 16
stack backtrace:
   0: rust_begin_unwind
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:665:5
   1: core::panicking::panic_fmt
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panicking.rs:74:14
   2: core::panicking::assert_failed_inner
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panicking.rs:410:17
   3: core::panicking::assert_failed
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panicking.rs:365:5
   4: <&generic_array::GenericArray<T,N> as core::convert::From<&[T]>>::from
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/generic-array-0.14.7/src/lib.rs:572:9
   5: <T as core::convert::Into<U>>::into
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/convert/mod.rs:759:9
   6: generic_array::GenericArray<T,N>::from_slice
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/generic-array-0.14.7/src/lib.rs:550:15
   7: webrtc_srtp::key_derivation::aes_cm_key_derivation
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-srtp-0.14.0/src/key_derivation.rs:43:15
   8: webrtc_srtp::cipher::cipher_aead_aes_gcm::CipherAeadAesGcm::new
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-srtp-0.14.0/src/cipher/cipher_aead_aes_gcm.rs:154:32
   9: webrtc_srtp::context::Context::new
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-srtp-0.14.0/src/context/mod.rs:127:26
  10: webrtc_srtp::session::Session::new::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-srtp-0.14.0/src/session/mod.rs:44:29
  11: webrtc::dtls_transport::RTCDtlsTransport::start_srtp::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-0.12.0/src/dtls_transport/mod.rs:217:26
  12: webrtc::dtls_transport::RTCDtlsTransport::start::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-0.12.0/src/dtls_transport/mod.rs:475:27
  13: webrtc::peer_connection::peer_connection_internal::PeerConnectionInternal::start_transports::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-0.12.0/src/peer_connection/peer_connection_internal.rs:708:14
  14: webrtc::peer_connection::RTCPeerConnection::set_remote_description::{{closure}}::{{closure}}::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-0.12.0/src/peer_connection/mod.rs:1610:34
  15: <core::pin::Pin<P> as core::future::future::Future>::poll
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/future/future.rs:123:9
  16: webrtc::peer_connection::operation::Operations::start::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-0.12.0/src/peer_connection/operation/mod.rs:124:34
  17: webrtc::peer_connection::operation::Operations::new::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/webrtc-0.12.0/src/peer_connection/operation/mod.rs:57:60
  18: tokio::runtime::task::core::Core<T,S>::poll::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/core.rs:331:17
  19: tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/loom/std/unsafe_cell.rs:16:9
  20: tokio::runtime::task::core::Core<T,S>::poll
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/core.rs:320:30
  21: tokio::runtime::task::harness::poll_future::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:532:19
  22: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panic/unwind_safe.rs:272:9
  23: std::panicking::try::do_call
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:557:40
  24: std::panicking::try
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:521:19
  25: std::panic::catch_unwind
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panic.rs:350:14
  26: tokio::runtime::task::harness::poll_future
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:520:18
  27: tokio::runtime::task::harness::Harness<T,S>::poll_inner
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:209:27
  28: tokio::runtime::task::harness::Harness<T,S>::poll
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:154:15
  29: tokio::runtime::task::raw::RawTask::poll
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/raw.rs:201:18
  30: tokio::runtime::task::LocalNotified<S>::run
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/mod.rs:449:9
  31: tokio::runtime::scheduler::multi_thread::worker::Context::run_task::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/scheduler/multi_thread/worker.rs:659:22
  32: tokio::runtime::coop::with_budget
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/coop.rs:107:5
  33: tokio::runtime::coop::budget
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/coop.rs:73:5
  34: tokio::runtime::scheduler::multi_thread::worker::Context::run_task
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/scheduler/multi_thread/worker.rs:595:9
  35: tokio::runtime::scheduler::multi_thread::worker::Context::run
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/scheduler/multi_thread/worker.rs:546:24
  36: tokio::runtime::scheduler::multi_thread::worker::run::{{closure}}::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/scheduler/multi_thread/worker.rs:511:21
  37: tokio::runtime::context::scoped::Scoped<T>::set
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/context/scoped.rs:40:9
  38: tokio::runtime::context::set_scheduler::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/context.rs:180:26
  39: std::thread::local::LocalKey<T>::try_with
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/thread/local.rs:283:12
  40: std::thread::local::LocalKey<T>::with
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/thread/local.rs:260:9
  41: tokio::runtime::context::set_scheduler
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/context.rs:180:17
  42: tokio::runtime::scheduler::multi_thread::worker::run::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/scheduler/multi_thread/worker.rs:506:9
  43: tokio::runtime::context::runtime::enter_runtime
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/context/runtime.rs:65:16
  44: tokio::runtime::scheduler::multi_thread::worker::run
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/scheduler/multi_thread/worker.rs:498:5
  45: tokio::runtime::scheduler::multi_thread::worker::Launch::launch::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/scheduler/multi_thread/worker.rs:464:45
  46: <tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/blocking/task.rs:42:21
  47: tokio::runtime::task::core::Core<T,S>::poll::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/core.rs:331:17
  48: tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/loom/std/unsafe_cell.rs:16:9
  49: tokio::runtime::task::core::Core<T,S>::poll
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/core.rs:320:30
  50: tokio::runtime::task::harness::poll_future::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:532:19
  51: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panic/unwind_safe.rs:272:9
  52: std::panicking::try::do_call
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:557:40
  53: std::panicking::try
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:521:19
  54: std::panic::catch_unwind
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panic.rs:350:14
  55: tokio::runtime::task::harness::poll_future
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:520:18
  56: tokio::runtime::task::harness::Harness<T,S>::poll_inner
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:209:27
  57: tokio::runtime::task::harness::Harness<T,S>::poll
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/harness.rs:154:15
  58: tokio::runtime::task::raw::RawTask::poll
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/raw.rs:201:18
  59: tokio::runtime::task::UnownedTask<S>::run
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/task/mod.rs:486:9
  60: tokio::runtime::blocking::pool::Task::run
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/blocking/pool.rs:161:9
  61: tokio::runtime::blocking::pool::Inner::run
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/blocking/pool.rs:511:17
  62: tokio::runtime::blocking::pool::Spawner::spawn_thread::{{closure}}
             at /home/deluvi/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.43.0/src/runtime/blocking/pool.rs:469:13

After digging, I found out that the panic is due to trying to fit a 32 bytes slice into a 16 bytes AES128 key.

At this point, I decided to debug the issue by patching the library to add debug prints. Here is what I found.

First, the cipher picked:

[/home/deluvi/work/webrtc/webrtc/src/dtls_transport/mod.rs:201:17] cipher_suite.as_ref().unwrap().to_string() = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"

So AES128, which makes sense that we expected a 16 bytes key. But why did the library generated a 32 bytes key ?

I found out that the key len is calculated in extract_session_keys_from_dtls. By adding further debug prints, I found out that:

[/home/deluvi/work/webrtc/srtp/src/config.rs:46:23] self.profile.key_len() = 32
[/home/deluvi/work/webrtc/srtp/src/config.rs:47:9] &self.profile = AeadAes256Gcm

Aes256, what?!

After digging a bit more, I found out that this profile can be set through the SRTP protection profile extension:

[/home/deluvi/work/webrtc/webrtc/src/dtls_transport/mod.rs:417:28] dtls_conn.selected_srtpprotection_profile() = Srtp_Aead_Aes_256_Gcm

I found out that this was picked in flight 0:

[/home/deluvi/work/webrtc/dtls/src/flight/flight0.rs:118:29] &e.protection_profiles = [
    Srtp_Aead_Aes_256_Gcm,
    Srtp_Aead_Aes_128_Gcm,
    Srtp_Aes128_Cm_Hmac_Sha1_80,
]

This correspond to the use_srtp extension that the server gives if I understood correctly.

This list is given to find_matching_srtp_profile, which pick the first compatible srtp profile. The Aes256 one being the first, it is the one that got picked by the client.

We take the key length of the srtp profile (Aes256, 32 bytes), which does not match the key length of the overall cipher (Aes128, 16 bytes), which cause the issue.

By patching the crate and overriding the dtls_conn.selected_srtpprotection_profile() to Srtp_Aead_Aes_128_Gcm, I managed to successfully communicate with OpenAI backend, so this was indeed a bad handling of the use_srtp extension by the crate.

@rainliu
Copy link
Member

rainliu commented Jan 23, 2025

Thanks for this detailed analysis. Could you submit a PR to fix this issue?

@shannonrdunn
Copy link

Ran into the same thing, thanks @Deluvi for posting this as I thought it was me

Found a resolution for my code without patching the crate:

use webrtc::dtls::extension::extension_use_srtp::SrtpProtectionProfile;
...
        let mut setting_engine = webrtc::api::setting_engine::SettingEngine::default();
        setting_engine.set_srtp_protection_profiles(vec![
            SrtpProtectionProfile::Srtp_Aead_Aes_128_Gcm,
            SrtpProtectionProfile::Srtp_Aes128_Cm_Hmac_Sha1_80,
        ]);
        // Create the API with the MediaEngine and Interceptors
        let api = APIBuilder::new()
            .with_setting_engine(setting_engine)
            .with_media_engine(media_engine)
            .with_interceptor_registry(registry)
            .build();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants