Skip to content

Panic due to improper handling of use_srtp extension #649

Open
@Deluvi

Description

@Deluvi

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions