1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 // Original author: ekr@rtfm.com
8
9 #include "transportlayersrtp.h"
10 #include "transportlayerdtls.h"
11
12 #include "logging.h"
13 #include "nsError.h"
14 #include "mozilla/Assertions.h"
15 #include "transportlayerdtls.h"
16 #include "srtp.h"
17
18 namespace mozilla {
19
20 MOZ_MTLOG_MODULE("mtransport")
21
22 static char kDTLSExporterLabel[] = "EXTRACTOR-dtls_srtp";
23
TransportLayerSrtp(TransportLayerDtls & dtls)24 TransportLayerSrtp::TransportLayerSrtp(TransportLayerDtls& dtls) {
25 // We need to connect to the dtls layer, not the ice layer, because even
26 // though the packets that DTLS decrypts don't flow through us, we do base our
27 // keying information on the keying information established by the DTLS layer.
28 dtls.SignalStateChange.connect(this, &TransportLayerSrtp::StateChange);
29
30 TL_SET_STATE(dtls.state());
31 }
32
WasInserted()33 void TransportLayerSrtp::WasInserted() {
34 // Connect to the lower layers
35 if (!Setup()) {
36 TL_SET_STATE(TS_ERROR);
37 }
38 }
39
Setup()40 bool TransportLayerSrtp::Setup() {
41 CheckThread();
42 if (!downward_) {
43 MOZ_MTLOG(ML_ERROR, "SRTP layer with nothing below. This is useless");
44 return false;
45 }
46
47 // downward_ is the TransportLayerIce
48 downward_->SignalPacketReceived.connect(this,
49 &TransportLayerSrtp::PacketReceived);
50
51 return true;
52 }
53
SendPacket(MediaPacket & packet)54 TransportResult TransportLayerSrtp::SendPacket(MediaPacket& packet) {
55 if (state() != TS_OPEN) {
56 return TE_ERROR;
57 }
58
59 if (packet.len() < 4) {
60 MOZ_ASSERT(false);
61 return TE_ERROR;
62 }
63
64 MOZ_ASSERT(packet.capacity() - packet.len() >= SRTP_MAX_EXPANSION);
65
66 int out_len;
67 nsresult res;
68 switch (packet.type()) {
69 case MediaPacket::RTP:
70 res = mSendSrtp->ProtectRtp(packet.data(), packet.len(),
71 packet.capacity(), &out_len);
72 packet.SetType(MediaPacket::SRTP);
73 break;
74 case MediaPacket::RTCP:
75 res = mSendSrtp->ProtectRtcp(packet.data(), packet.len(),
76 packet.capacity(), &out_len);
77 packet.SetType(MediaPacket::SRTCP);
78 break;
79 default:
80 MOZ_CRASH("SRTP layer asked to send packet that is neither RTP or RTCP");
81 }
82
83 if (NS_FAILED(res)) {
84 MOZ_MTLOG(ML_ERROR,
85 "Error protecting "
86 << (packet.type() == MediaPacket::RTP ? "RTP" : "RTCP")
87 << " len=" << packet.len() << "[" << std::hex
88 << packet.data()[0] << " " << packet.data()[1] << " "
89 << packet.data()[2] << " " << packet.data()[3] << "]");
90 return TE_ERROR;
91 }
92
93 size_t unencrypted_len = packet.len();
94 packet.SetLength(out_len);
95
96 TransportResult bytes = downward_->SendPacket(packet);
97 if (bytes == out_len) {
98 // Whole packet was written, but the encrypted length might be different.
99 // Don't confuse the caller.
100 return unencrypted_len;
101 }
102
103 if (bytes == TE_WOULDBLOCK) {
104 return TE_WOULDBLOCK;
105 }
106
107 return TE_ERROR;
108 }
109
StateChange(TransportLayer * layer,State state)110 void TransportLayerSrtp::StateChange(TransportLayer* layer, State state) {
111 if (state == TS_OPEN && !mSendSrtp) {
112 TransportLayerDtls* dtls = static_cast<TransportLayerDtls*>(layer);
113 MOZ_ASSERT(dtls); // DTLS is mandatory
114
115 uint16_t cipher_suite;
116 nsresult res = dtls->GetSrtpCipher(&cipher_suite);
117 if (NS_FAILED(res)) {
118 MOZ_MTLOG(ML_DEBUG, "DTLS-SRTP disabled");
119 TL_SET_STATE(TS_ERROR);
120 return;
121 }
122
123 unsigned int key_size = SrtpFlow::KeySize(cipher_suite);
124 unsigned int salt_size = SrtpFlow::SaltSize(cipher_suite);
125 unsigned int master_key_size = key_size + salt_size;
126 MOZ_ASSERT(master_key_size <= SRTP_MAX_KEY_LENGTH);
127
128 // SRTP Key Exporter as per RFC 5764 S 4.2
129 unsigned char srtp_block[SRTP_MAX_KEY_LENGTH * 2];
130 res = dtls->ExportKeyingMaterial(kDTLSExporterLabel, false, "", srtp_block,
131 sizeof(srtp_block));
132 if (NS_FAILED(res)) {
133 MOZ_MTLOG(ML_ERROR, "Failed to compute DTLS-SRTP keys. This is an error");
134 TL_SET_STATE(TS_ERROR);
135 return;
136 }
137
138 // Slice and dice as per RFC 5764 S 4.2
139 unsigned char client_write_key[SRTP_MAX_KEY_LENGTH];
140 unsigned char server_write_key[SRTP_MAX_KEY_LENGTH];
141 unsigned int offset = 0;
142 memcpy(client_write_key, srtp_block + offset, key_size);
143 offset += key_size;
144 memcpy(server_write_key, srtp_block + offset, key_size);
145 offset += key_size;
146 memcpy(client_write_key + key_size, srtp_block + offset, salt_size);
147 offset += salt_size;
148 memcpy(server_write_key + key_size, srtp_block + offset, salt_size);
149 MOZ_ASSERT((offset + salt_size) == (2 * master_key_size));
150
151 unsigned char* write_key;
152 unsigned char* read_key;
153
154 if (dtls->role() == TransportLayerDtls::CLIENT) {
155 write_key = client_write_key;
156 read_key = server_write_key;
157 } else {
158 write_key = server_write_key;
159 read_key = client_write_key;
160 }
161
162 MOZ_ASSERT(!mSendSrtp && !mRecvSrtp);
163 mSendSrtp =
164 SrtpFlow::Create(cipher_suite, false, write_key, master_key_size);
165 mRecvSrtp = SrtpFlow::Create(cipher_suite, true, read_key, master_key_size);
166 if (!mSendSrtp || !mRecvSrtp) {
167 MOZ_MTLOG(ML_ERROR, "Couldn't create SRTP flow.");
168 TL_SET_STATE(TS_ERROR);
169 return;
170 }
171
172 MOZ_MTLOG(ML_INFO, "Created SRTP flow!");
173 }
174
175 TL_SET_STATE(state);
176 }
177
PacketReceived(TransportLayer * layer,MediaPacket & packet)178 void TransportLayerSrtp::PacketReceived(TransportLayer* layer,
179 MediaPacket& packet) {
180 if (state() != TS_OPEN) {
181 return;
182 }
183
184 if (!packet.data()) {
185 // Something ate this, probably the DTLS layer
186 return;
187 }
188
189 if (packet.type() != MediaPacket::SRTP &&
190 packet.type() != MediaPacket::SRTCP) {
191 return;
192 }
193
194 // We want to keep the encrypted packet around for packet dumping
195 packet.CopyDataToEncrypted();
196 int outLen;
197 nsresult res;
198
199 if (packet.type() == MediaPacket::SRTP) {
200 packet.SetType(MediaPacket::RTP);
201 res = mRecvSrtp->UnprotectRtp(packet.data(), packet.len(), packet.len(),
202 &outLen);
203 } else {
204 packet.SetType(MediaPacket::RTCP);
205 res = mRecvSrtp->UnprotectRtcp(packet.data(), packet.len(), packet.len(),
206 &outLen);
207 }
208
209 if (NS_SUCCEEDED(res)) {
210 packet.SetLength(outLen);
211 SignalPacketReceived(this, packet);
212 } else {
213 // TODO: What do we do wrt packet dumping here? Maybe signal an empty
214 // packet? Signal the still-encrypted packet?
215 MOZ_MTLOG(ML_ERROR,
216 "Error unprotecting "
217 << (packet.type() == MediaPacket::RTP ? "RTP" : "RTCP")
218 << " len=" << packet.len() << "[" << std::hex
219 << packet.data()[0] << " " << packet.data()[1] << " "
220 << packet.data()[2] << " " << packet.data()[3] << "]");
221 }
222 }
223
224 } // namespace mozilla
225