FFmpeg
tls_schannel.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Hendrik Leppkes
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /** Based on the CURL SChannel module */
22 
23 #include "libavutil/mem.h"
24 #include "avformat.h"
25 #include "internal.h"
26 #include "network.h"
27 #include "os_support.h"
28 #include "url.h"
29 #include "tls.h"
30 
31 #define SECURITY_WIN32
32 #include <windows.h>
33 #include <security.h>
34 #include <schnlsp.h>
35 #include <sddl.h>
36 
37 #define SCHANNEL_INITIAL_BUFFER_SIZE 4096
38 #define SCHANNEL_FREE_BUFFER_SIZE 1024
39 
40 /* mingw does not define this symbol */
41 #ifndef SECBUFFER_ALERT
42 #define SECBUFFER_ALERT 17
43 #endif
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 
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");
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");
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);
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);
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);
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);
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);
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");
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");
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");
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");
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");
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");
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());
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);
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);
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);
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);
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);
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);
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);
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());
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());
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());
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_cert_from_store(void *logctx, const char *cert_store_name, const char *cert_subj, PCCERT_CONTEXT *crtctx)
506 {
507  HCERTSTORE cert_store = NULL;
508  int ret = 0;
509 
510  cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, cert_store_name);
511  if (!cert_store) {
512  av_log(logctx, AV_LOG_ERROR, "Opening user cert store %s failed\n", cert_store_name);
514  goto end;
515  }
516 
517  *crtctx = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_A, cert_subj, NULL);
518  if (!*crtctx) {
519  av_log(logctx, AV_LOG_ERROR, "Could not find certificate in store\n");
521  goto end;
522  }
523 
524 end:
525  if (cert_store)
526  CertCloseStore(cert_store, 0);
527 
528  return ret;
529 }
530 
531 static int tls_load_key_cert(char *key_url, char *cert_url, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
532 {
533  AVBPrint key_bp, cert_bp;
534  int ret = 0;
535 
537  av_bprint_init(&cert_bp, 1, MAX_CERTIFICATE_SIZE);
538 
539  /* Read key file. */
540  ret = ff_url_read_all(key_url, &key_bp);
541  if (ret < 0) {
542  av_log(NULL, AV_LOG_ERROR, "Failed to open key file %s\n", key_url);
543  goto end;
544  }
545 
546  ret = ff_url_read_all(cert_url, &cert_bp);
547  if (ret < 0) {
548  av_log(NULL, AV_LOG_ERROR, "Failed to open cert file %s\n", cert_url);
549  goto end;
550  }
551 
552  ret = tls_import_key_cert(key_bp.str, cert_bp.str, key, crtctx);
553  if (ret < 0)
554  goto end;
555 
556 end:
557  av_bprint_finalize(&key_bp, NULL);
558  av_bprint_finalize(&cert_bp, NULL);
559 
560  return ret;
561 }
562 
563 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)
564 {
565  NCRYPT_KEY_HANDLE key = 0;
566  PCCERT_CONTEXT crtctx = NULL;
567 
568  int ret = tls_load_key_cert(key_url, cert_url, &key, &crtctx);
569  if (ret < 0)
570  goto end;
571 
572  ret = tls_export_key_cert(key, crtctx, key_buf, key_sz, cert_buf, cert_sz, fingerprint);
573  if (ret < 0)
574  goto end;
575 
576 end:
577  if (key)
578  if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
579  NCryptFreeObject(key);
580  if (crtctx)
581  CertFreeCertificateContext(crtctx);
582 
583  return ret;
584 }
585 
586 typedef struct TLSContext {
587  const AVClass *class;
589 
592 
593  CredHandle cred_handle;
594  TimeStamp cred_timestamp;
595 
596  CtxtHandle ctxt_handle;
598  TimeStamp ctxt_timestamp;
599 
602 
603  uint8_t *enc_buf;
606 
607  uint8_t *dec_buf;
610 
611  char *send_buf;
614 
615  SecPkgContext_StreamSizes sizes;
616 
620 } TLSContext;
621 
623 {
624  TLSContext *c = h->priv_data;
625  TLSShared *s = &c->tls_shared;
626 
627  if (s->is_dtls)
628  c->tls_shared.udp = sock;
629  else
630  c->tls_shared.tcp = sock;
631 
632  return 0;
633 }
634 
635 int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
636 {
637  TLSContext *c = h->priv_data;
638 
639  SecPkgContext_KeyingMaterialInfo keying_info = { 0 };
640  SecPkgContext_KeyingMaterial keying_material = { 0 };
641 
642  const char* dst = "EXTRACTOR-dtls_srtp";
643  SECURITY_STATUS sspi_ret;
644 
645  if (!c->have_context)
646  return AVERROR(EINVAL);
647 
648  keying_info.cbLabel = strlen(dst) + 1;
649  keying_info.pszLabel = (LPSTR)dst;
650  keying_info.cbContextValue = 0;
651  keying_info.pbContextValue = NULL;
652  keying_info.cbKeyingMaterial = materials_sz;
653 
654  sspi_ret = SetContextAttributes(&c->ctxt_handle, SECPKG_ATTR_KEYING_MATERIAL_INFO, &keying_info, sizeof(keying_info));
655  if (sspi_ret != SEC_E_OK) {
656  av_log(h, AV_LOG_ERROR, "Setting keying material info failed: %lx\n", sspi_ret);
657  return AVERROR_EXTERNAL;
658  }
659 
660  sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_KEYING_MATERIAL, &keying_material);
661  if (sspi_ret != SEC_E_OK) {
662  av_log(h, AV_LOG_ERROR, "Querying keying material failed: %lx\n", sspi_ret);
663  return AVERROR_EXTERNAL;
664  }
665 
666  memcpy(dtls_srtp_materials, keying_material.pbKeyingMaterial, FFMIN(materials_sz, keying_material.cbKeyingMaterial));
667  FreeContextBuffer(keying_material.pbKeyingMaterial);
668 
669  if (keying_material.cbKeyingMaterial > materials_sz) {
670  av_log(h, AV_LOG_WARNING, "Keying material size mismatch: %ld > %zu\n", keying_material.cbKeyingMaterial, materials_sz);
671  return AVERROR(ENOSPC);
672  }
673 
674  return 0;
675 }
676 
678 {
679  TLSContext *c = h->priv_data;
680  return c->tls_shared.state;
681 }
682 
683 static void init_sec_buffer(SecBuffer *buffer, unsigned long type,
684  void *data, unsigned long size)
685 {
686  buffer->cbBuffer = size;
687  buffer->BufferType = type;
688  buffer->pvBuffer = data;
689 }
690 
691 static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers,
692  unsigned long buffer_count)
693 {
694  desc->ulVersion = SECBUFFER_VERSION;
695  desc->pBuffers = buffers;
696  desc->cBuffers = buffer_count;
697 }
698 
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 
729 {
730  TLSContext *c = h->priv_data;
731  TLSShared *s = &c->tls_shared;
732  URLContext *uc = s->is_dtls ? s->udp : s->tcp;
733  int ret;
734 
735  if (c->connected) {
736  SecBufferDesc BuffDesc;
737  SecBuffer Buffer;
738  SECURITY_STATUS sspi_ret;
739  SecBuffer outbuf;
740  SecBufferDesc outbuf_desc;
741 
742  DWORD dwshut = SCHANNEL_SHUTDOWN;
743  init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
744  init_sec_buffer_desc(&BuffDesc, &Buffer, 1);
745 
746  uc->flags &= ~AVIO_FLAG_NONBLOCK;
748  if (ret < 0)
749  return ret;
750 
751  sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc);
752  if (sspi_ret != SEC_E_OK)
753  av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n");
754 
755  init_sec_buffer(&outbuf, SECBUFFER_TOKEN, NULL, 0);
756  init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
757 
758  do {
759  if (s->listen)
760  sspi_ret = AcceptSecurityContext(&c->cred_handle, &c->ctxt_handle, NULL, c->request_flags, 0,
761  &c->ctxt_handle, &outbuf_desc, &c->context_flags,
762  &c->ctxt_timestamp);
763  else
764  sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,
765  c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,
766  &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
767 
768  if (outbuf.pvBuffer) {
769  if (outbuf.cbBuffer > 0) {
770  ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
771  if (ret < 0 || ret != outbuf.cbBuffer)
772  av_log(h, AV_LOG_ERROR, "Failed to send close message\n");
773  }
774  FreeContextBuffer(outbuf.pvBuffer);
775  }
776  } while(sspi_ret == SEC_I_MESSAGE_FRAGMENT || sspi_ret == SEC_I_CONTINUE_NEEDED);
777 
778  av_log(h, AV_LOG_DEBUG, "Close session result: 0x%lx\n", sspi_ret);
779 
780  c->connected = 0;
781  }
782  return 0;
783 }
784 
785 static int tls_close(URLContext *h)
786 {
787  TLSContext *c = h->priv_data;
788  TLSShared *s = &c->tls_shared;
789 
791 
792  DeleteSecurityContext(&c->ctxt_handle);
793  FreeCredentialsHandle(&c->cred_handle);
794 
795  av_freep(&c->enc_buf);
796  c->enc_buf_size = c->enc_buf_offset = 0;
797 
798  av_freep(&c->dec_buf);
799  c->dec_buf_size = c->dec_buf_offset = 0;
800 
801  av_freep(&c->send_buf);
802  c->send_buf_size = c->send_buf_offset = 0;
803 
804  if (s->is_dtls) {
805  if (!s->external_sock)
806  ffurl_closep(&c->tls_shared.udp);
807  } else {
808  ffurl_closep(&c->tls_shared.tcp);
809  }
810 
811  return 0;
812 }
813 
814 static int tls_handshake_loop(URLContext *h, int initial)
815 {
816  TLSContext *c = h->priv_data;
817  TLSShared *s = &c->tls_shared;
818  URLContext *uc = s->is_dtls ? s->udp : s->tcp;
819  SECURITY_STATUS sspi_ret;
820  SecBuffer outbuf[3] = { 0 };
821  SecBufferDesc outbuf_desc;
822  SecBuffer inbuf[3];
823  SecBufferDesc inbuf_desc;
824  struct sockaddr_storage recv_addr = { 0 };
825  socklen_t recv_addr_len = 0;
826  int i, ret = 0, read_data = initial;
827 
828  if (c->enc_buf == NULL) {
829  c->enc_buf_offset = 0;
831  if (ret < 0)
832  goto fail;
833  c->enc_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
834  }
835 
836  if (c->dec_buf == NULL) {
837  c->dec_buf_offset = 0;
839  if (ret < 0)
840  goto fail;
841  c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
842  }
843 
844  uc->flags &= ~AVIO_FLAG_NONBLOCK;
845 
846  while (1) {
847  if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) {
848  c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
849  ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
850  if (ret < 0) {
851  c->enc_buf_size = c->enc_buf_offset = 0;
852  goto fail;
853  }
854  }
855 
856  if (read_data) {
857  ret = ffurl_read(uc, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset);
858  if (ret < 0) {
859  av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n");
860  goto fail;
861  }
862  c->enc_buf_offset += ret;
863  if (s->is_dtls && !recv_addr_len) {
864  ff_udp_get_last_recv_addr(uc, &recv_addr, &recv_addr_len);
865 
866  if (s->listen) {
867  ret = ff_udp_set_remote_addr(uc, (struct sockaddr *)&recv_addr, recv_addr_len, 1);
868  if (ret < 0) {
869  av_log(h, AV_LOG_ERROR, "Failed connecting udp context\n");
870  goto fail;
871  }
872  av_log(h, AV_LOG_TRACE, "Set UDP remote addr on UDP socket, now 'connected'\n");
873  }
874  }
875  }
876 
877  /* input buffers */
878  init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset);
879  init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
880  if (s->listen && s->is_dtls) {
881  init_sec_buffer(&inbuf[2], SECBUFFER_EXTRA, &recv_addr, recv_addr_len);
882  init_sec_buffer_desc(&inbuf_desc, inbuf, 3);
883  } else {
884  init_sec_buffer_desc(&inbuf_desc, inbuf, 2);
885  }
886 
887  if (inbuf[0].pvBuffer == NULL) {
888  av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n");
889  ret = AVERROR(ENOMEM);
890  goto fail;
891  }
892 
893  memcpy(inbuf[0].pvBuffer, c->enc_buf, c->enc_buf_offset);
894 
895  /* output buffers */
896  init_sec_buffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
897  init_sec_buffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
898  init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
899  init_sec_buffer_desc(&outbuf_desc, outbuf, 3);
900 
901  if (s->listen)
902  sspi_ret = AcceptSecurityContext(&c->cred_handle, c->have_context ? &c->ctxt_handle : NULL, &inbuf_desc,
903  c->request_flags, 0, &c->ctxt_handle, &outbuf_desc,
904  &c->context_flags, &c->ctxt_timestamp);
905  else
906  sspi_ret = InitializeSecurityContext(&c->cred_handle, c->have_context ? &c->ctxt_handle : NULL,
907  s->host, c->request_flags, 0, 0, &inbuf_desc, 0, &c->ctxt_handle,
908  &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
909  av_freep(&inbuf[0].pvBuffer);
910 
911  av_log(h, AV_LOG_TRACE, "Handshake res with %d bytes of data: 0x%lx\n", c->enc_buf_offset, sspi_ret);
912 
913  if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
914  av_log(h, AV_LOG_TRACE, "Received incomplete handshake, need more data\n");
915  read_data = 1;
916  continue;
917  }
918 
919  c->have_context = 1;
920 
921  /* remote requests a client certificate - attempt to continue without one anyway */
922  if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS &&
923  !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
924  av_log(h, AV_LOG_VERBOSE, "Client certificate has been requested, ignoring\n");
925  c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
926  read_data = 0;
927  continue;
928  }
929 
930  /* continue handshake */
931  if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_I_MESSAGE_FRAGMENT || sspi_ret == SEC_E_OK) {
932  for (i = 0; i < 3; i++) {
933  if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
934  ret = ffurl_write(uc, outbuf[i].pvBuffer, outbuf[i].cbBuffer);
935  if (ret < 0 || ret != outbuf[i].cbBuffer) {
936  av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n");
937  ret = AVERROR(EIO);
938  goto fail;
939  }
940  }
941 
942  if (outbuf[i].pvBuffer != NULL) {
943  FreeContextBuffer(outbuf[i].pvBuffer);
944  outbuf[i].pvBuffer = NULL;
945  }
946  }
947  } else {
948  if (sspi_ret == SEC_E_WRONG_PRINCIPAL)
949  av_log(h, AV_LOG_ERROR, "SNI or certificate check failed\n");
950  else
951  av_log(h, AV_LOG_ERROR, "Creating security context failed (0x%lx)\n", sspi_ret);
953  goto fail;
954  }
955 
956  if (sspi_ret == SEC_I_MESSAGE_FRAGMENT) {
957  av_log(h, AV_LOG_TRACE, "Writing fragmented output message part\n");
958  read_data = 0;
959  continue;
960  }
961 
962  if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
963  if (c->enc_buf_offset > inbuf[1].cbBuffer) {
964  memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer,
965  inbuf[1].cbBuffer);
966  c->enc_buf_offset = inbuf[1].cbBuffer;
967  if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
968  av_log(h, AV_LOG_TRACE, "Sent reply, handshake continues. %d extra bytes\n", (int)inbuf[1].cbBuffer);
969  read_data = 0;
970  continue;
971  }
972  }
973  } else {
974  c->enc_buf_offset = 0;
975  }
976 
977  if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
978  av_log(h, AV_LOG_TRACE, "Handshake continues\n");
979  read_data = 1;
980  continue;
981  }
982 
983  break;
984  }
985 
986  av_log(h, AV_LOG_TRACE, "Handshake completed\n");
987 
988  return 0;
989 
990 fail:
991  /* free any remaining output data */
992  for (i = 0; i < 3; i++) {
993  if (outbuf[i].pvBuffer != NULL) {
994  FreeContextBuffer(outbuf[i].pvBuffer);
995  outbuf[i].pvBuffer = NULL;
996  }
997  }
998 
999  av_log(h, AV_LOG_TRACE, "Handshake failed\n");
1000 
1001  return ret;
1002 }
1003 
1005 {
1006  TLSContext *c = h->priv_data;
1007  TLSShared *s = &c->tls_shared;
1008  URLContext *uc = s->is_dtls ? s->udp : s->tcp;
1009  SecBuffer outbuf;
1010  SecBufferDesc outbuf_desc;
1011  SECURITY_STATUS sspi_ret;
1012  int ret;
1013 
1014  init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1015  init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
1016 
1017  c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
1018  ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY;
1019  if (s->is_dtls)
1020  c->request_flags |= ISC_REQ_DATAGRAM;
1021  else
1022  c->request_flags |= ISC_REQ_STREAM;
1023 
1024  sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0,
1025  NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags,
1026  &c->ctxt_timestamp);
1027  if (sspi_ret != SEC_I_CONTINUE_NEEDED) {
1028  av_log(h, AV_LOG_ERROR, "Unable to create initial security context (0x%lx)\n", sspi_ret);
1029  ret = AVERROR_UNKNOWN;
1030  goto fail;
1031  }
1032 
1033  c->have_context = 1;
1034 
1035  uc->flags &= ~AVIO_FLAG_NONBLOCK;
1036  ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
1037  FreeContextBuffer(outbuf.pvBuffer);
1038  if (ret < 0 || ret != outbuf.cbBuffer) {
1039  av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n");
1040  ret = AVERROR(EIO);
1041  goto fail;
1042  }
1043 
1044  return tls_handshake_loop(h, 1);
1045 
1046 fail:
1047  DeleteSecurityContext(&c->ctxt_handle);
1048  return ret;
1049 }
1050 
1052 {
1053  TLSContext *c = h->priv_data;
1054  TLSShared *s = &c->tls_shared;
1055 
1056  c->request_flags = ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT |
1057  ASC_REQ_CONFIDENTIALITY | ASC_REQ_ALLOCATE_MEMORY;
1058  if (s->is_dtls)
1059  c->request_flags |= ASC_REQ_DATAGRAM;
1060  else
1061  c->request_flags |= ASC_REQ_STREAM;
1062 
1063  c->have_context = 0;
1064 
1065  return tls_handshake_loop(h, 1);
1066 }
1067 
1069 {
1070  TLSContext *c = h->priv_data;
1071  TLSShared *s = &c->tls_shared;
1072  SECURITY_STATUS sspi_ret;
1073  int ret = 0;
1074 
1075  if (s->listen)
1077  else
1079 
1080  if (ret < 0)
1081  goto fail;
1082 
1083  if (s->is_dtls && s->mtu > 0) {
1084  ULONG mtu = s->mtu;
1085  sspi_ret = SetContextAttributes(&c->ctxt_handle, SECPKG_ATTR_DTLS_MTU, &mtu, sizeof(mtu));
1086  if (sspi_ret != SEC_E_OK) {
1087  av_log(h, AV_LOG_ERROR, "Failed setting DTLS MTU to %d.\n", s->mtu);
1088  ret = AVERROR(EINVAL);
1089  goto fail;
1090  }
1091  av_log(h, AV_LOG_VERBOSE, "Set DTLS MTU to %d\n", s->mtu);
1092  }
1093 
1094  c->connected = 1;
1095  s->state = DTLS_STATE_FINISHED;
1096 
1097 fail:
1098  return ret;
1099 }
1100 
1101 static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
1102 {
1103  TLSContext *c = h->priv_data;
1104  TLSShared *s = &c->tls_shared;
1105  SECURITY_STATUS sspi_ret;
1106  SCHANNEL_CRED schannel_cred = { 0 };
1107  PCCERT_CONTEXT crtctx = NULL;
1108  NCRYPT_KEY_HANDLE key = 0;
1109  int ret = 0;
1110 
1111  if (!s->external_sock) {
1112  if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
1113  goto fail;
1114  }
1115 
1116  /* SChannel Options */
1117  schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
1118 
1119  if (s->listen) {
1120  if (c->cert_store_name && c->cert_store_subject) {
1121  ret = tls_cert_from_store(h, c->cert_store_name, c->cert_store_subject, &crtctx);
1122  } else if (s->key_buf && s->cert_buf) {
1123  ret = tls_import_key_cert(s->key_buf, s->cert_buf, &key, &crtctx);
1124  } else if (s->key_file && s->cert_file) {
1125  ret = tls_load_key_cert(s->key_file, s->cert_file, &key, &crtctx);
1126  } else {
1127  av_log(h, AV_LOG_VERBOSE, "No server certificate provided, using self-signed\n");
1128  ret = tls_gen_self_signed(&key, &crtctx);
1129  }
1130 
1131  if (ret < 0)
1132  goto fail;
1133 
1134  schannel_cred.cCreds = 1;
1135  schannel_cred.paCred = &crtctx;
1136 
1137  schannel_cred.dwFlags = SCH_CRED_NO_SYSTEM_MAPPER | SCH_CRED_MANUAL_CRED_VALIDATION;
1138 
1139  if (s->is_dtls)
1140  schannel_cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_SERVER;
1141  } else {
1142  if (s->verify)
1143  schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
1144  SCH_CRED_REVOCATION_CHECK_CHAIN;
1145  else
1146  schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
1147  SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
1148  SCH_CRED_IGNORE_REVOCATION_OFFLINE;
1149 
1150  if (s->is_dtls)
1151  schannel_cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_CLIENT;
1152  }
1153 
1154  /* Get credential handle */
1155  sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
1156  s->listen ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
1157  NULL, &schannel_cred, NULL, NULL, &c->cred_handle,
1158  &c->cred_timestamp);
1159  if (sspi_ret != SEC_E_OK) {
1160  av_log(h, AV_LOG_ERROR, "Unable to acquire security credentials (0x%lx)\n", sspi_ret);
1161  ret = AVERROR_UNKNOWN;
1162  goto fail;
1163  }
1164 
1165  if (!s->external_sock) {
1166  ret = tls_handshake(h);
1167  if (ret < 0)
1168  goto fail;
1169  }
1170 
1171  goto end;
1172 
1173 fail:
1174  tls_close(h);
1175 
1176 end:
1177  if (crtctx)
1178  CertFreeCertificateContext(crtctx);
1179  if (key)
1180  if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
1181  NCryptFreeObject(key);
1182 
1183  return ret;
1184 }
1185 
1186 static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
1187 {
1188  TLSContext *c = h->priv_data;
1189  TLSShared *s = &c->tls_shared;
1190 
1191  s->is_dtls = 1;
1192 
1193  return tls_open(h, uri, flags, options);
1194 }
1195 
1196 static int tls_read(URLContext *h, uint8_t *buf, int len)
1197 {
1198  TLSContext *c = h->priv_data;
1199  TLSShared *s = &c->tls_shared;
1200  URLContext *uc = s->is_dtls ? s->udp : s->tcp;
1201  SECURITY_STATUS sspi_ret = SEC_E_OK;
1202  SecBuffer inbuf[4];
1203  SecBufferDesc inbuf_desc;
1204  int size, ret = 0;
1205  int min_enc_buf_size = len + SCHANNEL_FREE_BUFFER_SIZE;
1206 
1207  /* If we have some left-over data from previous network activity,
1208  * return it first in case it is enough. It may contain
1209  * data that is required to know whether this connection
1210  * is still required or not, esp. in case of HTTP keep-alive
1211  * connections. */
1212  if (c->dec_buf_offset > 0)
1213  goto cleanup;
1214 
1215  if (c->sspi_close_notify)
1216  goto cleanup;
1217 
1218  if (!c->connection_closed) {
1219  size = c->enc_buf_size - c->enc_buf_offset;
1220  if (size < SCHANNEL_FREE_BUFFER_SIZE || c->enc_buf_size < min_enc_buf_size) {
1221  c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
1222  if (c->enc_buf_size < min_enc_buf_size)
1223  c->enc_buf_size = min_enc_buf_size;
1224  ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
1225  if (ret < 0) {
1226  c->enc_buf_size = c->enc_buf_offset = 0;
1227  return ret;
1228  }
1229  }
1230 
1231  uc->flags &= ~AVIO_FLAG_NONBLOCK;
1232  uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1233 
1234  ret = ffurl_read(uc, c->enc_buf + c->enc_buf_offset,
1235  c->enc_buf_size - c->enc_buf_offset);
1236  if (ret == AVERROR_EOF) {
1237  c->connection_closed = 1;
1238  ret = 0;
1239  } else if (ret == AVERROR(EAGAIN)) {
1240  ret = 0;
1241  } else if (ret < 0) {
1242  av_log(h, AV_LOG_ERROR, "Unable to read from socket\n");
1243  return ret;
1244  }
1245 
1246  c->enc_buf_offset += ret;
1247  }
1248 
1249  while (c->enc_buf_offset > 0 && sspi_ret == SEC_E_OK) {
1250  /* input buffer */
1251  init_sec_buffer(&inbuf[0], SECBUFFER_DATA, c->enc_buf, c->enc_buf_offset);
1252 
1253  /* additional buffers for possible output */
1254  init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1255  init_sec_buffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1256  init_sec_buffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1257  init_sec_buffer_desc(&inbuf_desc, inbuf, 4);
1258 
1259  sspi_ret = DecryptMessage(&c->ctxt_handle, &inbuf_desc, 0, NULL);
1260  if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_RENEGOTIATE ||
1261  sspi_ret == SEC_I_CONTEXT_EXPIRED) {
1262  /* handle decrypted data */
1263  if (inbuf[1].BufferType == SECBUFFER_DATA) {
1264  /* grow buffer if needed */
1265  size = inbuf[1].cbBuffer > SCHANNEL_FREE_BUFFER_SIZE ?
1266  inbuf[1].cbBuffer : SCHANNEL_FREE_BUFFER_SIZE;
1267  if (c->dec_buf_size - c->dec_buf_offset < size || c->dec_buf_size < len) {
1268  c->dec_buf_size = c->dec_buf_offset + size;
1269  if (c->dec_buf_size < len)
1270  c->dec_buf_size = len;
1271  ret = av_reallocp(&c->dec_buf, c->dec_buf_size);
1272  if (ret < 0) {
1273  c->dec_buf_size = c->dec_buf_offset = 0;
1274  return ret;
1275  }
1276  }
1277 
1278  /* copy decrypted data to buffer */
1279  size = inbuf[1].cbBuffer;
1280  if (size) {
1281  memcpy(c->dec_buf + c->dec_buf_offset, inbuf[1].pvBuffer, size);
1282  c->dec_buf_offset += size;
1283  }
1284  }
1285  if (inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1286  if (c->enc_buf_offset > inbuf[3].cbBuffer) {
1287  memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[3].cbBuffer,
1288  inbuf[3].cbBuffer);
1289  c->enc_buf_offset = inbuf[3].cbBuffer;
1290  }
1291  } else
1292  c->enc_buf_offset = 0;
1293 
1294  if (sspi_ret == SEC_I_RENEGOTIATE) {
1295  if (c->enc_buf_offset) {
1296  av_log(h, AV_LOG_ERROR, "Cannot renegotiate, encrypted data buffer not empty\n");
1297  ret = AVERROR_UNKNOWN;
1298  goto cleanup;
1299  }
1300 
1301  av_log(h, AV_LOG_VERBOSE, "Re-negotiating security context\n");
1302  ret = tls_handshake_loop(h, 0);
1303  if (ret < 0) {
1304  goto cleanup;
1305  }
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 
1312  continue;
1313  } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) {
1314  c->sspi_close_notify = 1;
1315  if (!c->connection_closed) {
1316  c->connection_closed = 1;
1317  av_log(h, AV_LOG_VERBOSE, "Server closed the connection\n");
1318  }
1319  ret = 0;
1320  goto cleanup;
1321  }
1322  } else if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
1323  ret = AVERROR(EAGAIN);
1324  goto cleanup;
1325  } else {
1326  av_log(h, AV_LOG_ERROR, "Unable to decrypt message (error 0x%x)\n", (unsigned)sspi_ret);
1327  ret = AVERROR(EIO);
1328  goto cleanup;
1329  }
1330  }
1331 
1332  ret = 0;
1333 
1334 cleanup:
1335  size = FFMIN(len, c->dec_buf_offset);
1336  if (size) {
1337  memcpy(buf, c->dec_buf, size);
1338  memmove(c->dec_buf, c->dec_buf + size, c->dec_buf_offset - size);
1339  c->dec_buf_offset -= size;
1340 
1341  return size;
1342  }
1343 
1344  if (ret == 0 && !c->connection_closed)
1345  ret = AVERROR(EAGAIN);
1346 
1347  return ret < 0 ? ret : AVERROR_EOF;
1348 }
1349 
1350 static int tls_write(URLContext *h, const uint8_t *buf, int len)
1351 {
1352  TLSContext *c = h->priv_data;
1353  TLSShared *s = &c->tls_shared;
1354  URLContext *uc = s->is_dtls ? s->udp : s->tcp;
1355  SECURITY_STATUS sspi_ret;
1356  SecBuffer outbuf[4];
1357  SecBufferDesc outbuf_desc;
1358  int ret = 0;
1359 
1360  uc->flags &= ~AVIO_FLAG_NONBLOCK;
1361  uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1362 
1364  if (ret < 0)
1365  return ret;
1366 
1367  if (c->sizes.cbMaximumMessage == 0) {
1368  sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes);
1369  if (sspi_ret != SEC_E_OK)
1370  return AVERROR_UNKNOWN;
1371  }
1372 
1373  /* limit how much data we can consume */
1374  len = FFMIN(len, c->sizes.cbMaximumMessage - c->sizes.cbHeader - c->sizes.cbTrailer);
1375 
1376  c->send_buf_size = c->sizes.cbHeader + len + c->sizes.cbTrailer;
1377  c->send_buf = av_malloc(c->send_buf_size);
1378  if (c->send_buf == NULL)
1379  return AVERROR(ENOMEM);
1380 
1381  init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1382  c->send_buf, c->sizes.cbHeader);
1383  init_sec_buffer(&outbuf[1], SECBUFFER_DATA,
1384  c->send_buf + c->sizes.cbHeader, len);
1385  init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1386  c->send_buf + c->sizes.cbHeader + len,
1387  c->sizes.cbTrailer);
1388  init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1389  init_sec_buffer_desc(&outbuf_desc, outbuf, 4);
1390 
1391  memcpy(outbuf[1].pvBuffer, buf, len);
1392 
1393  sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0);
1394  if (sspi_ret != SEC_E_OK) {
1395  av_freep(&c->send_buf);
1396  av_log(h, AV_LOG_ERROR, "Encrypting data failed\n");
1397  if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY)
1398  return AVERROR(ENOMEM);
1399  return AVERROR(EIO);
1400  }
1401 
1402  c->send_buf_size = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1403  c->send_buf_offset = 0;
1404 
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;
1413  }
1414 
1415  return outbuf[1].cbBuffer;
1416 }
1417 
1419 {
1420  TLSContext *c = h->priv_data;
1421  TLSShared *s = &c->tls_shared;
1422  return ffurl_get_file_handle(s->is_dtls ? s->udp : s->tcp);
1423 }
1424 
1426 {
1427  TLSContext *c = h->priv_data;
1428  TLSShared *s = &c->tls_shared;
1429  return ffurl_get_short_seek(s->is_dtls ? s->udp : s->tcp);
1430 }
1431 
1432 #define OFFSET(x) offsetof(TLSContext, x)
1433 static const AVOption options[] = {
1434  TLS_COMMON_OPTIONS(TLSContext, tls_shared),
1435  { "cert_store_subject", "Load certificate (and associated key) from users keystore by subject",
1436  OFFSET(cert_store_subject), AV_OPT_TYPE_STRING, .flags = TLS_OPTFL },
1437  { "cert_store_name", "Name of the specific cert store to search in (for cert_store_subject)",
1438  OFFSET(cert_store_name), AV_OPT_TYPE_STRING, { .str = "MY" }, .flags = TLS_OPTFL },
1439  { NULL }
1440 };
1441 
1442 static const AVClass tls_class = {
1443  .class_name = "tls",
1444  .item_name = av_default_item_name,
1445  .option = options,
1446  .version = LIBAVUTIL_VERSION_INT,
1447 };
1448 
1450  .name = "tls",
1451  .url_open2 = tls_open,
1452  .url_read = tls_read,
1453  .url_write = tls_write,
1454  .url_close = tls_close,
1455  .url_get_file_handle = tls_get_file_handle,
1456  .url_get_short_seek = tls_get_short_seek,
1457  .priv_data_size = sizeof(TLSContext),
1459  .priv_data_class = &tls_class,
1460 };
1461 
1462 static const AVClass dtls_class = {
1463  .class_name = "dtls",
1464  .item_name = av_default_item_name,
1465  .option = options,
1466  .version = LIBAVUTIL_VERSION_INT,
1467 };
1468 
1470  .name = "dtls",
1471  .url_open2 = dtls_open,
1472  .url_handshake = tls_handshake,
1473  .url_close = tls_close,
1474  .url_read = tls_read,
1475  .url_write = tls_write,
1476  .url_get_file_handle = tls_get_file_handle,
1477  .url_get_short_seek = tls_get_short_seek,
1478  .priv_data_size = sizeof(TLSContext),
1480  .priv_data_class = &dtls_class,
1481 };
flags
const SwsFlags flags[]
Definition: swscale.c:61
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
TLSContext
Definition: tls_gnutls.c:44
read_data
static int read_data(void *opaque, uint8_t *buf, int buf_size)
Definition: dashdec.c:1772
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:33
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
TLSContext::cert_store_name
char * cert_store_name
Definition: tls_schannel.c:591
ff_ssl_read_key_cert
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)
Definition: tls_schannel.c:563
TLSContext::context_flags
ULONG context_flags
Definition: tls_schannel.c:601
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
ff_ssl_gen_key_cert
int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
Definition: tls_schannel.c:370
tls_server_handshake
static int tls_server_handshake(URLContext *h)
Definition: tls_schannel.c:1051
TLSContext::request_flags
ULONG request_flags
Definition: tls_schannel.c:600
ffurl_write
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: url.h:202
SCHANNEL_FREE_BUFFER_SIZE
#define SCHANNEL_FREE_BUFFER_SIZE
Definition: tls_schannel.c:38
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:130
TLSContext::have_context
int have_context
Definition: tls_schannel.c:597
ff_tls_protocol
const URLProtocol ff_tls_protocol
Definition: tls_schannel.c:1449
AVOption
AVOption.
Definition: opt.h:429
data
const char data[16]
Definition: mxf.c:149
ff_dtls_protocol
const URLProtocol ff_dtls_protocol
Definition: tls_schannel.c:1469
options
static const AVOption options[]
Definition: tls_schannel.c:1433
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
AVDictionary
Definition: dict.c:32
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:73
hash
uint8_t hash[HASH_SIZE]
Definition: movenc.c:58
URLProtocol
Definition: url.h:51
os_support.h
TLSContext::dec_buf
uint8_t * dec_buf
Definition: tls_schannel.c:607
TLSContext::cred_handle
CredHandle cred_handle
Definition: tls_schannel.c:593
sockaddr_storage
Definition: network.h:111
tls_class
static const AVClass tls_class
Definition: tls_schannel.c:1442
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
tls_write
static int tls_write(URLContext *h, const uint8_t *buf, int len)
Definition: tls_schannel.c:1350
TLS_COMMON_OPTIONS
#define TLS_COMMON_OPTIONS(pstruct, options_field)
Definition: tls.h:89
av_bprint_init_for_buffer
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition: bprint.c:85
fail
#define fail()
Definition: checkasm.h:196
ffurl_get_short_seek
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition: avio.c:839
tls_open
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: tls_schannel.c:1101
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
TLSContext::sspi_close_notify
int sspi_close_notify
Definition: tls_schannel.c:619
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
init_sec_buffer_desc
static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, unsigned long buffer_count)
Definition: tls_schannel.c:691
s
#define s(width, name)
Definition: cbs_vp9.c:198
TLSContext::dec_buf_offset
int dec_buf_offset
Definition: tls_schannel.c:609
TLSContext::cert_store_subject
char * cert_store_subject
Definition: tls_schannel.c:590
TLS_OPTFL
#define TLS_OPTFL
Definition: tls.h:79
URLContext::flags
int flags
Definition: url.h:40
OFFSET
#define OFFSET(x)
Definition: tls_schannel.c:1432
tls_read
static int tls_read(URLContext *h, uint8_t *buf, int len)
Definition: tls_schannel.c:1196
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
key
const char * key
Definition: hwcontext_opencl.c:189
TLSContext::send_buf_size
int send_buf_size
Definition: tls_schannel.c:612
TLSContext::enc_buf_offset
int enc_buf_offset
Definition: tls_schannel.c:605
ff_udp_set_remote_addr
int ff_udp_set_remote_addr(URLContext *h, const struct sockaddr *dest_addr, socklen_t dest_addr_len, int do_connect)
This function is identical to ff_udp_set_remote_url, except that it takes a sockaddr directly.
Definition: udp.c:471
internal.h
tls_handshake
static int tls_handshake(URLContext *h)
Definition: tls_schannel.c:1068
SECBUFFER_ALERT
#define SECBUFFER_ALERT
Definition: tls_schannel.c:42
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
NULL
#define NULL
Definition: coverity.c:32
tls_shutdown_client
static int tls_shutdown_client(URLContext *h)
Definition: tls_schannel.c:728
ff_tls_set_external_socket
int ff_tls_set_external_socket(URLContext *h, URLContext *sock)
Definition: tls_schannel.c:622
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:240
ff_udp_get_last_recv_addr
void ff_udp_get_last_recv_addr(URLContext *h, struct sockaddr_storage *addr, socklen_t *addr_len)
Definition: udp.c:509
init_sec_buffer
static void init_sec_buffer(SecBuffer *buffer, unsigned long type, void *data, unsigned long size)
Definition: tls_schannel.c:683
options
Definition: swscale.c:43
der_to_fingerprint
static int der_to_fingerprint(const char *data, size_t len, char **fingerprint)
Definition: tls_schannel.c:124
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
tls_close
static int tls_close(URLContext *h)
Definition: tls_schannel.c:785
ff_url_read_all
int ff_url_read_all(const char *url, AVBPrint *bp)
Read all data from the given URL url and store it in the given buffer bp.
Definition: tls.c:150
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
size
int size
Definition: twinvq_data.h:10344
av_reallocp
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:188
TLSContext::tls_shared
TLSShared tls_shared
Definition: tls_gnutls.c:46
URLProtocol::name
const char * name
Definition: url.h:52
tls_load_key_cert
static int tls_load_key_cert(char *key_url, char *cert_url, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
Definition: tls_schannel.c:531
TLSContext::send_buf
char * send_buf
Definition: tls_schannel.c:611
tls_process_send_buffer
static int tls_process_send_buffer(URLContext *h)
Definition: tls_schannel.c:699
header
static const uint8_t header[24]
Definition: sdr2.c:68
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
dtls_class
static const AVClass dtls_class
Definition: tls_schannel.c:1462
pem_to_der
static int pem_to_der(const char *pem, char **buf, int *out_len)
Definition: tls_schannel.c:101
tls_export_key_cert
static int tls_export_key_cert(NCRYPT_KEY_HANDLE key, PCCERT_CONTEXT crtctx, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
Definition: tls_schannel.c:324
tls_cert_from_store
static int tls_cert_from_store(void *logctx, const char *cert_store_name, const char *cert_subj, PCCERT_CONTEXT *crtctx)
Definition: tls_schannel.c:505
TLSContext::enc_buf_size
int enc_buf_size
Definition: tls_schannel.c:604
URLContext
Definition: url.h:35
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
TLSContext::send_buf_offset
int send_buf_offset
Definition: tls_schannel.c:613
TLSContext::ctxt_timestamp
TimeStamp ctxt_timestamp
Definition: tls_schannel.c:598
TLSContext::connected
int connected
Definition: tls_schannel.c:617
TLSContext::ctxt_handle
CtxtHandle ctxt_handle
Definition: tls_schannel.c:596
tls_client_handshake
static int tls_client_handshake(URLContext *h)
Definition: tls_schannel.c:1004
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
TLSContext::cred_timestamp
TimeStamp cred_timestamp
Definition: tls_schannel.c:594
url.h
len
int len
Definition: vorbis_enc_data.h:426
TLSContext::sizes
SecPkgContext_StreamSizes sizes
Definition: tls_schannel.c:615
FF_NCRYPT_TEMP_KEY_NAME
#define FF_NCRYPT_TEMP_KEY_NAME
Definition: tls_schannel.c:58
der_to_pem
static int der_to_pem(const char *data, size_t len, const char *header, char *buf, size_t bufsize)
Definition: tls_schannel.c:60
ffurl_closep
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:589
tls_import_key_cert
static int tls_import_key_cert(char *key_buf, char *cert_buf, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
Definition: tls_schannel.c:393
ff_tls_open_underlying
int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options)
Definition: tls.c:69
ret
ret
Definition: filter_design.txt:187
SCHANNEL_INITIAL_BUFFER_SIZE
#define SCHANNEL_INITIAL_BUFFER_SIZE
Definition: tls_schannel.c:37
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:81
avformat.h
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:99
ff_dtls_export_materials
int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
Definition: tls_schannel.c:635
network.h
TLSContext::enc_buf
uint8_t * enc_buf
Definition: tls_schannel.c:603
tls.h
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
L
#define L(x)
Definition: vpx_arith.h:36
desc
const char * desc
Definition: libsvtav1.c:79
tls_get_file_handle
static int tls_get_file_handle(URLContext *h)
Definition: tls_schannel.c:1418
mem.h
MAX_CERTIFICATE_SIZE
#define MAX_CERTIFICATE_SIZE
Maximum size limit of a certificate and private key size.
Definition: tls.h:34
TLSShared
Definition: tls.h:47
dtls_open
static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition: tls_schannel.c:1186
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
ff_dtls_state
int ff_dtls_state(URLContext *h)
Definition: tls_schannel.c:677
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:636
TLSContext::connection_closed
int connection_closed
Definition: tls_schannel.c:618
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
TLSContext::dec_buf_size
int dec_buf_size
Definition: tls_schannel.c:608
tls_gen_self_signed
static int tls_gen_self_signed(NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
Definition: tls_schannel.c:145
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
tls_handshake_loop
static int tls_handshake_loop(URLContext *h, int initial)
Definition: tls_schannel.c:814
h
h
Definition: vp9dsp_template.c:2070
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
DTLS_STATE_FINISHED
@ DTLS_STATE_FINISHED
Definition: tls.h:40
ffurl_get_file_handle
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition: avio.c:815
tls_get_short_seek
static int tls_get_short_seek(URLContext *h)
Definition: tls_schannel.c:1425
ffurl_read
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: url.h:181