SecureToken support
authorhyc <hyc@400ebc74-4327-4243-bc38-086b20814532>
Sat, 26 Dec 2009 23:37:45 +0000 (23:37 +0000)
committerhyc <hyc@400ebc74-4327-4243-bc38-086b20814532>
Sat, 26 Dec 2009 23:37:45 +0000 (23:37 +0000)
git-svn-id: svn://svn.mplayerhq.hu/rtmpdump/trunk@115 400ebc74-4327-4243-bc38-086b20814532

rtmp.c
rtmp.h
rtmpdump.c
rtmpsrv.c
streams.c

diff --git a/rtmp.c b/rtmp.c
index cd44d3e..23bc3c2 100644 (file)
--- a/rtmp.c
+++ b/rtmp.c
@@ -110,6 +110,8 @@ static bool WriteN(RTMP * r, const char *buffer, int n);
 
 static bool FillBuffer(RTMP * r);
 
+static void DecodeTEA(AVal *key, AVal *text);
+
 uint32_t
 RTMP_GetTime()
 {
@@ -872,6 +874,8 @@ SAVC(audioCodecs);
 SAVC(videoCodecs);
 SAVC(videoFunction);
 SAVC(objectEncoding);
+SAVC(secureToken);
+SAVC(secureTokenResponse);
 
 static bool
 SendConnectPacket(RTMP * r)
@@ -1292,6 +1296,33 @@ SendPlay(RTMP * r)
   return RTMP_SendPacket(r, &packet, true);
 }
 
+static bool
+SendSecureTokenResponse(RTMP *r, AVal *resp)
+{
+  RTMPPacket packet;
+  char pbuf[1024], *pend = pbuf+sizeof(pbuf);
+
+  packet.m_nChannel = 0x03;    /* control channel (invoke) */
+  packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
+  packet.m_packetType = 0x14;
+  packet.m_nInfoField2 = 0;
+  packet.m_nInfoField1 = 0;
+  packet.m_hasAbsTimestamp = 0;
+  packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+  char *enc = packet.m_body;
+  enc = AMF_EncodeString(enc, pend, &av_secureTokenResponse);
+  enc = AMF_EncodeNumber(enc, pend, 0.0);
+  *enc++ = AMF_NULL;
+  enc = AMF_EncodeString(enc, pend, resp);
+  if (!enc)
+    return false;
+
+  packet.m_nBodySize = enc - packet.m_body;
+
+  return RTMP_SendPacket(r, &packet, false);
+}
+
 /*
 from http://jira.red5.org/confluence/display/docs/Ping:
 
@@ -1445,12 +1476,21 @@ HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize)
 
       if (AVMATCH(&methodInvoked, &av_connect))
        {
+          if (r->Link.token.av_len)
+            {
+              AMFObjectProperty p;
+              if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p))
+                {
+                  DecodeTEA(&r->Link.token, &p.p_vu.p_aval);
+                  SendSecureTokenResponse(r, &p.p_vu.p_aval);
+                }
+            }
          SendServerBW(r);
          SendCtrl(r, 3, 0, 300);
 
          SendCreateStream(r, 2.0);
 
-         // Send the FCSubscribe if live stream or if subscribepath is set
+         /* Send the FCSubscribe if live stream or if subscribepath is set */
          if (r->Link.subscribepath.av_len)
            SendFCSubscribe(r, &r->Link.subscribepath);
          else if (r->Link.bLiveStream)
@@ -1572,8 +1612,8 @@ RTMP_FindFirstMatchingProperty(AMFObject * obj, const AVal * name,
 
       if (prop->p_type == AMF_OBJECT)
        {
-         return RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name,
-                                               p);
+         if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p))
+            return true;
        }
     }
   return false;
@@ -2273,3 +2313,71 @@ again:
 
   return true;
 }
+
+#define HEX2BIN(a)     (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
+#define BIN2HEX(a)     (((a)>9)?((a)+96):((a)+48))
+
+static void
+DecodeTEA(AVal *key, AVal *text)
+{
+  uint32_t *v, k[4] = {0}, u;
+  uint32_t z, y, sum=0, e, DELTA=0x9e3779b9;
+  int32_t p, q;
+  int i, n;
+  unsigned char *ptr, *out;
+
+  /* prep key */
+  ptr = (unsigned char *)key->av_val;
+  u = 0; n = 0;
+  v = k;
+  p = key->av_len > 16 ? 16:key->av_len;
+  for (i=0; i<p; i++)
+    {
+      u |= ptr[i] << (n*8);
+      if (n==3)
+        {
+          *v++ = u;
+          u = 0;
+          n = 0;
+        }
+      else
+        {
+          n++;
+        }
+    }
+  *v = u;
+
+  /* prep text */
+  n = (text->av_len+7)/8;
+  out = malloc(n*8);
+  ptr = (unsigned char *)text->av_val;
+  v = (uint32_t *)out;
+  for (i=0; i<n; i++)
+    {
+      u = (HEX2BIN(ptr[0]) << 4) + HEX2BIN(ptr[1]);
+      u |= ((HEX2BIN(ptr[2]) << 4) + HEX2BIN(ptr[3])) << 8;
+      u |= ((HEX2BIN(ptr[4]) << 4) + HEX2BIN(ptr[5])) << 16;
+      u |= ((HEX2BIN(ptr[6]) << 4) + HEX2BIN(ptr[7])) << 24;
+      *v++ = u;
+      ptr += 8;
+    }
+  v = (uint32_t *)out;
+
+#define MX (((z>>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z));
+  z=v[n-1];
+  y=v[0];
+  q = 6+52/n ;
+  sum = q*DELTA ;
+  while (sum != 0)
+    {
+      e = sum>>2 & 3;
+      for (p=n-1; p>0; p--) z = v[p-1], y = v[p] -= MX;
+      z = v[n-1];
+      y = v[0] -= MX;
+      sum -= DELTA;
+    }
+  /* bin 2 hex */
+  text->av_len /= 2;
+  memcpy(text->av_val, out, text->av_len);
+  free(out);
+}
diff --git a/rtmp.h b/rtmp.h
index 6ed968a..6551335 100644 (file)
--- a/rtmp.h
+++ b/rtmp.h
@@ -104,6 +104,7 @@ typedef struct RTMP_LNK
   AVal auth;
   AVal flashVer;
   AVal subscribepath;
+  AVal token;
 
   double seekTime;
   uint32_t length;
index 933b1b2..3ede300 100644 (file)
@@ -1096,6 +1096,7 @@ main(int argc, char **argv)
   AVal swfHash = { 0, 0 };
   uint32_t swfSize = 0;
   AVal flashVer = { 0, 0 };
+  AVal token = { 0, 0 };
   char *sockshost = 0;
 
   char *flvFile = 0;
@@ -1161,6 +1162,7 @@ main(int argc, char **argv)
     {"subscribe", 1, NULL, 'd'},
     {"start", 1, NULL, 'A'},
     {"stop", 1, NULL, 'B'},
+    {"token", 1, NULL, 'T'},
     {"hashes", 0, NULL, '#'},
     {"debug", 0, NULL, 'z'},
     {"quiet", 0, NULL, 'q'},
@@ -1170,7 +1172,7 @@ main(int argc, char **argv)
 
   while ((opt =
          getopt_long(argc, argv,
-                     "hVveqzr:s:t:p:a:b:f:o:u:n:c:l:y:m:k:d:A:B:w:x:S:#",
+                     "hVveqzr:s:t:p:a:b:f:o:u:n:c:l:y:m:k:d:A:B:T:w:x:S:#",
                      longopts, NULL)) != -1)
     {
       switch (opt)
@@ -1223,6 +1225,8 @@ main(int argc, char **argv)
          LogPrintf
            ("--stop|-B num           Stop at num seconds into stream\n");
          LogPrintf
+           ("--token|-T key          Key for SecureToken response\n");
+         LogPrintf
            ("--hashes|-#             Display progress with hashes, not with the byte counter\n");
          LogPrintf
            ("--buffer|-b             Buffer time in milliseconds (default: %lu), this option makes only sense in stdout mode (-o -)\n",
@@ -1391,6 +1395,9 @@ main(int argc, char **argv)
        case 'B':
          dStopOffset = (int) (atof(optarg) * 1000.0);
          break;
+       case 'T':
+         STR2AVAL(token, optarg);
+         break;
        case '#':
          bHashes = true;
          break;
@@ -1519,6 +1526,7 @@ main(int argc, char **argv)
                   &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
                   &flashVer, &subscribepath, dSeek, 0, bLiveStream, timeout);
 
+  rtmp.Link.token = token;
   off_t size = 0;
 
   // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams)
index 8459dc8..ed7350d 100644 (file)
--- a/rtmpsrv.c
+++ b/rtmpsrv.c
@@ -133,6 +133,7 @@ SAVC(mode);
 SAVC(level);
 SAVC(code);
 SAVC(description);
+SAVC(secureToken);
 
 static bool
 SendConnectResult(RTMP *r, double txn)
@@ -173,6 +174,10 @@ SendConnectResult(RTMP *r, double txn)
   STR2AVAL(av, "Connection succeeded.");
   enc = AMF_EncodeNamedString(enc, pend, &av_description, &av);
   enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);
+#if 0
+  STR2AVAL(av, "58656322c972d6cdf2d776167575045f8484ea888e31c086f7b5ffbd0baec55ce442c2fb");
+  enc = AMF_EncodeNamedString(enc, pend, &av_secureToken, &av);
+#endif
   STR2AVAL(p.p_name, "version");
   STR2AVAL(p.p_vu.p_aval, "3,5,1,525");
   p.p_type = AMF_STRING;
index 1409be7..5fabb83 100644 (file)
--- a/streams.c
+++ b/streams.c
@@ -100,6 +100,7 @@ typedef struct
   AVal auth;
   AVal swfHash;
   AVal flashVer;
+  AVal token;
   AVal subscribepath;
   uint32_t swfSize;
 
@@ -674,6 +675,7 @@ void processTCPrequest(STREAMING_SERVER * server,   // server socket and state (ou
   RTMP_SetupStream(&rtmp, req.protocol, req.hostname, req.rtmpport, NULL,      // sockshost
                   &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, dSeek, -1,  // length
                   req.bLiveStream, req.timeout);
+  rtmp.Link.token = req.token;
 
   LogPrintf("Connecting ... port: %d, app: %s\n", req.rtmpport, req.app);
   if (!RTMP_Connect(&rtmp))
@@ -1044,6 +1046,9 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req)
       req->dStopOffset = atoi(arg) * 1000;
       //printf("dStartOffset = %d\n", dStartOffset);
       break;
+    case 'T':
+      STR2AVAL(req->token, arg);
+      break;
     case 'q':
       debuglevel = LOGCRIT;
       break;
@@ -1112,6 +1117,7 @@ main(int argc, char **argv)
     {"subscribe", 1, NULL, 'd'},
     {"start", 1, NULL, 'A'},
     {"stop", 1, NULL, 'B'},
+    {"token", 1, NULL, 'T'},
     {"debug", 0, NULL, 'z'},
     {"quiet", 0, NULL, 'q'},
     {"verbose", 0, NULL, 'V'},
@@ -1123,7 +1129,7 @@ main(int argc, char **argv)
 
   while ((opt =
          getopt_long(argc, argv,
-                     "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:g:w:x:", longopts,
+                     "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:", longopts,
                      NULL)) != -1)
     {
       switch (opt)
@@ -1168,6 +1174,8 @@ main(int argc, char **argv)
          LogPrintf
            ("--stop|-B num           Stop at num seconds into stream\n");
          LogPrintf
+           ("--token|-T key          Key for SecureToken response\n");
+         LogPrintf
            ("--buffer|-b             Buffer time in milliseconds (default: %lu)\n\n",
             defaultRTMPRequest.bufferTime);