| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2009 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2009 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/pc/srtpfilter.h" | 11 #include "webrtc/pc/srtpfilter.h" |
| 12 | 12 |
| 13 #include <string.h> | 13 #include <string.h> |
| 14 | 14 |
| 15 #include <algorithm> | 15 #include <algorithm> |
| 16 | 16 |
| 17 #include "third_party/libsrtp/include/srtp.h" | |
| 18 #include "third_party/libsrtp/include/srtp_priv.h" | |
| 19 #include "webrtc/media/base/rtputils.h" | 17 #include "webrtc/media/base/rtputils.h" |
| 20 #include "webrtc/pc/externalhmac.h" | 18 #include "webrtc/pc/srtpsession.h" |
| 21 #include "webrtc/rtc_base/base64.h" | 19 #include "webrtc/rtc_base/base64.h" |
| 22 #include "webrtc/rtc_base/buffer.h" | 20 #include "webrtc/rtc_base/buffer.h" |
| 23 #include "webrtc/rtc_base/byteorder.h" | 21 #include "webrtc/rtc_base/byteorder.h" |
| 24 #include "webrtc/rtc_base/checks.h" | 22 #include "webrtc/rtc_base/checks.h" |
| 25 #include "webrtc/rtc_base/logging.h" | 23 #include "webrtc/rtc_base/logging.h" |
| 26 #include "webrtc/rtc_base/sslstreamadapter.h" | |
| 27 #include "webrtc/rtc_base/stringencode.h" | 24 #include "webrtc/rtc_base/stringencode.h" |
| 28 #include "webrtc/rtc_base/timeutils.h" | 25 #include "webrtc/rtc_base/timeutils.h" |
| 29 | 26 |
| 30 namespace cricket { | 27 namespace cricket { |
| 31 | 28 |
| 32 // NOTE: This is called from ChannelManager D'tor. | 29 // NOTE: This is called from ChannelManager D'tor. |
| 33 void ShutdownSrtp() { | 30 void ShutdownSrtp() { |
| 34 // If srtp_dealloc is not executed then this will clear all existing sessions. | 31 // If srtp_dealloc is not executed then this will clear all existing sessions. |
| 35 // This should be called when application is shutting down. | 32 // This should be called when application is shutting down. |
| 36 SrtpSession::Terminate(); | 33 SrtpSession::Terminate(); |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 std::string key_b64(key_params.substr(7)), key_str; | 474 std::string key_b64(key_params.substr(7)), key_str; |
| 478 if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, | 475 if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, |
| 479 &key_str, nullptr) || key_str.size() != len) { | 476 &key_str, nullptr) || key_str.size() != len) { |
| 480 return false; | 477 return false; |
| 481 } | 478 } |
| 482 | 479 |
| 483 memcpy(key, key_str.c_str(), len); | 480 memcpy(key, key_str.c_str(), len); |
| 484 return true; | 481 return true; |
| 485 } | 482 } |
| 486 | 483 |
| 487 /////////////////////////////////////////////////////////////////////////////// | |
| 488 // SrtpSession | |
| 489 | |
| 490 bool SrtpSession::inited_ = false; | |
| 491 | |
| 492 // This lock protects SrtpSession::inited_. | |
| 493 rtc::GlobalLockPod SrtpSession::lock_; | |
| 494 | |
| 495 SrtpSession::SrtpSession() {} | |
| 496 | |
| 497 SrtpSession::~SrtpSession() { | |
| 498 if (session_) { | |
| 499 srtp_set_user_data(session_, nullptr); | |
| 500 srtp_dealloc(session_); | |
| 501 } | |
| 502 } | |
| 503 | |
| 504 bool SrtpSession::SetSend(int cs, const uint8_t* key, size_t len) { | |
| 505 return SetKey(ssrc_any_outbound, cs, key, len); | |
| 506 } | |
| 507 | |
| 508 bool SrtpSession::UpdateSend(int cs, const uint8_t* key, size_t len) { | |
| 509 return UpdateKey(ssrc_any_outbound, cs, key, len); | |
| 510 } | |
| 511 | |
| 512 bool SrtpSession::SetRecv(int cs, const uint8_t* key, size_t len) { | |
| 513 return SetKey(ssrc_any_inbound, cs, key, len); | |
| 514 } | |
| 515 | |
| 516 bool SrtpSession::UpdateRecv(int cs, const uint8_t* key, size_t len) { | |
| 517 return UpdateKey(ssrc_any_inbound, cs, key, len); | |
| 518 } | |
| 519 | |
| 520 bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) { | |
| 521 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 522 if (!session_) { | |
| 523 LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session"; | |
| 524 return false; | |
| 525 } | |
| 526 | |
| 527 int need_len = in_len + rtp_auth_tag_len_; // NOLINT | |
| 528 if (max_len < need_len) { | |
| 529 LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length " | |
| 530 << max_len << " is less than the needed " << need_len; | |
| 531 return false; | |
| 532 } | |
| 533 | |
| 534 *out_len = in_len; | |
| 535 int err = srtp_protect(session_, p, out_len); | |
| 536 int seq_num; | |
| 537 GetRtpSeqNum(p, in_len, &seq_num); | |
| 538 if (err != srtp_err_status_ok) { | |
| 539 LOG(LS_WARNING) << "Failed to protect SRTP packet, seqnum=" | |
| 540 << seq_num << ", err=" << err << ", last seqnum=" | |
| 541 << last_send_seq_num_; | |
| 542 return false; | |
| 543 } | |
| 544 last_send_seq_num_ = seq_num; | |
| 545 return true; | |
| 546 } | |
| 547 | |
| 548 bool SrtpSession::ProtectRtp(void* p, | |
| 549 int in_len, | |
| 550 int max_len, | |
| 551 int* out_len, | |
| 552 int64_t* index) { | |
| 553 if (!ProtectRtp(p, in_len, max_len, out_len)) { | |
| 554 return false; | |
| 555 } | |
| 556 return (index) ? GetSendStreamPacketIndex(p, in_len, index) : true; | |
| 557 } | |
| 558 | |
| 559 bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) { | |
| 560 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 561 if (!session_) { | |
| 562 LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session"; | |
| 563 return false; | |
| 564 } | |
| 565 | |
| 566 int need_len = in_len + sizeof(uint32_t) + rtcp_auth_tag_len_; // NOLINT | |
| 567 if (max_len < need_len) { | |
| 568 LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length " | |
| 569 << max_len << " is less than the needed " << need_len; | |
| 570 return false; | |
| 571 } | |
| 572 | |
| 573 *out_len = in_len; | |
| 574 int err = srtp_protect_rtcp(session_, p, out_len); | |
| 575 if (err != srtp_err_status_ok) { | |
| 576 LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err; | |
| 577 return false; | |
| 578 } | |
| 579 return true; | |
| 580 } | |
| 581 | |
| 582 bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) { | |
| 583 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 584 if (!session_) { | |
| 585 LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session"; | |
| 586 return false; | |
| 587 } | |
| 588 | |
| 589 *out_len = in_len; | |
| 590 int err = srtp_unprotect(session_, p, out_len); | |
| 591 if (err != srtp_err_status_ok) { | |
| 592 LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err; | |
| 593 return false; | |
| 594 } | |
| 595 return true; | |
| 596 } | |
| 597 | |
| 598 bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) { | |
| 599 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 600 if (!session_) { | |
| 601 LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session"; | |
| 602 return false; | |
| 603 } | |
| 604 | |
| 605 *out_len = in_len; | |
| 606 int err = srtp_unprotect_rtcp(session_, p, out_len); | |
| 607 if (err != srtp_err_status_ok) { | |
| 608 LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err; | |
| 609 return false; | |
| 610 } | |
| 611 return true; | |
| 612 } | |
| 613 | |
| 614 bool SrtpSession::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) { | |
| 615 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 616 RTC_DCHECK(IsExternalAuthActive()); | |
| 617 if (!IsExternalAuthActive()) { | |
| 618 return false; | |
| 619 } | |
| 620 | |
| 621 ExternalHmacContext* external_hmac = nullptr; | |
| 622 // stream_template will be the reference context for other streams. | |
| 623 // Let's use it for getting the keys. | |
| 624 srtp_stream_ctx_t* srtp_context = session_->stream_template; | |
| 625 #if defined(SRTP_MAX_MKI_LEN) | |
| 626 // libsrtp 2.1.0 | |
| 627 if (srtp_context && srtp_context->session_keys && | |
| 628 srtp_context->session_keys->rtp_auth) { | |
| 629 external_hmac = reinterpret_cast<ExternalHmacContext*>( | |
| 630 srtp_context->session_keys->rtp_auth->state); | |
| 631 } | |
| 632 #else | |
| 633 // libsrtp 2.0.0 | |
| 634 // TODO(jbauch): Remove after switching to libsrtp 2.1.0 | |
| 635 if (srtp_context && srtp_context->rtp_auth) { | |
| 636 external_hmac = reinterpret_cast<ExternalHmacContext*>( | |
| 637 srtp_context->rtp_auth->state); | |
| 638 } | |
| 639 #endif | |
| 640 | |
| 641 if (!external_hmac) { | |
| 642 LOG(LS_ERROR) << "Failed to get auth keys from libsrtp!."; | |
| 643 return false; | |
| 644 } | |
| 645 | |
| 646 *key = external_hmac->key; | |
| 647 *key_len = external_hmac->key_length; | |
| 648 *tag_len = rtp_auth_tag_len_; | |
| 649 return true; | |
| 650 } | |
| 651 | |
| 652 int SrtpSession::GetSrtpOverhead() const { | |
| 653 return rtp_auth_tag_len_; | |
| 654 } | |
| 655 | |
| 656 void SrtpSession::EnableExternalAuth() { | |
| 657 RTC_DCHECK(!session_); | |
| 658 external_auth_enabled_ = true; | |
| 659 } | |
| 660 | |
| 661 bool SrtpSession::IsExternalAuthEnabled() const { | |
| 662 return external_auth_enabled_; | |
| 663 } | |
| 664 | |
| 665 bool SrtpSession::IsExternalAuthActive() const { | |
| 666 return external_auth_active_; | |
| 667 } | |
| 668 | |
| 669 bool SrtpSession::GetSendStreamPacketIndex(void* p, | |
| 670 int in_len, | |
| 671 int64_t* index) { | |
| 672 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 673 srtp_hdr_t* hdr = reinterpret_cast<srtp_hdr_t*>(p); | |
| 674 srtp_stream_ctx_t* stream = srtp_get_stream(session_, hdr->ssrc); | |
| 675 if (!stream) { | |
| 676 return false; | |
| 677 } | |
| 678 | |
| 679 // Shift packet index, put into network byte order | |
| 680 *index = static_cast<int64_t>( | |
| 681 rtc::NetworkToHost64( | |
| 682 srtp_rdbx_get_packet_index(&stream->rtp_rdbx) << 16)); | |
| 683 return true; | |
| 684 } | |
| 685 | |
| 686 | |
| 687 bool SrtpSession::DoSetKey(int type, int cs, const uint8_t* key, size_t len) { | |
| 688 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 689 | |
| 690 srtp_policy_t policy; | |
| 691 memset(&policy, 0, sizeof(policy)); | |
| 692 if (cs == rtc::SRTP_AES128_CM_SHA1_80) { | |
| 693 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); | |
| 694 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); | |
| 695 } else if (cs == rtc::SRTP_AES128_CM_SHA1_32) { | |
| 696 // RTP HMAC is shortened to 32 bits, but RTCP remains 80 bits. | |
| 697 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); | |
| 698 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); | |
| 699 } else if (cs == rtc::SRTP_AEAD_AES_128_GCM) { | |
| 700 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp); | |
| 701 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp); | |
| 702 } else if (cs == rtc::SRTP_AEAD_AES_256_GCM) { | |
| 703 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp); | |
| 704 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp); | |
| 705 } else { | |
| 706 LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create") | |
| 707 << " SRTP session: unsupported cipher_suite " << cs; | |
| 708 return false; | |
| 709 } | |
| 710 | |
| 711 int expected_key_len; | |
| 712 int expected_salt_len; | |
| 713 if (!rtc::GetSrtpKeyAndSaltLengths(cs, &expected_key_len, | |
| 714 &expected_salt_len)) { | |
| 715 // This should never happen. | |
| 716 LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create") | |
| 717 << " SRTP session: unsupported cipher_suite without length information" | |
| 718 << cs; | |
| 719 return false; | |
| 720 } | |
| 721 | |
| 722 if (!key || | |
| 723 len != static_cast<size_t>(expected_key_len + expected_salt_len)) { | |
| 724 LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create") | |
| 725 << " SRTP session: invalid key"; | |
| 726 return false; | |
| 727 } | |
| 728 | |
| 729 policy.ssrc.type = static_cast<srtp_ssrc_type_t>(type); | |
| 730 policy.ssrc.value = 0; | |
| 731 policy.key = const_cast<uint8_t*>(key); | |
| 732 // TODO(astor) parse window size from WSH session-param | |
| 733 policy.window_size = 1024; | |
| 734 policy.allow_repeat_tx = 1; | |
| 735 // If external authentication option is enabled, supply custom auth module | |
| 736 // id EXTERNAL_HMAC_SHA1 in the policy structure. | |
| 737 // We want to set this option only for rtp packets. | |
| 738 // By default policy structure is initialized to HMAC_SHA1. | |
| 739 // Enable external HMAC authentication only for outgoing streams and only | |
| 740 // for cipher suites that support it (i.e. only non-GCM cipher suites). | |
| 741 if (type == ssrc_any_outbound && IsExternalAuthEnabled() && | |
| 742 !rtc::IsGcmCryptoSuite(cs)) { | |
| 743 policy.rtp.auth_type = EXTERNAL_HMAC_SHA1; | |
| 744 } | |
| 745 if (!encrypted_header_extension_ids_.empty()) { | |
| 746 policy.enc_xtn_hdr = const_cast<int*>(&encrypted_header_extension_ids_[0]); | |
| 747 policy.enc_xtn_hdr_count = | |
| 748 static_cast<int>(encrypted_header_extension_ids_.size()); | |
| 749 } | |
| 750 policy.next = nullptr; | |
| 751 | |
| 752 if (!session_) { | |
| 753 int err = srtp_create(&session_, &policy); | |
| 754 if (err != srtp_err_status_ok) { | |
| 755 session_ = nullptr; | |
| 756 LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err; | |
| 757 return false; | |
| 758 } | |
| 759 srtp_set_user_data(session_, this); | |
| 760 } else { | |
| 761 int err = srtp_update(session_, &policy); | |
| 762 if (err != srtp_err_status_ok) { | |
| 763 LOG(LS_ERROR) << "Failed to update SRTP session, err=" << err; | |
| 764 return false; | |
| 765 } | |
| 766 } | |
| 767 | |
| 768 rtp_auth_tag_len_ = policy.rtp.auth_tag_len; | |
| 769 rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len; | |
| 770 external_auth_active_ = (policy.rtp.auth_type == EXTERNAL_HMAC_SHA1); | |
| 771 return true; | |
| 772 } | |
| 773 | |
| 774 bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, size_t len) { | |
| 775 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 776 if (session_) { | |
| 777 LOG(LS_ERROR) << "Failed to create SRTP session: " | |
| 778 << "SRTP session already created"; | |
| 779 return false; | |
| 780 } | |
| 781 | |
| 782 if (!Init()) { | |
| 783 return false; | |
| 784 } | |
| 785 | |
| 786 return DoSetKey(type, cs, key, len); | |
| 787 } | |
| 788 | |
| 789 bool SrtpSession::UpdateKey(int type, int cs, const uint8_t* key, size_t len) { | |
| 790 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 791 if (!session_) { | |
| 792 LOG(LS_ERROR) << "Failed to update non-existing SRTP session"; | |
| 793 return false; | |
| 794 } | |
| 795 | |
| 796 return DoSetKey(type, cs, key, len); | |
| 797 } | |
| 798 | |
| 799 void SrtpSession::SetEncryptedHeaderExtensionIds( | |
| 800 const std::vector<int>& encrypted_header_extension_ids) { | |
| 801 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 802 encrypted_header_extension_ids_ = encrypted_header_extension_ids; | |
| 803 } | |
| 804 | |
| 805 bool SrtpSession::Init() { | |
| 806 rtc::GlobalLockScope ls(&lock_); | |
| 807 | |
| 808 if (!inited_) { | |
| 809 int err; | |
| 810 err = srtp_init(); | |
| 811 if (err != srtp_err_status_ok) { | |
| 812 LOG(LS_ERROR) << "Failed to init SRTP, err=" << err; | |
| 813 return false; | |
| 814 } | |
| 815 | |
| 816 err = srtp_install_event_handler(&SrtpSession::HandleEventThunk); | |
| 817 if (err != srtp_err_status_ok) { | |
| 818 LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err; | |
| 819 return false; | |
| 820 } | |
| 821 | |
| 822 err = external_crypto_init(); | |
| 823 if (err != srtp_err_status_ok) { | |
| 824 LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err; | |
| 825 return false; | |
| 826 } | |
| 827 inited_ = true; | |
| 828 } | |
| 829 | |
| 830 return true; | |
| 831 } | |
| 832 | |
| 833 void SrtpSession::Terminate() { | |
| 834 rtc::GlobalLockScope ls(&lock_); | |
| 835 | |
| 836 if (inited_) { | |
| 837 int err = srtp_shutdown(); | |
| 838 if (err) { | |
| 839 LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err; | |
| 840 return; | |
| 841 } | |
| 842 inited_ = false; | |
| 843 } | |
| 844 } | |
| 845 | |
| 846 void SrtpSession::HandleEvent(const srtp_event_data_t* ev) { | |
| 847 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 848 switch (ev->event) { | |
| 849 case event_ssrc_collision: | |
| 850 LOG(LS_INFO) << "SRTP event: SSRC collision"; | |
| 851 break; | |
| 852 case event_key_soft_limit: | |
| 853 LOG(LS_INFO) << "SRTP event: reached soft key usage limit"; | |
| 854 break; | |
| 855 case event_key_hard_limit: | |
| 856 LOG(LS_INFO) << "SRTP event: reached hard key usage limit"; | |
| 857 break; | |
| 858 case event_packet_index_limit: | |
| 859 LOG(LS_INFO) << "SRTP event: reached hard packet limit (2^48 packets)"; | |
| 860 break; | |
| 861 default: | |
| 862 LOG(LS_INFO) << "SRTP event: unknown " << ev->event; | |
| 863 break; | |
| 864 } | |
| 865 } | |
| 866 | |
| 867 void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) { | |
| 868 // Callback will be executed from same thread that calls the "srtp_protect" | |
| 869 // and "srtp_unprotect" functions. | |
| 870 SrtpSession* session = static_cast<SrtpSession*>( | |
| 871 srtp_get_user_data(ev->session)); | |
| 872 if (session) { | |
| 873 session->HandleEvent(ev); | |
| 874 } | |
| 875 } | |
| 876 | |
| 877 } // namespace cricket | 484 } // namespace cricket |
| OLD | NEW |