SrtpSession.cpp 8.85 KB
Newer Older
xiongziliang committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/**
ISC License

Copyright © 2015, Iñaki Baz Castillo <ibc@aliax.net>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#define MS_CLASS "RTC::SrtpSession"
20 21
// #define MS_LOG_DEV_LEVEL 3

ziyue committed
22
#include "SrtpSession.hpp"
ziyue committed
23
#include <cstring> // std::memset(), std::memcpy()
24
#include "logger.h"
25
#include "Util/util.h"
26
#include "Util/logger.h"
27
using namespace toolkit;
28

ziyue committed
29 30 31 32
namespace RTC
{
	/* Static. */

33
    static std::vector<const char *> errors = {
ziyue committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
            // From 0 (srtp_err_status_ok) to 24 (srtp_err_status_pfkey_err).
            "success (srtp_err_status_ok)",
            "unspecified failure (srtp_err_status_fail)",
            "unsupported parameter (srtp_err_status_bad_param)",
            "couldn't allocate memory (srtp_err_status_alloc_fail)",
            "couldn't deallocate memory (srtp_err_status_dealloc_fail)",
            "couldn't initialize (srtp_err_status_init_fail)",
            "can’t process as much data as requested (srtp_err_status_terminus)",
            "authentication failure (srtp_err_status_auth_fail)",
            "cipher failure (srtp_err_status_cipher_fail)",
            "replay check failed (bad index) (srtp_err_status_replay_fail)",
            "replay check failed (index too old) (srtp_err_status_replay_old)",
            "algorithm failed test routine (srtp_err_status_algo_fail)",
            "unsupported operation (srtp_err_status_no_such_op)",
            "no appropriate context found (srtp_err_status_no_ctx)",
            "unable to perform desired validation (srtp_err_status_cant_check)",
            "can’t use key any more (srtp_err_status_key_expired)",
            "error in use of socket (srtp_err_status_socket_err)",
            "error in use POSIX signals (srtp_err_status_signal_err)",
            "nonce check failed (srtp_err_status_nonce_bad)",
            "couldn’t read data (srtp_err_status_read_fail)",
            "couldn’t write data (srtp_err_status_write_fail)",
            "error parsing data (srtp_err_status_parse_err)",
            "error encoding data (srtp_err_status_encode_err)",
            "error while using semaphores (srtp_err_status_semaphore_err)",
            "error while using pfkey (srtp_err_status_pfkey_err)"};
60 61 62 63
// clang-format on

/* Static methods. */

64 65 66 67 68 69 70 71 72 73 74 75
    const char *DepLibSRTP::GetErrorString(srtp_err_status_t code) {
        // This throws out_of_range if the given index is not in the vector.
        return errors.at(code);
    }

    bool DepLibSRTP::IsError(srtp_err_status_t code) {
        return (code != srtp_err_status_ok);
    }

    INSTANCE_IMP(DepLibSRTP);

    DepLibSRTP::DepLibSRTP(){
ziyue committed
76
        MS_TRACE();
77

ziyue committed
78
        MS_DEBUG_TAG(info, "libsrtp version: \"%s\"", srtp_get_version_string());
79

ziyue committed
80
        srtp_err_status_t err = srtp_init();
81

82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
#if 0
        srtp_install_log_handler([](srtp_log_level_t level,
                                    const char *msg,
                                    void *data) {
            printf("%s\n", msg);
        }, nullptr);
        srtp_set_debug_module("srtp", 1);
        srtp_set_debug_module("hmac sha-1", 1);
        srtp_set_debug_module("aes icm", 1);
        srtp_set_debug_module("alloc", 1);
        srtp_set_debug_module("stat test", 1);
        srtp_set_debug_module("cipher", 1);
        srtp_set_debug_module("auth func", 1);
        srtp_set_debug_module("crypto kernel", 1);
        srtp_list_debug_modules();
#endif

99
        if (DepLibSRTP::IsError(err)) {
ziyue committed
100
            MS_THROW_ERROR("srtp_init() failed: %s", DepLibSRTP::GetErrorString(err));
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
        }

        // Set libsrtp event handler.
        err = srtp_install_event_handler([](srtp_event_data_t *data){
            MS_TRACE();
            switch (data->event)
            {
                case event_ssrc_collision:
                    MS_WARN_TAG(srtp, "SSRC collision occurred");
                    break;

                case event_key_soft_limit:
                    MS_WARN_TAG(srtp, "stream reached the soft key usage limit and will expire soon");
                    break;

                case event_key_hard_limit:
                    MS_WARN_TAG(srtp, "stream reached the hard key usage limit and has expired");
                    break;

                case event_packet_index_limit:
                    MS_WARN_TAG(srtp, "stream reached the hard packet limit (2^48 packets)");
                    break;
            }
        });

        if (DepLibSRTP::IsError(err))
        {
            MS_THROW_ERROR("srtp_install_event_handler() failed: %s", DepLibSRTP::GetErrorString(err));
        }
130 131
    }

132
    DepLibSRTP::~DepLibSRTP(){
ziyue committed
133 134
        MS_TRACE();
        srtp_shutdown();
135 136
    }

137
    /////////////////////////////////////////////////////////////////////////////////////
ziyue committed
138 139 140 141 142

	/* Instance methods. */

	SrtpSession::SrtpSession(Type type, CryptoSuite cryptoSuite, uint8_t* key, size_t keyLen)
	{
143
        _env = DepLibSRTP::Instance().shared_from_this();
ziyue committed
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
		MS_TRACE();

		srtp_policy_t policy; // NOLINT(cppcoreguidelines-pro-type-member-init)

		// Set all policy fields to 0.
		std::memset(&policy, 0, sizeof(srtp_policy_t));

		switch (cryptoSuite)
		{
			case CryptoSuite::AES_CM_128_HMAC_SHA1_80:
			{
				srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
				srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);

				break;
			}

			case CryptoSuite::AES_CM_128_HMAC_SHA1_32:
			{
				srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
				// NOTE: Must be 80 for RTCP.
				srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);

				break;
			}

			case CryptoSuite::AEAD_AES_256_GCM:
			{
				srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
				srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
174

ziyue committed
175 176
				break;
			}
177

ziyue committed
178 179 180 181
			case CryptoSuite::AEAD_AES_128_GCM:
			{
				srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
				srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
182

ziyue committed
183 184
				break;
			}
185

ziyue committed
186 187 188 189 190
			default:
			{
				MS_ABORT("unknown SRTP crypto suite");
			}
		}
191

ziyue committed
192 193 194
		MS_ASSERT(
		  (int)keyLen == policy.rtp.cipher_key_len,
		  "given keyLen does not match policy.rtp.cipher_keyLen");
195

ziyue committed
196 197 198 199 200
		switch (type)
		{
			case Type::INBOUND:
				policy.ssrc.type = ssrc_any_inbound;
				break;
201

ziyue committed
202 203 204 205
			case Type::OUTBOUND:
				policy.ssrc.type = ssrc_any_outbound;
				break;
		}
206

ziyue committed
207 208 209 210 211 212
		policy.ssrc.value = 0;
		policy.key        = key;
		// Required for sending RTP retransmission without RTX.
		policy.allow_repeat_tx = 1;
		policy.window_size     = 1024;
		policy.next            = nullptr;
213

ziyue committed
214 215
		// Set the SRTP session.
		srtp_err_status_t err = srtp_create(&this->session, &policy);
216

ziyue committed
217 218 219
		if (DepLibSRTP::IsError(err))
			MS_THROW_ERROR("srtp_create() failed: %s", DepLibSRTP::GetErrorString(err));
	}
220

ziyue committed
221 222 223
	SrtpSession::~SrtpSession()
	{
		MS_TRACE();
224

ziyue committed
225 226 227
		if (this->session != nullptr)
		{
			srtp_err_status_t err = srtp_dealloc(this->session);
228

ziyue committed
229 230 231 232
			if (DepLibSRTP::IsError(err))
				MS_ABORT("srtp_dealloc() failed: %s", DepLibSRTP::GetErrorString(err));
		}
	}
233

234
	bool SrtpSession::EncryptRtp(uint8_t* data, int* len)
ziyue committed
235 236 237
	{
		MS_TRACE();
		srtp_err_status_t err =
238
		  srtp_protect(this->session, static_cast<void*>(data), reinterpret_cast<int*>(len));
239

ziyue committed
240 241
		if (DepLibSRTP::IsError(err))
		{
242 243
            WarnL << "srtp_protect() failed:" << DepLibSRTP::GetErrorString(err);
            return false;
ziyue committed
244
		}
245

ziyue committed
246 247
		return true;
	}
248

249
	bool SrtpSession::DecryptSrtp(uint8_t* data, int* len)
ziyue committed
250 251
	{
		MS_TRACE();
252

ziyue committed
253 254
		srtp_err_status_t err =
		  srtp_unprotect(this->session, static_cast<void*>(data), reinterpret_cast<int*>(len));
255

ziyue committed
256 257
		if (DepLibSRTP::IsError(err))
		{
258
            WarnL << "srtp_unprotect() failed:" << DepLibSRTP::GetErrorString(err);
ziyue committed
259 260
			return false;
		}
261

ziyue committed
262 263
		return true;
	}
264

265
	bool SrtpSession::EncryptRtcp(uint8_t* data, int* len)
ziyue committed
266 267 268
	{
		MS_TRACE();
		srtp_err_status_t err = srtp_protect_rtcp(
269
		  this->session, static_cast<void*>(data), reinterpret_cast<int*>(len));
270

ziyue committed
271 272
		if (DepLibSRTP::IsError(err))
		{
273
            WarnL << "srtp_protect_rtcp() failed:" << DepLibSRTP::GetErrorString(err);
ziyue committed
274 275
			return false;
		}
276

ziyue committed
277 278
		return true;
	}
279

280
	bool SrtpSession::DecryptSrtcp(uint8_t* data, int* len)
ziyue committed
281 282
	{
		MS_TRACE();
283

ziyue committed
284 285
		srtp_err_status_t err =
		  srtp_unprotect_rtcp(this->session, static_cast<void*>(data), reinterpret_cast<int*>(len));
286

ziyue committed
287 288
		if (DepLibSRTP::IsError(err))
		{
289
            WarnL << "srtp_unprotect_rtcp() failed:" << DepLibSRTP::GetErrorString(err);
ziyue committed
290 291
			return false;
		}
292

ziyue committed
293 294 295
		return true;
	}
} // namespace RTC