From b9529ca6c8cc0ae056fa95e67eb71797c2243375 Mon Sep 17 00:00:00 2001 From: hyc Date: Sat, 26 Dec 2009 23:37:45 +0000 Subject: [PATCH] SecureToken support git-svn-id: svn://svn.mplayerhq.hu/rtmpdump/trunk@115 400ebc74-4327-4243-bc38-086b20814532 --- rtmp.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++-- rtmp.h | 1 + rtmpdump.c | 10 ++++- rtmpsrv.c | 5 +++ streams.c | 10 ++++- 5 files changed, 135 insertions(+), 5 deletions(-) diff --git a/rtmp.c b/rtmp.c index cd44d3e..23bc3c2 100644 --- 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; iav_len+7)/8; + out = malloc(n*8); + ptr = (unsigned char *)text->av_val; + v = (uint32_t *)out; + for (i=0; i>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 --- 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; diff --git a/rtmpdump.c b/rtmpdump.c index 933b1b2..3ede300 100644 --- a/rtmpdump.c +++ b/rtmpdump.c @@ -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) @@ -1222,6 +1224,8 @@ main(int argc, char **argv) ("--start|-A num Start at num seconds into stream (not valid when using --live)\n"); 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 @@ -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) diff --git a/rtmpsrv.c b/rtmpsrv.c index 8459dc8..ed7350d 100644 --- 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; diff --git a/streams.c b/streams.c index 1409be7..5fabb83 100644 --- 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) @@ -1167,6 +1173,8 @@ main(int argc, char **argv) ("--start|-A num Start at num seconds into stream (not valid when using --live)\n"); 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); -- 2.50.1