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