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 |