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