rtmpproto.c 52.6 KB
Newer Older
1 2 3 4
/*
 * RTMP network protocol
 * Copyright (c) 2009 Kostya Shishkov
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * Libav is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19 20 21 22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
23
 * @file
24 25 26 27 28
 * RTMP protocol
 */

#include "libavcodec/bytestream.h"
#include "libavutil/avstring.h"
29
#include "libavutil/intfloat.h"
30
#include "libavutil/lfg.h"
31
#include "libavutil/opt.h"
32 33
#include "libavutil/sha.h"
#include "avformat.h"
34
#include "internal.h"
35 36 37 38 39

#include "network.h"

#include "flv.h"
#include "rtmp.h"
Samuel Pitoiset's avatar
Samuel Pitoiset committed
40
#include "rtmpcrypt.h"
41
#include "rtmppkt.h"
42
#include "url.h"
43

44 45
//#define DEBUG

46
#define APP_MAX_LENGTH 128
47
#define PLAYPATH_MAX_LENGTH 256
48
#define TCURL_MAX_LENGTH 512
49
#define FLASHVER_MAX_LENGTH 64
50

51 52 53 54
/** RTMP protocol handler state */
typedef enum {
    STATE_START,      ///< client has not done anything yet
    STATE_HANDSHAKED, ///< client has performed handshake
55 56
    STATE_RELEASING,  ///< client releasing stream before publish it (for output)
    STATE_FCPUBLISH,  ///< client FCPublishing stream (for output)
57 58 59
    STATE_CONNECTING, ///< client connected to server successfully
    STATE_READY,      ///< client has sent all needed commands and waits for server reply
    STATE_PLAYING,    ///< client has started receiving multimedia data from server
60
    STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
61
    STATE_STOPPED,    ///< the broadcast has been stopped
62 63 64 65
} ClientState;

/** protocol handler context */
typedef struct RTMPContext {
66
    const AVClass *class;
67 68 69
    URLContext*   stream;                     ///< TCP stream used in interactions with RTMP server
    RTMPPacket    prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
    int           chunk_size;                 ///< size of the chunks RTMP packets are divided into
70
    int           is_input;                   ///< input/output flag
71
    char          *playpath;                  ///< stream identifier to play (with possible "mp4:" prefix)
72
    int           live;                       ///< 0: recorded, -1: live, -2: both
73
    char          *app;                       ///< name of application
74
    char          *conn;                      ///< append arbitrary AMF data to the Connect message
75 76 77 78 79
    ClientState   state;                      ///< current state
    int           main_channel_id;            ///< an additional channel ID which is used for some invocations
    uint8_t*      flv_data;                   ///< buffer with data for demuxer
    int           flv_size;                   ///< current buffer size
    int           flv_off;                    ///< number of bytes read from current buffer
80
    int           flv_nb_packets;             ///< number of flv packets published
81
    RTMPPacket    out_pkt;                    ///< rtmp packet, created from flv a/v or metadata (for output)
82 83 84
    uint32_t      client_report_size;         ///< number of bytes after which client should report to server
    uint32_t      bytes_read;                 ///< number of bytes read from server
    uint32_t      last_bytes_read;            ///< number of bytes read last reported to server
85
    int           skip_bytes;                 ///< number of bytes to skip from the input FLV stream in the next write call
86 87
    uint8_t       flv_header[11];             ///< partial incoming flv packet header
    int           flv_header_bytes;           ///< number of initialized bytes in flv_header
88
    int           nb_invokes;                 ///< keeps track of invoke messages
89
    int           create_stream_invoke;       ///< invoke id for the create stream command
90
    char*         tcurl;                      ///< url of the target stream
91
    char*         flashver;                   ///< version of the flash plugin
92
    char*         swfurl;                     ///< url of the swf player
93
    int           server_bw;                  ///< server bandwidth
94
    int           client_buffer_time;         ///< client buffer time in ms
95
    int           flush_interval;             ///< number of packets flushed in the same request (RTMPT only)
Samuel Pitoiset's avatar
Samuel Pitoiset committed
96
    int           encrypted;                  ///< use an encrypted connection (RTMPE only)
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
} RTMPContext;

#define PLAYER_KEY_OPEN_PART_LEN 30   ///< length of partial key used for first client digest signing
/** Client key used for digest signing */
static const uint8_t rtmp_player_key[] = {
    'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
    'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',

    0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
    0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
    0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
};

#define SERVER_KEY_OPEN_PART_LEN 36   ///< length of partial key used for first server digest signing
/** Key used for RTMP server digest signing */
static const uint8_t rtmp_server_key[] = {
    'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
    'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
    'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',

    0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
    0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
    0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
};

122 123
static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
{
124
    char *field, *value;
125 126 127 128 129 130 131 132 133 134 135 136 137 138
    char type;

    /* The type must be B for Boolean, N for number, S for string, O for
     * object, or Z for null. For Booleans the data must be either 0 or 1 for
     * FALSE or TRUE, respectively. Likewise for Objects the data must be
     * 0 or 1 to end or begin an object, respectively. Data items in subobjects
     * may be named, by prefixing the type with 'N' and specifying the name
     * before the value (ie. NB:myFlag:1). This option may be used multiple times
     * to construct arbitrary AMF sequences. */
    if (param[0] && param[1] == ':') {
        type = param[0];
        value = param + 2;
    } else if (param[0] == 'N' && param[1] && param[2] == ':') {
        type = param[1];
139 140 141 142 143 144
        field = param + 3;
        value = strchr(field, ':');
        if (!value)
            goto fail;
        *value = '\0';
        value++;
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

        if (!field || !value)
            goto fail;

        ff_amf_write_field_name(p, field);
    } else {
        goto fail;
    }

    switch (type) {
    case 'B':
        ff_amf_write_bool(p, value[0] != '0');
        break;
    case 'S':
        ff_amf_write_string(p, value);
        break;
    case 'N':
        ff_amf_write_number(p, strtod(value, NULL));
        break;
    case 'Z':
        ff_amf_write_null(p);
        break;
    case 'O':
        if (value[0] != '0')
            ff_amf_write_object_start(p);
        else
            ff_amf_write_object_end(p);
        break;
    default:
        goto fail;
        break;
    }

    return 0;

fail:
    av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
    return AVERROR(EINVAL);
}

185
/**
186
 * Generate 'connect' call and send it to the server.
187
 */
188
static int gen_connect(URLContext *s, RTMPContext *rt)
189 190
{
    RTMPPacket pkt;
191
    uint8_t *p;
192 193 194 195 196
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 4096)) < 0)
        return ret;
197 198 199 200

    p = pkt.data;

    ff_amf_write_string(&p, "connect");
201
    ff_amf_write_number(&p, ++rt->nb_invokes);
202 203
    ff_amf_write_object_start(&p);
    ff_amf_write_field_name(&p, "app");
204
    ff_amf_write_string(&p, rt->app);
205

206
    if (!rt->is_input) {
207 208 209
        ff_amf_write_field_name(&p, "type");
        ff_amf_write_string(&p, "nonprivate");
    }
210
    ff_amf_write_field_name(&p, "flashVer");
211
    ff_amf_write_string(&p, rt->flashver);
212 213 214 215 216 217

    if (rt->swfurl) {
        ff_amf_write_field_name(&p, "swfUrl");
        ff_amf_write_string(&p, rt->swfurl);
    }

218
    ff_amf_write_field_name(&p, "tcUrl");
219
    ff_amf_write_string(&p, rt->tcurl);
220
    if (rt->is_input) {
221 222 223 224
        ff_amf_write_field_name(&p, "fpad");
        ff_amf_write_bool(&p, 0);
        ff_amf_write_field_name(&p, "capabilities");
        ff_amf_write_number(&p, 15.0);
225 226 227 228

        /* Tell the server we support all the audio codecs except
         * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
         * which are unused in the RTMP protocol implementation. */
229
        ff_amf_write_field_name(&p, "audioCodecs");
230
        ff_amf_write_number(&p, 4071.0);
231 232 233 234
        ff_amf_write_field_name(&p, "videoCodecs");
        ff_amf_write_number(&p, 252.0);
        ff_amf_write_field_name(&p, "videoFunction");
        ff_amf_write_number(&p, 1.0);
235
    }
236 237
    ff_amf_write_object_end(&p);

238
    if (rt->conn) {
239
        char *param = rt->conn;
240 241 242

        // Write arbitrary AMF data to the Connect message.
        while (param != NULL) {
243 244 245 246 247 248 249
            char *sep;
            param += strspn(param, " ");
            if (!*param)
                break;
            sep = strchr(param, ' ');
            if (sep)
                *sep = '\0';
250 251 252 253 254 255
            if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
                // Invalid AMF parameter.
                ff_rtmp_packet_destroy(&pkt);
                return ret;
            }

256 257 258 259
            if (sep)
                param = sep + 1;
            else
                break;
260 261 262
        }
    }

263 264
    pkt.data_size = p - pkt.data;

265 266
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
267
    ff_rtmp_packet_destroy(&pkt);
268

269
    return ret;
270 271
}

272
/**
273
 * Generate 'releaseStream' call and send it to the server. It should make
274 275
 * the server release some channel for media streams.
 */
276
static int gen_release_stream(URLContext *s, RTMPContext *rt)
277 278 279
{
    RTMPPacket pkt;
    uint8_t *p;
280
    int ret;
281

282 283 284
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 29 + strlen(rt->playpath))) < 0)
        return ret;
285

286
    av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
287 288
    p = pkt.data;
    ff_amf_write_string(&p, "releaseStream");
289
    ff_amf_write_number(&p, ++rt->nb_invokes);
290 291 292
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);

293 294
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
295
    ff_rtmp_packet_destroy(&pkt);
296

297
    return ret;
298 299 300
}

/**
301
 * Generate 'FCPublish' call and send it to the server. It should make
302 303
 * the server preapare for receiving media streams.
 */
304
static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
305 306 307
{
    RTMPPacket pkt;
    uint8_t *p;
308
    int ret;
309

310 311 312
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 25 + strlen(rt->playpath))) < 0)
        return ret;
313

314
    av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
315 316
    p = pkt.data;
    ff_amf_write_string(&p, "FCPublish");
317
    ff_amf_write_number(&p, ++rt->nb_invokes);
318 319 320
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);

321 322
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
323
    ff_rtmp_packet_destroy(&pkt);
324

325
    return ret;
326 327 328
}

/**
329
 * Generate 'FCUnpublish' call and send it to the server. It should make
330 331
 * the server destroy stream.
 */
332
static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
333 334 335
{
    RTMPPacket pkt;
    uint8_t *p;
336
    int ret;
337

338 339 340
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 27 + strlen(rt->playpath))) < 0)
        return ret;
341

342
    av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
343 344
    p = pkt.data;
    ff_amf_write_string(&p, "FCUnpublish");
345
    ff_amf_write_number(&p, ++rt->nb_invokes);
346 347 348
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);

349 350
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
351
    ff_rtmp_packet_destroy(&pkt);
352

353
    return ret;
354 355
}

356
/**
357
 * Generate 'createStream' call and send it to the server. It should make
358 359
 * the server allocate some channel for media streams.
 */
360
static int gen_create_stream(URLContext *s, RTMPContext *rt)
361 362 363
{
    RTMPPacket pkt;
    uint8_t *p;
364
    int ret;
365

366
    av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
367 368 369 370

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 25)) < 0)
        return ret;
371 372 373

    p = pkt.data;
    ff_amf_write_string(&p, "createStream");
374
    ff_amf_write_number(&p, ++rt->nb_invokes);
375
    ff_amf_write_null(&p);
376
    rt->create_stream_invoke = rt->nb_invokes;
377

378 379
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
380
    ff_rtmp_packet_destroy(&pkt);
381

382
    return ret;
383 384 385 386
}


/**
387
 * Generate 'deleteStream' call and send it to the server. It should make
388 389
 * the server remove some channel for media streams.
 */
390
static int gen_delete_stream(URLContext *s, RTMPContext *rt)
391 392 393
{
    RTMPPacket pkt;
    uint8_t *p;
394
    int ret;
395

396
    av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
397 398 399 400

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 34)) < 0)
        return ret;
401 402 403

    p = pkt.data;
    ff_amf_write_string(&p, "deleteStream");
404
    ff_amf_write_number(&p, ++rt->nb_invokes);
405
    ff_amf_write_null(&p);
406
    ff_amf_write_number(&p, rt->main_channel_id);
407

408 409
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
410
    ff_rtmp_packet_destroy(&pkt);
411

412
    return ret;
413 414
}

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
/**
 * Generate client buffer time and send it to the server.
 */
static int gen_buffer_time(URLContext *s, RTMPContext *rt)
{
    RTMPPacket pkt;
    uint8_t *p;
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
                                     1, 10)) < 0)
        return ret;

    p = pkt.data;
    bytestream_put_be16(&p, 3);
    bytestream_put_be32(&p, rt->main_channel_id);
    bytestream_put_be32(&p, rt->client_buffer_time);

    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
    ff_rtmp_packet_destroy(&pkt);

    return ret;
}

440
/**
441
 * Generate 'play' call and send it to the server, then ping the server
442 443
 * to start actual playing.
 */
444
static int gen_play(URLContext *s, RTMPContext *rt)
445 446 447
{
    RTMPPacket pkt;
    uint8_t *p;
448
    int ret;
449

450
    av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
451 452 453 454 455

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
                                     0, 29 + strlen(rt->playpath))) < 0)
        return ret;

456 457 458 459
    pkt.extra = rt->main_channel_id;

    p = pkt.data;
    ff_amf_write_string(&p, "play");
460
    ff_amf_write_number(&p, ++rt->nb_invokes);
461 462
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);
463
    ff_amf_write_number(&p, rt->live);
464

465 466
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
467 468
    ff_rtmp_packet_destroy(&pkt);

469
    return ret;
470 471
}

472
/**
473
 * Generate 'publish' call and send it to the server.
474
 */
475
static int gen_publish(URLContext *s, RTMPContext *rt)
476 477 478
{
    RTMPPacket pkt;
    uint8_t *p;
479
    int ret;
480

481
    av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
482 483 484 485 486

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
                                     0, 30 + strlen(rt->playpath))) < 0)
        return ret;

487 488 489 490
    pkt.extra = rt->main_channel_id;

    p = pkt.data;
    ff_amf_write_string(&p, "publish");
491
    ff_amf_write_number(&p, ++rt->nb_invokes);
492 493 494 495
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);
    ff_amf_write_string(&p, "live");

496 497
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
498
    ff_rtmp_packet_destroy(&pkt);
499 500

    return ret;
501 502
}

503
/**
504
 * Generate ping reply and send it to the server.
505
 */
506
static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
507 508 509
{
    RTMPPacket pkt;
    uint8_t *p;
510 511 512 513 514
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
                                     ppkt->timestamp + 1, 6)) < 0)
        return ret;
515 516 517

    p = pkt.data;
    bytestream_put_be16(&p, 7);
518
    bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
519 520
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
521
    ff_rtmp_packet_destroy(&pkt);
522

523
    return ret;
524 525
}

526 527 528
/**
 * Generate server bandwidth message and send it to the server.
 */
529
static int gen_server_bw(URLContext *s, RTMPContext *rt)
530 531 532
{
    RTMPPacket pkt;
    uint8_t *p;
533 534 535 536 537
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
                                     0, 4)) < 0)
        return ret;
538 539

    p = pkt.data;
540
    bytestream_put_be32(&p, rt->server_bw);
541 542
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
543
    ff_rtmp_packet_destroy(&pkt);
544

545
    return ret;
546 547
}

548 549 550
/**
 * Generate check bandwidth message and send it to the server.
 */
551
static int gen_check_bw(URLContext *s, RTMPContext *rt)
552 553 554
{
    RTMPPacket pkt;
    uint8_t *p;
555
    int ret;
556

557 558 559
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 21)) < 0)
        return ret;
560 561 562 563 564 565

    p = pkt.data;
    ff_amf_write_string(&p, "_checkbw");
    ff_amf_write_number(&p, ++rt->nb_invokes);
    ff_amf_write_null(&p);

566 567
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
568
    ff_rtmp_packet_destroy(&pkt);
569 570

    return ret;
571 572
}

573
/**
574
 * Generate report on bytes read so far and send it to the server.
575
 */
576
static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
577 578 579
{
    RTMPPacket pkt;
    uint8_t *p;
580 581 582 583 584
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
                                     ts, 4)) < 0)
        return ret;
585 586 587

    p = pkt.data;
    bytestream_put_be32(&p, rt->bytes_read);
588 589
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
590
    ff_rtmp_packet_destroy(&pkt);
591

592
    return ret;
593 594
}

595 596
int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
                        const uint8_t *key, int keylen, uint8_t *dst)
597 598 599 600 601 602
{
    struct AVSHA *sha;
    uint8_t hmac_buf[64+32] = {0};
    int i;

    sha = av_mallocz(av_sha_size);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
603 604
    if (!sha)
        return AVERROR(ENOMEM);
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632

    if (keylen < 64) {
        memcpy(hmac_buf, key, keylen);
    } else {
        av_sha_init(sha, 256);
        av_sha_update(sha,key, keylen);
        av_sha_final(sha, hmac_buf);
    }
    for (i = 0; i < 64; i++)
        hmac_buf[i] ^= HMAC_IPAD_VAL;

    av_sha_init(sha, 256);
    av_sha_update(sha, hmac_buf, 64);
    if (gap <= 0) {
        av_sha_update(sha, src, len);
    } else { //skip 32 bytes used for storing digest
        av_sha_update(sha, src, gap);
        av_sha_update(sha, src + gap + 32, len - gap - 32);
    }
    av_sha_final(sha, hmac_buf + 64);

    for (i = 0; i < 64; i++)
        hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
    av_sha_init(sha, 256);
    av_sha_update(sha, hmac_buf, 64+32);
    av_sha_final(sha, dst);

    av_free(sha);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
633 634

    return 0;
635 636
}

637 638 639 640 641 642 643 644 645 646 647 648
int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
                            int add_val)
{
    int i, digest_pos = 0;

    for (i = 0; i < 4; i++)
        digest_pos += buf[i + off];
    digest_pos = digest_pos % mod_val + add_val;

    return digest_pos;
}

649
/**
650
 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
651 652 653
 * will be stored) into that packet.
 *
 * @param buf handshake data (1536 bytes)
Samuel Pitoiset's avatar
Samuel Pitoiset committed
654
 * @param encrypted use an encrypted connection (RTMPE)
655 656
 * @return offset to the digest inside input data
 */
Samuel Pitoiset's avatar
Samuel Pitoiset committed
657
static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
658
{
659
    int ret, digest_pos;
660

Samuel Pitoiset's avatar
Samuel Pitoiset committed
661 662 663 664
    if (encrypted)
        digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
    else
        digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
665

666 667 668
    ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
                              rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
                              buf + digest_pos);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
669 670 671
    if (ret < 0)
        return ret;

672 673 674 675
    return digest_pos;
}

/**
676
 * Verify that the received server response has the expected digest value.
677 678 679 680 681 682 683 684
 *
 * @param buf handshake data received from the server (1536 bytes)
 * @param off position to search digest offset from
 * @return 0 if digest is valid, digest position otherwise
 */
static int rtmp_validate_digest(uint8_t *buf, int off)
{
    uint8_t digest[32];
685
    int ret, digest_pos;
686

687
    digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
688

689 690 691
    ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
                              rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
                              digest);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
692 693 694
    if (ret < 0)
        return ret;

695 696 697 698 699 700
    if (!memcmp(digest, buf + digest_pos, 32))
        return digest_pos;
    return 0;
}

/**
701
 * Perform handshake with the server by means of exchanging pseudorandom data
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
 * signed with HMAC-SHA2 digest.
 *
 * @return 0 if handshake succeeds, negative value otherwise
 */
static int rtmp_handshake(URLContext *s, RTMPContext *rt)
{
    AVLFG rnd;
    uint8_t tosend    [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
        3,                // unencrypted data
        0, 0, 0, 0,       // client uptime
        RTMP_CLIENT_VER1,
        RTMP_CLIENT_VER2,
        RTMP_CLIENT_VER3,
        RTMP_CLIENT_VER4,
    };
    uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
    uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
    int i;
    int server_pos, client_pos;
Samuel Pitoiset's avatar
Samuel Pitoiset committed
721 722 723
    uint8_t digest[32], signature[32];
    int encrypted = rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL;
    int ret, type = 0;
724

725
    av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
726 727 728 729 730

    av_lfg_init(&rnd, 0xDEADC0DE);
    // generate handshake packet - 1536 bytes of pseudorandom data
    for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
        tosend[i] = av_lfg_get(&rnd) >> 24;
Samuel Pitoiset's avatar
Samuel Pitoiset committed
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748

    if (encrypted) {
        /* When the client wants to use RTMPE, we have to change the command
         * byte to 0x06 which means to use encrypted data and we have to set
         * the flash version to at least 9.0.115.0. */
        tosend[0] = 6;
        tosend[5] = 128;
        tosend[6] = 0;
        tosend[7] = 3;
        tosend[8] = 2;

        /* Initialize the Diffie-Hellmann context and generate the public key
         * to send to the server. */
        if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
            return ret;
    }

    client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, encrypted);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
749 750
    if (client_pos < 0)
        return client_pos;
751

752 753 754 755 756 757
    if ((ret = ffurl_write(rt->stream, tosend,
                           RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
        av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
        return ret;
    }

758 759
    if ((ret = ffurl_read_complete(rt->stream, serverdata,
                                   RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
760
        av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
761
        return ret;
762
    }
763 764 765

    if ((ret = ffurl_read_complete(rt->stream, clientdata,
                                   RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
766
        av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
767
        return ret;
768 769
    }

Samuel Pitoiset's avatar
Samuel Pitoiset committed
770
    av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
771
    av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
772 773
           serverdata[5], serverdata[6], serverdata[7], serverdata[8]);

774
    if (rt->is_input && serverdata[5] >= 3) {
775
        server_pos = rtmp_validate_digest(serverdata + 1, 772);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
776 777 778
        if (server_pos < 0)
            return server_pos;

779
        if (!server_pos) {
Samuel Pitoiset's avatar
Samuel Pitoiset committed
780
            type = 1;
781
            server_pos = rtmp_validate_digest(serverdata + 1, 8);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
782 783 784
            if (server_pos < 0)
                return server_pos;

785
            if (!server_pos) {
786
                av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
787
                return AVERROR(EIO);
788
            }
789 790
        }

791 792 793
        ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
                                  rtmp_server_key, sizeof(rtmp_server_key),
                                  digest);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
794 795 796
        if (ret < 0)
            return ret;

797
        ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
Samuel Pitoiset's avatar
Samuel Pitoiset committed
798
                                  0, digest, 32, signature);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
799 800 801
        if (ret < 0)
            return ret;

Samuel Pitoiset's avatar
Samuel Pitoiset committed
802 803 804 805 806 807 808 809 810 811 812 813
        if (encrypted) {
            /* Compute the shared secret key sent by the server and initialize
             * the RC4 encryption. */
            if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
                                                   tosend + 1, type)) < 0)
                return ret;

            /* Encrypt the signature received by the server. */
            ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
        }

        if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
814
            av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
815
            return AVERROR(EIO);
816
        }
817

818 819
        for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
            tosend[i] = av_lfg_get(&rnd) >> 24;
820 821 822
        ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
                                  rtmp_player_key, sizeof(rtmp_player_key),
                                  digest);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
823 824 825
        if (ret < 0)
            return ret;

826 827 828
        ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
                                  digest, 32,
                                  tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
829 830
        if (ret < 0)
            return ret;
831

Samuel Pitoiset's avatar
Samuel Pitoiset committed
832 833 834 835 836 837 838
        if (encrypted) {
            /* Encrypt the signature to be send to the server. */
            ff_rtmpe_encrypt_sig(rt->stream, tosend +
                                 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
                                 serverdata[0]);
        }

839
        // write reply back to the server
840 841 842
        if ((ret = ffurl_write(rt->stream, tosend,
                               RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
            return ret;
Samuel Pitoiset's avatar
Samuel Pitoiset committed
843 844 845 846 847 848

        if (encrypted) {
            /* Set RC4 keys for encryption and update the keystreams. */
            if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
                return ret;
        }
849
    } else {
Samuel Pitoiset's avatar
Samuel Pitoiset committed
850 851 852 853 854 855 856 857 858 859 860 861 862 863
        if (encrypted) {
            /* Compute the shared secret key sent by the server and initialize
             * the RC4 encryption. */
            if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
                            tosend + 1, 1)) < 0)
                return ret;

            if (serverdata[0] == 9) {
                /* Encrypt the signature received by the server. */
                ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
                                     serverdata[0]);
            }
        }

864 865 866
        if ((ret = ffurl_write(rt->stream, serverdata + 1,
                               RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
            return ret;
Samuel Pitoiset's avatar
Samuel Pitoiset committed
867 868 869 870 871 872

        if (encrypted) {
            /* Set RC4 keys for encryption and update the keystreams. */
            if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
                return ret;
        }
873 874
    }

875 876 877 878
    return 0;
}

/**
879
 * Parse received packet and possibly perform some action depending on
880 881 882 883 884 885 886 887
 * the packet contents.
 * @return 0 for no errors, negative values for serious errors which prevent
 *         further communications, positive values for uncritical errors
 */
static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
{
    int i, t;
    const uint8_t *data_end = pkt->data + pkt->data_size;
888
    int ret;
889

890
#ifdef DEBUG
891
    ff_rtmp_packet_dump(s, pkt);