|
48 | 48 | */
|
49 | 49 | #define MAX_SDP_SIZE 8192
|
50 | 50 |
|
| 51 | +/** |
| 52 | + * Maximum size limit of a certificate and private key size. |
| 53 | + */ |
| 54 | +#define MAX_CERTIFICATE_SIZE 8192 |
| 55 | + |
51 | 56 | /**
|
52 | 57 | * Maximum size of the buffer for sending and receiving UDP packets.
|
53 | 58 | * Please note that this size does not limit the size of the UDP packet that can be sent.
|
|
152 | 157 | /* Calculate the elapsed time from starttime to endtime in milliseconds. */
|
153 | 158 | #define ELAPSED(starttime, endtime) ((int)(endtime - starttime) / 1000)
|
154 | 159 |
|
| 160 | +/** |
| 161 | + * Read all data from the given URL url and store it in the given buffer bp. |
| 162 | + */ |
| 163 | +static int url_read_all(AVFormatContext *s, const char *url, AVBPrint *bp) |
| 164 | +{ |
| 165 | + int ret = 0; |
| 166 | + AVDictionary *opts = NULL; |
| 167 | + URLContext *uc = NULL; |
| 168 | + char buf[MAX_URL_SIZE]; |
| 169 | + |
| 170 | + ret = ffurl_open_whitelist(&uc, url, AVIO_FLAG_READ, &s->interrupt_callback, |
| 171 | + &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); |
| 172 | + if (ret < 0) { |
| 173 | + av_log(s, AV_LOG_ERROR, "WHIP: Failed to open url %s\n", url); |
| 174 | + goto end; |
| 175 | + } |
| 176 | + |
| 177 | + while (1) { |
| 178 | + ret = ffurl_read(uc, buf, sizeof(buf)); |
| 179 | + if (ret == AVERROR_EOF) { |
| 180 | + /* Reset the error because we read all response as answer util EOF. */ |
| 181 | + ret = 0; |
| 182 | + break; |
| 183 | + } |
| 184 | + if (ret <= 0) { |
| 185 | + av_log(s, AV_LOG_ERROR, "WHIP: Failed to read from url=%s, key is %s\n", url, bp->str); |
| 186 | + goto end; |
| 187 | + } |
| 188 | + |
| 189 | + av_bprintf(bp, "%.*s", ret, buf); |
| 190 | + if (!av_bprint_is_complete(bp)) { |
| 191 | + av_log(s, AV_LOG_ERROR, "WHIP: Exceed max size %.*s, %s\n", ret, buf, bp->str); |
| 192 | + ret = AVERROR(EIO); |
| 193 | + goto end; |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | +end: |
| 198 | + ffurl_closep(&uc); |
| 199 | + av_dict_free(&opts); |
| 200 | + return ret; |
| 201 | +} |
| 202 | + |
155 | 203 | /* STUN Attribute, comprehension-required range (0x0000-0x7FFF) */
|
156 | 204 | enum STUNAttr {
|
157 | 205 | STUN_ATTR_USERNAME = 0x0006, /// shared secret response/bind request
|
@@ -424,42 +472,61 @@ static long openssl_dtls_bio_out_callback_ex(BIO *b, int oper, const char *argp,
|
424 | 472 | return retvalue;
|
425 | 473 | }
|
426 | 474 |
|
427 |
| -static int openssl_read_certificate(DTLSContext *ctx) |
| 475 | +static int openssl_read_certificate(AVFormatContext *s, DTLSContext *ctx) |
428 | 476 | {
|
429 | 477 | int ret = 0;
|
430 |
| - FILE *fp_key = NULL, *fp_cert = NULL; |
| 478 | + BIO *key_b = NULL, *cert_b = NULL; |
| 479 | + AVBPrint key_bp, cert_bp; |
| 480 | + |
| 481 | + /* To prevent a crash during cleanup, always initialize it. */ |
| 482 | + av_bprint_init(&key_bp, 1, MAX_CERTIFICATE_SIZE); |
| 483 | + av_bprint_init(&cert_bp, 1, MAX_CERTIFICATE_SIZE); |
431 | 484 |
|
432 |
| - fp_key = fopen(ctx->key_file, "r"); |
433 |
| - if (!fp_key) { |
| 485 | + /* Read key file. */ |
| 486 | + ret = url_read_all(s, ctx->key_file, &key_bp); |
| 487 | + if (ret < 0) { |
434 | 488 | av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to open key file %s\n", ctx->key_file);
|
435 |
| - ret = AVERROR(EIO); |
436 | 489 | goto end;
|
437 | 490 | }
|
438 | 491 |
|
439 |
| - ctx->dtls_pkey = PEM_read_PrivateKey(fp_key, NULL, NULL, NULL); |
| 492 | + if ((key_b = BIO_new(BIO_s_mem())) == NULL) { |
| 493 | + ret = AVERROR(ENOMEM); |
| 494 | + goto end; |
| 495 | + } |
| 496 | + |
| 497 | + BIO_write(key_b, key_bp.str, key_bp.len); |
| 498 | + ctx->dtls_pkey = PEM_read_bio_PrivateKey(key_b, NULL, NULL, NULL); |
440 | 499 | if (!ctx->dtls_pkey) {
|
441 | 500 | av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to read private key from %s\n", ctx->key_file);
|
442 | 501 | ret = AVERROR(EIO);
|
443 | 502 | goto end;
|
444 | 503 | }
|
445 | 504 |
|
446 |
| - fp_cert = fopen(ctx->cert_file, "r"); |
447 |
| - if (!fp_cert) { |
448 |
| - av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to open certificate file %s\n", ctx->cert_file); |
449 |
| - ret = AVERROR(EIO); |
| 505 | + /* Read certificate. */ |
| 506 | + ret = url_read_all(s, ctx->cert_file, &cert_bp); |
| 507 | + if (ret < 0) { |
| 508 | + av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to open cert file %s\n", ctx->cert_file); |
| 509 | + goto end; |
| 510 | + } |
| 511 | + |
| 512 | + if ((cert_b = BIO_new(BIO_s_mem())) == NULL) { |
| 513 | + ret = AVERROR(ENOMEM); |
450 | 514 | goto end;
|
451 | 515 | }
|
452 | 516 |
|
453 |
| - ctx->dtls_cert = PEM_read_X509(fp_cert, NULL, NULL, NULL); |
| 517 | + BIO_write(cert_b, cert_bp.str, cert_bp.len); |
| 518 | + ctx->dtls_cert = PEM_read_bio_X509(cert_b, NULL, NULL, NULL); |
454 | 519 | if (!ctx->dtls_cert) {
|
455 | 520 | av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to read certificate from %s\n", ctx->cert_file);
|
456 | 521 | ret = AVERROR(EIO);
|
457 | 522 | goto end;
|
458 | 523 | }
|
459 | 524 |
|
460 | 525 | end:
|
461 |
| - if (fp_key) fclose(fp_key); |
462 |
| - if (fp_cert) fclose(fp_cert); |
| 526 | + BIO_free(key_b); |
| 527 | + av_bprint_finalize(&key_bp, NULL); |
| 528 | + BIO_free(cert_b); |
| 529 | + av_bprint_finalize(&cert_bp, NULL); |
463 | 530 | return ret;
|
464 | 531 | }
|
465 | 532 |
|
@@ -778,15 +845,15 @@ static av_cold int openssl_dtls_init_context(DTLSContext *ctx)
|
778 | 845 | * ff_openssl_init in tls_openssl.c has already called SSL_library_init(), and therefore,
|
779 | 846 | * there is no need to call it again.
|
780 | 847 | */
|
781 |
| -static av_cold int dtls_context_init(DTLSContext *ctx) |
| 848 | +static av_cold int dtls_context_init(AVFormatContext *s, DTLSContext *ctx) |
782 | 849 | {
|
783 | 850 | int ret = 0;
|
784 | 851 |
|
785 | 852 | ctx->dtls_init_starttime = av_gettime();
|
786 | 853 |
|
787 | 854 | if (ctx->cert_file && ctx->key_file) {
|
788 | 855 | /* Read the private key and file from the file. */
|
789 |
| - if ((ret = openssl_read_certificate(ctx)) < 0) { |
| 856 | + if ((ret = openssl_read_certificate(s, ctx)) < 0) { |
790 | 857 | av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to read DTLS certificate from cert=%s, key=%s\n",
|
791 | 858 | ctx->cert_file, ctx->key_file);
|
792 | 859 | return ret;
|
@@ -1147,7 +1214,7 @@ static av_cold int initialize(AVFormatContext *s)
|
1147 | 1214 | if (whip->key_file)
|
1148 | 1215 | whip->dtls_ctx.key_file = av_strdup(whip->key_file);
|
1149 | 1216 |
|
1150 |
| - if ((ret = dtls_context_init(&whip->dtls_ctx)) < 0) { |
| 1217 | + if ((ret = dtls_context_init(s, &whip->dtls_ctx)) < 0) { |
1151 | 1218 | av_log(whip, AV_LOG_ERROR, "WHIP: Failed to init DTLS context\n");
|
1152 | 1219 | return ret;
|
1153 | 1220 | }
|
|
0 commit comments