srtp: basic implementation based on libsrtp2

Type: feature

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: Ic5e99938a5f130e83de6d590d2f89252d055bceb
This commit is contained in:
Florin Coras
2021-01-06 17:35:17 -08:00
committed by Dave Wallace
parent 6bb77dec70
commit 6621abf49a
15 changed files with 1543 additions and 4 deletions
+5
View File
@@ -754,6 +754,11 @@ M: Neale Ranns <neale@graphiant.com>
M: Matthew Smith <mgsmith@netgate.com>
F: src/plugins/linux-cp/
Plugin - SRTP
I: srtp
M: Florin Coras <fcoras@cisco.com>
F: src/plugins/srtp/
cJSON
I: cjson
M: Ole Troan <ot@cisco.com>
+1
View File
@@ -24,3 +24,4 @@ Programming notes for developers.
- @subpage snap_doc
- @subpage srv6_ad_flow_plugin_doc
- @subpage strongswan_test_doc
- @subpage srtp_doc
@@ -342,6 +342,9 @@ format_transport_proto (u8 * s, va_list * args)
case TRANSPORT_PROTO_DTLS:
s = format (s, "DTLS");
break;
case TRANSPORT_PROTO_SRTP:
s = format (s, "SRTP");
break;
default:
s = format (s, "UNKNOWN");
break;
+2 -1
View File
@@ -141,6 +141,7 @@ typedef struct vcl_test_session
vppcom_endpt_t endpt;
uint8_t ip[16];
vppcom_data_segment_t ds[2];
void *opaque;
} vcl_test_session_t;
static __thread int __wrk_index = 0;
@@ -169,7 +170,7 @@ typedef struct
typedef struct
{
const vcl_test_proto_vft_t *protos[VPPCOM_PROTO_DTLS + 1];
const vcl_test_proto_vft_t *protos[VPPCOM_PROTO_SRTP + 1];
uint32_t ckpair_index;
vcl_test_cfg_t cfg;
vcl_test_wrk_t *wrk;
+284
View File
@@ -677,6 +677,290 @@ static const vcl_test_proto_vft_t vcl_test_quic = {
VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_QUIC, vcl_test_quic);
static unsigned char test_key[46] = {
0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0, 0xd6, 0x4f, 0xa3, 0x2c,
0x06, 0xde, 0x41, 0x39, 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6, 0xc1, 0x73, 0xc3, 0x17, 0xf2, 0xda,
0xbe, 0x35, 0x77, 0x93, 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
};
typedef struct
{
unsigned char cc : 4;
unsigned char x : 1;
unsigned char p : 1;
unsigned char version : 2;
unsigned char pt : 7;
unsigned char m : 1;
uint16_t seq;
uint32_t ts;
uint32_t ssrc;
} rtp_hdr_t;
typedef struct
{
rtp_hdr_t tx_hdr;
rtp_hdr_t rx_hdr;
} rtp_headers_t;
typedef struct transport_endpt_cfg_srtp_policy
{
uint32_t ssrc_type;
uint32_t ssrc_value;
uint32_t window_size;
uint8_t allow_repeat_tx;
uint8_t key_len;
uint8_t key[46];
} transport_endpt_cfg_srtp_policy_t;
typedef struct transport_endpt_cfg_srtp
{
transport_endpt_cfg_srtp_policy_t policy[2];
} transport_endpt_cfg_srtp_t;
static void
vt_session_add_srtp_policy (vcl_test_session_t *ts, int is_connect)
{
transport_endpt_cfg_srtp_t *srtp_cfg;
transport_endpt_cfg_srtp_policy_t *test_policy;
uint32_t rx_ssrc, tx_ssrc;
uint32_t cfg_size;
rx_ssrc = is_connect ? 0xcafebeef : 0xbeefcafe;
tx_ssrc = is_connect ? 0xbeefcafe : 0xcafebeef;
cfg_size = sizeof (transport_endpt_cfg_srtp_t);
srtp_cfg = malloc (cfg_size);
memset (srtp_cfg, 0, cfg_size);
test_policy = &srtp_cfg->policy[0];
test_policy->ssrc_type = 1 /* ssrc_specific */;
test_policy->ssrc_value = rx_ssrc;
memcpy (test_policy->key, test_key, sizeof (test_key));
test_policy->key_len = sizeof (test_key);
test_policy->window_size = 128;
test_policy->allow_repeat_tx = 1;
test_policy = &srtp_cfg->policy[1];
test_policy->ssrc_type = 1 /* ssrc_specific */;
test_policy->ssrc_value = tx_ssrc;
memcpy (test_policy->key, test_key, sizeof (test_key));
test_policy->key_len = sizeof (test_key);
test_policy->window_size = 128;
test_policy->allow_repeat_tx = 1;
vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_ENDPT_EXT_CFG, srtp_cfg,
&cfg_size);
free (srtp_cfg);
}
static void
vt_srtp_session_init (vcl_test_session_t *ts, int is_connect)
{
uint32_t rx_ssrc, tx_ssrc;
rtp_headers_t *rtp_hdrs;
rtp_hdr_t *hdr;
rx_ssrc = is_connect ? 0xcafebeef : 0xbeefcafe;
tx_ssrc = is_connect ? 0xbeefcafe : 0xcafebeef;
rtp_hdrs = malloc (sizeof (rtp_headers_t));
memset (rtp_hdrs, 0, sizeof (*rtp_hdrs));
ts->opaque = rtp_hdrs;
hdr = &rtp_hdrs->rx_hdr;
hdr->version = 2;
hdr->p = 0;
hdr->x = 0;
hdr->cc = 0;
hdr->m = 0;
hdr->pt = 0x1;
hdr->seq = 0;
hdr->ts = 0;
hdr->ssrc = htonl (rx_ssrc);
hdr = &rtp_hdrs->tx_hdr;
hdr->version = 2;
hdr->p = 0;
hdr->x = 0;
hdr->cc = 0;
hdr->m = 0;
hdr->pt = 0x1;
hdr->seq = 0;
hdr->ts = 0;
hdr->ssrc = htonl (tx_ssrc);
}
static int
vt_srtp_write (vcl_test_session_t *ts, void *buf, uint32_t nbytes)
{
int tx_bytes = 0, nbytes_left = nbytes, rv;
vcl_test_stats_t *stats = &ts->stats;
rtp_hdr_t *hdr;
hdr = &((rtp_headers_t *) ts->opaque)->tx_hdr;
hdr->seq = htons (ntohs (hdr->seq) + 1);
hdr->ts = htonl (ntohl (hdr->ts) + 1);
memcpy (buf, hdr, sizeof (*hdr));
do
{
stats->tx_xacts++;
rv = vppcom_session_write (ts->fd, buf, nbytes_left);
if (rv < 0)
{
if ((rv == VPPCOM_EAGAIN || rv == VPPCOM_EWOULDBLOCK))
stats->tx_eagain++;
break;
}
tx_bytes += rv;
nbytes_left = nbytes_left - rv;
buf += rv;
stats->tx_incomp++;
}
while (tx_bytes != nbytes);
if (tx_bytes < 0)
return 0;
stats->tx_bytes += tx_bytes;
return (tx_bytes);
}
static inline int
vt_srtp_read (vcl_test_session_t *ts, void *buf, uint32_t nbytes)
{
vcl_test_stats_t *stats = &ts->stats;
rtp_hdr_t *hdr;
int rx_bytes;
stats->rx_xacts++;
rx_bytes = vppcom_session_read (ts->fd, buf, nbytes);
if (rx_bytes <= 0)
{
if (rx_bytes == VPPCOM_EAGAIN || rx_bytes == VPPCOM_EWOULDBLOCK)
stats->rx_eagain++;
else
return -1;
}
if (rx_bytes < nbytes)
stats->rx_incomp++;
stats->rx_bytes += rx_bytes;
hdr = &((rtp_headers_t *) ts->opaque)->rx_hdr;
if (((rtp_hdr_t *) buf)->ssrc != hdr->ssrc)
hdr->ssrc = ((rtp_hdr_t *) buf)->ssrc;
return (rx_bytes);
}
static int
vt_srtp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
{
uint32_t flags, flen;
int rv;
ts->fd = vppcom_session_create (VPPCOM_PROTO_SRTP, 0 /* is_nonblocking */);
if (ts->fd < 0)
{
vterr ("vppcom_session_create()", ts->fd);
return ts->fd;
}
vt_session_add_srtp_policy (ts, 1 /* is connect */);
/* Connect is blocking */
rv = vppcom_session_connect (ts->fd, endpt);
if (rv < 0)
{
vterr ("vppcom_session_connect()", rv);
return rv;
}
ts->read = vt_srtp_read;
ts->write = vt_srtp_write;
flags = O_NONBLOCK;
flen = sizeof (flags);
vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
vt_srtp_session_init (ts, 1 /* is connect */);
return 0;
}
static int
vt_srtp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
{
int rv;
ts->fd = vppcom_session_create (VPPCOM_PROTO_SRTP, 1 /* is_nonblocking */);
if (ts->fd < 0)
{
vterr ("vppcom_session_create()", ts->fd);
return ts->fd;
}
vt_session_add_srtp_policy (ts, 0 /* is connect */);
rv = vppcom_session_bind (ts->fd, endpt);
if (rv < 0)
{
vterr ("vppcom_session_bind()", rv);
return rv;
}
rv = vppcom_session_listen (ts->fd, 10);
if (rv < 0)
{
vterr ("vppcom_session_listen()", rv);
return rv;
}
return 0;
}
static int
vt_srtp_accept (int listen_fd, vcl_test_session_t *ts)
{
int client_fd;
client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
if (client_fd < 0)
{
vterr ("vppcom_session_accept()", client_fd);
return client_fd;
}
ts->fd = client_fd;
ts->is_open = 1;
ts->read = vt_srtp_read;
ts->write = vt_srtp_write;
vt_srtp_session_init (ts, 0 /* is connect */);
return 0;
}
static int
vt_srtp_close (vcl_test_session_t *ts)
{
free (ts->opaque);
return 0;
}
static const vcl_test_proto_vft_t vcl_test_srtp = {
.open = vt_srtp_connect,
.listen = vt_srtp_listen,
.accept = vt_srtp_accept,
.close = vt_srtp_close,
};
VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_SRTP, vcl_test_srtp);
/*
* fd.io coding-style-patch-verification: ON
*
+41
View File
@@ -0,0 +1,41 @@
# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include (CheckFunctionExists)
vpp_plugin_find_library(srtp SRTP_LIB libsrtp2.a)
if (NOT SRTP_LIB)
message(WARNING "srtp plugin - srtp2 lib not found - plugin disabled")
return()
endif()
vpp_find_path(SRTP_INCLUDE_DIR NAMES srtp2/srtp.h)
if (NOT SRTP_INCLUDE_DIR)
message(WARNING "srtp plugin - srtp.h not found - plugin disabled")
return()
endif()
include_directories (${SRTP_INCLUDE_DIR})
set(CMAKE_REQUIRED_FLAGS "-fPIC -shared -pthread -Wno-unused-command-line-argument ${SRTP_LIB}")
set(CMAKE_REQUIRED_INCLUDES "${SRTP_INCLUDE_DIR}")
add_vpp_plugin(srtp
SOURCES
srtp.c
LINK_LIBRARIES
${SRTP_LIB}
)
+8
View File
@@ -0,0 +1,8 @@
---
name: SRTP (Secure Real-time Transport Protocol)
maintainer: Florin Coras <fcoras@cisco.com>
features:
- SRTP transport protocol implementation
description: "SRTP transport protocol implementation based on libsrtp2"
state: experimental
properties: [MULTITHREAD]
File diff suppressed because it is too large Load Diff
+120
View File
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2021 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include <vnet/session/application_interface.h>
#include <vnet/session/application.h>
#include <srtp2/srtp.h>
#ifndef SRC_PLUGINS_SRTP_SRTP_H_
#define SRC_PLUGINS_SRTP_SRTP_H_
#define SRTP_DEBUG 0
#if SRTP_DEBUG
#define SRTP_DBG(_lvl, _fmt, _args...) \
if (_lvl <= SRTP_DEBUG) \
clib_warning (_fmt, ##_args)
#else
#define SRTP_DBG(_lvl, _fmt, _args...)
#endif
typedef struct srtp_cxt_id_
{
union
{
session_handle_t app_session_handle;
u32 parent_app_api_ctx;
};
session_handle_t srtp_session_handle;
u32 parent_app_wrk_index;
u32 srtp_ctx;
u32 listener_ctx_index;
u8 udp_is_ip4;
} srtp_ctx_id_t;
STATIC_ASSERT (sizeof (srtp_ctx_id_t) <= TRANSPORT_CONN_ID_LEN,
"ctx id must be less than TRANSPORT_CONN_ID_LEN");
#define SRTP_MAX_KEYLEN 46 /**< libsrtp AES 256 key len with salt */
typedef struct transport_endpt_cfg_srtp_policy
{
u32 ssrc_type;
u32 ssrc_value;
u32 window_size;
u8 allow_repeat_tx;
u8 key_len;
u8 key[SRTP_MAX_KEYLEN];
} transport_endpt_cfg_srtp_policy_t;
typedef struct transport_endpt_cfg_srtp
{
transport_endpt_cfg_srtp_policy_t policies[2];
} transport_endpt_cfg_srtp_t;
typedef struct srtp_ctx_
{
union
{
transport_connection_t connection;
srtp_ctx_id_t c_srtp_ctx_id;
};
#define parent_app_wrk_index c_srtp_ctx_id.parent_app_wrk_index
#define app_session_handle c_srtp_ctx_id.app_session_handle
#define srtp_session_handle c_srtp_ctx_id.srtp_session_handle
#define listener_ctx_index c_srtp_ctx_id.listener_ctx_index
#define udp_is_ip4 c_srtp_ctx_id.udp_is_ip4
#define srtp_ctx_engine c_srtp_ctx_id.srtp_engine_id
#define srtp_ssl_ctx c_srtp_ctx_id.ssl_ctx
#define srtp_ctx_handle c_c_index
/* Temporary storage for session open opaque. Overwritten once
* underlying tcp connection is established */
#define parent_app_api_context c_srtp_ctx_id.parent_app_api_ctx
u8 is_passive_close;
u8 resume;
u8 app_closed;
u8 no_app_session;
u8 is_migrated;
srtp_t srtp_ctx;
srtp_policy_t srtp_policy[2];
} srtp_tc_t;
typedef struct srtp_main_
{
srtp_tc_t **ctx_pool;
srtp_tc_t *listener_ctx_pool;
u32 app_index;
clib_rwlock_t half_open_rwlock;
/*
* Config
*/
u64 first_seg_size;
u32 fifo_size;
} srtp_main_t;
#endif /* SRC_PLUGINS_SRTP_SRTP_H_ */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
+72
View File
@@ -0,0 +1,72 @@
# SRTP (Secure Real-time Transport Protocol) {#srtp_doc}
libsrtp2 based SRTP transport protocol implementation.
## Maturity level
Experimental
## Quickstart
1. Install libsrtp2-dev. On debian based OS:
```
sudo apt get install libsrtp2-dev
```
2. Build vpp
```
make build
```
3. Test protocol using vcl test server and client. On server side, start vpp and server app:
```
export VT_PATH=$WS/build-root/build-vpp_debug-native/vpp/bin
$VT_PATH/vcl_test_server 1234 -p srtp
```
On client side:
```
export VT_PATH=$WS/build-root/build-vpp_debug-native/vpp/bin
$VT_PATH/vcl_test_client <server-ip> 1234 -U -X -S -N 10000 -T 128 -p srtp
```
## Custom libsrtp2 build
1. Create `build/external/packages/srtp.mk` with following example contents:
```
srtp_version := 2.3.0
srtp_tarball := srtp_$(srtp_version).tar.gz
srtp_tarball_md5sum := da38ee5d9c31be212a12964c22d7f795
srtp_tarball_strip_dirs := 1
srtp_url := https://github.com/cisco/libsrtp/archive/v$(srtp_version).tar.gz
define srtp_build_cmds
@cd $(srtp_build_dir) && \
$(CMAKE) -DCMAKE_INSTALL_PREFIX:PATH=$(srtp_install_dir) \
-DCMAKE_C_FLAGS='-fPIC -fvisibility=hidden' $(srtp_src_dir) > $(srtp_build_log)
@$(MAKE) $(MAKE_ARGS) -C $(srtp_build_dir) > $(srtp_build_log)
endef
define srtp_config_cmds
@true
endef
define srtp_install_cmds
@$(MAKE) $(MAKE_ARGS) -C $(srtp_build_dir) install > $(srtp_install_log)
endef
$(eval $(call package,srtp))
```
2. Include `srtp.mk` in `build/external/Makefile` and add to install target.
3. Rebuild external dependencies:
```
make install-ext-deps
```
+2 -1
View File
@@ -626,7 +626,8 @@ vcl_ip_copy_to_ep (ip46_address_t * ip, vppcom_endpt_t * ep, u8 is_ip4)
static inline int
vcl_proto_is_dgram (uint8_t proto)
{
return proto == VPPCOM_PROTO_UDP || proto == VPPCOM_PROTO_DTLS;
return proto == VPPCOM_PROTO_UDP || proto == VPPCOM_PROTO_DTLS ||
proto == VPPCOM_PROTO_SRTP;
}
static inline u8
+7
View File
@@ -1666,6 +1666,10 @@ vppcom_unformat_proto (uint8_t * proto, char *proto_str)
*proto = VPPCOM_PROTO_DTLS;
else if (!strcmp (proto_str, "dtls"))
*proto = VPPCOM_PROTO_DTLS;
else if (!strcmp (proto_str, "SRTP"))
*proto = VPPCOM_PROTO_SRTP;
else if (!strcmp (proto_str, "srtp"))
*proto = VPPCOM_PROTO_SRTP;
else
return 1;
return 0;
@@ -4128,6 +4132,9 @@ vppcom_proto_str (vppcom_proto_t proto)
case VPPCOM_PROTO_DTLS:
proto_str = "DTLS";
break;
case VPPCOM_PROTO_SRTP:
proto_str = "SRTP";
break;
default:
proto_str = "UNKNOWN";
break;
+1
View File
@@ -53,6 +53,7 @@ extern "C"
VPPCOM_PROTO_TLS,
VPPCOM_PROTO_QUIC,
VPPCOM_PROTO_DTLS,
VPPCOM_PROTO_SRTP,
} vppcom_proto_t;
typedef enum
+1 -1
View File
@@ -1966,7 +1966,7 @@ session_main_init (vlib_main_t * vm)
smm->evt_qs_segment_size = 1 << 20;
#endif
smm->last_transport_proto_type = TRANSPORT_PROTO_DTLS;
smm->last_transport_proto_type = TRANSPORT_PROTO_SRTP;
return 0;
}
+2 -1
View File
@@ -163,7 +163,8 @@ STATIC_ASSERT (sizeof (transport_connection_t) <= 128,
_ (NONE, "ct", "C") \
_ (TLS, "tls", "J") \
_ (QUIC, "quic", "Q") \
_ (DTLS, "dtls", "D")
_ (DTLS, "dtls", "D") \
_ (SRTP, "srtp", "R")
typedef enum _transport_proto
{