Browse code

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@martin.st>

Samuel Pitoiset authored on 2012/08/14 00:05:00
Showing 3 changed files
... ...
@@ -242,6 +242,12 @@ Name of live stream to subscribe to. By default no value will be sent.
242 242
 It is only sent if the option is specified or if rtmp_live
243 243
 is set to live.
244 244
 
245
+@item rtmp_swfhash
246
+SHA256 hash of the decompressed SWF file (32 bytes).
247
+
248
+@item rtmp_swfsize
249
+Size of the decompressed SWF file, required for SWFVerification.
250
+
245 251
 @item rtmp_swfurl
246 252
 URL of the SWF player for the media. By default no value will be sent.
247 253
 
... ...
@@ -91,7 +91,11 @@ typedef struct RTMPContext {
91 91
     int           nb_invokes;                 ///< keeps track of invoke messages
92 92
     char*         tcurl;                      ///< url of the target stream
93 93
     char*         flashver;                   ///< version of the flash plugin
94
+    char*         swfhash;                    ///< SHA256 hash of the decompressed SWF file (32 bytes)
95
+    int           swfhash_len;                ///< length of the SHA256 hash
96
+    int           swfsize;                    ///< size of the decompressed SWF file
94 97
     char*         swfurl;                     ///< url of the swf player
98
+    char          swfverification[42];        ///< hash of the SWF verification
95 99
     char*         pageurl;                    ///< url of the web page
96 100
     char*         subscribe;                  ///< name of live stream to subscribe
97 101
     int           server_bw;                  ///< server bandwidth
... ...
@@ -593,6 +597,27 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
593 593
 }
594 594
 
595 595
 /**
596
+ * Generate SWF verification message and send it to the server.
597
+ */
598
+static int gen_swf_verification(URLContext *s, RTMPContext *rt)
599
+{
600
+    RTMPPacket pkt;
601
+    uint8_t *p;
602
+    int ret;
603
+
604
+    av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
605
+    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
606
+                                     0, 44)) < 0)
607
+        return ret;
608
+
609
+    p = pkt.data;
610
+    bytestream_put_be16(&p, 27);
611
+    memcpy(p, rt->swfverification, 42);
612
+
613
+    return rtmp_send_packet(rt, &pkt, 0);
614
+}
615
+
616
+/**
596 617
  * Generate server bandwidth message and send it to the server.
597 618
  */
598 619
 static int gen_server_bw(URLContext *s, RTMPContext *rt)
... ...
@@ -776,6 +801,30 @@ static int rtmp_validate_digest(uint8_t *buf, int off)
776 776
     return 0;
777 777
 }
778 778
 
779
+static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
780
+                                      uint8_t *buf)
781
+{
782
+    uint8_t *p;
783
+    int ret;
784
+
785
+    if (rt->swfhash_len != 32) {
786
+        av_log(s, AV_LOG_ERROR,
787
+               "Hash of the decompressed SWF file is not 32 bytes long.\n");
788
+        return AVERROR(EINVAL);
789
+    }
790
+
791
+    p = &rt->swfverification[0];
792
+    bytestream_put_byte(&p, 1);
793
+    bytestream_put_byte(&p, 1);
794
+    bytestream_put_be32(&p, rt->swfsize);
795
+    bytestream_put_be32(&p, rt->swfsize);
796
+
797
+    if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
798
+        return ret;
799
+
800
+    return 0;
801
+}
802
+
779 803
 /**
780 804
  * Perform handshake with the server by means of exchanging pseudorandom data
781 805
  * signed with HMAC-SHA2 digest.
... ...
@@ -866,6 +915,14 @@ static int rtmp_handshake(URLContext *s, RTMPContext *rt)
866 866
             }
867 867
         }
868 868
 
869
+        /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
870
+         * key are the last 32 bytes of the server handshake. */
871
+        if (rt->swfsize) {
872
+            if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
873
+                                                  RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
874
+                return ret;
875
+        }
876
+
869 877
         ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
870 878
                                   rtmp_server_key, sizeof(rtmp_server_key),
871 879
                                   digest);
... ...
@@ -1001,6 +1058,13 @@ static int handle_ping(URLContext *s, RTMPPacket *pkt)
1001 1001
     if (t == 6) {
1002 1002
         if ((ret = gen_pong(s, rt, pkt)) < 0)
1003 1003
             return ret;
1004
+    } else if (t == 26) {
1005
+        if (rt->swfsize) {
1006
+            if ((ret = gen_swf_verification(s, rt)) < 0)
1007
+                return ret;
1008
+        } else {
1009
+            av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1010
+        }
1004 1011
     }
1005 1012
 
1006 1013
     return 0;
... ...
@@ -1717,6 +1781,8 @@ static const AVOption rtmp_options[] = {
1717 1717
     {"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},
1718 1718
     {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
1719 1719
     {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
1720
+    {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
1721
+    {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {0}, 0, INT_MAX, DEC},
1720 1722
     {"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},
1721 1723
     {"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},
1722 1724
     { NULL },
... ...
@@ -31,7 +31,7 @@
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 54
33 33
 #define LIBAVFORMAT_VERSION_MINOR 13
34
-#define LIBAVFORMAT_VERSION_MICRO  2
34
+#define LIBAVFORMAT_VERSION_MICRO  3
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
37 37
                                                LIBAVFORMAT_VERSION_MINOR, \