2727#ifdef HAVE_CONFIG_H
2828#include <config.h>
2929#endif
30+ #include <stdio.h> // FILE, etc
31+ #include <string.h> // strstr, strcat
32+ #if defined(_WIN32 ) || defined(_WIN64 )
33+ #include <direct.h>
34+ #define getcwd _getcwd // "deprecation" warning
35+ #else
36+ #include <unistd.h> // getcwd
37+ #endif
3038
3139#include "gstsigning.h"
3240#include "gstsigning_defines.h"
3341#include <signed-video-framework/signed_video_common.h>
3442#include <signed-video-framework/signed_video_openssl.h>
3543#include <signed-video-framework/signed_video_sign.h>
44+ #include <signed-video-framework/sv_vendor_axis_communications.h>
3645
3746GST_DEBUG_CATEGORY_STATIC (gst_signing_debug );
3847#define GST_CAT_DEFAULT gst_signing_debug
3948
49+ enum
50+ {
51+ PROP_0 ,
52+ PROP_PROVISIONED
53+ };
54+ #define DEFAULT_PROVISIONED 0 // Key is not provisioned
55+
4056struct _GstSigningPrivate {
57+ gint provisioned ;
4158 signed_video_t * signed_video ;
4259 GstClockTime last_pts ;
4360};
@@ -72,6 +89,42 @@ setup_signing(GstSigning *signing, GstCaps *caps);
7289static gboolean
7390terminate_signing (GstSigning * signing );
7491
92+ static void
93+ gst_signing_get_property (GObject * object , guint prop_id , GValue * value , GParamSpec * pspec )
94+ {
95+ GstSigning * signing = GST_SIGNING (object );
96+
97+ GST_OBJECT_LOCK (signing );
98+ switch (prop_id ) {
99+ case PROP_PROVISIONED :
100+ g_value_set_int (value , signing -> priv -> provisioned );
101+ break ;
102+ default :
103+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object , prop_id , pspec );
104+ break ;
105+ }
106+ GST_OBJECT_UNLOCK (signing );
107+ }
108+
109+ static void
110+ gst_signing_set_property (GObject * object , guint prop_id , const GValue * value , GParamSpec * pspec )
111+ {
112+ GstSigning * signing = GST_SIGNING (object );
113+ GstSigningPrivate * priv = signing -> priv ;
114+
115+ GST_OBJECT_LOCK (signing );
116+ switch (prop_id ) {
117+ case PROP_PROVISIONED :
118+ priv -> provisioned = g_value_get_int (value );
119+ GST_DEBUG_OBJECT (object , "new provisioned value: %d" , priv -> provisioned );
120+ break ;
121+ default :
122+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object , prop_id , pspec );
123+ break ;
124+ }
125+ GST_OBJECT_UNLOCK (signing );
126+ }
127+
75128static void
76129gst_signing_class_init (GstSigningClass * klass )
77130{
@@ -89,13 +142,20 @@ gst_signing_class_init(GstSigningClass *klass)
89142 transform_class -> sink_event = GST_DEBUG_FUNCPTR (gst_signing_sink_event );
90143
91144 gst_element_class_set_static_metadata (element_class , "Signed Video" , "Formatter/Video" ,
92- "Add SEI nalus containing signatures for authentication." ,
145+ "Add SEIs containing signatures for authentication." ,
93146 "Signed Video Framework <github.com/AxisCommunications/signed-video-framework-examples>" );
94147
95148 gst_element_class_add_static_pad_template (element_class , & sink_template );
96149 gst_element_class_add_static_pad_template (element_class , & src_template );
97150
98151 gobject_class -> finalize = gst_signing_finalize ;
152+ gobject_class -> get_property = gst_signing_get_property ;
153+ gobject_class -> set_property = gst_signing_set_property ;
154+
155+ // Install properties
156+ g_object_class_install_property (gobject_class , PROP_PROVISIONED ,
157+ g_param_spec_int ("provisioned" , "Provisioned key" , "Use pre-generated key and certificate" ,
158+ 0 , 1 , DEFAULT_PROVISIONED , G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS ));
99159}
100160
101161static void
@@ -168,7 +228,8 @@ create_buffer_with_current_time(GstSigning *signing)
168228 * Returns the number of nalus that were prepended to @current_au,
169229 * or -1 on error. */
170230static gint
171- get_and_add_sei (GstSigning * signing , GstBuffer * current_au , gint idx , const guint8 * peek_nalu , gsize peek_nalu_size )
231+ get_and_add_sei (GstSigning * signing , GstBuffer * current_au , gint idx , const guint8 * peek_nalu ,
232+ gsize peek_nalu_size )
172233{
173234 SignedVideoReturnCode sv_rc ;
174235 gint prepend_count = 0 ;
@@ -180,7 +241,8 @@ get_and_add_sei(GstSigning *signing, GstBuffer * current_au, gint idx, const gui
180241 * signed_video_get_sei(signed_video_t *self, uint8_t **sei, size_t *sei_size,
181242 * unsigned *payload_offset, const uint8_t *peek_nalu,
182243 * size_t peek_nalu_size, unsigned *num_pending_seis); */
183- sv_rc = signed_video_get_sei (signing -> priv -> signed_video , & sei , & sei_size , NULL , peek_nalu , peek_nalu_size , NULL );
244+ sv_rc = signed_video_get_sei (signing -> priv -> signed_video , & sei , & sei_size , NULL , peek_nalu ,
245+ peek_nalu_size , NULL );
184246 while (sv_rc == SV_OK && sei_size > 0 && sei ) {
185247 GstMemory * prepend_mem ;
186248
@@ -193,7 +255,8 @@ get_and_add_sei(GstSigning *signing, GstBuffer * current_au, gint idx, const gui
193255 gst_buffer_insert_memory (current_au , idx , prepend_mem );
194256 prepend_count ++ ;
195257
196- sv_rc = signed_video_get_sei (signing -> priv -> signed_video , & sei , & sei_size , NULL , peek_nalu , peek_nalu_size , NULL );
258+ sv_rc = signed_video_get_sei (signing -> priv -> signed_video , & sei , & sei_size , NULL , peek_nalu ,
259+ peek_nalu_size , NULL );
197260 }
198261
199262 if (sv_rc != SV_OK ) {
@@ -220,7 +283,8 @@ gst_signing_transform_ip(GstBaseTransform *trans, GstBuffer *buf)
220283 priv -> last_pts = GST_BUFFER_PTS (buf );
221284 // last_pts is an GstClockTime object, which is measured in nanoseconds.
222285 const gint64 timestamp_usec = (const gint64 )(priv -> last_pts / 1000 );
223- const gint64 * timestamp_usec_ptr = priv -> last_pts == GST_CLOCK_TIME_NONE ? NULL : & timestamp_usec ;
286+ const gint64 * timestamp_usec_ptr =
287+ priv -> last_pts == GST_CLOCK_TIME_NONE ? NULL : & timestamp_usec ;
224288
225289 GST_DEBUG_OBJECT (signing , "got buffer with %d memories" , gst_buffer_n_memory (buf ));
226290 while (idx < gst_buffer_n_memory (buf )) {
@@ -331,6 +395,82 @@ terminate_signing(GstSigning *signing)
331395 return TRUE;
332396}
333397
398+ #define MAX_PATH_LENGTH 500
399+ static gboolean
400+ read_file_content (const char * filename , char * * content , gsize * content_size )
401+ {
402+ gboolean success = FALSE;
403+ FILE * fp = NULL ;
404+ char full_path [MAX_PATH_LENGTH ] = {0 };
405+ char cwd [MAX_PATH_LENGTH ] = {0 };
406+
407+ * content = NULL ;
408+ * content_size = 0 ;
409+
410+ if (!getcwd (cwd , sizeof (cwd ))) {
411+ goto done ;
412+ }
413+
414+ // Find the root location of the library.
415+ char * lib_root = NULL ;
416+ char * next_lib_root = strstr (cwd , "signed-video-framework-examples" );
417+ if (!next_lib_root ) {
418+ // Current location is not inside signed-video-framework. Assuming current working directory is
419+ // the parent directory, to give it another try. If that is not the case opening the |full_path|
420+ // will fail, which is fine since the true location is not known anyhow.
421+ strcat (cwd , "/signed-video-framework-examples" );
422+ next_lib_root = strstr (cwd , "signed-video-framework-examples" );
423+ }
424+ while (next_lib_root ) {
425+ lib_root = next_lib_root ;
426+ next_lib_root = strstr (next_lib_root + 1 , "signed-video-framework-examples" );
427+ }
428+ if (!lib_root ) {
429+ goto done ;
430+ }
431+ // Terminate string after lib root.
432+ memset (lib_root + strlen ("signed-video-framework-examples" ), '\0' , 1 );
433+
434+ // Get certificate chain from folder test-files/.
435+ strcat (full_path , cwd );
436+ strcat (full_path , "/test-files/" );
437+ strcat (full_path , filename );
438+
439+ fp = fopen (full_path , "rb" );
440+ if (!fp ) {
441+ goto done ;
442+ }
443+
444+ fseek (fp , 0L , SEEK_END );
445+ size_t file_size = ftell (fp );
446+ if (file_size == 0 ) {
447+ goto done ;
448+ }
449+
450+ * content = calloc (1 , file_size + 1 ); // One extra byte for '\0' in case the content is a string.
451+ if (!(* content )) {
452+ goto done ;
453+ }
454+
455+ rewind (fp );
456+ if (fread (* content , sizeof (char ), file_size / sizeof (char ), fp ) == 0 ) {
457+ goto done ;
458+ }
459+ * content_size = file_size ;
460+
461+ success = TRUE;
462+
463+ done :
464+ if (fp ) {
465+ fclose (fp );
466+ }
467+ if (!success ) {
468+ free (* content );
469+ }
470+
471+ return success ;
472+ }
473+
334474static gboolean
335475setup_signing (GstSigning * signing , GstCaps * caps )
336476{
@@ -340,6 +480,8 @@ setup_signing(GstSigning *signing, GstCaps *caps)
340480 SignedVideoCodec codec ;
341481 char * private_key = NULL ;
342482 size_t private_key_size = 0 ;
483+ char * certificate_chain = NULL ;
484+ size_t certificate_chain_size = 0 ;
343485
344486 g_assert (caps != NULL );
345487
@@ -367,9 +509,26 @@ setup_signing(GstSigning *signing, GstCaps *caps)
367509 GST_ERROR_OBJECT (signing , "could not create Signed Video object" );
368510 goto create_failed ;
369511 }
370- if (signed_video_generate_ecdsa_private_key (PATH_TO_KEY_FILES , & private_key , & private_key_size ) != SV_OK ) {
371- GST_DEBUG_OBJECT (signing , "failed to generate pem file" );
372- goto generate_private_key_failed ;
512+
513+ if (!priv -> provisioned ) {
514+ if (signed_video_generate_ecdsa_private_key (PATH_TO_KEY_FILES , & private_key , & private_key_size ) != SV_OK ) {
515+ GST_DEBUG_OBJECT (signing , "failed to generate pem file" );
516+ goto generate_private_key_failed ;
517+ }
518+ } else {
519+ if (!read_file_content ("private_ecdsa_key.pem" , & private_key , & private_key_size )) {
520+ goto generate_private_key_failed ;
521+ }
522+ if (!read_file_content ("cert_chain.pem" , & certificate_chain , & certificate_chain_size )) {
523+ goto read_cert_failed ;
524+ }
525+ // Use the Axis api to set the certificate chain without attestation. This will
526+ // trigger factory provisioned signing in the library.
527+ if (sv_vendor_axis_communications_set_attestation_report (priv -> signed_video , NULL , 0 ,
528+ certificate_chain ) != SV_OK ) {
529+ GST_DEBUG_OBJECT (signing , "failed to set certificate chain content" );
530+ goto set_cert_failed ;
531+ }
373532 }
374533 if (signed_video_set_private_key (priv -> signed_video , private_key , private_key_size ) != SV_OK ) {
375534 GST_DEBUG_OBJECT (signing , "failed to set private key content" );
@@ -384,12 +543,18 @@ setup_signing(GstSigning *signing, GstCaps *caps)
384543 goto product_info_failed ;
385544 }
386545
546+ g_free (certificate_chain );
547+ g_free (private_key );
548+
387549 return TRUE;
388550
389551product_info_failed :
390552set_private_key_failed :
391- generate_private_key_failed :
553+ set_cert_failed :
554+ g_free (certificate_chain );
555+ read_cert_failed :
392556 g_free (private_key );
557+ generate_private_key_failed :
393558 signed_video_free (priv -> signed_video );
394559 priv -> signed_video = NULL ;
395560create_failed :
0 commit comments