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
38563856 tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls"
38573857 tls_protocol_select="tcp_protocol"
38583858 # TODO: Support libtls, mbedtls, and gnutls.
3859−dtls_protocol_deps_any="openssl"
3859+dtls_protocol_deps_any="openssl schannel"
38603860 dtls_protocol_select="udp_protocol"
38613861 udp_protocol_select="network"
38623862 udplite_protocol_select="network"
@@ -7265,8 +7265,10 @@ enabled securetransport && · 3402 unmodified lines
72657265
72667266 enabled schannel &&
72677267 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 &&
72687270 test_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" &&
7269− schannel_extralibs="-lsecur32" ||
7271+ schannel_extralibs="-lsecur32 -lncrypt -lcrypt32" ||
72707272 disable schannel
72717273
72727274 makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo
libavformat/tls_schannel.c+828−62
@@ -32,6 +32,7 @@ · 31 unmodified lines
3232 #include <windows.h>
3333 #include <security.h>
3434 #include <schnlsp.h>
35+#include <sddl.h>
3536
3637 #define SCHANNEL_INITIAL_BUFFER_SIZE 4096
3738 #define SCHANNEL_FREE_BUFFER_SIZE 1024
@@ -41,6 +42,521 @@ · 3 unmodified lines
4142 #define SECBUFFER_ALERT 17
4243 #endif
4344
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+
60+static 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+
96+end:
97+ av_free(base64);
98+ return ret;
99+}
100+
101+static 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+
124+static 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+
145+static 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+
304+fail:
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+
324+static 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+
365+end:
366+ av_free(keybuf);
367+ return ret;
368+}
369+
370+int 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+
383+end:
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+
393+static 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+
485+fail:
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+
495+end:
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+
505+static 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+
530+end:
531+ av_bprint_finalize(&key_bp, NULL);
532+ av_bprint_finalize(&cert_bp, NULL);
533+
534+ return ret;
535+}
536+
537+int 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+
550+end:
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+
44560 typedef struct TLSContext {
45561 const AVClass *class;
46562 TLSShared tls_shared;
@@ -49,6 +565,7 @@ typedef struct TLSContext { · 2 unmodified lines
49565 TimeStamp cred_timestamp;
50566
51567 CtxtHandle ctxt_handle;
568+ int have_context;
52569 TimeStamp ctxt_timestamp;
53570
54571 ULONG request_flags;
@@ -69,6 +586,67 @@ typedef struct TLSContext { · 14 unmodified lines
69586 int sspi_close_notify;
70587 } TLSContext;
71588
589+int 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+
602+int 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+
644+int ff_dtls_state(URLContext *h)
645+{
646+ TLSContext *c = h->priv_data;
647+ return c->tls_shared.state;
648+}
649+
72650 static void init_sec_buffer(SecBuffer *buffer, unsigned long type,
73651 void *data, unsigned long size)
74652 {
@@ -89,6 +667,7 @@ static int tls_shutdown_client(URLContext *h) · 14 unmodified lines
89667 {
90668 TLSContext *c = h->priv_data;
91669 TLSShared *s = &c->tls_shared;
670+ URLContext *uc = s->is_dtls ? s->udp : s->tcp;
92671 int ret;
93672
94673 if (c->connected) {
@@ -106,19 +685,31 @@ static int tls_shutdown_client(URLContext *h) · 11 unmodified lines
106685 if (sspi_ret != SEC_E_OK)
107686 av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n");
108687
109− init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
688+ init_sec_buffer(&outbuf, SECBUFFER_TOKEN, NULL, 0);
110689 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
111690
112− sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,
113− c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,
114− &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
115− if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) {
116− s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;
117− ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);
118− FreeContextBuffer(outbuf.pvBuffer);
119− if (ret < 0 || ret != outbuf.cbBuffer)
120− av_log(h, AV_LOG_ERROR, "Failed to send close message\n");
121− }
691+ do {
692+ if (s->listen)
693+ sspi_ret = AcceptSecurityContext(&c->cred_handle, &c->ctxt_handle, NULL, c->request_flags, 0,
694+ &c->ctxt_handle, &outbuf_desc, &c->context_flags,
695+ &c->ctxt_timestamp);
696+ else
697+ sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,
698+ c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,
699+ &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
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);
122713
123714 c->connected = 0;
124715 }
@@ -128,6 +719,7 @@ static int tls_shutdown_client(URLContext *h) · 3 unmodified lines
128719 static int tls_close(URLContext *h)
129720 {
130721 TLSContext *c = h->priv_data;
722+ TLSShared *s = &c->tls_shared;
131723
132724 tls_shutdown_client(h);
133725
@@ -140,19 +732,28 @@ static int tls_close(URLContext *h) · 6 unmodified lines
140732 av_freep(&c->dec_buf);
141733 c->dec_buf_size = c->dec_buf_offset = 0;
142734
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+
144742 return 0;
145743 }
146744
147−static int tls_client_handshake_loop(URLContext *h, int initial)
745+static int tls_handshake_loop(URLContext *h, int initial)
148746 {
149747 TLSContext *c = h->priv_data;
150748 TLSShared *s = &c->tls_shared;
749+ URLContext *uc = s->is_dtls ? s->udp : s->tcp;
151750 SECURITY_STATUS sspi_ret;
152751 SecBuffer outbuf[3] = { 0 };
153752 SecBufferDesc outbuf_desc;
154− SecBuffer inbuf[2];
753+ SecBuffer inbuf[3];
155754 SecBufferDesc inbuf_desc;
755+ struct sockaddr_storage recv_addr = { 0 };
756+ socklen_t recv_addr_len = 0;
156757 int i, ret = 0, read_data = initial;
157758
158759 if (c->enc_buf == NULL) {
@@ -171,6 +772,8 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 12 unmodified lines
171772 c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
172773 }
173774
775+ uc->flags &= ~AVIO_FLAG_NONBLOCK;
776+
174777 while (1) {
175778 if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) {
176779 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
182785 }
183786
184787 if (read_data) {
185− ret = ffurl_read(c->tls_shared.tcp, c->enc_buf + c->enc_buf_offset,
186− c->enc_buf_size - c->enc_buf_offset);
788+ ret = ffurl_read(uc, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset);
187789 if (ret < 0) {
188790 av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n");
189791 goto fail;
190792 }
191793 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+ }
192806 }
193807
194808 /* input buffers */
195809 init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset);
196810 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+ }
198817
199818 if (inbuf[0].pvBuffer == NULL) {
200819 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
210829 init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
211830 init_sec_buffer_desc(&outbuf_desc, outbuf, 3);
212831
213− sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags,
214− 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &c->context_flags,
215− &c->ctxt_timestamp);
832+ if (s->listen)
833+ sspi_ret = AcceptSecurityContext(&c->cred_handle, c->have_context ? &c->ctxt_handle : NULL, &inbuf_desc,
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);
216840 av_freep(&inbuf[0].pvBuffer);
217841
842+ av_log(h, AV_LOG_TRACE, "Handshake res with %d bytes of data: 0x%lx\n", c->enc_buf_offset, sspi_ret);
843+
218844 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");
220846 read_data = 1;
221847 continue;
222848 }
223849
850+ c->have_context = 1;
851+
224852 /* remote requests a client certificate - attempt to continue without one anyway */
225853 if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS &&
226854 !(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
231859 }
232860
233861 /* 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) {
235863 for (i = 0; i < 3; i++) {
236864 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);
238866 if (ret < 0 || ret != outbuf[i].cbBuffer) {
239867 av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n");
240868 ret = AVERROR(EIO);
@@ -256,12 +884,19 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 15 unmodified lines
256884 goto fail;
257885 }
258886
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+
259893 if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
260894 if (c->enc_buf_offset > inbuf[1].cbBuffer) {
261895 memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer,
262896 inbuf[1].cbBuffer);
263897 c->enc_buf_offset = inbuf[1].cbBuffer;
264898 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);
265900 read_data = 0;
266901 continue;
267902 }
@@ -271,6 +906,7 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 3 unmodified lines
271906 }
272907
273908 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
909+ av_log(h, AV_LOG_TRACE, "Handshake continues\n");
274910 read_data = 1;
275911 continue;
276912 }
@@ -278,6 +914,8 @@ static int tls_client_handshake_loop(URLContext *h, int initial) · 1 unmodified line
278914 break;
279915 }
280916
917+ av_log(h, AV_LOG_TRACE, "Handshake completed\n");
918+
281919 return 0;
282920
283921 fail:
@@ -289,6 +927,8 @@ fail: · 5 unmodified lines
289927 }
290928 }
291929
930+ av_log(h, AV_LOG_TRACE, "Handshake failed\n");
931+
292932 return ret;
293933 }
294934
@@ -296,6 +936,7 @@ static int tls_client_handshake(URLContext *h) · 1 unmodified line
296936 {
297937 TLSContext *c = h->priv_data;
298938 TLSShared *s = &c->tls_shared;
939+ URLContext *uc = s->is_dtls ? s->udp : s->tcp;
299940 SecBuffer outbuf;
300941 SecBufferDesc outbuf_desc;
301942 SECURITY_STATUS sspi_ret;
@@ -305,8 +946,11 @@ static int tls_client_handshake(URLContext *h) · 3 unmodified lines
305946 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
306947
307948 c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
308− ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
309− ISC_REQ_STREAM;
949+ ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY;
950+ if (s->is_dtls)
951+ c->request_flags |= ISC_REQ_DATAGRAM;
952+ else
953+ c->request_flags |= ISC_REQ_STREAM;
310954
311955 sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0,
312956 NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags,
@@ -317,8 +961,10 @@ static int tls_client_handshake(URLContext *h) · 4 unmodified lines
317961 goto fail;
318962 }
319963
320− s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;
321− ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);
964+ c->have_context = 1;
965+
966+ uc->flags &= ~AVIO_FLAG_NONBLOCK;
967+ ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
322968 FreeContextBuffer(outbuf.pvBuffer);
323969 if (ret < 0 || ret != outbuf.cbBuffer) {
324970 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
326972 goto fail;
327973 }
328974
329− return tls_client_handshake_loop(h, 1);
975+ return tls_handshake_loop(h, 1);
330976
331977 fail:
332978 DeleteSecurityContext(&c->ctxt_handle);
333979 return ret;
334980 }
335981
336−static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
982+static 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+
999+static int tls_handshake(URLContext *h)
3371000 {
3381001 TLSContext *c = h->priv_data;
3391002 TLSShared *s = &c->tls_shared;
3401003 SECURITY_STATUS sspi_ret;
341− SCHANNEL_CRED schannel_cred = { 0 };
342− int ret;
1004+ int ret = 0;
3431005
344− if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
345− goto fail;
1006+ if (s->listen)
1007+ ret = tls_server_handshake(h);
1008+ else
1009+ ret = tls_client_handshake(h);
3461010
347− if (s->listen) {
348− av_log(h, AV_LOG_ERROR, "TLS Listen Sockets with SChannel is not implemented.\n");
349− ret = AVERROR(EINVAL);
1011+ if (ret < 0)
3501012 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+
1028+fail:
1029+ return ret;
1030+}
1031+
1032+static 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;
3511045 }
3521046
3531047 /* SChannel Options */
3541048 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
3551049
356− if (s->verify)
357− schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
358− SCH_CRED_REVOCATION_CHECK_CHAIN;
359− else
360− schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
361− SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
362− SCH_CRED_IGNORE_REVOCATION_OFFLINE;
1050+ if (s->listen) {
1051+ if (s->key_buf && s->cert_buf) {
1052+ ret = tls_import_key_cert(s->key_buf, s->cert_buf, &key, &crtctx);
1053+ if (ret < 0)
1054+ goto fail;
1055+ } else if (s->key_file && s->cert_file) {
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+ }
3631085
3641086 /* Get credential handle */
365− sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND,
366− NULL, &schannel_cred, NULL, NULL, &c->cred_handle,
1087+ sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
1088+ s->listen ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
1089+ NULL, &schannel_cred, NULL, NULL, &c->cred_handle,
3671090 &c->cred_timestamp);
3681091 if (sspi_ret != SEC_E_OK) {
3691092 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
3711094 goto fail;
3721095 }
3731096
374− ret = tls_client_handshake(h);
375− if (ret < 0)
376− goto fail;
377−
378− c->connected = 1;
1097+ if (!s->external_sock) {
1098+ ret = tls_handshake(h);
1099+ if (ret < 0)
1100+ goto fail;
1101+ }
3791102
380− return 0;
1103+ goto end;
3811104
3821105 fail:
3831106 tls_close(h);
1107+
1108+end:
1109+ if (crtctx)
1110+ CertFreeCertificateContext(crtctx);
1111+ if (key)
1112+ if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
1113+ NCryptFreeObject(key);
1114+
3841115 return ret;
3851116 }
3861117
1118+static 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+
3871128 static int tls_read(URLContext *h, uint8_t *buf, int len)
3881129 {
3891130 TLSContext *c = h->priv_data;
3901131 TLSShared *s = &c->tls_shared;
1132+ URLContext *uc = s->is_dtls ? s->udp : s->tcp;
3911133 SECURITY_STATUS sspi_ret = SEC_E_OK;
3921134 SecBuffer inbuf[4];
3931135 SecBufferDesc inbuf_desc;
@@ -418,10 +1160,10 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) · 24 unmodified lines
4181160 }
4191161 }
4201162
421− s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;
422− s->tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1163+ uc->flags &= ~AVIO_FLAG_NONBLOCK;
1164+ uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
4231165
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,
4251167 c->enc_buf_size - c->enc_buf_offset);
4261168 if (ret == AVERROR_EOF) {
4271169 c->connection_closed = 1;
@@ -489,7 +1231,7 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) · 61 unmodified lines
4891231 }
4901232
4911233 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);
4931235 if (ret < 0) {
4941236 goto cleanup;
4951237 }
@@ -536,6 +1278,7 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 40 unmodified lines
5361278 {
5371279 TLSContext *c = h->priv_data;
5381280 TLSShared *s = &c->tls_shared;
1281+ URLContext *uc = s->is_dtls ? s->udp : s->tcp;
5391282 SECURITY_STATUS sspi_ret;
5401283 int ret = 0, data_size;
5411284 uint8_t *data = NULL;
@@ -549,7 +1292,7 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 7 unmodified lines
5491292 }
5501293
5511294 /* 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);
5531296
5541297 data_size = c->sizes.cbHeader + len + c->sizes.cbTrailer;
5551298 data = av_malloc(data_size);
@@ -572,10 +1315,10 @@ static int tls_write(URLContext *h, const uint8_t *buf, int len) · 16 unmodified lines
5721315 if (sspi_ret == SEC_E_OK) {
5731316 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
5741317
575− s->tcp->flags &= ~AVIO_FLAG_NONBLOCK;
576− s->tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1318+ uc->flags &= ~AVIO_FLAG_NONBLOCK;
1319+ uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
5771320
578− ret = ffurl_write(s->tcp, data, len);
1321+ ret = ffurl_write(uc, data, len);
5791322 if (ret == AVERROR(EAGAIN)) {
5801323 goto done;
5811324 } else if (ret < 0 || ret != len) {
@@ -600,13 +1343,15 @@ done: · 18 unmodified lines
6001343 static int tls_get_file_handle(URLContext *h)
6011344 {
6021345 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);
6041348 }
6051349
6061350 static int tls_get_short_seek(URLContext *h)
6071351 {
608− TLSContext *s = h->priv_data;
609− return ffurl_get_short_seek(s->tls_shared.tcp);
1352+ TLSContext *c = h->priv_data;
1353+ TLSShared *s = &c->tls_shared;
1354+ return ffurl_get_short_seek(s->is_dtls ? s->udp : s->tcp);
6101355 }
6111356
6121357 static const AVOption options[] = {
@@ -633,3 +1378,24 @@ const URLProtocol ff_tls_protocol = { · 20 unmodified lines
6331378 .flags = URL_PROTOCOL_FLAG_NETWORK,
6341379 .priv_data_class = &tls_class,
6351380 };
1381+
1382+static 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+
1389+const 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
3232 #include "version_major.h"
3333
3434 #define LIBAVFORMAT_VERSION_MINOR 1
35−#define LIBAVFORMAT_VERSION_MICRO 102
35+#define LIBAVFORMAT_VERSION_MICRO 103
3636
3737 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
3838 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