History

avformat/tls_schannel: fix non-blocking write breaking TLS sessions

Timo Rothenpieler committed 1 year ago

Commit 9b6638e1 parent 9cd86c41 file · +79 −32Browse files

Unified · Split

libavformat/tls_schannel.c+79−32
@@ -608,6 +608,10 @@ typedef struct TLSContext { · 607 unmodified lines
608 int dec_buf_size;608 int dec_buf_size;
609 int dec_buf_offset;609 int dec_buf_offset;
610 610
611 char *send_buf;
612 int send_buf_size;
613 int send_buf_offset;
614
611 SecPkgContext_StreamSizes sizes;615 SecPkgContext_StreamSizes sizes;
612 616
613 int connected;617 int connected;
@@ -692,6 +696,35 @@ static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, · 78 unmodified lines
692 desc->cBuffers = buffer_count;696 desc->cBuffers = buffer_count;
693}697}
694 698
699static int tls_process_send_buffer(URLContext *h)
700{
701 TLSContext *c = h->priv_data;
702 TLSShared *s = &c->tls_shared;
703 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
704 int ret;
705
706 if (!c->send_buf)
707 return 0;
708
709 ret = ffurl_write(uc, c->send_buf + c->send_buf_offset, c->send_buf_size - c->send_buf_offset);
710 if (ret == AVERROR(EAGAIN)) {
711 return AVERROR(EAGAIN);
712 } else if (ret < 0) {
713 av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n");
714 return AVERROR(EIO);
715 }
716
717 c->send_buf_offset += ret;
718
719 if (c->send_buf_offset < c->send_buf_size)
720 return AVERROR(EAGAIN);
721
722 av_freep(&c->send_buf);
723 c->send_buf_size = c->send_buf_offset = 0;
724
725 return 0;
726}
727
695static int tls_shutdown_client(URLContext *h)728static int tls_shutdown_client(URLContext *h)
696{729{
697 TLSContext *c = h->priv_data;730 TLSContext *c = h->priv_data;
@@ -710,6 +743,11 @@ static int tls_shutdown_client(URLContext *h) · 12 unmodified lines
710 init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));743 init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
711 init_sec_buffer_desc(&BuffDesc, &Buffer, 1);744 init_sec_buffer_desc(&BuffDesc, &Buffer, 1);
712 745
746 uc->flags &= ~AVIO_FLAG_NONBLOCK;
747 ret = tls_process_send_buffer(h);
748 if (ret < 0)
749 return ret;
750
713 sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc);751 sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc);
714 if (sspi_ret != SEC_E_OK)752 if (sspi_ret != SEC_E_OK)
715 av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n");753 av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n");
@@ -729,7 +767,6 @@ static int tls_shutdown_client(URLContext *h) · 13 unmodified lines
729 767
730 if (outbuf.pvBuffer) {768 if (outbuf.pvBuffer) {
731 if (outbuf.cbBuffer > 0) {769 if (outbuf.cbBuffer > 0) {
732 uc->flags &= ~AVIO_FLAG_NONBLOCK;
733 ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);770 ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
734 if (ret < 0 || ret != outbuf.cbBuffer)771 if (ret < 0 || ret != outbuf.cbBuffer)
735 av_log(h, AV_LOG_ERROR, "Failed to send close message\n");772 av_log(h, AV_LOG_ERROR, "Failed to send close message\n");
@@ -761,6 +798,9 @@ static int tls_close(URLContext *h) · 25 unmodified lines
761 av_freep(&c->dec_buf);798 av_freep(&c->dec_buf);
762 c->dec_buf_size = c->dec_buf_offset = 0;799 c->dec_buf_size = c->dec_buf_offset = 0;
763 800
801 av_freep(&c->send_buf);
802 c->send_buf_size = c->send_buf_offset = 0;
803
764 if (s->is_dtls) {804 if (s->is_dtls) {
765 if (!s->external_sock)805 if (!s->external_sock)
766 ffurl_closep(&c->tls_shared.udp);806 ffurl_closep(&c->tls_shared.udp);
@@ -1264,6 +1304,11 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) · 497 unmodified lines
1264 goto cleanup;1304 goto cleanup;
1265 }1305 }
1266 sspi_ret = SEC_E_OK;1306 sspi_ret = SEC_E_OK;
1307
1308 /* if somehow any send data was left, it is now invalid */
1309 av_freep(&c->send_buf);
1310 c->send_buf_size = c->send_buf_offset = 0;
1311
1267 continue;1312 continue;
1268 } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) {1313 } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) {
1269 c->sspi_close_notify = 1;1314 c->sspi_close_notify = 1;
@@ -1308,10 +1353,16 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 38 unmodified lines
1308 TLSShared *s = &c->tls_shared;1353 TLSShared *s = &c->tls_shared;
1309 URLContext *uc = s->is_dtls ? s->udp : s->tcp;1354 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
1310 SECURITY_STATUS sspi_ret;1355 SECURITY_STATUS sspi_ret;
1311 int ret = 0, data_size;
1312 uint8_t *data = NULL;
1313 SecBuffer outbuf[4];1356 SecBuffer outbuf[4];
1314 SecBufferDesc outbuf_desc;1357 SecBufferDesc outbuf_desc;
1358 int ret = 0;
1359
1360 uc->flags &= ~AVIO_FLAG_NONBLOCK;
1361 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1362
1363 ret = tls_process_send_buffer(h);
1364 if (ret < 0)
1365 return ret;
1315 1366
1316 if (c->sizes.cbMaximumMessage == 0) {1367 if (c->sizes.cbMaximumMessage == 0) {
1317 sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes);1368 sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes);
@@ -1322,50 +1373,46 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 4 unmodified lines
1322 /* limit how much data we can consume */1373 /* limit how much data we can consume */
1323 len = FFMIN(len, c->sizes.cbMaximumMessage - c->sizes.cbHeader - c->sizes.cbTrailer);1374 len = FFMIN(len, c->sizes.cbMaximumMessage - c->sizes.cbHeader - c->sizes.cbTrailer);
1324 1375
1325 data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer;1376 c->send_buf_size = c->sizes.cbHeader + len + c->sizes.cbTrailer;
1326 data = av_malloc(data_size);1377 c->send_buf = av_malloc(c->send_buf_size);
1327 if (data == NULL)1378 if (c->send_buf == NULL)
1328 return AVERROR(ENOMEM);1379 return AVERROR(ENOMEM);
1329 1380
1330 init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER,1381 init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1331 data, c->sizes.cbHeader);1382 c->send_buf, c->sizes.cbHeader);
1332 init_sec_buffer(&outbuf[1], SECBUFFER_DATA,1383 init_sec_buffer(&outbuf[1], SECBUFFER_DATA,
1333 data + c->sizes.cbHeader, len);1384 c->send_buf + c->sizes.cbHeader, len);
1334 init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,1385 init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1335 data + c->sizes.cbHeader + len,1386 c->send_buf + c->sizes.cbHeader + len,
1336 c->sizes.cbTrailer);1387 c->sizes.cbTrailer);
1337 init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);1388 init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1338 init_sec_buffer_desc(&outbuf_desc, outbuf, 4);1389 init_sec_buffer_desc(&outbuf_desc, outbuf, 4);
1339 1390
1340 memcpy(outbuf[1].pvBuffer, buf, len);1391 memcpy(outbuf[1].pvBuffer, buf, len);
1341 1392
1342 sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0);1393 sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0);
1343 if (sspi_ret == SEC_E_OK) {1394 if (sspi_ret != SEC_E_OK) {
1344 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;1395 av_freep(&c->send_buf);
1345
1346 uc->flags &= ~AVIO_FLAG_NONBLOCK;
1347 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1348
1349 ret = ffurl_write(uc, data, len);
1350 if (ret == AVERROR(EAGAIN)) {
1351 goto done;
1352 } else if (ret < 0 || ret != len) {
1353 ret = AVERROR(EIO);
1354 av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n");
1355 goto done;
1356 }
1357 } else {
1358 av_log(h, AV_LOG_ERROR, "Encrypting data failed\n");1396 av_log(h, AV_LOG_ERROR, "Encrypting data failed\n");
1359 if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY)1397 if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY)
1360 ret = AVERROR(ENOMEM);1398 return AVERROR(ENOMEM);
1361 else1399 return AVERROR(EIO);
1362 ret = AVERROR(EIO);1400 }
1363 goto done;1401
1402 c->send_buf_size = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1403 c->send_buf_offset = 0;
1404
1405 ret = tls_process_send_buffer(h);
1406 if (ret == AVERROR(EAGAIN)) {
1407 /* We always need to signal that we consumed all (encryped) data since schannel must not
1408 be fed the same data again. Sending will then be completed next call to this function,
1409 and EAGAIN returned until all remaining buffer is sent. */
1410 return outbuf[1].cbBuffer;
1411 } else if (ret < 0) {
1412 return ret;
1364 }1413 }
1365 1414
1366done:1415 return outbuf[1].cbBuffer;
1367 av_freep(&data);
1368 return ret < 0 ? ret : outbuf[1].cbBuffer;
1369}1416}
1370 1417
1371static int tls_get_file_handle(URLContext *h)1418static int tls_get_file_handle(URLContext *h)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t