Need help on RTSP server and TLS including verify peer (ca cert) and (cert,key).

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view

Need help on RTSP server and TLS including verify peer (ca cert) and (cert,key).

enthusiastic geek
This post was updated on .
I have modified RTSP server example (test-video.c) as follows to include cacert as a database file. However on the receiving end I am not sure how to construct the rtspsrc pipeline with TLS (I can use pipeline without TLS but I want TLS). If I remove
gst_rtsp_auth_set_tls_authentication_mode(auth, G_TLS_AUTHENTICATION_REQUIRED);
 from the server code and on the client side use

  g_object_set (G_OBJECT (source), "tls-validation-flags", 0x00000040, NULL);
 instead of

  g_object_set (G_OBJECT (source), "tls-validation-flags", 0x0000007f, NULL);
then both my server and client code work, but it defeats the purpose of x509 digital certificates. Can anyone who is experienced in "tls-database" property on rtspsrc or "tls-interaction" property on rtspsrc guide me on this?

RTSP Server

#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <gio/gio.h>

/* define this if you want the resource to only be available when using
 * user/password as the password */
#undef WITH_AUTH
#define WITH_AUTH 1

/* define this if you want the server to use TLS (it will also need WITH_AUTH
 * to be defined) */
#undef WITH_TLS
#define WITH_TLS 1

/* this timeout is periodically run to clean up the expired sessions from the
 * pool. This needs to be run explicitly currently but might be done
 * automatically as part of the mainloop. */
static gboolean
timeout (GstRTSPServer * server)
  GstRTSPSessionPool *pool;

  pool = gst_rtsp_server_get_session_pool (server);
  gst_rtsp_session_pool_cleanup (pool);
  g_object_unref (pool);

  return TRUE;

main (int argc, char *argv[])
  GMainLoop *loop;
  GstRTSPServer *server;
  GstRTSPMountPoints *mounts;
  GstRTSPMediaFactory *factory;
#ifdef WITH_AUTH
  GstRTSPAuth *auth;
  GstRTSPToken *token;
  gchar *basic;
  GstRTSPPermissions *permissions;
#ifdef WITH_TLS
  GTlsCertificate *cert;
  GTlsCertificate *ca_cert;
  GError *error = NULL;

  gst_init (&argc, &argv);

  loop = g_main_loop_new (NULL, FALSE);

  /* create a server instance */
  server = gst_rtsp_server_new ();

#ifdef WITH_AUTH
  /* make a new authentication manager. it can be added to control access to all
   * the factories on the server or on individual factories. */
  auth = gst_rtsp_auth_new ();
#ifdef WITH_TLS
  cert = g_tls_certificate_new_from_files("/home/enthusiasticgeek/toyIntermediate.pem","/home/enthusiasticgeek/toyDecryptedIntermediate.key",&error);
/*  cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----"
      "-----END CERTIFICATE-----"
      "-----BEGIN PRIVATE KEY-----"
      "W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, &error);
  if (cert == NULL) {
    g_printerr ("failed to parse PEM: %s\n", error->message);
    return -1;
  GTlsDatabase* database = g_tls_file_database_new ("/home/enthusiasticgeek/toyCA.pem", &error);
  gst_rtsp_auth_set_tls_database (auth, database);
  ca_cert = g_tls_certificate_new_from_file("/home/enthusiasticgeek/toyCA.pem",&error);
  if (ca_cert == NULL) {
    g_printerr ("failed to parse CA PEM: %s\n", error->message);
    return -1;
  gst_rtsp_auth_set_tls_authentication_mode(auth, G_TLS_AUTHENTICATION_REQUIRED);
 GTlsCertificateFlags verification = g_tls_certificate_verify(cert, NULL, ca_cert);
  g_print("verification code = %d\n", verification);
  gst_rtsp_auth_set_tls_certificate (auth, cert);
  g_object_unref (cert);

  /* make user token */
  token =
      "user", NULL);
  basic = gst_rtsp_auth_make_basic ("user", "password");
  gst_rtsp_auth_add_basic (auth, basic, token);
  g_free (basic);
  gst_rtsp_token_unref (token);

  /* configure in the server */
  gst_rtsp_server_set_auth (server, auth);

  /* get the mount points for this server, every server has a default object
   * that be used to map uri mount points to media factories */
  mounts = gst_rtsp_server_get_mount_points (server);

  /* make a media factory for a test stream. The default media factory can use
   * gst-launch syntax to create pipelines.
   * any launch line works as long as it contains elements named pay%d. Each
   * element with pay%d names will be a stream */
  factory = gst_rtsp_media_factory_new ();
  gst_rtsp_media_factory_set_launch (factory, "( "
      "videotestsrc ! video/x-raw,width=352,height=288,framerate=15/1 ! "
      "x264enc ! rtph264pay name=pay0 pt=96 "
      "audiotestsrc ! audio/x-raw,rate=8000 ! "
      "alawenc ! rtppcmapay name=pay1 pt=97 " ")");
#ifdef WITH_AUTH
  /* add permissions for the user media role */
  permissions = gst_rtsp_permissions_new ();
  gst_rtsp_permissions_add_role (permissions, "user",
  gst_rtsp_media_factory_set_permissions (factory, permissions);
  gst_rtsp_permissions_unref (permissions);
#ifdef WITH_TLS
  gst_rtsp_media_factory_set_profiles (factory, GST_RTSP_PROFILE_SAVP);

  /* attach the test factory to the /test url */
  gst_rtsp_mount_points_add_factory (mounts, "/test", factory);

  /* don't need the ref to the mapper anymore */
  g_object_unref (mounts);

  /* attach the server to the default maincontext */
  if (gst_rtsp_server_attach (server, NULL) == 0)
    goto failed;

  /* add a timeout for the session cleanup */
  g_timeout_add_seconds (2, (GSourceFunc) timeout, server);

  /* start serving, this never stops */
#ifdef WITH_TLS
  g_print ("stream ready at rtsps://\n");
  g_print ("stream ready at rtsp://\n");
  g_main_loop_run (loop);

  return 0;

  /* ERRORS */
    g_print ("failed to attach the server\n");
    return -1;

My client code is as follows

RTSP Client

//Display RTSP streaming of video
 //(c) 2011 enthusiasticgeek
 // This code is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of

#include <string.h>
#include <math.h>
#include <gst/gst.h>
#include <glib.h>
#include <gio/gio.h>

static gboolean bus_call (GstBus *bus,GstMessage *msg, gpointer data){
  GMainLoop *loop = (GMainLoop *) data;

  switch (GST_MESSAGE_TYPE (msg)) {

      g_print ("Stream Ends\n");
      g_main_loop_quit (loop);

      gchar  *debug;
      GError *error;

      gst_message_parse_error (msg, &error, &debug);
      g_free (debug);

      g_printerr ("Error: %s\n", error->message);
      g_error_free (error);

      g_main_loop_quit (loop);

  return TRUE;

static void on_pad_added (GstElement *element, GstPad *pad, gpointer data){

  GstPad *sinkpad;
  GstElement *decoder = (GstElement *) data;

  /* We can now link this pad with the rtsp-decoder sink pad */
  g_print ("Dynamic pad created, linking source/demuxer\n");

  sinkpad = gst_element_get_static_pad (decoder, "sink");

  gst_pad_link (pad, sinkpad);

  gst_object_unref (sinkpad);

int main (int argc, char *argv[])
  GMainLoop *loop;
  GstBus *bus;
  GstElement *source;
  GstElement *decoder;
  GstElement *sink;
  GstElement *pipeline;
  GstElement *demux;
  GstElement *parse;
  GstElement *videoconvert;

  /* Initializing GStreamer */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

 //gst-launch-0.10 rtspsrc location=rtsp://<ip> ! decodebin ! ffmpegvideoconvert ! autovideosink
 //gst-launch -v rtspsrc location="rtsp://<ip> ! rtpmp4vdepay ! mpeg4videoparse ! ffdec_mpeg4 ! ffmpegvideoconvert! autovideosink
 //gst-launch -v rtspsrc location="rtsp://<ip> ! rtpmp4vdepay ! ffdec_mpeg4 ! ffmpegvideoconvert! autovideosink
  /* Create Pipe's Elements */
  pipeline = gst_pipeline_new ("video player");
  g_assert (pipeline);
  source   = gst_element_factory_make ("rtspsrc", "Source");
  g_assert (source);
  demux = gst_element_factory_make ("rtph264depay", "Depay");
  g_assert (demux);
  parse = gst_element_factory_make ("h264parse", "Parse");
  g_assert (parse);
  decoder = gst_element_factory_make ("avdec_h264", "Decoder");
  g_assert (decoder);
  videoconvert     = gst_element_factory_make ("videoconvert", "VideoConvert");
  sink     = gst_element_factory_make ("autovideosink", "Output");
  g_assert (sink);

  /*Make sure: Every elements was created ok*/
  if (!pipeline || !source || !demux || !parse || !decoder || !videoconvert || !sink) {
    g_printerr ("One of the elements wasn't create... Exiting\n");
    return -1;

  g_print(" \nPipeline is Part(A) ->(dynamic/runtime link)  Part(B)[ Part(B-1) -> Part(B-2) -> Part(B-3) ]\n\n");
  g_print(" [source](dynamic)->(dynamic)[demux]->[parse]->[decoder]->[videoconvert]->[videosink] \n\n");

  /* Set video Source */
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);
  //g_object_set (G_OBJECT (source), "do-rtcp", TRUE, NULL);
  g_object_set (G_OBJECT (source), "latency", 0, NULL);
  g_object_set (G_OBJECT (source), "user-id", "user", NULL);
  g_object_set (G_OBJECT (source), "user-pw", "password", NULL);
  // generic error
  //g_object_set (G_OBJECT (source), "tls-validation-flags", 0x00000040, NULL);
  //validate all
  g_object_set (G_OBJECT (source), "tls-validation-flags", 0x0000007f, NULL);
  GTlsCertificate *cert;
  GTlsCertificate *ca_cert;
  GError *error=NULL;
  cert = g_tls_certificate_new_from_files("/home/enthusiasticgeek/toyIntermediate.pem","/home/enthusiasticgeek/toyDecryptedIntermediate.key",&error);
 if (cert == NULL) {
    g_printerr ("failed to parse PEM: %s\n", error->message);
    return -1;
  GTlsDatabase* database = g_tls_file_database_new ("/home/enthusiasticgeek/toyCA.pem", &error);
  //GTlsDatabase* database = g_tls_file_database_new ("/home/enthusiasticgeek/toyCombined.pem", &error);
  ca_cert = g_tls_certificate_new_from_file("/home/enthusiasticgeek/toyCA.pem",&error);
  if (ca_cert == NULL) {
    g_printerr ("failed to parse CA PEM: %s\n", error->message);
    return -1;
  g_object_set (G_OBJECT (source), "tls-database", database, NULL);

  /* Putting a Message handler */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  /* Add Elements to the Bin */
  gst_bin_add_many (GST_BIN (pipeline), source, demux, parse, decoder, videoconvert, sink, NULL);

  /* Link confirmation */
  if (!gst_element_link_many (demux, parse, decoder, videoconvert, sink, NULL)){
     g_warning ("Linking part (B) Fail...");

  g_print("\nNote that the source will be linked to the demuxer(depayload) dynamically.\n\
     The reason is that rtspsrc may contain various elements (for example\n\
     audio and video). The source pad(s) will be created at run time,\n\
     by the rtspsrc when it detects the amount and nature of elements.\n\
     Therefore we connect a callback function which will be executed\n\
     when the \"pad-added\" is emitted.\n");

  /* Dynamic Pad Creation */
  if(! g_signal_connect (source, "pad-added", G_CALLBACK (on_pad_added),demux))
    g_warning ("Linking part (A) with part (B) Fail...");
  /* Run the pipeline */
  g_print ("Playing: %s\n", argv[1]);
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
  g_main_loop_run (loop);

  /* Ending Playback */
  g_print ("End of the Streaming... ending the playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);

  /* Eliminating Pipeline */
  g_print ("Eliminating Pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));

  return 0;
Reply | Threaded
Open this post in threaded view

Re: Need help on RTSP server and TLS including verify peer (ca cert) and (cert,key).

enthusiastic geek