History

avformat/tls_schannel: add DTLS support

Timo Rothenpieler committed 1 year ago

Commit 90fa9631 parent 6af09953 files · +833 −65Browse files

Unified · Split

3 files
  1. configure +4 −2
  2. libavformat/tls_schannel.c +828 −62
  3. libavformat/version.h +1 −1
configure+4−2
@@ -3856,7 +3856,7 @@ tcp_protocol_select="network" · 3855 unmodified lines
3856tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls"3856tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls"
3857tls_protocol_select="tcp_protocol"3857tls_protocol_select="tcp_protocol"
3858# TODO: Support libtls, mbedtls, and gnutls.3858# TODO: Support libtls, mbedtls, and gnutls.
3859dtls_protocol_deps_any="openssl"3859dtls_protocol_deps_any="openssl schannel"
3860dtls_protocol_select="udp_protocol"3860dtls_protocol_select="udp_protocol"
3861udp_protocol_select="network"3861udp_protocol_select="network"
3862udplite_protocol_select="network"3862udplite_protocol_select="network"
@@ -7265,8 +7265,10 @@ enabled securetransport && · 3402 unmodified lines
7265 7265
7266enabled schannel &&7266enabled schannel &&
7267 check_func_headers "windows.h security.h" InitializeSecurityContext -DSECURITY_WIN32 -lsecur32 &&7267 check_func_headers "windows.h security.h" InitializeSecurityContext -DSECURITY_WIN32 -lsecur32 &&
7268 check_func_headers "windows.h ncrypt.h" NCryptOpenStorageProvider -DSECURITY_WIN32 -lncrypt &&
7269 check_func_headers "windows.h wincrypt.h" CertCreateSelfSignCertificate -DSECURITY_WIN32 -lcrypt32 &&
7268 test_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" &&7270 test_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" &&
7269 schannel_extralibs="-lsecur32" ||7271 schannel_extralibs="-lsecur32 -lncrypt -lcrypt32" ||
7270 disable schannel7272 disable schannel
7271 7273
7272makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo7274makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo
libavformat/tls_schannel.c+828−62
@@ -32,6 +32,7 @@ · 31 unmodified lines
32#include <windows.h>32#include <windows.h>
33#include <security.h>33#include <security.h>
34#include <schnlsp.h>34#include <schnlsp.h>
35#include <sddl.h>
35 36
36#define SCHANNEL_INITIAL_BUFFER_SIZE 409637#define SCHANNEL_INITIAL_BUFFER_SIZE 4096
37#define SCHANNEL_FREE_BUFFER_SIZE 102438#define SCHANNEL_FREE_BUFFER_SIZE 1024
@@ -41,6 +42,521 @@ · 3 unmodified lines
41#define SECBUFFER_ALERT 1742#define SECBUFFER_ALERT 17
42#endif43#endif
43 44
45/* This is the name used for the private key in the MS Keystore.
46 * There is as of time of writing no way to use schannel without
47 * persisting the private key. Which usually means the default MS
48 * keystore will write it to disk unencrypted, user-read/writable.
49 * To combat this as much as possible, the code makes sure to
50 * delete the private key ASAP once SChannel has gotten ahold of
51 * it.
52 * Apparently this is because SChannel neglects marshaling the
53 * private key alongside the certificate for the out-of-process
54 * tls handler.
55 * See this GitHub issue for the most detailed explanation out there:
56 * https://github.com/dotnet/runtime/issues/23749#issuecomment-485947319
57 */
58#define FF_NCRYPT_TEMP_KEY_NAME L"FFMPEG_TEMP_TLS_KEY"
59
60static int der_to_pem(const char *data, size_t len, const char *header, char *buf, size_t bufsize)
61{
62 const int line_length = 64;
63 AVBPrint pem;
64 DWORD base64len = 0;
65 char *base64 = NULL;
66 int ret = 0;
67
68 if (!CryptBinaryToStringA(data, len, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &base64len)) {
69 av_log(NULL, AV_LOG_ERROR, "CryptBinaryToString failed\n");
70 ret = AVERROR_EXTERNAL;
71 goto end;
72 }
73
74 base64 = av_malloc(base64len);
75
76 if (!CryptBinaryToStringA(data, len, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, base64, &base64len)) {
77 av_log(NULL, AV_LOG_ERROR, "CryptBinaryToString failed\n");
78 ret = AVERROR_EXTERNAL;
79 goto end;
80 }
81
82 av_bprint_init_for_buffer(&pem, buf, bufsize);
83 av_bprintf(&pem, "-----BEGIN %s-----\n", header);
84
85 for (DWORD i = 0; i < base64len; i += line_length) {
86 av_bprintf(&pem, "%.*s\n", line_length, base64 + i);
87 }
88
89 av_bprintf(&pem, "-----END %s-----\n", header);
90
91 if (!av_bprint_is_complete(&pem)) {
92 ret = AVERROR(ENOSPC);
93 goto end;
94 }
95
96end:
97 av_free(base64);
98 return ret;
99}
100
101static int pem_to_der(const char *pem, char **buf, int *out_len)
102{
103 DWORD derlen = 0;
104
105 if (!CryptStringToBinaryA(pem, 0, CRYPT_STRING_BASE64HEADER, NULL, &derlen, NULL, NULL)) {
106 av_log(NULL, AV_LOG_ERROR, "CryptStringToBinaryA failed\n");
107 return AVERROR(EINVAL);
108 }
109
110 *buf = av_malloc(derlen);
111 if (!*buf)
112 return AVERROR(ENOMEM);
113
114 if (!CryptStringToBinaryA(pem, 0, CRYPT_STRING_BASE64HEADER, *buf, &derlen, NULL, NULL)) {
115 av_log(NULL, AV_LOG_ERROR, "CryptStringToBinaryA failed\n");
116 return AVERROR(EINVAL);
117 }
118
119 *out_len = derlen;
120
121 return 0;
122}
123
124static int der_to_fingerprint(const char *data, size_t len, char **fingerprint)
125{
126 AVBPrint buf;
127 unsigned char hash[32];
128 DWORD hashsize = sizeof(hash);
129
130 if (!CryptHashCertificate2(BCRYPT_SHA256_ALGORITHM, 0, NULL, data, len, hash, &hashsize))
131 {
132 av_log(NULL, AV_LOG_ERROR, "CryptHashCertificate2 failed\n");
133 return AVERROR_EXTERNAL;
134 }
135
136 av_bprint_init(&buf, hashsize*3, hashsize*3);
137
138 for (int i = 0; i < hashsize - 1; i++)
139 av_bprintf(&buf, "%02X:", hash[i]);
140 av_bprintf(&buf, "%02X", hash[hashsize - 1]);
141
142 return av_bprint_finalize(&buf, fingerprint);
143}
144
145static int tls_gen_self_signed(NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
146{
147 NCRYPT_PROV_HANDLE provider = 0;
148 CERT_NAME_BLOB subject = { 0 };
149
150 DWORD export_props = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
151 DWORD usage_props = NCRYPT_ALLOW_ALL_USAGES;
152 LPCSTR ext_usages[] = { szOID_PKIX_KP_SERVER_AUTH };
153 BYTE key_usage = CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DIGITAL_SIGNATURE_KEY_USAGE;
154 CRYPT_BIT_BLOB key_usage_blob = { 0 };
155 CERT_ENHKEY_USAGE eku = { 0 };
156 CERT_BASIC_CONSTRAINTS2_INFO basic_constraints = { 0 };
157 CERT_ALT_NAME_ENTRY san_entry = { 0 };
158 CERT_ALT_NAME_INFO san_info = { 0 };
159 CERT_EXTENSION ext[4] = { 0 };
160 CERT_EXTENSIONS exts = { 0 };
161 CRYPT_ALGORITHM_IDENTIFIER sig_alg = { (LPSTR)szOID_ECDSA_SHA256 };
162 CRYPT_KEY_PROV_INFO prov_info = { 0 };
163 const char *subj_str = "CN=lavf";
164
165 SECURITY_STATUS sspi_ret;
166 int ret = 0;
167
168 *crtctx = NULL;
169
170 sspi_ret = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0);
171 if (sspi_ret != ERROR_SUCCESS) {
172 av_log(NULL, AV_LOG_ERROR, "NCryptOpenStorageProvider failed(0x%lx)\n", sspi_ret);
173 ret = AVERROR_EXTERNAL;
174 goto fail;
175 }
176
177 sspi_ret = NCryptCreatePersistedKey(provider, key, BCRYPT_ECDSA_P256_ALGORITHM, FF_NCRYPT_TEMP_KEY_NAME, 0, NCRYPT_OVERWRITE_KEY_FLAG);
178 if (sspi_ret != ERROR_SUCCESS) {
179 av_log(NULL, AV_LOG_ERROR, "NCryptCreatePersistedKey failed(0x%lx)\n", sspi_ret);
180 ret = AVERROR_EXTERNAL;
181 goto fail;
182 }
183
184 sspi_ret = NCryptSetProperty(*key, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE)&export_props, sizeof(export_props), 0);
185 if (sspi_ret != ERROR_SUCCESS) {
186 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_EXPORT_POLICY_PROPERTY) failed(0x%lx)\n", sspi_ret);
187 ret = AVERROR_EXTERNAL;
188 goto fail;
189 }
190
191 sspi_ret = NCryptSetProperty(*key, NCRYPT_KEY_USAGE_PROPERTY, (PBYTE)&usage_props, sizeof(usage_props), 0);
192 if (sspi_ret != ERROR_SUCCESS) {
193 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_KEY_USAGE_PROPERTY) failed(0x%lx)\n", sspi_ret);
194 ret = AVERROR_EXTERNAL;
195 goto fail;
196 }
197
198 sspi_ret = NCryptFinalizeKey(*key, 0);
199 if (sspi_ret != ERROR_SUCCESS) {
200 av_log(NULL, AV_LOG_ERROR, "NCryptFinalizeKey failed(0x%lx)\n", sspi_ret);
201 ret = AVERROR_EXTERNAL;
202 goto fail;
203 }
204
205 if (!CertStrToNameA(X509_ASN_ENCODING, subj_str, 0, NULL, NULL, &subject.cbData, NULL))
206 {
207 av_log(NULL, AV_LOG_ERROR, "Initial subj init failed\n");
208 ret = AVERROR_EXTERNAL;
209 goto fail;
210 }
211
212 subject.pbData = av_malloc(subject.cbData);
213 if (!subject.pbData) {
214 ret = AVERROR(ENOMEM);
215 goto fail;
216 }
217
218 if (!CertStrToNameA(X509_ASN_ENCODING, subj_str, 0, NULL, subject.pbData, &subject.cbData, NULL))
219 {
220 av_log(NULL, AV_LOG_ERROR, "Subj init failed\n");
221 ret = AVERROR_EXTERNAL;
222 goto fail;
223 }
224
225 // Extended Key Usage extension
226 eku.cUsageIdentifier = 1;
227 eku.rgpszUsageIdentifier = (LPSTR*)ext_usages;
228
229 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &eku,
230 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[0].Value.pbData, &ext[0].Value.cbData)) {
231 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for EKU failed\n");
232 ret = AVERROR_EXTERNAL;
233 goto fail;
234 }
235
236 ext[0].pszObjId = (LPSTR)szOID_ENHANCED_KEY_USAGE;
237 ext[0].fCritical = TRUE;
238
239 // Key usage extension
240 key_usage_blob.cbData = sizeof(key_usage);
241 key_usage_blob.pbData = &key_usage;
242
243 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_BITS, &key_usage_blob,
244 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[1].Value.pbData, &ext[1].Value.cbData)) {
245 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for KU failed\n");
246 ret = AVERROR_EXTERNAL;
247 goto fail;
248 }
249
250 ext[1].pszObjId = (LPSTR)szOID_KEY_USAGE;
251 ext[1].fCritical = TRUE;
252
253 // Cert Basic Constraints
254 basic_constraints.fCA = FALSE;
255
256 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &basic_constraints,
257 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[2].Value.pbData, &ext[2].Value.cbData)) {
258 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for KU failed\n");
259 ret = AVERROR_EXTERNAL;
260 goto fail;
261 }
262
263 ext[2].pszObjId = (LPSTR)szOID_BASIC_CONSTRAINTS2;
264 ext[2].fCritical = TRUE;
265
266 // Subject Alt Names
267 san_entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
268 san_entry.pwszDNSName = (LPWSTR)L"localhost";
269
270 san_info.cAltEntry = 1;
271 san_info.rgAltEntry = &san_entry;
272
273 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, &san_info,
274 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[3].Value.pbData, &ext[3].Value.cbData)) {
275 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for KU failed\n");
276 ret = AVERROR_EXTERNAL;
277 goto fail;
278 }
279
280 ext[3].pszObjId = (LPSTR)szOID_SUBJECT_ALT_NAME2;
281 ext[3].fCritical = TRUE;
282
283 exts.cExtension = 4;
284 exts.rgExtension = ext;
285
286 prov_info.pwszProvName = (LPWSTR)MS_KEY_STORAGE_PROVIDER;
287 prov_info.pwszContainerName = (LPWSTR)FF_NCRYPT_TEMP_KEY_NAME;
288 prov_info.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
289
290 *crtctx = CertCreateSelfSignCertificate(*key, &subject, 0, &prov_info, &sig_alg, NULL, NULL, &exts);
291 if (!*crtctx) {
292 av_log(NULL, AV_LOG_ERROR, "CertCreateSelfSignCertificate failed: %lu\n", GetLastError());
293 ret = AVERROR_EXTERNAL;
294 goto fail;
295 }
296
297 NCryptFreeObject(provider);
298 av_free(subject.pbData);
299 for (int i = 0; i < FF_ARRAY_ELEMS(ext); i++)
300 LocalFree(ext[i].Value.pbData);
301
302 return 0;
303
304fail:
305 if (*crtctx)
306 CertFreeCertificateContext(*crtctx);
307 if (*key)
308 if (NCryptDeleteKey(*key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
309 NCryptFreeObject(*key);
310 if (provider)
311 NCryptFreeObject(provider);
312 if (subject.pbData)
313 av_free(subject.pbData);
314 for (int i = 0; i < FF_ARRAY_ELEMS(ext); i++)
315 if (ext[i].Value.pbData)
316 LocalFree(ext[i].Value.pbData);
317
318 *key = 0;
319 *crtctx = NULL;
320
321 return ret;
322}
323
324static int tls_export_key_cert(NCRYPT_KEY_HANDLE key, PCCERT_CONTEXT crtctx,
325 char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
326{
327 DWORD keysize = 0;
328 char *keybuf = NULL;
329
330 SECURITY_STATUS sspi_ret;
331 int ret = 0;
332
333 sspi_ret = NCryptExportKey(key, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL, NULL, 0, &keysize, 0);
334 if (sspi_ret != ERROR_SUCCESS) {
335 av_log(NULL, AV_LOG_ERROR, "Initial NCryptExportKey failed(0x%lx)\n", sspi_ret);
336 ret = AVERROR_EXTERNAL;
337 goto end;
338 }
339
340 keybuf = av_malloc(keysize);
341 if (!keybuf) {
342 ret = AVERROR(ENOMEM);
343 goto end;
344 }
345
346 sspi_ret = NCryptExportKey(key, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL, keybuf, keysize, &keysize, 0);
347 if (sspi_ret != ERROR_SUCCESS) {
348 av_log(NULL, AV_LOG_ERROR, "Initial NCryptExportKey failed(0x%lx)\n", sspi_ret);
349 ret = AVERROR_EXTERNAL;
350 goto end;
351 }
352
353 ret = der_to_pem(keybuf, keysize, "PRIVATE KEY", key_buf, key_sz);
354 if (ret < 0)
355 goto end;
356
357 ret = der_to_pem(crtctx->pbCertEncoded, crtctx->cbCertEncoded, "CERTIFICATE", cert_buf, cert_sz);
358 if (ret < 0)
359 goto end;
360
361 ret = der_to_fingerprint(crtctx->pbCertEncoded, crtctx->cbCertEncoded, fingerprint);
362 if (ret < 0)
363 goto end;
364
365end:
366 av_free(keybuf);
367 return ret;
368}
369
370int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
371{
372 NCRYPT_KEY_HANDLE key = 0;
373 PCCERT_CONTEXT crtctx = NULL;
374
375 int ret = tls_gen_self_signed(&key, &crtctx);
376 if (ret < 0)
377 goto end;
378
379 ret = tls_export_key_cert(key, crtctx, key_buf, key_sz, cert_buf, cert_sz, fingerprint);
380 if (ret < 0)
381 goto end;
382
383end:
384 if (key)
385 if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
386 NCryptFreeObject(key);
387 if (crtctx)
388 CertFreeCertificateContext(crtctx);
389
390 return ret;
391}
392
393static int tls_import_key_cert(char *key_buf, char *cert_buf, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
394{
395 NCRYPT_PROV_HANDLE provider = 0;
396
397 DWORD export_props = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
398 DWORD usage_props = NCRYPT_ALLOW_ALL_USAGES;
399 NCryptBufferDesc buffer_desc = { 0 };
400 NCryptBuffer buffer = { 0 };
401 CRYPT_KEY_PROV_INFO prov_info = { 0 };
402
403 int key_der_len = 0, cert_der_len = 0;
404 char *key_der = NULL, *cert_der = NULL;
405
406 SECURITY_STATUS sspi_ret;
407 int ret = 0;
408
409 ret = pem_to_der(key_buf, &key_der, &key_der_len);
410 if (ret < 0)
411 goto fail;
412
413 ret = pem_to_der(cert_buf, &cert_der, &cert_der_len);
414 if (ret < 0)
415 goto fail;
416
417 sspi_ret = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0);
418 if (sspi_ret != ERROR_SUCCESS) {
419 av_log(NULL, AV_LOG_ERROR, "NCryptOpenStorageProvider failed(0x%lx)\n", sspi_ret);
420 ret = AVERROR_EXTERNAL;
421 goto fail;
422 }
423
424 buffer_desc.ulVersion = NCRYPTBUFFER_VERSION;
425 buffer_desc.cBuffers = 1;
426 buffer_desc.pBuffers = &buffer;
427
428 buffer.BufferType = NCRYPTBUFFER_PKCS_KEY_NAME;
429 buffer.pvBuffer = (LPWSTR)FF_NCRYPT_TEMP_KEY_NAME;
430 buffer.cbBuffer = sizeof(FF_NCRYPT_TEMP_KEY_NAME);
431
432 sspi_ret = NCryptImportKey(provider, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, &buffer_desc, key, key_der, key_der_len, NCRYPT_DO_NOT_FINALIZE_FLAG | NCRYPT_OVERWRITE_KEY_FLAG);
433 if (sspi_ret != ERROR_SUCCESS) {
434 av_log(NULL, AV_LOG_ERROR, "NCryptImportKey failed(0x%lx)\n", sspi_ret);
435 ret = AVERROR_EXTERNAL;
436 goto fail;
437 }
438
439 sspi_ret = NCryptSetProperty(*key, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE)&export_props, sizeof(export_props), 0);
440 if (sspi_ret != ERROR_SUCCESS) {
441 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_EXPORT_POLICY_PROPERTY) failed(0x%lx)\n", sspi_ret);
442 ret = AVERROR_EXTERNAL;
443 goto fail;
444 }
445
446 sspi_ret = NCryptSetProperty(*key, NCRYPT_KEY_USAGE_PROPERTY, (PBYTE)&usage_props, sizeof(usage_props), 0);
447 if (sspi_ret != ERROR_SUCCESS) {
448 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_KEY_USAGE_PROPERTY) failed(0x%lx)\n", sspi_ret);
449 ret = AVERROR_EXTERNAL;
450 goto fail;
451 }
452
453 sspi_ret = NCryptFinalizeKey(*key, 0);
454 if (sspi_ret != ERROR_SUCCESS) {
455 av_log(NULL, AV_LOG_ERROR, "NCryptFinalizeKey failed(0x%lx)\n", sspi_ret);
456 ret = AVERROR_EXTERNAL;
457 goto fail;
458 }
459
460 *crtctx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert_der, cert_der_len);
461 if (!*crtctx) {
462 av_log(NULL, AV_LOG_ERROR, "CertCreateCertificateContext failed: %lu\n", GetLastError());
463 ret = AVERROR_EXTERNAL;
464 goto fail;
465 }
466
467 if (!CertSetCertificateContextProperty(*crtctx, CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, key)) {
468 av_log(NULL, AV_LOG_ERROR, "CertSetCertificateContextProperty(CERT_NCRYPT_KEY_HANDLE_PROP_ID) failed: %lu\n", GetLastError());
469 ret = AVERROR_EXTERNAL;
470 goto fail;
471 }
472
473 prov_info.pwszProvName = (LPWSTR)MS_KEY_STORAGE_PROVIDER;
474 prov_info.pwszContainerName = (LPWSTR)FF_NCRYPT_TEMP_KEY_NAME;
475 prov_info.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
476
477 if (!CertSetCertificateContextProperty(*crtctx, CERT_KEY_PROV_INFO_PROP_ID, 0, &prov_info)) {
478 av_log(NULL, AV_LOG_ERROR, "CertSetCertificateContextProperty(CERT_KEY_PROV_INFO_PROP_ID) failed: %lu\n", GetLastError());
479 ret = AVERROR_EXTERNAL;
480 goto fail;
481 }
482
483 goto end;
484
485fail:
486 if (*key)
487 if (NCryptDeleteKey(*key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
488 NCryptFreeObject(*key);
489 if (*crtctx)
490 CertFreeCertificateContext(*crtctx);
491
492 *key = 0;
493 *crtctx = NULL;
494
495end:
496 if (key_der)
497 av_free(key_der);
498 if (cert_der)
499 av_free(cert_der);
500 if (provider)
501 NCryptFreeObject(provider);
502 return ret;
503}
504
505static int tls_load_key_cert(char *key_url, char *cert_url, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
506{
507 AVBPrint key_bp, cert_bp;
508 int ret = 0;
509
510 av_bprint_init(&key_bp, 1, MAX_CERTIFICATE_SIZE);
511 av_bprint_init(&cert_bp, 1, MAX_CERTIFICATE_SIZE);
512
513 /* Read key file. */
514 ret = ff_url_read_all(key_url, &key_bp);
515 if (ret < 0) {
516 av_log(NULL, AV_LOG_ERROR, "Failed to open key file %s\n", key_url);
517 goto end;
518 }
519
520 ret = ff_url_read_all(cert_url, &cert_bp);
521 if (ret < 0) {
522 av_log(NULL, AV_LOG_ERROR, "Failed to open cert file %s\n", cert_url);
523 goto end;
524 }
525
526 ret = tls_import_key_cert(key_bp.str, cert_bp.str, key, crtctx);
527 if (ret < 0)
528 goto end;
529
530end:
531 av_bprint_finalize(&key_bp, NULL);
532 av_bprint_finalize(&cert_bp, NULL);
533
534 return ret;
535}
536
537int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
538{
539 NCRYPT_KEY_HANDLE key = 0;
540 PCCERT_CONTEXT crtctx = NULL;
541
542 int ret = tls_load_key_cert(key_url, cert_url, &key, &crtctx);
543 if (ret < 0)
544 goto end;
545
546 ret = tls_export_key_cert(key, crtctx, key_buf, key_sz, cert_buf, cert_sz, fingerprint);
547 if (ret < 0)
548 goto end;
549
550end:
551 if (key)
552 if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
553 NCryptFreeObject(key);
554 if (crtctx)
555 CertFreeCertificateContext(crtctx);
556
557 return ret;
558}
559
44typedef struct TLSContext {560typedef struct TLSContext {
45 const AVClass *class;561 const AVClass *class;
46 TLSShared tls_shared;562 TLSShared tls_shared;
@@ -49,6 +565,7 @@ typedef struct TLSContext { · 2 unmodified lines
49 TimeStamp cred_timestamp;565 TimeStamp cred_timestamp;
50 566
51 CtxtHandle ctxt_handle;567 CtxtHandle ctxt_handle;
568 int have_context;
52 TimeStamp ctxt_timestamp;569 TimeStamp ctxt_timestamp;
53 570
54 ULONG request_flags;571 ULONG request_flags;
@@ -69,6 +586,67 @@ typedef struct TLSContext { · 14 unmodified lines
69 int sspi_close_notify;586 int sspi_close_notify;
70} TLSContext;587} TLSContext;
71 588
589int ff_tls_set_external_socket(URLContext *h, URLContext *sock)
590{
591 TLSContext *c = h->priv_data;
592 TLSShared *s = &c->tls_shared;
593
594 if (s->is_dtls)
595 c->tls_shared.udp = sock;
596 else
597 c->tls_shared.tcp = sock;
598
599 return 0;
600}
601
602int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
603{
604 TLSContext *c = h->priv_data;
605
606 SecPkgContext_KeyingMaterialInfo keying_info = { 0 };
607 SecPkgContext_KeyingMaterial keying_material = { 0 };
608
609 const char* dst = "EXTRACTOR-dtls_srtp";
610 SECURITY_STATUS sspi_ret;
611
612 if (!c->have_context)
613 return AVERROR(EINVAL);
614
615 keying_info.cbLabel = strlen(dst) + 1;
616 keying_info.pszLabel = (LPSTR)dst;
617 keying_info.cbContextValue = 0;
618 keying_info.pbContextValue = NULL;
619 keying_info.cbKeyingMaterial = materials_sz;
620
621 sspi_ret = SetContextAttributes(&c->ctxt_handle, SECPKG_ATTR_KEYING_MATERIAL_INFO, &keying_info, sizeof(keying_info));
622 if (sspi_ret != SEC_E_OK) {
623 av_log(h, AV_LOG_ERROR, "Setting keying material info failed: %lx\n", sspi_ret);
624 return AVERROR_EXTERNAL;
625 }
626
627 sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_KEYING_MATERIAL, &keying_material);
628 if (sspi_ret != SEC_E_OK) {
629 av_log(h, AV_LOG_ERROR, "Querying keying material failed: %lx\n", sspi_ret);
630 return AVERROR_EXTERNAL;
631 }
632
633 memcpy(dtls_srtp_materials, keying_material.pbKeyingMaterial, FFMIN(materials_sz, keying_material.cbKeyingMaterial));
634 FreeContextBuffer(keying_material.pbKeyingMaterial);
635
636 if (keying_material.cbKeyingMaterial > materials_sz) {
637 av_log(h, AV_LOG_WARNING, "Keying material size mismatch: %ld > %zu\n", keying_material.cbKeyingMaterial, materials_sz);
638 return AVERROR(ENOSPC);
639 }
640
641 return 0;
642}
643
644int ff_dtls_state(URLContext *h)
645{
646 TLSContext *c = h->priv_data;
647 return c->tls_shared.state;
648}
649
72static void init_sec_buffer(SecBuffer *buffer, unsigned long type,650static void init_sec_buffer(SecBuffer *buffer, unsigned long type,
73 void *data, unsigned long size)651 void *data, unsigned long size)
74{652{
@@ -89,6 +667,7 @@ static int tls_shutdown_client(URLContext *h) · 14 unmodified lines
89{667{
90 TLSContext *c = h->priv_data;668 TLSContext *c = h->priv_data;
91 TLSShared *s = &c->tls_shared;669 TLSShared *s = &c->tls_shared;
670 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
92 int ret;671 int ret;
93 672
94 if (c->connected) {673 if (c->connected) {
@@ -106,19 +685,31 @@ static int tls_shutdown_client(URLContext *h) · 11 unmodified lines
106 if (sspi_ret != SEC_E_OK)685 if (sspi_ret != SEC_E_OK)
107 av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n");686 av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n");
108 687
109 init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);688 init_sec_buffer(&outbuf, SECBUFFER_TOKEN, NULL, 0);
110 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);689 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
111 690
112 sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,691 do {
113 c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,692 if (s->listen)
114 &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);693 sspi_ret = AcceptSecurityContext(&c->cred_handle, &c->ctxt_handle, NULL, c->request_flags, 0,
115 if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) {694 &c->ctxt_handle, &outbuf_desc, &c->context_flags,
116 s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;695 &c->ctxt_timestamp);
117 ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);696 else
118 FreeContextBuffer(outbuf.pvBuffer);697 sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,
119 if (ret < 0 || ret != outbuf.cbBuffer)698 c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,
120 av_log(h, AV_LOG_ERROR, "Failed to send close message\n");699 &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
121 }700
701 if (outbuf.pvBuffer) {
702 if (outbuf.cbBuffer > 0) {
703 uc->flags &= ~AVIO_FLAG_NONBLOCK;
704 ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
705 if (ret < 0 || ret != outbuf.cbBuffer)
706 av_log(h, AV_LOG_ERROR, "Failed to send close message\n");
707 }
708 FreeContextBuffer(outbuf.pvBuffer);
709 }
710 } while(sspi_ret == SEC_I_MESSAGE_FRAGMENT || sspi_ret == SEC_I_CONTINUE_NEEDED);
711
712 av_log(h, AV_LOG_DEBUG, "Close session result: 0x%lx\n", sspi_ret);
122 713
123 c->connected = 0;714 c->connected = 0;
124 }715 }
@@ -128,6 +719,7 @@ static int tls_shutdown_client(URLContext *h) · 3 unmodified lines
128static int tls_close(URLContext *h)719static int tls_close(URLContext *h)
129{720{
130 TLSContext *c = h->priv_data;721 TLSContext *c = h->priv_data;
722 TLSShared *s = &c->tls_shared;
131 723
132 tls_shutdown_client(h);724 tls_shutdown_client(h);
133 725
@@ -140,19 +732,28 @@ static int tls_close(URLContext *h) · 6 unmodified lines
140 av_freep(&c->dec_buf);732 av_freep(&c->dec_buf);
141 c->dec_buf_size = c->dec_buf_offset = 0;733 c->dec_buf_size = c->dec_buf_offset = 0;
142 734
143 ffurl_closep(&c->tls_shared.tcp);735 if (s->is_dtls) {
736 if (!s->external_sock)
737 ffurl_closep(&c->tls_shared.udp);
738 } else {
739 ffurl_closep(&c->tls_shared.tcp);
740 }
741
144 return 0;742 return 0;
145}743}
146 744
147static int tls_client_handshake_loop(URLContext *h, int initial)745static int tls_handshake_loop(URLContext *h, int initial)
148{746{
149 TLSContext *c = h->priv_data;747 TLSContext *c = h->priv_data;
150 TLSShared *s = &c->tls_shared;748 TLSShared *s = &c->tls_shared;
749 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
151 SECURITY_STATUS sspi_ret;750 SECURITY_STATUS sspi_ret;
152 SecBuffer outbuf[3] = { 0 };751 SecBuffer outbuf[3] = { 0 };
153 SecBufferDesc outbuf_desc;752 SecBufferDesc outbuf_desc;
154 SecBuffer inbuf[2];753 SecBuffer inbuf[3];
155 SecBufferDesc inbuf_desc;754 SecBufferDesc inbuf_desc;
755 struct sockaddr_storage recv_addr = { 0 };
756 socklen_t recv_addr_len = 0;
156 int i, ret = 0, read_data = initial;757 int i, ret = 0, read_data = initial;
157 758
158 if (c->enc_buf == NULL) {759 if (c->enc_buf == NULL) {
@@ -171,6 +772,8 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 12 unmodified lines
171 c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;772 c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
172 }773 }
173 774
775 uc->flags &= ~AVIO_FLAG_NONBLOCK;
776
174 while (1) {777 while (1) {
175 if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) {778 if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) {
176 c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;779 c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
@@ -182,19 +785,35 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 5 unmodified lines
182 }785 }
183 786
184 if (read_data) {787 if (read_data) {
185 ret = ffurl_read(c->tls_shared.tcp, c->enc_buf + c->enc_buf_offset,788 ret = ffurl_read(uc, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset);
186 c->enc_buf_size - c->enc_buf_offset);
187 if (ret < 0) {789 if (ret < 0) {
188 av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n");790 av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n");
189 goto fail;791 goto fail;
190 }792 }
191 c->enc_buf_offset += ret;793 c->enc_buf_offset += ret;
794 if (s->is_dtls && !recv_addr_len) {
795 ff_udp_get_last_recv_addr(uc, &recv_addr, &recv_addr_len);
796
797 if (s->listen) {
798 ret = ff_udp_set_remote_addr(uc, (struct sockaddr *)&recv_addr, recv_addr_len, 1);
799 if (ret < 0) {
800 av_log(h, AV_LOG_ERROR, "Failed connecting udp context\n");
801 goto fail;
802 }
803 av_log(h, AV_LOG_TRACE, "Set UDP remote addr on UDP socket, now 'connected'\n");
804 }
805 }
192 }806 }
193 807
194 /* input buffers */808 /* input buffers */
195 init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset);809 init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset);
196 init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);810 init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
197 init_sec_buffer_desc(&inbuf_desc, inbuf, 2);811 if (s->listen && s->is_dtls) {
812 init_sec_buffer(&inbuf[2], SECBUFFER_EXTRA, &recv_addr, recv_addr_len);
813 init_sec_buffer_desc(&inbuf_desc, inbuf, 3);
814 } else {
815 init_sec_buffer_desc(&inbuf_desc, inbuf, 2);
816 }
198 817
199 if (inbuf[0].pvBuffer == NULL) {818 if (inbuf[0].pvBuffer == NULL) {
200 av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n");819 av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n");
@@ -210,17 +829,26 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 9 unmodified lines
210 init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);829 init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
211 init_sec_buffer_desc(&outbuf_desc, outbuf, 3);830 init_sec_buffer_desc(&outbuf_desc, outbuf, 3);
212 831
213 sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags,832 if (s->listen)
214 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &c->context_flags,833 sspi_ret = AcceptSecurityContext(&c->cred_handle, c->have_context ? &c->ctxt_handle : NULL, &inbuf_desc,
215 &c->ctxt_timestamp);834 c->request_flags, 0, &c->ctxt_handle, &outbuf_desc,
835 &c->context_flags, &c->ctxt_timestamp);
836 else
837 sspi_ret = InitializeSecurityContext(&c->cred_handle, c->have_context ? &c->ctxt_handle : NULL,
838 s->host, c->request_flags, 0, 0, &inbuf_desc, 0, &c->ctxt_handle,
839 &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
216 av_freep(&inbuf[0].pvBuffer);840 av_freep(&inbuf[0].pvBuffer);
217 841
842 av_log(h, AV_LOG_TRACE, "Handshake res with %d bytes of data: 0x%lx\n", c->enc_buf_offset, sspi_ret);
843
218 if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {844 if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
219 av_log(h, AV_LOG_DEBUG, "Received incomplete handshake, need more data\n");845 av_log(h, AV_LOG_TRACE, "Received incomplete handshake, need more data\n");
220 read_data = 1;846 read_data = 1;
221 continue;847 continue;
222 }848 }
223 849
850 c->have_context = 1;
851
224 /* remote requests a client certificate - attempt to continue without one anyway */852 /* remote requests a client certificate - attempt to continue without one anyway */
225 if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS &&853 if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS &&
226 !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {854 !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
@@ -231,10 +859,10 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 4 unmodified lines
231 }859 }
232 860
233 /* continue handshake */861 /* continue handshake */
234 if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_E_OK) {862 if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_I_MESSAGE_FRAGMENT || sspi_ret == SEC_E_OK) {
235 for (i = 0; i < 3; i++) {863 for (i = 0; i < 3; i++) {
236 if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {864 if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
237 ret = ffurl_write(c->tls_shared.tcp, outbuf[i].pvBuffer, outbuf[i].cbBuffer);865 ret = ffurl_write(uc, outbuf[i].pvBuffer, outbuf[i].cbBuffer);
238 if (ret < 0 || ret != outbuf[i].cbBuffer) {866 if (ret < 0 || ret != outbuf[i].cbBuffer) {
239 av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n");867 av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n");
240 ret = AVERROR(EIO);868 ret = AVERROR(EIO);
@@ -256,12 +884,19 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 15 unmodified lines
256 goto fail;884 goto fail;
257 }885 }
258 886
887 if (sspi_ret == SEC_I_MESSAGE_FRAGMENT) {
888 av_log(h, AV_LOG_TRACE, "Writing fragmented output message part\n");
889 read_data = 0;
890 continue;
891 }
892
259 if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {893 if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
260 if (c->enc_buf_offset > inbuf[1].cbBuffer) {894 if (c->enc_buf_offset > inbuf[1].cbBuffer) {
261 memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer,895 memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer,
262 inbuf[1].cbBuffer);896 inbuf[1].cbBuffer);
263 c->enc_buf_offset = inbuf[1].cbBuffer;897 c->enc_buf_offset = inbuf[1].cbBuffer;
264 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {898 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
899 av_log(h, AV_LOG_TRACE, "Sent reply, handshake continues. %d extra bytes\n", (int)inbuf[1].cbBuffer);
265 read_data = 0;900 read_data = 0;
266 continue;901 continue;
267 }902 }
@@ -271,6 +906,7 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 3 unmodified lines
271 }906 }
272 907
273 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {908 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
909 av_log(h, AV_LOG_TRACE, "Handshake continues\n");
274 read_data = 1;910 read_data = 1;
275 continue;911 continue;
276 }912 }
@@ -278,6 +914,8 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 1 unmodified line
278 break;914 break;
279 }915 }
280 916
917 av_log(h, AV_LOG_TRACE, "Handshake completed\n");
918
281 return 0;919 return 0;
282 920
283fail:921fail:
@@ -289,6 +927,8 @@ fail: · 5 unmodified lines
289 }927 }
290 }928 }
291 929
930 av_log(h, AV_LOG_TRACE, "Handshake failed\n");
931
292 return ret;932 return ret;
293}933}
294 934
@@ -296,6 +936,7 @@ static int tls_client_handshake(URLContext *h) · 1 unmodified line
296{936{
297 TLSContext *c = h->priv_data;937 TLSContext *c = h->priv_data;
298 TLSShared *s = &c->tls_shared;938 TLSShared *s = &c->tls_shared;
939 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
299 SecBuffer outbuf;940 SecBuffer outbuf;
300 SecBufferDesc outbuf_desc;941 SecBufferDesc outbuf_desc;
301 SECURITY_STATUS sspi_ret;942 SECURITY_STATUS sspi_ret;
@@ -305,8 +946,11 @@ static int tls_client_handshake(URLContext *h) · 3 unmodified lines
305 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);946 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
306 947
307 c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |948 c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
308 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |949 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY;
309 ISC_REQ_STREAM;950 if (s->is_dtls)
951 c->request_flags |= ISC_REQ_DATAGRAM;
952 else
953 c->request_flags |= ISC_REQ_STREAM;
310 954
311 sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0,955 sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0,
312 NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags,956 NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags,
@@ -317,8 +961,10 @@ static int tls_client_handshake(URLContext *h) · 4 unmodified lines
317 goto fail;961 goto fail;
318 }962 }
319 963
320 s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;964 c->have_context = 1;
321 ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);965
966 uc->flags &= ~AVIO_FLAG_NONBLOCK;
967 ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
322 FreeContextBuffer(outbuf.pvBuffer);968 FreeContextBuffer(outbuf.pvBuffer);
323 if (ret < 0 || ret != outbuf.cbBuffer) {969 if (ret < 0 || ret != outbuf.cbBuffer) {
324 av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n");970 av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n");
@@ -326,44 +972,121 @@ static int tls_client_handshake(URLContext *h) · 1 unmodified line
326 goto fail;972 goto fail;
327 }973 }
328 974
329 return tls_client_handshake_loop(h, 1);975 return tls_handshake_loop(h, 1);
330 976
331fail:977fail:
332 DeleteSecurityContext(&c->ctxt_handle);978 DeleteSecurityContext(&c->ctxt_handle);
333 return ret;979 return ret;
334}980}
335 981
336static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)982static int tls_server_handshake(URLContext *h)
983{
984 TLSContext *c = h->priv_data;
985 TLSShared *s = &c->tls_shared;
986
987 c->request_flags = ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT |
988 ASC_REQ_CONFIDENTIALITY | ASC_REQ_ALLOCATE_MEMORY;
989 if (s->is_dtls)
990 c->request_flags |= ASC_REQ_DATAGRAM;
991 else
992 c->request_flags |= ASC_REQ_STREAM;
993
994 c->have_context = 0;
995
996 return tls_handshake_loop(h, 1);
997}
998
999static int tls_handshake(URLContext *h)
337{1000{
338 TLSContext *c = h->priv_data;1001 TLSContext *c = h->priv_data;
339 TLSShared *s = &c->tls_shared;1002 TLSShared *s = &c->tls_shared;
340 SECURITY_STATUS sspi_ret;1003 SECURITY_STATUS sspi_ret;
341 SCHANNEL_CRED schannel_cred = { 0 };1004 int ret = 0;
342 int ret;
343 1005
344 if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)1006 if (s->listen)
345 goto fail;1007 ret = tls_server_handshake(h);
1008 else
1009 ret = tls_client_handshake(h);
346 1010
347 if (s->listen) {1011 if (ret < 0)
348 av_log(h, AV_LOG_ERROR, "TLS Listen Sockets with SChannel is not implemented.\n");
349 ret = AVERROR(EINVAL);
350 goto fail;1012 goto fail;
1013
1014 if (s->is_dtls && s->mtu > 0) {
1015 ULONG mtu = s->mtu;
1016 sspi_ret = SetContextAttributes(&c->ctxt_handle, SECPKG_ATTR_DTLS_MTU, &mtu, sizeof(mtu));
1017 if (sspi_ret != SEC_E_OK) {
1018 av_log(h, AV_LOG_ERROR, "Failed setting DTLS MTU to %d.\n", s->mtu);
1019 ret = AVERROR(EINVAL);
1020 goto fail;
1021 }
1022 av_log(h, AV_LOG_VERBOSE, "Set DTLS MTU to %d\n", s->mtu);
1023 }
1024
1025 c->connected = 1;
1026 s->state = DTLS_STATE_FINISHED;
1027
1028fail:
1029 return ret;
1030}
1031
1032static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
1033{
1034 TLSContext *c = h->priv_data;
1035 TLSShared *s = &c->tls_shared;
1036 SECURITY_STATUS sspi_ret;
1037 SCHANNEL_CRED schannel_cred = { 0 };
1038 PCCERT_CONTEXT crtctx = NULL;
1039 NCRYPT_KEY_HANDLE key = 0;
1040 int ret = 0;
1041
1042 if (!s->external_sock) {
1043 if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
1044 goto fail;
351 }1045 }
352 1046
353 /* SChannel Options */1047 /* SChannel Options */
354 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;1048 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
355 1049
356 if (s->verify)1050 if (s->listen) {
357 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |1051 if (s->key_buf && s->cert_buf) {
358 SCH_CRED_REVOCATION_CHECK_CHAIN;1052 ret = tls_import_key_cert(s->key_buf, s->cert_buf, &key, &crtctx);
359 else1053 if (ret < 0)
360 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |1054 goto fail;
361 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |1055 } else if (s->key_file && s->cert_file) {
362 SCH_CRED_IGNORE_REVOCATION_OFFLINE;1056 ret = tls_load_key_cert(s->key_file, s->cert_file, &key, &crtctx);
1057 if (ret < 0)
1058 goto fail;
1059 } else {
1060 av_log(h, AV_LOG_VERBOSE, "No server certificate provided, using self-signed\n");
1061 ret = tls_gen_self_signed(&key, &crtctx);
1062 if (ret < 0)
1063 goto fail;
1064 }
1065
1066 schannel_cred.cCreds = 1;
1067 schannel_cred.paCred = &crtctx;
1068
1069 schannel_cred.dwFlags = SCH_CRED_NO_SYSTEM_MAPPER | SCH_CRED_MANUAL_CRED_VALIDATION;
1070
1071 if (s->is_dtls)
1072 schannel_cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_SERVER;
1073 } else {
1074 if (s->verify)
1075 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
1076 SCH_CRED_REVOCATION_CHECK_CHAIN;
1077 else
1078 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
1079 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
1080 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
1081
1082 if (s->is_dtls)
1083 schannel_cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_CLIENT;
1084 }
363 1085
364 /* Get credential handle */1086 /* Get credential handle */
365 sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND,1087 sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
366 NULL, &schannel_cred, NULL, NULL, &c->cred_handle,1088 s->listen ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
1089 NULL, &schannel_cred, NULL, NULL, &c->cred_handle,
367 &c->cred_timestamp);1090 &c->cred_timestamp);
368 if (sspi_ret != SEC_E_OK) {1091 if (sspi_ret != SEC_E_OK) {
369 av_log(h, AV_LOG_ERROR, "Unable to acquire security credentials (0x%lx)\n", sspi_ret);1092 av_log(h, AV_LOG_ERROR, "Unable to acquire security credentials (0x%lx)\n", sspi_ret);
@@ -371,23 +1094,42 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op · 1 unmodified line
371 goto fail;1094 goto fail;
372 }1095 }
373 1096
374 ret = tls_client_handshake(h);1097 if (!s->external_sock) {
375 if (ret < 0)1098 ret = tls_handshake(h);
376 goto fail;1099 if (ret < 0)
377 1100 goto fail;
378 c->connected = 1;1101 }
379 1102
380 return 0;1103 goto end;
381 1104
382fail:1105fail:
383 tls_close(h);1106 tls_close(h);
1107
1108end:
1109 if (crtctx)
1110 CertFreeCertificateContext(crtctx);
1111 if (key)
1112 if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
1113 NCryptFreeObject(key);
1114
384 return ret;1115 return ret;
385}1116}
386 1117
1118static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
1119{
1120 TLSContext *c = h->priv_data;
1121 TLSShared *s = &c->tls_shared;
1122
1123 s->is_dtls = 1;
1124
1125 return tls_open(h, uri, flags, options);
1126}
1127
387static int tls_read(URLContext *h, uint8_t *buf, int len)1128static int tls_read(URLContext *h, uint8_t *buf, int len)
388{1129{
389 TLSContext *c = h->priv_data;1130 TLSContext *c = h->priv_data;
390 TLSShared *s = &c->tls_shared;1131 TLSShared *s = &c->tls_shared;
1132 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
391 SECURITY_STATUS sspi_ret = SEC_E_OK;1133 SECURITY_STATUS sspi_ret = SEC_E_OK;
392 SecBuffer inbuf[4];1134 SecBuffer inbuf[4];
393 SecBufferDesc inbuf_desc;1135 SecBufferDesc inbuf_desc;
@@ -418,10 +1160,10 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) · 24 unmodified lines
418 }1160 }
419 }1161 }
420 1162
421 s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;1163 uc->flags &= ~AVIO_FLAG_NONBLOCK;
422 s->tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK;1164 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
423 1165
424 ret = ffurl_read(s->tcp, c->enc_buf + c->enc_buf_offset,1166 ret = ffurl_read(uc, c->enc_buf + c->enc_buf_offset,
425 c->enc_buf_size - c->enc_buf_offset);1167 c->enc_buf_size - c->enc_buf_offset);
426 if (ret == AVERROR_EOF) {1168 if (ret == AVERROR_EOF) {
427 c->connection_closed = 1;1169 c->connection_closed = 1;
@@ -489,7 +1231,7 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) · 61 unmodified lines
489 }1231 }
490 1232
491 av_log(h, AV_LOG_VERBOSE, "Re-negotiating security context\n");1233 av_log(h, AV_LOG_VERBOSE, "Re-negotiating security context\n");
492 ret = tls_client_handshake_loop(h, 0);1234 ret = tls_handshake_loop(h, 0);
493 if (ret < 0) {1235 if (ret < 0) {
494 goto cleanup;1236 goto cleanup;
495 }1237 }
@@ -536,6 +1278,7 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 40 unmodified lines
536{1278{
537 TLSContext *c = h->priv_data;1279 TLSContext *c = h->priv_data;
538 TLSShared *s = &c->tls_shared;1280 TLSShared *s = &c->tls_shared;
1281 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
539 SECURITY_STATUS sspi_ret;1282 SECURITY_STATUS sspi_ret;
540 int ret = 0, data_size;1283 int ret = 0, data_size;
541 uint8_t *data = NULL;1284 uint8_t *data = NULL;
@@ -549,7 +1292,7 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 7 unmodified lines
549 }1292 }
550 1293
551 /* limit how much data we can consume */1294 /* limit how much data we can consume */
552 len = FFMIN(len, c->sizes.cbMaximumMessage);1295 len = FFMIN(len, c->sizes.cbMaximumMessage - c->sizes.cbHeader - c->sizes.cbTrailer);
553 1296
554 data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer;1297 data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer;
555 data = av_malloc(data_size);1298 data = av_malloc(data_size);
@@ -572,10 +1315,10 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 16 unmodified lines
572 if (sspi_ret == SEC_E_OK) {1315 if (sspi_ret == SEC_E_OK) {
573 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;1316 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
574 1317
575 s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;1318 uc->flags &= ~AVIO_FLAG_NONBLOCK;
576 s->tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK;1319 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
577 1320
578 ret = ffurl_write(s->tcp, data, len);1321 ret = ffurl_write(uc, data, len);
579 if (ret == AVERROR(EAGAIN)) {1322 if (ret == AVERROR(EAGAIN)) {
580 goto done;1323 goto done;
581 } else if (ret < 0 || ret != len) {1324 } else if (ret < 0 || ret != len) {
@@ -600,13 +1343,15 @@ done: · 18 unmodified lines
600static int tls_get_file_handle(URLContext *h)1343static int tls_get_file_handle(URLContext *h)
601{1344{
602 TLSContext *c = h->priv_data;1345 TLSContext *c = h->priv_data;
603 return ffurl_get_file_handle(c->tls_shared.tcp);1346 TLSShared *s = &c->tls_shared;
1347 return ffurl_get_file_handle(s->is_dtls ? s->udp : s->tcp);
604}1348}
605 1349
606static int tls_get_short_seek(URLContext *h)1350static int tls_get_short_seek(URLContext *h)
607{1351{
608 TLSContext *s = h->priv_data;1352 TLSContext *c = h->priv_data;
609 return ffurl_get_short_seek(s->tls_shared.tcp);1353 TLSShared *s = &c->tls_shared;
1354 return ffurl_get_short_seek(s->is_dtls ? s->udp : s->tcp);
610}1355}
611 1356
612static const AVOption options[] = {1357static const AVOption options[] = {
@@ -633,3 +1378,24 @@ const URLProtocol ff_tls_protocol = { · 20 unmodified lines
633 .flags = URL_PROTOCOL_FLAG_NETWORK,1378 .flags = URL_PROTOCOL_FLAG_NETWORK,
634 .priv_data_class = &tls_class,1379 .priv_data_class = &tls_class,
635};1380};
1381
1382static const AVClass dtls_class = {
1383 .class_name = "dtls",
1384 .item_name = av_default_item_name,
1385 .option = options,
1386 .version = LIBAVUTIL_VERSION_INT,
1387};
1388
1389const URLProtocol ff_dtls_protocol = {
1390 .name = "dtls",
1391 .url_open2 = dtls_open,
1392 .url_handshake = tls_handshake,
1393 .url_close = tls_close,
1394 .url_read = tls_read,
1395 .url_write = tls_write,
1396 .url_get_file_handle = tls_get_file_handle,
1397 .url_get_short_seek = tls_get_short_seek,
1398 .priv_data_size = sizeof(TLSContext),
1399 .flags = URL_PROTOCOL_FLAG_NETWORK,
1400 .priv_data_class = &dtls_class,
1401};
libavformat/version.h+1−1
@@ -32,7 +32,7 @@ · 31 unmodified lines
32#include "version_major.h"32#include "version_major.h"
33 33
34#define LIBAVFORMAT_VERSION_MINOR 134#define LIBAVFORMAT_VERSION_MINOR 1
35#define LIBAVFORMAT_VERSION_MICRO 10235#define LIBAVFORMAT_VERSION_MICRO 103
36 36
37#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \37#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
38 LIBAVFORMAT_VERSION_MINOR, \38 LIBAVFORMAT_VERSION_MINOR, \

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