mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
8da177c0bf
openssl 1.1.1e does some stricker EOF handling and will throw an error if the EOF is unexpected (like in the middle of a record). As we are streaming data into openssl here, it is entirely possible that we push data from multiple buffers/packets into openssl separately. From the openssl changelog: Changes between 1.1.1d and 1.1.1e [17 Mar 2020] *) Properly detect EOF while reading in libssl. Previously if we hit an EOF while reading in libssl then we would report an error back to the application (SSL_ERROR_SYSCALL) but errno would be 0. We now add an error to the stack (which means we instead return SSL_ERROR_SSL) and therefore give a hint as to what went wrong. [Matt Caswell] We can relax the EOF signalling to only return TRUE when we have stopped for any reason (EOS, error). Will also remove a spurious EOF error from previous openssl version. |
||
---|---|---|
.. | ||
gstdtlsagent.c | ||
gstdtlsagent.h | ||
gstdtlscertificate.c | ||
gstdtlscertificate.h | ||
gstdtlsconnection.c | ||
gstdtlsconnection.h | ||
gstdtlsdec.c | ||
gstdtlsdec.h | ||
gstdtlsenc.c | ||
gstdtlsenc.h | ||
gstdtlssrtpbin.c | ||
gstdtlssrtpbin.h | ||
gstdtlssrtpdec.c | ||
gstdtlssrtpdec.h | ||
gstdtlssrtpdemux.c | ||
gstdtlssrtpdemux.h | ||
gstdtlssrtpenc.c | ||
gstdtlssrtpenc.h | ||
meson.build | ||
plugin.c | ||
README |
INTRODUCTION ============ This document is an attempt to describe the basics of the DTLS element. It hasn't been written by the author(s) and so, besides being incomplete, *IT MIGHT ALSO BE INCORRECT*. So take it with a pinch of salt. As always, if in doubt ask the #gstreamer IRC channel. THE INTERNALS ============= This plugin provides two main elements (dtlssrtpdec and dtlssrtpenc) and a few minor elements necessary to implement them. The two elements dtlssrtpdec and dtlssrtpenc are the only ones you are supposed to include in, respectively, the RX and TX pipelines of your DTLS-enabled application. This means you're not supposed to directly include those minor elements in your pipelines. dtlssrtpenc ----------- This element is to be included in the TX pipeline and will initiate the DTLS handshake if configured to be the client. Its main configuration parameters are: - connection-id: a string that must match the connection-id in dtlssrtpdec; - is-client: a boolean that indicates whether this is going to be the client or the server during the DTLS handshake. Internally this element comprises the standard srtpenc element, the dtlsenc element and a funnel to connect both these elements to one single output. The srtpenc can be used to encrypt SRTP/SRTCP packets while the dtlsenc can be used to encrypt generic data, e.g. for non-SRTP applications. NB With the current implementation the TX pipeline containing the dtlssrtpenc must be created *AFTER* the RX pipeline. dtlssrtpdec ----------- It is to be included in the RX pipeline. Its main configuration parameters are: - connection-id: a string that must match the connection-id in dtlssrtpenc; - pem: a string that can be used to provide your own certificate *AND* private key in PEM format. The private key is required to carry out the handshake so do not forget it or the DTLS negotiation will fail; - peer_pem: a read only parameter that can be used to retrieve the certificate sent from the other party in PEM format once the handshake is completed. Internally this element comprises a dtlssrtpdemux, a standard srtpdec element and the dtlsdec element. The dtlssrtpdemux element switches SRT(C)P packets to the srtpdec element and DTLS packets to the dtlsdec element and discards any other unknown packet. So, similarly for the dtlssrtpenc case, DTLS-SRTP applications would exercise the srtpdec element and any other non-SRTP application would exercise the dtlsdec element. NB With the current implementation the RX pipeline containing the dtlssrtpdec must be created *BEFORE* the TX pipeline. EXAMPLE PIPELINE ================ The following is an example usage of the DTLS plugin. It is a python script that creates two endpoints that exchange encrypted audio using DTLS to exchange the encryption keys. NB In theory we would show an example gst-launch command. However that would not be enough because you need two pairs of TX/RX pipelines for a proper handshake and you can't use gst-launch two start 4 different pipelines. This why there is a python script in here. ``` #!/usr/bin/env python3 # create two endpoints, each with tx and rx pipelines using the DTLS # elements and let audio flowing for a while to give time for a packet capture import time from gi.repository import Gst, GObject, GLib GObject.threads_init() Gst.init(None) def _start_pipeline(pipeline): pipeline.set_state(Gst.State.PLAYING) pipeline.get_state(Gst.CLOCK_TIME_NONE) def _sleep_while_iterating_gloop(secs): """ block for secs seconds but iterate the gloop while you do """ for _ in range(10 * secs): gloop = GLib.MainLoop() gloop_context = gloop.get_context() gloop_context.iteration(may_block=False) time.sleep(0.1) def dtls_tx_pipeline_description(name, is_client, port): return ' ! '.join([ 'audiotestsrc is-live=true', 'audio/x-raw, rate=8000, format=S16LE, channels=1', 'opusenc frame-size=10', 'rtpopuspay pt=103', '.rtp_sink_0 dtlssrtpenc connection-id={name} is-client={client} .src', 'udpsink port={port}' ]).format(name=name, client=is_client, port=port) def dtls_rx_pipeline_description(name, port): return ' ! '.join([ 'udpsrc port={port}', '.sink dtlssrtpdec connection-id={name} .rtp_src', 'queue', 'fakesink async=false' ]).format(name=name, port=port) class Endpoint: def __init__(self, name, is_client, tx_port, rx_port): self.name = name tx_pipeline_description = dtls_tx_pipeline_description( name, is_client, tx_port ) rx_pipeline_description = dtls_rx_pipeline_description(name, rx_port) print(rx_pipeline_description) print(tx_pipeline_description) self.rx_pipeline = Gst.parse_launch(rx_pipeline_description) self.tx_pipeline = Gst.parse_launch(tx_pipeline_description) def start(self): # Start RX first, otherwise it fails due to the current implementation self.start_rx_pipeline() self.start_tx_pipeline() def start_rx_pipeline(self): _start_pipeline(self.rx_pipeline) def start_tx_pipeline(self): _start_pipeline(self.tx_pipeline) def stop(self): def stop_pipeline(p): p.set_state(Gst.State.NULL) p.get_state(Gst.CLOCK_TIME_NONE) stop_pipeline(self.tx_pipeline) stop_pipeline(self.rx_pipeline) blue = Endpoint("blue", is_client=True, tx_port=23000, rx_port=23002) red = Endpoint("red", is_client=False, tx_port=23002, rx_port=23000) red.start() blue.start() _sleep_while_iterating_gloop(3) red.stop() blue.stop() ```