Skip to content

Commit b65e953

Browse files
committed
WHIP: Read DTLS certificate file by ffurl.
1 parent 8a0bdfc commit b65e953

File tree

1 file changed

+83
-16
lines changed

1 file changed

+83
-16
lines changed

libavformat/whip.c

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
*/
4949
#define MAX_SDP_SIZE 8192
5050

51+
/**
52+
* Maximum size limit of a certificate and private key size.
53+
*/
54+
#define MAX_CERTIFICATE_SIZE 8192
55+
5156
/**
5257
* Maximum size of the buffer for sending and receiving UDP packets.
5358
* Please note that this size does not limit the size of the UDP packet that can be sent.
@@ -152,6 +157,49 @@
152157
/* Calculate the elapsed time from starttime to endtime in milliseconds. */
153158
#define ELAPSED(starttime, endtime) ((int)(endtime - starttime) / 1000)
154159

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+
155203
/* STUN Attribute, comprehension-required range (0x0000-0x7FFF) */
156204
enum STUNAttr {
157205
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,
424472
return retvalue;
425473
}
426474

427-
static int openssl_read_certificate(DTLSContext *ctx)
475+
static int openssl_read_certificate(AVFormatContext *s, DTLSContext *ctx)
428476
{
429477
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);
431484

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) {
434488
av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to open key file %s\n", ctx->key_file);
435-
ret = AVERROR(EIO);
436489
goto end;
437490
}
438491

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);
440499
if (!ctx->dtls_pkey) {
441500
av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to read private key from %s\n", ctx->key_file);
442501
ret = AVERROR(EIO);
443502
goto end;
444503
}
445504

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);
450514
goto end;
451515
}
452516

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);
454519
if (!ctx->dtls_cert) {
455520
av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to read certificate from %s\n", ctx->cert_file);
456521
ret = AVERROR(EIO);
457522
goto end;
458523
}
459524

460525
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);
463530
return ret;
464531
}
465532

@@ -778,15 +845,15 @@ static av_cold int openssl_dtls_init_context(DTLSContext *ctx)
778845
* ff_openssl_init in tls_openssl.c has already called SSL_library_init(), and therefore,
779846
* there is no need to call it again.
780847
*/
781-
static av_cold int dtls_context_init(DTLSContext *ctx)
848+
static av_cold int dtls_context_init(AVFormatContext *s, DTLSContext *ctx)
782849
{
783850
int ret = 0;
784851

785852
ctx->dtls_init_starttime = av_gettime();
786853

787854
if (ctx->cert_file && ctx->key_file) {
788855
/* 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) {
790857
av_log(ctx, AV_LOG_ERROR, "DTLS: Failed to read DTLS certificate from cert=%s, key=%s\n",
791858
ctx->cert_file, ctx->key_file);
792859
return ret;
@@ -1147,7 +1214,7 @@ static av_cold int initialize(AVFormatContext *s)
11471214
if (whip->key_file)
11481215
whip->dtls_ctx.key_file = av_strdup(whip->key_file);
11491216

1150-
if ((ret = dtls_context_init(&whip->dtls_ctx)) < 0) {
1217+
if ((ret = dtls_context_init(s, &whip->dtls_ctx)) < 0) {
11511218
av_log(whip, AV_LOG_ERROR, "WHIP: Failed to init DTLS context\n");
11521219
return ret;
11531220
}

0 commit comments

Comments
 (0)