在PeerConnection中无论是SetLocalDescription还是SetRemoteDescription,里面的第一个都是对SDP进行认证检测即调用ValidateSessionDescription,在ValidateSessionDescription中主要对如下三个方面进行了认证:
1 加密信息认证
2 ice信息认证
3 m-section中track个数进行认证
- RTCError VerifyCrypto(const SessionDescription* desc, bool dtls_enabled)
- {
- const cricket::ContentGroup* bundle = desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
- for (const cricket::ContentInfo& content_info : desc->contents())
- {
- 1 被拒绝的直接忽略
- if (content_info.rejected)
- {
- continue;
- }
-
- // Note what media is used with each crypto protocol, for all sections.
- NoteKeyProtocolAndMedia(dtls_enabled ? webrtc::kEnumCounterKeyProtocolDtls
- : webrtc::kEnumCounterKeyProtocolSdes,
- content_info.media_description()->type());
- const std::string& mid = content_info.name;
- if (bundle && bundle->HasContentName(mid) && mid != *(bundle->FirstContentName()))
- {
- // This isn't the first media section in the BUNDLE group, so it's not
- // required to have crypto attributes, since only the crypto attributes
- // from the first section actually get used.
- continue;
- }
-
- 2 如果开启BUNDLE,则看看第一个是否包含fingerprint,没有则返回false
-
- // If the content isn't rejected or bundled into another m= section, crypto
- // must be present.
- const MediaContentDescription* media = content_info.media_description();
- const TransportInfo* tinfo = desc->GetTransportInfoByName(mid);
- if (!media || !tinfo)
- {
- // Something is not right.
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, kInvalidSdp);
- }
- if (dtls_enabled)
- {
- if (!tinfo->description.identity_fingerprint)
- {
- RTC_LOG(LS_WARNING)
- << "Session description must have DTLS fingerprint if "
- "DTLS enabled.";
- return RTCError(RTCErrorType::INVALID_PARAMETER, kSdpWithoutDtlsFingerprint);
- }
- }
- else
- {
- if (media->cryptos().empty())
- {
- RTC_LOG(LS_WARNING)
- << "Session description must have SDES when DTLS disabled.";
- return RTCError(RTCErrorType::INVALID_PARAMETER, kSdpWithoutSdesCrypto);
- }
- }
- }
- return RTCError::OK();
- }
代码中已做标注
- bool VerifyIceUfragPwdPresent(const SessionDescription* desc)
- {
- 0 判断是否有BUNDLE,并获取BUNDLE列表即mid列表
- const cricket::ContentGroup* bundle = desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
- for (const cricket::ContentInfo& content_info : desc->contents())
- {
- 1 被拒绝的m-section直接continue
- if (content_info.rejected)
- {
- continue;
- }
-
- 2 如果开启了BUNDLE,并且当前m-section在BUNDLE中,但不是第一个m-section则直接continue
-
- const std::string& mid = content_info.name;
- if (bundle && bundle->HasContentName(mid) && mid != *(bundle->FirstContentName()))
- {
- // This isn't the first media section in the BUNDLE group, so it's not
- // required to have ufrag/password, since only the ufrag/password from
- // the first section actually get used.
- continue;
- }
-
- 3 如果第一个m-section中获取不到ice信息
- // If the content isn't rejected or bundled into another m= section,
- // ice-ufrag and ice-pwd must be present.
- const TransportInfo* tinfo = desc->GetTransportInfoByName(mid);
- if (!tinfo)
- {
- // Something is not right.
- RTC_LOG(LS_ERROR) << kInvalidSdp;
- return false;
- }
-
- 4 如果ice_ufrag或ice_pwd任意一个为空 则返回false
- if (tinfo->description.ice_ufrag.empty() || tinfo->description.ice_pwd.empty())
- {
- RTC_LOG(LS_ERROR) << "Session description must have ice ufrag and pwd.";
- return false;
- }
- }
- return true;
- }
- if (IsUnifiedPlan())
- {
- // Ensure that each audio and video media section has at most one
- // "StreamParams". This will return an error if receiving a session
- // description from a "Plan B" endpoint which adds multiple tracks of the
- // same type. With Unified Plan, there can only be at most one track per
- // media section.
- for (const ContentInfo& content : sdesc->description()->contents())
- {
- const MediaContentDescription& desc = *content.description;
- if ((desc.type() == cricket::MEDIA_TYPE_AUDIO ||
- desc.type() == cricket::MEDIA_TYPE_VIDEO) &&
- desc.streams().size() > 1u) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
- "Media section has more than one track specified "
- "with a=ssrc lines which is not supported with "
- "Unified Plan.");
- }
- }
- }
这里只列出了公共认证部分,针对answer还有一个m-section个数和顺序的认证,详见如下两个函数:
MediaSectionsHaveSameCount()和MediaSectionsInSameOrder()
从上可以得出,UnifiedPlan下开启BUNDLE时其认证的过程可以总结为:
1 加密信息在第一个m-section中必须有,其他m-section随意
2 同上,ice信息在第一个m-section中必须有,其他m-section随意
3 如果开启BUNDLE,每个m-section中必须有a=rtcp-mux属性
4 UnifiedPlan中,每个m-section中只能有一个track