|
|
|
|
@ -3,6 +3,7 @@
|
|
|
|
|
use strict;
|
|
|
|
|
use warnings;
|
|
|
|
|
use NGCP::Rtpengine::Test;
|
|
|
|
|
use NGCP::Rtpclient::SRTP;
|
|
|
|
|
use Test::More;
|
|
|
|
|
use File::Temp;
|
|
|
|
|
use IPC::Open3;
|
|
|
|
|
@ -115,13 +116,16 @@ sub rtp {
|
|
|
|
|
return pack('CCnNN a*', 0x80, $pt, $seq, $ts, $ssrc, $payload);
|
|
|
|
|
}
|
|
|
|
|
sub rcv {
|
|
|
|
|
my ($sock, $port, $match) = @_;
|
|
|
|
|
my ($sock, $port, $match, $cb, $cb_arg) = @_;
|
|
|
|
|
my $p = '';
|
|
|
|
|
alarm(1);
|
|
|
|
|
my $addr = $sock->recv($p, 65535, 0) or die;
|
|
|
|
|
alarm(0);
|
|
|
|
|
my ($hdr_mark, $pt, $seq, $ts, $ssrc, $payload) = unpack('CCnNN a*', $p);
|
|
|
|
|
print("rtp recv $pt $seq $ts $ssrc\n");
|
|
|
|
|
if ($cb) {
|
|
|
|
|
$p = $cb->($hdr_mark, $pt, $seq, $ts, $ssrc, $payload, $p, $cb_arg);
|
|
|
|
|
}
|
|
|
|
|
like $p, $match, 'received packet matches';
|
|
|
|
|
my @matches = $p =~ $match;
|
|
|
|
|
for my $m (@matches) {
|
|
|
|
|
@ -134,6 +138,21 @@ sub rcv {
|
|
|
|
|
}
|
|
|
|
|
return @matches;
|
|
|
|
|
}
|
|
|
|
|
sub srtp_rcv {
|
|
|
|
|
my ($sock, $port, $match, $srtp_ctx) = @_;
|
|
|
|
|
return rcv($sock, $port, $match, \&srtp_dec, $srtp_ctx);
|
|
|
|
|
}
|
|
|
|
|
sub srtp_dec {
|
|
|
|
|
my ($hdr_mark, $pt, $seq, $ts, $ssrc, $payload, $pack, $srtp_ctx) = @_;
|
|
|
|
|
if (!$srtp_ctx->{skey}) {
|
|
|
|
|
my ($key, $salt) = NGCP::Rtpclient::SRTP::decode_inline_base64($srtp_ctx->{key}, $srtp_ctx->{cs});
|
|
|
|
|
@$srtp_ctx{qw(skey sauth ssalt)} = NGCP::Rtpclient::SRTP::gen_rtp_session_keys($key, $salt);
|
|
|
|
|
}
|
|
|
|
|
my ($dec, $out_roc, $tag, $hmac) = NGCP::Rtpclient::SRTP::decrypt_rtp(@$srtp_ctx{qw(cs skey ssalt sauth roc)}, $pack);
|
|
|
|
|
$srtp_ctx->{roc} = $out_roc;
|
|
|
|
|
is $tag, substr($hmac, 0, length($tag)), 'SRTP auth tag matches';
|
|
|
|
|
return $dec;
|
|
|
|
|
}
|
|
|
|
|
sub escape {
|
|
|
|
|
return "\Q$_[0]\E";
|
|
|
|
|
}
|
|
|
|
|
@ -1545,6 +1564,78 @@ rcv($sock_b, -1, rtpm(8, $seq + 9, $ts + 160 * 4, $ssrc, $pcma_5));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
($sock_a, $sock_b) = new_call([qw(198.51.100.1 2050)], [qw(198.51.100.3 2052)]);
|
|
|
|
|
|
|
|
|
|
offer('media playback, SRTP', { ICE => 'remove', replace => ['origin'], DTLS => 'off' }, <<SDP);
|
|
|
|
|
v=0
|
|
|
|
|
o=- 1545997027 1 IN IP4 198.51.100.1
|
|
|
|
|
s=tester
|
|
|
|
|
t=0 0
|
|
|
|
|
m=audio 2050 RTP/SAVP 8
|
|
|
|
|
c=IN IP4 198.51.100.1
|
|
|
|
|
a=sendrecv
|
|
|
|
|
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:eMlRvW8mWU4WodT9JOvAM+pn6I0/EXOhT9n0KeKk
|
|
|
|
|
----------------------------------
|
|
|
|
|
v=0
|
|
|
|
|
o=- 1545997027 1 IN IP4 203.0.113.1
|
|
|
|
|
s=tester
|
|
|
|
|
t=0 0
|
|
|
|
|
m=audio PORT RTP/SAVP 8
|
|
|
|
|
c=IN IP4 203.0.113.1
|
|
|
|
|
a=rtpmap:8 PCMA/8000
|
|
|
|
|
a=sendrecv
|
|
|
|
|
a=rtcp:PORT
|
|
|
|
|
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:eMlRvW8mWU4WodT9JOvAM+pn6I0/EXOhT9n0KeKk
|
|
|
|
|
a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:CRYPTO128
|
|
|
|
|
a=crypto:3 AES_192_CM_HMAC_SHA1_80 inline:CRYPTO192
|
|
|
|
|
a=crypto:4 AES_192_CM_HMAC_SHA1_32 inline:CRYPTO192
|
|
|
|
|
a=crypto:5 AES_256_CM_HMAC_SHA1_80 inline:CRYPTO256
|
|
|
|
|
a=crypto:6 AES_256_CM_HMAC_SHA1_32 inline:CRYPTO256
|
|
|
|
|
a=crypto:7 F8_128_HMAC_SHA1_80 inline:CRYPTO128
|
|
|
|
|
a=crypto:8 F8_128_HMAC_SHA1_32 inline:CRYPTO128
|
|
|
|
|
a=crypto:9 NULL_HMAC_SHA1_80 inline:CRYPTO128
|
|
|
|
|
a=crypto:10 NULL_HMAC_SHA1_32 inline:CRYPTO128
|
|
|
|
|
SDP
|
|
|
|
|
|
|
|
|
|
answer('media playback, SRTP', { replace => ['origin'] }, <<SDP);
|
|
|
|
|
v=0
|
|
|
|
|
o=- 1545997027 1 IN IP4 198.51.100.3
|
|
|
|
|
s=tester
|
|
|
|
|
t=0 0
|
|
|
|
|
m=audio 2052 RTP/SAVP 8
|
|
|
|
|
c=IN IP4 198.51.100.3
|
|
|
|
|
a=sendrecv
|
|
|
|
|
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:DVM+BTeYX2UI1LaA9bgXrcBEDBxoItA9/39fSoRF
|
|
|
|
|
--------------------------------------
|
|
|
|
|
v=0
|
|
|
|
|
o=- 1545997027 1 IN IP4 203.0.113.1
|
|
|
|
|
s=tester
|
|
|
|
|
t=0 0
|
|
|
|
|
m=audio PORT RTP/SAVP 8
|
|
|
|
|
c=IN IP4 203.0.113.1
|
|
|
|
|
a=rtpmap:8 PCMA/8000
|
|
|
|
|
a=sendrecv
|
|
|
|
|
a=rtcp:PORT
|
|
|
|
|
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:DVM+BTeYX2UI1LaA9bgXrcBEDBxoItA9/39fSoRF
|
|
|
|
|
SDP
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$resp = rtpe_req('play media', 'media playback, SRTP', { 'from-tag' => $ft, blob => $wav_file });
|
|
|
|
|
is $resp->{duration}, 100, 'media duration';
|
|
|
|
|
|
|
|
|
|
my $srtp_ctx = {
|
|
|
|
|
cs => $NGCP::Rtpclient::SRTP::crypto_suites{AES_CM_128_HMAC_SHA1_80},
|
|
|
|
|
key => 'DVM+BTeYX2UI1LaA9bgXrcBEDBxoItA9/39fSoRF',
|
|
|
|
|
};
|
|
|
|
|
($seq, $ts, $ssrc) = srtp_rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1), $srtp_ctx);
|
|
|
|
|
srtp_rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2), $srtp_ctx);
|
|
|
|
|
srtp_rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3), $srtp_ctx);
|
|
|
|
|
srtp_rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4), $srtp_ctx);
|
|
|
|
|
srtp_rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5), $srtp_ctx);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
END {
|
|
|
|
|
if ($rtpe_pid) {
|
|
|
|
|
kill('INT', $rtpe_pid) or die;
|
|
|
|
|
|