[FFmpeg-cvslog] rtmp: Add support for SWFVerification

Samuel Pitoiset git at videolan.org
Wed Aug 15 16:02:54 CEST 2012


ffmpeg | branch: master | Samuel Pitoiset <samuel.pitoiset at gmail.com> | Mon Aug 13 17:05:00 2012 +0200| [635ac8e1be91e941908f85642e4bbb609e48193f] | committer: Martin Storsjö

rtmp: Add support for SWFVerification

Specifies how the server verifies client SWF files before allowing the
files to connect to an application. Verifying SWF files is a security
measure that prevents someone from creating their own SWF files that can
attempt to stream your resources.

Signed-off-by: Martin Storsjö <martin at martin.st>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=635ac8e1be91e941908f85642e4bbb609e48193f
---

 doc/protocols.texi      |    6 +++++
 libavformat/rtmpproto.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/version.h   |    2 +-
 3 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index bf67d89..bdb3e8c 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -242,6 +242,12 @@ Name of live stream to subscribe to. By default no value will be sent.
 It is only sent if the option is specified or if rtmp_live
 is set to live.
 
+ at item rtmp_swfhash
+SHA256 hash of the decompressed SWF file (32 bytes).
+
+ at item rtmp_swfsize
+Size of the decompressed SWF file, required for SWFVerification.
+
 @item rtmp_swfurl
 URL of the SWF player for the media. By default no value will be sent.
 
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index a90d9da..9b85e52 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -91,7 +91,11 @@ typedef struct RTMPContext {
     int           nb_invokes;                 ///< keeps track of invoke messages
     char*         tcurl;                      ///< url of the target stream
     char*         flashver;                   ///< version of the flash plugin
+    char*         swfhash;                    ///< SHA256 hash of the decompressed SWF file (32 bytes)
+    int           swfhash_len;                ///< length of the SHA256 hash
+    int           swfsize;                    ///< size of the decompressed SWF file
     char*         swfurl;                     ///< url of the swf player
+    char          swfverification[42];        ///< hash of the SWF verification
     char*         pageurl;                    ///< url of the web page
     char*         subscribe;                  ///< name of live stream to subscribe
     int           server_bw;                  ///< server bandwidth
@@ -593,6 +597,27 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
 }
 
 /**
+ * Generate SWF verification message and send it to the server.
+ */
+static int gen_swf_verification(URLContext *s, RTMPContext *rt)
+{
+    RTMPPacket pkt;
+    uint8_t *p;
+    int ret;
+
+    av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
+    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
+                                     0, 44)) < 0)
+        return ret;
+
+    p = pkt.data;
+    bytestream_put_be16(&p, 27);
+    memcpy(p, rt->swfverification, 42);
+
+    return rtmp_send_packet(rt, &pkt, 0);
+}
+
+/**
  * Generate server bandwidth message and send it to the server.
  */
 static int gen_server_bw(URLContext *s, RTMPContext *rt)
@@ -776,6 +801,30 @@ static int rtmp_validate_digest(uint8_t *buf, int off)
     return 0;
 }
 
+static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
+                                      uint8_t *buf)
+{
+    uint8_t *p;
+    int ret;
+
+    if (rt->swfhash_len != 32) {
+        av_log(s, AV_LOG_ERROR,
+               "Hash of the decompressed SWF file is not 32 bytes long.\n");
+        return AVERROR(EINVAL);
+    }
+
+    p = &rt->swfverification[0];
+    bytestream_put_byte(&p, 1);
+    bytestream_put_byte(&p, 1);
+    bytestream_put_be32(&p, rt->swfsize);
+    bytestream_put_be32(&p, rt->swfsize);
+
+    if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
+        return ret;
+
+    return 0;
+}
+
 /**
  * Perform handshake with the server by means of exchanging pseudorandom data
  * signed with HMAC-SHA2 digest.
@@ -866,6 +915,14 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
             }
         }
 
+        /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
+         * key are the last 32 bytes of the server handshake. */
+        if (rt->swfsize) {
+            if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
+                                                  RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
+                return ret;
+        }
+
         ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
                                   rtmp_server_key, sizeof(rtmp_server_key),
                                   digest);
@@ -1001,6 +1058,13 @@ static int handle_ping(URLContext *s, RTMPPacket *pkt)
     if (t == 6) {
         if ((ret = gen_pong(s, rt, pkt)) < 0)
             return ret;
+    } else if (t == 26) {
+        if (rt->swfsize) {
+            if ((ret = gen_swf_verification(s, rt)) < 0)
+                return ret;
+        } else {
+            av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
+        }
     }
 
     return 0;
@@ -1717,6 +1781,8 @@ static const AVOption rtmp_options[] = {
     {"rtmp_pageurl", "URL of the web page in which the media was embedded. By default no value will be sent.", OFFSET(pageurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
     {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
     {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
+    {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
+    {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {0}, 0, INT_MAX, DEC},
     {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
     {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
     { NULL },
diff --git a/libavformat/version.h b/libavformat/version.h
index e2cd0c7..54185fa 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -31,7 +31,7 @@
 
 #define LIBAVFORMAT_VERSION_MAJOR 54
 #define LIBAVFORMAT_VERSION_MINOR 13
-#define LIBAVFORMAT_VERSION_MICRO  2
+#define LIBAVFORMAT_VERSION_MICRO  3
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \



More information about the ffmpeg-cvslog mailing list