FFmpeg
Loading...
Searching...
No Matches
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 "config.h"
24#include "config_components.h"
25
26#include "libavutil/mem.h"
27#include "avformat.h"
28#include "internal.h"
29#include "network.h"
30#include "os_support.h"
31#include "url.h"
32#include "tls.h"
33
34#define SECURITY_WIN32
35#include <windows.h>
36#include <security.h>
37#include <schnlsp.h>
38#include <sddl.h>
39
40#define SCHANNEL_INITIAL_BUFFER_SIZE 4096
41#define SCHANNEL_FREE_BUFFER_SIZE 1024
42
43/* mingw does not define this symbol */
44#ifndef SECBUFFER_ALERT
45#define SECBUFFER_ALERT 17
46#endif
47
48/* This is the name used for the private key in the MS Keystore.
49 * There is as of time of writing no way to use schannel without
50 * persisting the private key. Which usually means the default MS
51 * keystore will write it to disk unencrypted, user-read/writable.
52 * To combat this as much as possible, the code makes sure to
53 * delete the private key ASAP once SChannel has gotten ahold of
54 * it.
55 * Apparently this is because SChannel neglects marshaling the
56 * private key alongside the certificate for the out-of-process
57 * tls handler.
58 * See this GitHub issue for the most detailed explanation out there:
59 * https://github.com/dotnet/runtime/issues/23749#issuecomment-485947319
60 */
61#define FF_NCRYPT_TEMP_KEY_NAME L"FFMPEG_TEMP_TLS_KEY"
62
63static int der_to_pem(const char *data, size_t len, const char *header, char *buf, size_t bufsize)
64{
65 const int line_length = 64;
66 AVBPrint pem;
67 DWORD base64len = 0;
68 char *base64 = NULL;
69 int ret = 0;
70
71 if (!CryptBinaryToStringA(data, len, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, NULL, &base64len)) {
72 av_log(NULL, AV_LOG_ERROR, "CryptBinaryToString failed\n");
73 ret = AVERROR_EXTERNAL;
74 goto end;
75 }
76
77 base64 = av_malloc(base64len);
78
79 if (!CryptBinaryToStringA(data, len, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, base64, &base64len)) {
80 av_log(NULL, AV_LOG_ERROR, "CryptBinaryToString failed\n");
81 ret = AVERROR_EXTERNAL;
82 goto end;
83 }
84
85 av_bprint_init_for_buffer(&pem, buf, bufsize);
86 av_bprintf(&pem, "-----BEGIN %s-----\n", header);
87
88 for (DWORD i = 0; i < base64len; i += line_length) {
89 av_bprintf(&pem, "%.*s\n", line_length, base64 + i);
90 }
91
92 av_bprintf(&pem, "-----END %s-----\n", header);
93
94 if (!av_bprint_is_complete(&pem)) {
95 ret = AVERROR(ENOSPC);
96 goto end;
97 }
98
99end:
100 av_free(base64);
101 return ret;
102}
103
104static int pem_to_der(const char *pem, char **buf, int *out_len)
105{
106 DWORD derlen = 0;
107
108 if (!CryptStringToBinaryA(pem, 0, CRYPT_STRING_BASE64HEADER, NULL, &derlen, NULL, NULL)) {
109 av_log(NULL, AV_LOG_ERROR, "CryptStringToBinaryA failed\n");
110 return AVERROR(EINVAL);
111 }
112
113 *buf = av_malloc(derlen);
114 if (!*buf)
115 return AVERROR(ENOMEM);
116
117 if (!CryptStringToBinaryA(pem, 0, CRYPT_STRING_BASE64HEADER, *buf, &derlen, NULL, NULL)) {
118 av_log(NULL, AV_LOG_ERROR, "CryptStringToBinaryA failed\n");
119 return AVERROR(EINVAL);
120 }
121
122 *out_len = derlen;
123
124 return 0;
125}
126
127static int der_to_fingerprint(const char *data, size_t len, char **fingerprint)
128{
129 AVBPrint buf;
130 unsigned char hash[32];
131 DWORD hashsize = sizeof(hash);
132
133 if (!CryptHashCertificate2(BCRYPT_SHA256_ALGORITHM, 0, NULL, data, len, hash, &hashsize))
134 {
135 av_log(NULL, AV_LOG_ERROR, "CryptHashCertificate2 failed\n");
136 return AVERROR_EXTERNAL;
137 }
138
139 av_bprint_init(&buf, hashsize*3, hashsize*3);
140
141 for (int i = 0; i < hashsize - 1; i++)
142 av_bprintf(&buf, "%02X:", hash[i]);
143 av_bprintf(&buf, "%02X", hash[hashsize - 1]);
144
145 return av_bprint_finalize(&buf, fingerprint);
146}
147
148static int tls_gen_self_signed(NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
149{
150 NCRYPT_PROV_HANDLE provider = 0;
151 CERT_NAME_BLOB subject = { 0 };
152
153 DWORD export_props = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
154 DWORD usage_props = NCRYPT_ALLOW_ALL_USAGES;
155 LPCSTR ext_usages[] = { szOID_PKIX_KP_SERVER_AUTH };
156 BYTE key_usage = CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DIGITAL_SIGNATURE_KEY_USAGE;
157 CRYPT_BIT_BLOB key_usage_blob = { 0 };
158 CERT_ENHKEY_USAGE eku = { 0 };
159 CERT_BASIC_CONSTRAINTS2_INFO basic_constraints = { 0 };
160 CERT_ALT_NAME_ENTRY san_entry = { 0 };
161 CERT_ALT_NAME_INFO san_info = { 0 };
162 CERT_EXTENSION ext[4] = { 0 };
163 CERT_EXTENSIONS exts = { 0 };
164 CRYPT_ALGORITHM_IDENTIFIER sig_alg = { (LPSTR)szOID_ECDSA_SHA256 };
165 CRYPT_KEY_PROV_INFO prov_info = { 0 };
166 const char *subj_str = "CN=lavf";
167
168 SECURITY_STATUS sspi_ret;
169 int ret = 0;
170
171 *crtctx = NULL;
172
173 sspi_ret = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0);
174 if (sspi_ret != ERROR_SUCCESS) {
175 av_log(NULL, AV_LOG_ERROR, "NCryptOpenStorageProvider failed(0x%lx)\n", sspi_ret);
176 ret = AVERROR_EXTERNAL;
177 goto fail;
178 }
179
180 sspi_ret = NCryptCreatePersistedKey(provider, key, BCRYPT_ECDSA_P256_ALGORITHM, FF_NCRYPT_TEMP_KEY_NAME, 0, NCRYPT_OVERWRITE_KEY_FLAG);
181 if (sspi_ret != ERROR_SUCCESS) {
182 av_log(NULL, AV_LOG_ERROR, "NCryptCreatePersistedKey failed(0x%lx)\n", sspi_ret);
183 ret = AVERROR_EXTERNAL;
184 goto fail;
185 }
186
187 sspi_ret = NCryptSetProperty(*key, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE)&export_props, sizeof(export_props), 0);
188 if (sspi_ret != ERROR_SUCCESS) {
189 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_EXPORT_POLICY_PROPERTY) failed(0x%lx)\n", sspi_ret);
190 ret = AVERROR_EXTERNAL;
191 goto fail;
192 }
193
194 sspi_ret = NCryptSetProperty(*key, NCRYPT_KEY_USAGE_PROPERTY, (PBYTE)&usage_props, sizeof(usage_props), 0);
195 if (sspi_ret != ERROR_SUCCESS) {
196 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_KEY_USAGE_PROPERTY) failed(0x%lx)\n", sspi_ret);
197 ret = AVERROR_EXTERNAL;
198 goto fail;
199 }
200
201 sspi_ret = NCryptFinalizeKey(*key, 0);
202 if (sspi_ret != ERROR_SUCCESS) {
203 av_log(NULL, AV_LOG_ERROR, "NCryptFinalizeKey failed(0x%lx)\n", sspi_ret);
204 ret = AVERROR_EXTERNAL;
205 goto fail;
206 }
207
208 if (!CertStrToNameA(X509_ASN_ENCODING, subj_str, 0, NULL, NULL, &subject.cbData, NULL))
209 {
210 av_log(NULL, AV_LOG_ERROR, "Initial subj init failed\n");
211 ret = AVERROR_EXTERNAL;
212 goto fail;
213 }
214
215 subject.pbData = av_malloc(subject.cbData);
216 if (!subject.pbData) {
217 ret = AVERROR(ENOMEM);
218 goto fail;
219 }
220
221 if (!CertStrToNameA(X509_ASN_ENCODING, subj_str, 0, NULL, subject.pbData, &subject.cbData, NULL))
222 {
223 av_log(NULL, AV_LOG_ERROR, "Subj init failed\n");
224 ret = AVERROR_EXTERNAL;
225 goto fail;
226 }
227
228 // Extended Key Usage extension
229 eku.cUsageIdentifier = 1;
230 eku.rgpszUsageIdentifier = (LPSTR*)ext_usages;
231
232 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &eku,
233 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[0].Value.pbData, &ext[0].Value.cbData)) {
234 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for EKU failed\n");
235 ret = AVERROR_EXTERNAL;
236 goto fail;
237 }
238
239 ext[0].pszObjId = (LPSTR)szOID_ENHANCED_KEY_USAGE;
240 ext[0].fCritical = TRUE;
241
242 // Key usage extension
243 key_usage_blob.cbData = sizeof(key_usage);
244 key_usage_blob.pbData = &key_usage;
245
246 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_BITS, &key_usage_blob,
247 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[1].Value.pbData, &ext[1].Value.cbData)) {
248 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for KU failed\n");
249 ret = AVERROR_EXTERNAL;
250 goto fail;
251 }
252
253 ext[1].pszObjId = (LPSTR)szOID_KEY_USAGE;
254 ext[1].fCritical = TRUE;
255
256 // Cert Basic Constraints
257 basic_constraints.fCA = FALSE;
258
259 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &basic_constraints,
260 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[2].Value.pbData, &ext[2].Value.cbData)) {
261 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for KU failed\n");
262 ret = AVERROR_EXTERNAL;
263 goto fail;
264 }
265
266 ext[2].pszObjId = (LPSTR)szOID_BASIC_CONSTRAINTS2;
267 ext[2].fCritical = TRUE;
268
269 // Subject Alt Names
270 san_entry.dwAltNameChoice = CERT_ALT_NAME_DNS_NAME;
271 san_entry.pwszDNSName = (LPWSTR)L"localhost";
272
273 san_info.cAltEntry = 1;
274 san_info.rgAltEntry = &san_entry;
275
276 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME, &san_info,
277 CRYPT_ENCODE_ALLOC_FLAG, NULL, &ext[3].Value.pbData, &ext[3].Value.cbData)) {
278 av_log(NULL, AV_LOG_ERROR, "CryptEncodeObjectEx for KU failed\n");
279 ret = AVERROR_EXTERNAL;
280 goto fail;
281 }
282
283 ext[3].pszObjId = (LPSTR)szOID_SUBJECT_ALT_NAME2;
284 ext[3].fCritical = TRUE;
285
286 exts.cExtension = 4;
287 exts.rgExtension = ext;
288
289 prov_info.pwszProvName = (LPWSTR)MS_KEY_STORAGE_PROVIDER;
290 prov_info.pwszContainerName = (LPWSTR)FF_NCRYPT_TEMP_KEY_NAME;
291 prov_info.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
292
293 *crtctx = CertCreateSelfSignCertificate(*key, &subject, 0, &prov_info, &sig_alg, NULL, NULL, &exts);
294 if (!*crtctx) {
295 av_log(NULL, AV_LOG_ERROR, "CertCreateSelfSignCertificate failed: %lu\n", GetLastError());
296 ret = AVERROR_EXTERNAL;
297 goto fail;
298 }
299
300 NCryptFreeObject(provider);
301 av_free(subject.pbData);
302 for (int i = 0; i < FF_ARRAY_ELEMS(ext); i++)
303 LocalFree(ext[i].Value.pbData);
304
305 return 0;
306
307fail:
308 if (*crtctx)
309 CertFreeCertificateContext(*crtctx);
310 if (*key)
311 if (NCryptDeleteKey(*key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
312 NCryptFreeObject(*key);
313 if (provider)
314 NCryptFreeObject(provider);
315 if (subject.pbData)
316 av_free(subject.pbData);
317 for (int i = 0; i < FF_ARRAY_ELEMS(ext); i++)
318 if (ext[i].Value.pbData)
319 LocalFree(ext[i].Value.pbData);
320
321 *key = 0;
322 *crtctx = NULL;
323
324 return ret;
325}
326
327static int tls_export_key_cert(NCRYPT_KEY_HANDLE key, PCCERT_CONTEXT crtctx,
328 char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
329{
330 DWORD keysize = 0;
331 char *keybuf = NULL;
332
333 SECURITY_STATUS sspi_ret;
334 int ret = 0;
335
336 sspi_ret = NCryptExportKey(key, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL, NULL, 0, &keysize, 0);
337 if (sspi_ret != ERROR_SUCCESS) {
338 av_log(NULL, AV_LOG_ERROR, "Initial NCryptExportKey failed(0x%lx)\n", sspi_ret);
339 ret = AVERROR_EXTERNAL;
340 goto end;
341 }
342
343 keybuf = av_malloc(keysize);
344 if (!keybuf) {
345 ret = AVERROR(ENOMEM);
346 goto end;
347 }
348
349 sspi_ret = NCryptExportKey(key, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, NULL, keybuf, keysize, &keysize, 0);
350 if (sspi_ret != ERROR_SUCCESS) {
351 av_log(NULL, AV_LOG_ERROR, "Initial NCryptExportKey failed(0x%lx)\n", sspi_ret);
352 ret = AVERROR_EXTERNAL;
353 goto end;
354 }
355
356 ret = der_to_pem(keybuf, keysize, "PRIVATE KEY", key_buf, key_sz);
357 if (ret < 0)
358 goto end;
359
360 ret = der_to_pem(crtctx->pbCertEncoded, crtctx->cbCertEncoded, "CERTIFICATE", cert_buf, cert_sz);
361 if (ret < 0)
362 goto end;
363
364 ret = der_to_fingerprint(crtctx->pbCertEncoded, crtctx->cbCertEncoded, fingerprint);
365 if (ret < 0)
366 goto end;
367
368end:
369 av_free(keybuf);
370 return ret;
371}
372
373int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
374{
375 NCRYPT_KEY_HANDLE key = 0;
376 PCCERT_CONTEXT crtctx = NULL;
377
378 int ret = tls_gen_self_signed(&key, &crtctx);
379 if (ret < 0)
380 goto end;
381
382 ret = tls_export_key_cert(key, crtctx, key_buf, key_sz, cert_buf, cert_sz, fingerprint);
383 if (ret < 0)
384 goto end;
385
386end:
387 if (key)
388 if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
389 NCryptFreeObject(key);
390 if (crtctx)
391 CertFreeCertificateContext(crtctx);
392
393 return ret;
394}
395
396static int tls_import_key_cert(char *key_buf, char *cert_buf, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
397{
398 NCRYPT_PROV_HANDLE provider = 0;
399
400 DWORD export_props = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
401 DWORD usage_props = NCRYPT_ALLOW_ALL_USAGES;
402 NCryptBufferDesc buffer_desc = { 0 };
403 NCryptBuffer buffer = { 0 };
404 CRYPT_KEY_PROV_INFO prov_info = { 0 };
405
406 int key_der_len = 0, cert_der_len = 0;
407 char *key_der = NULL, *cert_der = NULL;
408
409 SECURITY_STATUS sspi_ret;
410 int ret = 0;
411
412 ret = pem_to_der(key_buf, &key_der, &key_der_len);
413 if (ret < 0)
414 goto fail;
415
416 ret = pem_to_der(cert_buf, &cert_der, &cert_der_len);
417 if (ret < 0)
418 goto fail;
419
420 sspi_ret = NCryptOpenStorageProvider(&provider, MS_KEY_STORAGE_PROVIDER, 0);
421 if (sspi_ret != ERROR_SUCCESS) {
422 av_log(NULL, AV_LOG_ERROR, "NCryptOpenStorageProvider failed(0x%lx)\n", sspi_ret);
423 ret = AVERROR_EXTERNAL;
424 goto fail;
425 }
426
427 buffer_desc.ulVersion = NCRYPTBUFFER_VERSION;
428 buffer_desc.cBuffers = 1;
429 buffer_desc.pBuffers = &buffer;
430
431 buffer.BufferType = NCRYPTBUFFER_PKCS_KEY_NAME;
432 buffer.pvBuffer = (LPWSTR)FF_NCRYPT_TEMP_KEY_NAME;
433 buffer.cbBuffer = sizeof(FF_NCRYPT_TEMP_KEY_NAME);
434
435 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);
436 if (sspi_ret != ERROR_SUCCESS) {
437 av_log(NULL, AV_LOG_ERROR, "NCryptImportKey failed(0x%lx)\n", sspi_ret);
438 ret = AVERROR_EXTERNAL;
439 goto fail;
440 }
441
442 sspi_ret = NCryptSetProperty(*key, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE)&export_props, sizeof(export_props), 0);
443 if (sspi_ret != ERROR_SUCCESS) {
444 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_EXPORT_POLICY_PROPERTY) failed(0x%lx)\n", sspi_ret);
445 ret = AVERROR_EXTERNAL;
446 goto fail;
447 }
448
449 sspi_ret = NCryptSetProperty(*key, NCRYPT_KEY_USAGE_PROPERTY, (PBYTE)&usage_props, sizeof(usage_props), 0);
450 if (sspi_ret != ERROR_SUCCESS) {
451 av_log(NULL, AV_LOG_ERROR, "NCryptSetProperty(NCRYPT_KEY_USAGE_PROPERTY) failed(0x%lx)\n", sspi_ret);
452 ret = AVERROR_EXTERNAL;
453 goto fail;
454 }
455
456 sspi_ret = NCryptFinalizeKey(*key, 0);
457 if (sspi_ret != ERROR_SUCCESS) {
458 av_log(NULL, AV_LOG_ERROR, "NCryptFinalizeKey failed(0x%lx)\n", sspi_ret);
459 ret = AVERROR_EXTERNAL;
460 goto fail;
461 }
462
463 *crtctx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, cert_der, cert_der_len);
464 if (!*crtctx) {
465 av_log(NULL, AV_LOG_ERROR, "CertCreateCertificateContext failed: %lu\n", GetLastError());
466 ret = AVERROR_EXTERNAL;
467 goto fail;
468 }
469
470 if (!CertSetCertificateContextProperty(*crtctx, CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, key)) {
471 av_log(NULL, AV_LOG_ERROR, "CertSetCertificateContextProperty(CERT_NCRYPT_KEY_HANDLE_PROP_ID) failed: %lu\n", GetLastError());
472 ret = AVERROR_EXTERNAL;
473 goto fail;
474 }
475
476 prov_info.pwszProvName = (LPWSTR)MS_KEY_STORAGE_PROVIDER;
477 prov_info.pwszContainerName = (LPWSTR)FF_NCRYPT_TEMP_KEY_NAME;
478 prov_info.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
479
480 if (!CertSetCertificateContextProperty(*crtctx, CERT_KEY_PROV_INFO_PROP_ID, 0, &prov_info)) {
481 av_log(NULL, AV_LOG_ERROR, "CertSetCertificateContextProperty(CERT_KEY_PROV_INFO_PROP_ID) failed: %lu\n", GetLastError());
482 ret = AVERROR_EXTERNAL;
483 goto fail;
484 }
485
486 goto end;
487
488fail:
489 if (*key)
490 if (NCryptDeleteKey(*key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
491 NCryptFreeObject(*key);
492 if (*crtctx)
493 CertFreeCertificateContext(*crtctx);
494
495 *key = 0;
496 *crtctx = NULL;
497
498end:
499 if (key_der)
500 av_free(key_der);
501 if (cert_der)
502 av_free(cert_der);
503 if (provider)
504 NCryptFreeObject(provider);
505 return ret;
506}
507
508static int tls_cert_from_store(void *logctx, const char *cert_store_name, const char *cert_subj, PCCERT_CONTEXT *crtctx)
509{
510 HCERTSTORE cert_store = NULL;
511 int ret = 0;
512
513 cert_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, cert_store_name);
514 if (!cert_store) {
515 av_log(logctx, AV_LOG_ERROR, "Opening user cert store %s failed\n", cert_store_name);
516 ret = AVERROR_EXTERNAL;
517 goto end;
518 }
519
520 *crtctx = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_A, cert_subj, NULL);
521 if (!*crtctx) {
522 av_log(logctx, AV_LOG_ERROR, "Could not find certificate in store\n");
523 ret = AVERROR_EXTERNAL;
524 goto end;
525 }
526
527end:
528 if (cert_store)
529 CertCloseStore(cert_store, 0);
530
531 return ret;
532}
533
534static int tls_load_key_cert(char *key_url, char *cert_url, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
535{
536 AVBPrint key_bp, cert_bp;
537 int ret = 0;
538
541
542 /* Read key file. */
543 ret = ff_url_read_all(key_url, &key_bp);
544 if (ret < 0) {
545 av_log(NULL, AV_LOG_ERROR, "Failed to open key file %s\n", key_url);
546 goto end;
547 }
548
549 ret = ff_url_read_all(cert_url, &cert_bp);
550 if (ret < 0) {
551 av_log(NULL, AV_LOG_ERROR, "Failed to open cert file %s\n", cert_url);
552 goto end;
553 }
554
555 ret = tls_import_key_cert(key_bp.str, cert_bp.str, key, crtctx);
556 if (ret < 0)
557 goto end;
558
559end:
560 av_bprint_finalize(&key_bp, NULL);
561 av_bprint_finalize(&cert_bp, NULL);
562
563 return ret;
564}
565
566int 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)
567{
568 NCRYPT_KEY_HANDLE key = 0;
569 PCCERT_CONTEXT crtctx = NULL;
570
571 int ret = tls_load_key_cert(key_url, cert_url, &key, &crtctx);
572 if (ret < 0)
573 goto end;
574
575 ret = tls_export_key_cert(key, crtctx, key_buf, key_sz, cert_buf, cert_sz, fingerprint);
576 if (ret < 0)
577 goto end;
578
579end:
580 if (key)
581 if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
582 NCryptFreeObject(key);
583 if (crtctx)
584 CertFreeCertificateContext(crtctx);
585
586 return ret;
587}
588
589typedef struct TLSContext {
590 TLSShared tls_shared;
591
594
595 CredHandle cred_handle;
596 TimeStamp cred_timestamp;
597
598 CtxtHandle ctxt_handle;
600 TimeStamp ctxt_timestamp;
601
604
605 uint8_t *enc_buf;
608
609 uint8_t *dec_buf;
612
613 char *send_buf;
616
617 SecPkgContext_StreamSizes sizes;
618
622
624} TLSContext;
625
627{
628 TLSContext *c = h->priv_data;
629 TLSShared *s = &c->tls_shared;
630
631 if (s->is_dtls)
632 c->tls_shared.udp = sock;
633 else
634 c->tls_shared.tcp = sock;
635
636 return 0;
637}
638
639int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
640{
641#if HAVE_SECPKGCONTEXT_KEYINGMATERIALINFO
642 TLSContext *c = h->priv_data;
643
644 SecPkgContext_KeyingMaterialInfo keying_info = { 0 };
645 SecPkgContext_KeyingMaterial keying_material = { 0 };
646
647 const char* dst = "EXTRACTOR-dtls_srtp";
648 SECURITY_STATUS sspi_ret;
649
650 if (!c->have_context)
651 return AVERROR(EINVAL);
652
653 keying_info.cbLabel = strlen(dst) + 1;
654 keying_info.pszLabel = (LPSTR)dst;
655 keying_info.cbContextValue = 0;
656 keying_info.pbContextValue = NULL;
657 keying_info.cbKeyingMaterial = materials_sz;
658
659 sspi_ret = SetContextAttributes(&c->ctxt_handle, SECPKG_ATTR_KEYING_MATERIAL_INFO, &keying_info, sizeof(keying_info));
660 if (sspi_ret != SEC_E_OK) {
661 av_log(h, AV_LOG_ERROR, "Setting keying material info failed: %lx\n", sspi_ret);
662 return AVERROR_EXTERNAL;
663 }
664
665 sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_KEYING_MATERIAL, &keying_material);
666 if (sspi_ret != SEC_E_OK) {
667 av_log(h, AV_LOG_ERROR, "Querying keying material failed: %lx\n", sspi_ret);
668 return AVERROR_EXTERNAL;
669 }
670
671 memcpy(dtls_srtp_materials, keying_material.pbKeyingMaterial, FFMIN(materials_sz, keying_material.cbKeyingMaterial));
672 FreeContextBuffer(keying_material.pbKeyingMaterial);
673
674 if (keying_material.cbKeyingMaterial > materials_sz) {
675 av_log(h, AV_LOG_WARNING, "Keying material size mismatch: %ld > %zu\n", keying_material.cbKeyingMaterial, materials_sz);
676 return AVERROR(ENOSPC);
677 }
678
679 return 0;
680#else
681 return AVERROR(ENOSYS);
682#endif
683}
684
685static void init_sec_buffer(SecBuffer *buffer, unsigned long type,
686 void *data, unsigned long size)
687{
688 buffer->cbBuffer = size;
689 buffer->BufferType = type;
690 buffer->pvBuffer = data;
691}
692
693static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers,
694 unsigned long buffer_count)
695{
696 desc->ulVersion = SECBUFFER_VERSION;
697 desc->pBuffers = buffers;
698 desc->cBuffers = buffer_count;
699}
700
702{
703 TLSContext *c = h->priv_data;
704 TLSShared *s = &c->tls_shared;
705 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
706 int ret;
707
708 if (!c->send_buf)
709 return 0;
710
711 ret = ffurl_write(uc, c->send_buf + c->send_buf_offset, c->send_buf_size - c->send_buf_offset);
712 if (ret == AVERROR(EAGAIN)) {
713 return AVERROR(EAGAIN);
714 } else if (ret < 0) {
715 av_log(h, AV_LOG_ERROR, "Writing encrypted data to socket failed\n");
716 return AVERROR(EIO);
717 }
718
719 c->send_buf_offset += ret;
720
721 if (c->send_buf_offset < c->send_buf_size)
722 return AVERROR(EAGAIN);
723
724 av_freep(&c->send_buf);
725 c->send_buf_size = c->send_buf_offset = 0;
726
727 return 0;
728}
729
731{
732 TLSContext *c = h->priv_data;
733 TLSShared *s = &c->tls_shared;
734 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
735 int ret;
736
737 if (c->connected) {
738 SecBufferDesc BuffDesc;
739 SecBuffer Buffer;
740 SECURITY_STATUS sspi_ret;
741 SecBuffer outbuf;
742 SecBufferDesc outbuf_desc;
743
744 DWORD dwshut = SCHANNEL_SHUTDOWN;
745 init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
746 init_sec_buffer_desc(&BuffDesc, &Buffer, 1);
747
750 if (ret < 0)
751 return ret;
752
753 sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc);
754 if (sspi_ret != SEC_E_OK)
755 av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n");
756
757 init_sec_buffer(&outbuf, SECBUFFER_TOKEN, NULL, 0);
758 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
759
760 do {
761 if (s->listen)
762 sspi_ret = AcceptSecurityContext(&c->cred_handle, &c->ctxt_handle, NULL, c->request_flags, 0,
763 &c->ctxt_handle, &outbuf_desc, &c->context_flags,
764 &c->ctxt_timestamp);
765 else
766 sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,
767 c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,
768 &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
769
770 if (outbuf.pvBuffer) {
771 if (outbuf.cbBuffer > 0) {
772 ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
773 if (ret < 0 || ret != outbuf.cbBuffer)
774 av_log(h, AV_LOG_ERROR, "Failed to send close message\n");
775 }
776 FreeContextBuffer(outbuf.pvBuffer);
777 }
778 } while(
779#ifdef SEC_I_MESSAGE_FRAGMENT
780 sspi_ret == SEC_I_MESSAGE_FRAGMENT ||
781#endif
782 sspi_ret == SEC_I_CONTINUE_NEEDED);
783
784 av_log(h, AV_LOG_DEBUG, "Close session result: 0x%lx\n", sspi_ret);
785
786 c->connected = 0;
787 }
788 return 0;
789}
790
792{
793 TLSContext *c = h->priv_data;
794 TLSShared *s = &c->tls_shared;
795
797
798 DeleteSecurityContext(&c->ctxt_handle);
799 FreeCredentialsHandle(&c->cred_handle);
800
801 av_freep(&c->enc_buf);
802 c->enc_buf_size = c->enc_buf_offset = 0;
803
804 av_freep(&c->dec_buf);
805 c->dec_buf_size = c->dec_buf_offset = 0;
806
807 av_freep(&c->send_buf);
808 c->send_buf_size = c->send_buf_offset = 0;
809
810 if (s->is_dtls) {
811 if (!s->external_sock)
812 ffurl_closep(&c->tls_shared.udp);
813 } else {
814 ffurl_closep(&c->tls_shared.tcp);
815 }
816
817 return 0;
818}
819
820static int tls_handshake_loop(URLContext *h, int initial)
821{
822 TLSContext *c = h->priv_data;
823 TLSShared *s = &c->tls_shared;
824 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
825 SECURITY_STATUS sspi_ret;
826 SecBuffer outbuf[3] = { 0 };
827 SecBufferDesc outbuf_desc;
828 SecBuffer inbuf[3];
829 SecBufferDesc inbuf_desc;
830 struct sockaddr_storage recv_addr = { 0 };
831 socklen_t recv_addr_len = 0;
832 int i, ret = 0, read_data = initial;
833
834 if (c->enc_buf == NULL) {
835 c->enc_buf_offset = 0;
837 if (ret < 0)
838 goto fail;
839 c->enc_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
840 }
841
842 if (c->dec_buf == NULL) {
843 c->dec_buf_offset = 0;
845 if (ret < 0)
846 goto fail;
847 c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE;
848 }
849
851
852 while (1) {
853 if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) {
854 c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
855 ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
856 if (ret < 0) {
857 c->enc_buf_size = c->enc_buf_offset = 0;
858 goto fail;
859 }
860 }
861
862 if (read_data) {
863 ret = ffurl_read(uc, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset);
864 if (ret < 0) {
865 av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n");
866 goto fail;
867 }
868 c->enc_buf_offset += ret;
869 if (s->is_dtls && !recv_addr_len) {
870 ff_udp_get_last_recv_addr(uc, &recv_addr, &recv_addr_len);
871
872 if (s->listen) {
873 ret = ff_udp_set_remote_addr(uc, (struct sockaddr *)&recv_addr, recv_addr_len, 1);
874 if (ret < 0) {
875 av_log(h, AV_LOG_ERROR, "Failed connecting udp context\n");
876 goto fail;
877 }
878 av_log(h, AV_LOG_TRACE, "Set UDP remote addr on UDP socket, now 'connected'\n");
879 }
880 }
881 }
882
883 /* input buffers */
884 init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset);
885 init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
886 if (s->listen && s->is_dtls) {
887 init_sec_buffer(&inbuf[2], SECBUFFER_EXTRA, &recv_addr, recv_addr_len);
888 init_sec_buffer_desc(&inbuf_desc, inbuf, 3);
889 } else {
890 init_sec_buffer_desc(&inbuf_desc, inbuf, 2);
891 }
892
893 if (inbuf[0].pvBuffer == NULL) {
894 av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n");
895 ret = AVERROR(ENOMEM);
896 goto fail;
897 }
898
899 memcpy(inbuf[0].pvBuffer, c->enc_buf, c->enc_buf_offset);
900
901 /* output buffers */
902 init_sec_buffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
903 init_sec_buffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
904 init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
905 init_sec_buffer_desc(&outbuf_desc, outbuf, 3);
906
907 if (s->listen)
908 sspi_ret = AcceptSecurityContext(&c->cred_handle, c->have_context ? &c->ctxt_handle : NULL, &inbuf_desc,
909 c->request_flags, 0, &c->ctxt_handle, &outbuf_desc,
910 &c->context_flags, &c->ctxt_timestamp);
911 else
912 sspi_ret = InitializeSecurityContext(&c->cred_handle, c->have_context ? &c->ctxt_handle : NULL,
913 s->host, c->request_flags, 0, 0, &inbuf_desc, 0, &c->ctxt_handle,
914 &outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
915 av_freep(&inbuf[0].pvBuffer);
916
917 av_log(h, AV_LOG_TRACE, "Handshake res with %d bytes of data: 0x%lx\n", c->enc_buf_offset, sspi_ret);
918
919 if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
920 av_log(h, AV_LOG_TRACE, "Received incomplete handshake, need more data\n");
921 read_data = 1;
922 continue;
923 }
924
925 c->have_context = 1;
926
927 /* remote requests a client certificate - attempt to continue without one anyway */
928 if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS &&
929 !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
930 av_log(h, AV_LOG_WARNING, "Server requested a client certificate\n");
931 c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
932 read_data = 0;
933 continue;
934 }
935
936 /* continue handshake */
937 if (sspi_ret == SEC_I_CONTINUE_NEEDED ||
938#ifdef SEC_I_MESSAGE_FRAGMENT
939 sspi_ret == SEC_I_MESSAGE_FRAGMENT ||
940#endif
941 sspi_ret == SEC_E_OK) {
942 for (i = 0; i < 3; i++) {
943 if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
944 ret = ffurl_write(uc, outbuf[i].pvBuffer, outbuf[i].cbBuffer);
945 if (ret < 0 || ret != outbuf[i].cbBuffer) {
946 av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n");
947 ret = AVERROR(EIO);
948 goto fail;
949 }
950 }
951
952 if (outbuf[i].pvBuffer != NULL) {
953 FreeContextBuffer(outbuf[i].pvBuffer);
954 outbuf[i].pvBuffer = NULL;
955 }
956 }
957 } else {
958 if (sspi_ret == SEC_E_WRONG_PRINCIPAL)
959 av_log(h, AV_LOG_ERROR, "SNI or certificate check failed\n");
960 else
961 av_log(h, AV_LOG_ERROR, "Creating security context failed (0x%lx)\n", sspi_ret);
962 ret = AVERROR_UNKNOWN;
963 goto fail;
964 }
965
966#ifdef SEC_I_MESSAGE_FRAGMENT
967 if (sspi_ret == SEC_I_MESSAGE_FRAGMENT) {
968 av_log(h, AV_LOG_TRACE, "Writing fragmented output message part\n");
969 read_data = 0;
970 continue;
971 }
972#endif
973
974 if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
975 if (c->enc_buf_offset > inbuf[1].cbBuffer) {
976 memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer,
977 inbuf[1].cbBuffer);
978 c->enc_buf_offset = inbuf[1].cbBuffer;
979 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
980 av_log(h, AV_LOG_TRACE, "Sent reply, handshake continues. %d extra bytes\n", (int)inbuf[1].cbBuffer);
981 read_data = 0;
982 continue;
983 }
984 }
985 } else {
986 c->enc_buf_offset = 0;
987 }
988
989 if (sspi_ret == SEC_I_CONTINUE_NEEDED) {
990 av_log(h, AV_LOG_TRACE, "Handshake continues\n");
991 read_data = 1;
992 continue;
993 }
994
995 break;
996 }
997
998 av_log(h, AV_LOG_TRACE, "Handshake completed\n");
999
1000 return 0;
1001
1002fail:
1003 /* free any remaining output data */
1004 for (i = 0; i < 3; i++) {
1005 if (outbuf[i].pvBuffer != NULL) {
1006 FreeContextBuffer(outbuf[i].pvBuffer);
1007 outbuf[i].pvBuffer = NULL;
1008 }
1009 }
1010
1011 av_log(h, AV_LOG_TRACE, "Handshake failed\n");
1012
1013 return ret;
1014}
1015
1017{
1018 TLSContext *c = h->priv_data;
1019 TLSShared *s = &c->tls_shared;
1020 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
1021 SecBuffer outbuf;
1022 SecBufferDesc outbuf_desc;
1023 SECURITY_STATUS sspi_ret;
1024 int ret;
1025
1026 init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
1027 init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
1028
1029 c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
1030 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY;
1031 if (s->is_dtls)
1032 c->request_flags |= ISC_REQ_DATAGRAM;
1033 else
1034 c->request_flags |= ISC_REQ_STREAM;
1035 if (c->have_private_cert)
1036 c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1037
1038 sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0,
1039 NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags,
1040 &c->ctxt_timestamp);
1041 if (sspi_ret != SEC_I_CONTINUE_NEEDED) {
1042 av_log(h, AV_LOG_ERROR, "Unable to create initial security context (0x%lx)\n", sspi_ret);
1043 ret = AVERROR_UNKNOWN;
1044 goto fail;
1045 }
1046
1047 c->have_context = 1;
1048
1050 ret = ffurl_write(uc, outbuf.pvBuffer, outbuf.cbBuffer);
1051 FreeContextBuffer(outbuf.pvBuffer);
1052 if (ret < 0 || ret != outbuf.cbBuffer) {
1053 av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n");
1054 ret = AVERROR(EIO);
1055 goto fail;
1056 }
1057
1058 return tls_handshake_loop(h, 1);
1059
1060fail:
1061 DeleteSecurityContext(&c->ctxt_handle);
1062 return ret;
1063}
1064
1066{
1067 TLSContext *c = h->priv_data;
1068 TLSShared *s = &c->tls_shared;
1069
1070 c->request_flags = ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT |
1071 ASC_REQ_CONFIDENTIALITY | ASC_REQ_ALLOCATE_MEMORY;
1072 if (s->is_dtls)
1073 c->request_flags |= ASC_REQ_DATAGRAM;
1074 else
1075 c->request_flags |= ASC_REQ_STREAM;
1076
1077 c->have_context = 0;
1078
1079 return tls_handshake_loop(h, 1);
1080}
1081
1083{
1084 TLSContext *c = h->priv_data;
1085 TLSShared *s = &c->tls_shared;
1086 SECURITY_STATUS sspi_ret;
1087 int ret = 0;
1088
1089 if (s->listen)
1090 ret = tls_server_handshake(h);
1091 else
1092 ret = tls_client_handshake(h);
1093
1094 if (ret < 0)
1095 goto fail;
1096
1097#if CONFIG_DTLS_PROTOCOL
1098 if (s->is_dtls && s->mtu > 0) {
1099 ULONG mtu = s->mtu;
1100 sspi_ret = SetContextAttributes(&c->ctxt_handle, SECPKG_ATTR_DTLS_MTU, &mtu, sizeof(mtu));
1101 if (sspi_ret != SEC_E_OK) {
1102 av_log(h, AV_LOG_ERROR, "Failed setting DTLS MTU to %d.\n", s->mtu);
1103 ret = AVERROR(EINVAL);
1104 goto fail;
1105 }
1106 av_log(h, AV_LOG_VERBOSE, "Set DTLS MTU to %d\n", s->mtu);
1107 }
1108#endif
1109
1110 c->connected = 1;
1111
1112fail:
1113 return ret;
1114}
1115
1116static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
1117{
1118 TLSContext *c = h->priv_data;
1119 TLSShared *s = &c->tls_shared;
1120 SECURITY_STATUS sspi_ret;
1121 SCHANNEL_CRED schannel_cred = { 0 };
1122 PCCERT_CONTEXT crtctx = NULL;
1123 NCRYPT_KEY_HANDLE key = 0;
1124 int ret = 0;
1125
1126 if (!s->external_sock) {
1127 if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
1128 goto fail;
1129 }
1130
1131 /* SChannel Options */
1132 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
1133
1134 if (c->cert_store_name && c->cert_store_subject) {
1135 ret = tls_cert_from_store(h, c->cert_store_name, c->cert_store_subject, &crtctx);
1136 } else if (s->key_buf && s->cert_buf) {
1137 ret = tls_import_key_cert(s->key_buf, s->cert_buf, &key, &crtctx);
1138 } else if (s->key_file && s->cert_file) {
1139 ret = tls_load_key_cert(s->key_file, s->cert_file, &key, &crtctx);
1140 } else if (!s->listen && (s->key_buf || s->cert_buf || s->key_file || s->cert_file)) {
1141 av_log(h, AV_LOG_WARNING, "Both cert and key of same kind required, ignoring\n");
1142 } else if (s->listen) {
1143 av_log(h, AV_LOG_VERBOSE, "No server certificate provided, using self-signed\n");
1144 ret = tls_gen_self_signed(&key, &crtctx);
1145 }
1146
1147 if (ret < 0)
1148 goto fail;
1149
1150 if (crtctx) {
1151 schannel_cred.cCreds = 1;
1152 schannel_cred.paCred = &crtctx;
1153 c->have_private_cert = 1;
1154 }
1155
1156 if (s->listen) {
1157 schannel_cred.dwFlags = SCH_CRED_NO_SYSTEM_MAPPER | SCH_CRED_MANUAL_CRED_VALIDATION;
1158
1159#if CONFIG_DTLS_PROTOCOL
1160 if (s->is_dtls)
1161 schannel_cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_SERVER;
1162#endif
1163 } else {
1164 if (s->verify)
1165 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
1166 SCH_CRED_REVOCATION_CHECK_CHAIN;
1167 else
1168 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
1169 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
1170 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
1171 schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
1172
1173#if CONFIG_DTLS_PROTOCOL
1174 if (s->is_dtls)
1175 schannel_cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_CLIENT;
1176#endif
1177 }
1178
1179 /* Get credential handle */
1180 sspi_ret = AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
1181 s->listen ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
1182 NULL, &schannel_cred, NULL, NULL, &c->cred_handle,
1183 &c->cred_timestamp);
1184 if (sspi_ret != SEC_E_OK) {
1185 av_log(h, AV_LOG_ERROR, "Unable to acquire security credentials (0x%lx)\n", sspi_ret);
1186 ret = AVERROR_UNKNOWN;
1187 goto fail;
1188 }
1189
1190 if (!s->external_sock) {
1191 ret = tls_handshake(h);
1192 if (ret < 0)
1193 goto fail;
1194 }
1195
1196 goto end;
1197
1198fail:
1199 tls_close(h);
1200
1201end:
1202 if (crtctx)
1203 CertFreeCertificateContext(crtctx);
1204 if (key)
1205 if (NCryptDeleteKey(key, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
1206 NCryptFreeObject(key);
1207
1208 return ret;
1209}
1210
1211#if CONFIG_DTLS_PROTOCOL
1212static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
1213{
1214 TLSContext *c = h->priv_data;
1215 TLSShared *s = &c->tls_shared;
1216
1217 s->is_dtls = 1;
1218
1219 return tls_open(h, uri, flags, options);
1220}
1221#endif
1222
1223static int tls_read(URLContext *h, uint8_t *buf, int len)
1224{
1225 TLSContext *c = h->priv_data;
1226 TLSShared *s = &c->tls_shared;
1227 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
1228 SECURITY_STATUS sspi_ret = SEC_E_OK;
1229 SecBuffer inbuf[4];
1230 SecBufferDesc inbuf_desc;
1231 int size, ret = 0;
1232 int min_enc_buf_size = len + SCHANNEL_FREE_BUFFER_SIZE;
1233
1234 /* If we have some left-over data from previous network activity,
1235 * return it first in case it is enough. It may contain
1236 * data that is required to know whether this connection
1237 * is still required or not, esp. in case of HTTP keep-alive
1238 * connections. */
1239 if (c->dec_buf_offset > 0)
1240 goto cleanup;
1241
1242 if (c->sspi_close_notify)
1243 goto cleanup;
1244
1245 if (!c->connection_closed) {
1246 size = c->enc_buf_size - c->enc_buf_offset;
1247 if (size < SCHANNEL_FREE_BUFFER_SIZE || c->enc_buf_size < min_enc_buf_size) {
1248 c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE;
1249 if (c->enc_buf_size < min_enc_buf_size)
1250 c->enc_buf_size = min_enc_buf_size;
1251 ret = av_reallocp(&c->enc_buf, c->enc_buf_size);
1252 if (ret < 0) {
1253 c->enc_buf_size = c->enc_buf_offset = 0;
1254 return ret;
1255 }
1256 }
1257
1259 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1260
1261 ret = ffurl_read(uc, c->enc_buf + c->enc_buf_offset,
1262 c->enc_buf_size - c->enc_buf_offset);
1263 if (ret == AVERROR_EOF) {
1264 c->connection_closed = 1;
1265 ret = 0;
1266 } else if (ret == AVERROR(EAGAIN)) {
1267 ret = 0;
1268 } else if (ret < 0) {
1269 av_log(h, AV_LOG_ERROR, "Unable to read from socket\n");
1270 return ret;
1271 }
1272
1273 c->enc_buf_offset += ret;
1274 }
1275
1276 while (c->enc_buf_offset > 0 && sspi_ret == SEC_E_OK) {
1277 /* input buffer */
1278 init_sec_buffer(&inbuf[0], SECBUFFER_DATA, c->enc_buf, c->enc_buf_offset);
1279
1280 /* additional buffers for possible output */
1281 init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1282 init_sec_buffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1283 init_sec_buffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1284 init_sec_buffer_desc(&inbuf_desc, inbuf, 4);
1285
1286 sspi_ret = DecryptMessage(&c->ctxt_handle, &inbuf_desc, 0, NULL);
1287 if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_RENEGOTIATE ||
1288 sspi_ret == SEC_I_CONTEXT_EXPIRED) {
1289 /* handle decrypted data */
1290 if (inbuf[1].BufferType == SECBUFFER_DATA) {
1291 /* grow buffer if needed */
1292 size = inbuf[1].cbBuffer > SCHANNEL_FREE_BUFFER_SIZE ?
1293 inbuf[1].cbBuffer : SCHANNEL_FREE_BUFFER_SIZE;
1294 if (c->dec_buf_size - c->dec_buf_offset < size || c->dec_buf_size < len) {
1295 c->dec_buf_size = c->dec_buf_offset + size;
1296 if (c->dec_buf_size < len)
1297 c->dec_buf_size = len;
1298 ret = av_reallocp(&c->dec_buf, c->dec_buf_size);
1299 if (ret < 0) {
1300 c->dec_buf_size = c->dec_buf_offset = 0;
1301 return ret;
1302 }
1303 }
1304
1305 /* copy decrypted data to buffer */
1306 size = inbuf[1].cbBuffer;
1307 if (size) {
1308 memcpy(c->dec_buf + c->dec_buf_offset, inbuf[1].pvBuffer, size);
1309 c->dec_buf_offset += size;
1310 }
1311 }
1312 if (inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1313 if (c->enc_buf_offset > inbuf[3].cbBuffer) {
1314 memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[3].cbBuffer,
1315 inbuf[3].cbBuffer);
1316 c->enc_buf_offset = inbuf[3].cbBuffer;
1317 }
1318 } else
1319 c->enc_buf_offset = 0;
1320
1321 if (sspi_ret == SEC_I_RENEGOTIATE) {
1322 if (c->enc_buf_offset) {
1323 av_log(h, AV_LOG_ERROR, "Cannot renegotiate, encrypted data buffer not empty\n");
1324 ret = AVERROR_UNKNOWN;
1325 goto cleanup;
1326 }
1327
1328 av_log(h, AV_LOG_VERBOSE, "Re-negotiating security context\n");
1329 ret = tls_handshake_loop(h, 0);
1330 if (ret < 0) {
1331 goto cleanup;
1332 }
1333 sspi_ret = SEC_E_OK;
1334
1335 /* if somehow any send data was left, it is now invalid */
1336 av_freep(&c->send_buf);
1337 c->send_buf_size = c->send_buf_offset = 0;
1338
1339 continue;
1340 } else if (sspi_ret == SEC_I_CONTEXT_EXPIRED) {
1341 c->sspi_close_notify = 1;
1342 if (!c->connection_closed) {
1343 c->connection_closed = 1;
1344 av_log(h, AV_LOG_VERBOSE, "Server closed the connection\n");
1345 }
1346 ret = 0;
1347 goto cleanup;
1348 }
1349 } else if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) {
1350 ret = AVERROR(EAGAIN);
1351 goto cleanup;
1352 } else {
1353 av_log(h, AV_LOG_ERROR, "Unable to decrypt message (error 0x%x)\n", (unsigned)sspi_ret);
1354 ret = AVERROR(EIO);
1355 goto cleanup;
1356 }
1357 }
1358
1359 ret = 0;
1360
1361cleanup:
1362 size = FFMIN(len, c->dec_buf_offset);
1363 if (size) {
1364 memcpy(buf, c->dec_buf, size);
1365 memmove(c->dec_buf, c->dec_buf + size, c->dec_buf_offset - size);
1366 c->dec_buf_offset -= size;
1367
1368 return size;
1369 }
1370
1371 if (ret == 0 && !c->connection_closed)
1372 ret = AVERROR(EAGAIN);
1373
1374 return ret < 0 ? ret : AVERROR_EOF;
1375}
1376
1377static int tls_write(URLContext *h, const uint8_t *buf, int len)
1378{
1379 TLSContext *c = h->priv_data;
1380 TLSShared *s = &c->tls_shared;
1381 URLContext *uc = s->is_dtls ? s->udp : s->tcp;
1382 SECURITY_STATUS sspi_ret;
1383 SecBuffer outbuf[4];
1384 SecBufferDesc outbuf_desc;
1385 int ret = 0;
1386
1388 uc->flags |= h->flags & AVIO_FLAG_NONBLOCK;
1389
1391 if (ret < 0)
1392 return ret;
1393
1394 if (c->sizes.cbMaximumMessage == 0) {
1395 sspi_ret = QueryContextAttributes(&c->ctxt_handle, SECPKG_ATTR_STREAM_SIZES, &c->sizes);
1396 if (sspi_ret != SEC_E_OK)
1397 return AVERROR_UNKNOWN;
1398 }
1399
1400 /* limit how much data we can consume */
1401 len = FFMIN(len, c->sizes.cbMaximumMessage - c->sizes.cbHeader - c->sizes.cbTrailer);
1402
1403 c->send_buf_size = c->sizes.cbHeader + len + c->sizes.cbTrailer;
1404 c->send_buf = av_malloc(c->send_buf_size);
1405 if (c->send_buf == NULL)
1406 return AVERROR(ENOMEM);
1407
1408 init_sec_buffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1409 c->send_buf, c->sizes.cbHeader);
1410 init_sec_buffer(&outbuf[1], SECBUFFER_DATA,
1411 c->send_buf + c->sizes.cbHeader, len);
1412 init_sec_buffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1413 c->send_buf + c->sizes.cbHeader + len,
1414 c->sizes.cbTrailer);
1415 init_sec_buffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1416 init_sec_buffer_desc(&outbuf_desc, outbuf, 4);
1417
1418 memcpy(outbuf[1].pvBuffer, buf, len);
1419
1420 sspi_ret = EncryptMessage(&c->ctxt_handle, 0, &outbuf_desc, 0);
1421 if (sspi_ret != SEC_E_OK) {
1422 av_freep(&c->send_buf);
1423 av_log(h, AV_LOG_ERROR, "Encrypting data failed\n");
1424 if (sspi_ret == SEC_E_INSUFFICIENT_MEMORY)
1425 return AVERROR(ENOMEM);
1426 return AVERROR(EIO);
1427 }
1428
1429 c->send_buf_size = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1430 c->send_buf_offset = 0;
1431
1433 if (ret == AVERROR(EAGAIN)) {
1434 /* We always need to signal that we consumed all (encrypted) data since schannel must not
1435 be fed the same data again. Sending will then be completed next call to this function,
1436 and EAGAIN returned until all remaining buffer is sent. */
1437 return outbuf[1].cbBuffer;
1438 } else if (ret < 0) {
1439 return ret;
1440 }
1441
1442 return outbuf[1].cbBuffer;
1443}
1444
1446{
1447 TLSContext *c = h->priv_data;
1448 TLSShared *s = &c->tls_shared;
1449 return ffurl_get_file_handle(s->is_dtls ? s->udp : s->tcp);
1450}
1451
1453{
1454 TLSContext *c = h->priv_data;
1455 TLSShared *s = &c->tls_shared;
1456 return ffurl_get_short_seek(s->is_dtls ? s->udp : s->tcp);
1457}
1458
1459#define OFFSET(x) offsetof(TLSContext, x)
1460static const AVOption options[] = {
1461 TLS_COMMON_OPTIONS(TLSContext, tls_shared),
1462 { "cert_store_subject", "Load certificate (and associated key) from users keystore by subject",
1463 OFFSET(cert_store_subject), AV_OPT_TYPE_STRING, .flags = TLS_OPTFL },
1464 { "cert_store_name", "Name of the specific cert store to search in (for cert_store_subject)",
1465 OFFSET(cert_store_name), AV_OPT_TYPE_STRING, { .str = "MY" }, .flags = TLS_OPTFL },
1466 { NULL }
1467};
1468
1469#if CONFIG_TLS_PROTOCOL
1470static const AVClass tls_class = {
1471 .class_name = "tls",
1472 .item_name = av_default_item_name,
1473 .option = options,
1474 .version = LIBAVUTIL_VERSION_INT,
1475};
1476
1478 .name = "tls",
1479 .url_open2 = tls_open,
1480 .url_read = tls_read,
1481 .url_write = tls_write,
1482 .url_close = tls_close,
1483 .url_get_file_handle = tls_get_file_handle,
1484 .url_get_short_seek = tls_get_short_seek,
1485 .priv_data_size = sizeof(TLSContext),
1487 .priv_data_class = &tls_class,
1488};
1489#endif
1490
1491#if CONFIG_DTLS_PROTOCOL
1492static const AVClass dtls_class = {
1493 .class_name = "dtls",
1494 .item_name = av_default_item_name,
1495 .option = options,
1496 .version = LIBAVUTIL_VERSION_INT,
1497};
1498
1500 .name = "dtls",
1501 .url_open2 = dtls_open,
1502 .url_handshake = tls_handshake,
1503 .url_close = tls_close,
1504 .url_read = tls_read,
1505 .url_write = tls_write,
1506 .url_get_file_handle = tls_get_file_handle,
1507 .url_get_short_seek = tls_get_short_seek,
1508 .priv_data_size = sizeof(TLSContext),
1510 .priv_data_class = &dtls_class,
1511};
1512#endif
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static uint8_t hash[HASH_SIZE]
#define L(x)
Definition vpx_arith.h:36
Main libavformat public API header.
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:663
int ffurl_get_short_seek(void *urlcontext)
Return the current short seek threshold value for this URL.
Definition avio.c:913
int ffurl_get_file_handle(URLContext *h)
Return the file descriptor associated with this URL.
Definition avio.c:889
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition avio.h:636
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:121
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:68
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
static int read_data(void *opaque, uint8_t *buf, int buf_size)
Definition dashdec.c:1848
const char * key
static av_cold void cleanup(FlashSV2Context *s)
#define fail
Definition test.h:479
@ 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:275
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:234
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition bprint.c:84
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition log.h:236
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
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:289
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
uint32_t type
Definition jpegmpfenc.c:80
const char * desc
Definition libsvtav1.c:83
#define FFMIN(a, b)
Definition macros.h:49
Memory handling functions.
const char data[16]
Definition mxf.c:149
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:472
void ff_udp_get_last_recv_addr(URLContext *h, struct sockaddr_storage *addr, socklen_t *addr_len)
Definition udp.c:510
#define av_malloc(s)
Definition ops_static.c:52
miscellaneous OS support macros and functions.
const URLProtocol ff_dtls_protocol
Definition tls_gnutls.c:791
const URLProtocol ff_tls_protocol
Definition tls_gnutls.c:771
static const uint8_t header[24]
Definition sdr2.c:68
#define FF_ARRAY_ELEMS(a)
Describe the class of an AVClass context structure.
Definition log.h:76
AVOption.
Definition opt.h:428
CredHandle cred_handle
char * cert_store_subject
int connection_closed
int have_private_cert
uint8_t * enc_buf
TimeStamp cred_timestamp
TimeStamp ctxt_timestamp
ULONG request_flags
char * send_buf
int sspi_close_notify
char * cert_store_name
int send_buf_offset
SecPkgContext_StreamSizes sizes
CtxtHandle ctxt_handle
uint8_t * dec_buf
TLSShared tls_shared
Definition tls_gnutls.c:337
ULONG context_flags
int flags
Definition url.h:40
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
static char buffer[20]
Definition seek.c:32
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:128
int ff_tls_open_underlying(TLSShared *c, URLContext *parent, const char *uri, AVDictionary **options)
Definition tls.c:54
#define MAX_CERTIFICATE_SIZE
Maximum size limit of a certificate and private key size.
Definition tls.h:34
#define TLS_COMMON_OPTIONS(pstruct, options_field)
Definition tls.h:101
#define TLS_OPTFL
Definition tls.h:88
static int tls_handshake(URLContext *h)
Definition tls_gnutls.c:506
static int tls_close(URLContext *h)
Definition tls_gnutls.c:419
static const AVClass tls_class
Definition tls_gnutls.c:764
static int tls_read(URLContext *h, uint8_t *buf, int size)
Definition tls_gnutls.c:707
static int dtls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition tls_gnutls.c:699
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
Definition tls_gnutls.c:532
static int tls_get_short_seek(URLContext *h)
Definition tls_gnutls.c:753
static int tls_write(URLContext *h, const uint8_t *buf, int size)
Definition tls_gnutls.c:724
static const AVClass dtls_class
Definition tls_gnutls.c:784
static int tls_get_file_handle(URLContext *h)
Definition tls_gnutls.c:747
#define FF_NCRYPT_TEMP_KEY_NAME
static int tls_handshake(URLContext *h)
static int tls_close(URLContext *h)
static int tls_load_key_cert(char *key_url, char *cert_url, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
static void init_sec_buffer_desc(SecBufferDesc *desc, SecBuffer *buffers, unsigned long buffer_count)
static int tls_handshake_loop(URLContext *h, int initial)
static int pem_to_der(const char *pem, char **buf, int *out_len)
static int tls_server_handshake(URLContext *h)
static int tls_read(URLContext *h, uint8_t *buf, int len)
int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
static int tls_shutdown_client(URLContext *h)
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)
static int tls_write(URLContext *h, const uint8_t *buf, int len)
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)
static int der_to_fingerprint(const char *data, size_t len, char **fingerprint)
static int tls_client_handshake(URLContext *h)
int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz)
static int tls_cert_from_store(void *logctx, const char *cert_store_name, const char *cert_subj, PCCERT_CONTEXT *crtctx)
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
static void init_sec_buffer(SecBuffer *buffer, unsigned long type, void *data, unsigned long size)
#define SCHANNEL_INITIAL_BUFFER_SIZE
static int tls_get_short_seek(URLContext *h)
static int tls_import_key_cert(char *key_buf, char *cert_buf, NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
static int der_to_pem(const char *data, size_t len, const char *header, char *buf, size_t bufsize)
#define OFFSET(x)
static int tls_get_file_handle(URLContext *h)
static int tls_process_send_buffer(URLContext *h)
int ff_tls_set_external_socket(URLContext *h, URLContext *sock)
#define SECBUFFER_ALERT
static int tls_gen_self_signed(NCRYPT_KEY_HANDLE *key, PCCERT_CONTEXT *crtctx)
#define SCHANNEL_FREE_BUFFER_SIZE
int size
unbuffered private I/O API
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:205
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:184
#define URL_PROTOCOL_FLAG_NETWORK
Definition url.h:33
int len
static double c[64]