2 * Copyright (c) 2015 Hendrik Leppkes
4 * This file is part of FFmpeg.
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.
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.
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
21 /** Based on the CURL SChannel module */
24 #include "config_components.h"
26 #include "libavutil/mem.h"
30 #include "os_support.h"
34 #define SECURITY_WIN32
40 #define SCHANNEL_INITIAL_BUFFER_SIZE 4096
41 #define SCHANNEL_FREE_BUFFER_SIZE 1024
43 /* mingw does not define this symbol */
44 #ifndef SECBUFFER_ALERT
45 #define SECBUFFER_ALERT 17
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
55 * Apparently this is because SChannel neglects marshaling the
56 * private key alongside the certificate for the out-of-process
58 * See this GitHub issue for the most detailed explanation out there:
59 * https://github.com/dotnet/runtime/issues/23749#issuecomment-485947319
61 #define FF_NCRYPT_TEMP_KEY_NAME L"FFMPEG_TEMP_TLS_KEY"
63 static int der_to_pem(const char *data
, size_t len
, const char *header
, char *buf
, size_t bufsize
)
65 const int line_length
= 64;
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
;
77 base64
= av_malloc(base64len
);
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
;
85 av_bprint_init_for_buffer(&pem
, buf
, bufsize
);
86 av_bprintf(&pem
, "-----BEGIN %s-----\n", header
);
88 for (DWORD i
= 0; i
< base64len
; i
+= line_length
) {
89 av_bprintf(&pem
, "%.*s\n", line_length
, base64
+ i
);
92 av_bprintf(&pem
, "-----END %s-----\n", header
);
94 if (!av_bprint_is_complete(&pem
)) {
95 ret
= AVERROR(ENOSPC
);
104 static int pem_to_der(const char *pem
, char **buf
, int *out_len
)
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
);
113 *buf
= av_malloc(derlen
);
115 return AVERROR(ENOMEM
);
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
);
127 static int der_to_fingerprint(const char *data
, size_t len
, char **fingerprint
)
130 unsigned char hash
[32];
131 DWORD hashsize
= sizeof(hash
);
133 if (!CryptHashCertificate2(BCRYPT_SHA256_ALGORITHM
, 0, NULL
, data
, len
, hash
, &hashsize
))
135 av_log(NULL
, AV_LOG_ERROR
, "CryptHashCertificate2 failed\n");
136 return AVERROR_EXTERNAL
;
139 av_bprint_init(&buf
, hashsize
*3, hashsize
*3);
141 for (int i
= 0; i
< hashsize
- 1; i
++)
142 av_bprintf(&buf
, "%02X:", hash
[i
]);
143 av_bprintf(&buf
, "%02X", hash
[hashsize
- 1]);
145 return av_bprint_finalize(&buf
, fingerprint
);
148 static int tls_gen_self_signed(NCRYPT_KEY_HANDLE
*key
, PCCERT_CONTEXT
*crtctx
)
150 NCRYPT_PROV_HANDLE provider
= 0;
151 CERT_NAME_BLOB subject
= { 0 };
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";
168 SECURITY_STATUS sspi_ret
;
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
;
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
;
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
;
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
;
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
;
208 if (!CertStrToNameA(X509_ASN_ENCODING
, subj_str
, 0, NULL
, NULL
, &subject
.cbData
, NULL
))
210 av_log(NULL
, AV_LOG_ERROR
, "Initial subj init failed\n");
211 ret
= AVERROR_EXTERNAL
;
215 subject
.pbData
= av_malloc(subject
.cbData
);
216 if (!subject
.pbData
) {
217 ret
= AVERROR(ENOMEM
);
221 if (!CertStrToNameA(X509_ASN_ENCODING
, subj_str
, 0, NULL
, subject
.pbData
, &subject
.cbData
, NULL
))
223 av_log(NULL
, AV_LOG_ERROR
, "Subj init failed\n");
224 ret
= AVERROR_EXTERNAL
;
228 // Extended Key Usage extension
229 eku
.cUsageIdentifier
= 1;
230 eku
.rgpszUsageIdentifier
= (LPSTR
*)ext_usages
;
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
;
239 ext
[0].pszObjId
= (LPSTR
)szOID_ENHANCED_KEY_USAGE
;
240 ext
[0].fCritical
= TRUE
;
242 // Key usage extension
243 key_usage_blob
.cbData
= sizeof(key_usage
);
244 key_usage_blob
.pbData
= &key_usage
;
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
;
253 ext
[1].pszObjId
= (LPSTR
)szOID_KEY_USAGE
;
254 ext
[1].fCritical
= TRUE
;
256 // Cert Basic Constraints
257 basic_constraints
.fCA
= FALSE
;
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
;
266 ext
[2].pszObjId
= (LPSTR
)szOID_BASIC_CONSTRAINTS2
;
267 ext
[2].fCritical
= TRUE
;
270 san_entry
.dwAltNameChoice
= CERT_ALT_NAME_DNS_NAME
;
271 san_entry
.pwszDNSName
= (LPWSTR
)L
"localhost";
273 san_info
.cAltEntry
= 1;
274 san_info
.rgAltEntry
= &san_entry
;
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
;
283 ext
[3].pszObjId
= (LPSTR
)szOID_SUBJECT_ALT_NAME2
;
284 ext
[3].fCritical
= TRUE
;
287 exts
.rgExtension
= ext
;
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
;
293 *crtctx
= CertCreateSelfSignCertificate(*key
, &subject
, 0, &prov_info
, &sig_alg
, NULL
, NULL
, &exts
);
295 av_log(NULL
, AV_LOG_ERROR
, "CertCreateSelfSignCertificate failed: %lu\n", GetLastError());
296 ret
= AVERROR_EXTERNAL
;
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
);
309 CertFreeCertificateContext(*crtctx
);
311 if (NCryptDeleteKey(*key
, NCRYPT_SILENT_FLAG
) != ERROR_SUCCESS
)
312 NCryptFreeObject(*key
);
314 NCryptFreeObject(provider
);
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
);
327 static 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
)
333 SECURITY_STATUS sspi_ret
;
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
;
343 keybuf
= av_malloc(keysize
);
345 ret
= AVERROR(ENOMEM
);
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
;
356 ret
= der_to_pem(keybuf
, keysize
, "PRIVATE KEY", key_buf
, key_sz
);
360 ret
= der_to_pem(crtctx
->pbCertEncoded
, crtctx
->cbCertEncoded
, "CERTIFICATE", cert_buf
, cert_sz
);
364 ret
= der_to_fingerprint(crtctx
->pbCertEncoded
, crtctx
->cbCertEncoded
, fingerprint
);
373 int ff_ssl_gen_key_cert(char *key_buf
, size_t key_sz
, char *cert_buf
, size_t cert_sz
, char **fingerprint
)
375 NCRYPT_KEY_HANDLE key
= 0;
376 PCCERT_CONTEXT crtctx
= NULL
;
378 int ret
= tls_gen_self_signed(&key
, &crtctx
);
382 ret
= tls_export_key_cert(key
, crtctx
, key_buf
, key_sz
, cert_buf
, cert_sz
, fingerprint
);
388 if (NCryptDeleteKey(key
, NCRYPT_SILENT_FLAG
) != ERROR_SUCCESS
)
389 NCryptFreeObject(key
);
391 CertFreeCertificateContext(crtctx
);
396 static int tls_import_key_cert(char *key_buf
, char *cert_buf
, NCRYPT_KEY_HANDLE
*key
, PCCERT_CONTEXT
*crtctx
)
398 NCRYPT_PROV_HANDLE provider
= 0;
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 };
406 int key_der_len
= 0, cert_der_len
= 0;
407 char *key_der
= NULL
, *cert_der
= NULL
;
409 SECURITY_STATUS sspi_ret
;
412 ret
= pem_to_der(key_buf
, &key_der
, &key_der_len
);
416 ret
= pem_to_der(cert_buf
, &cert_der
, &cert_der_len
);
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
;
427 buffer_desc
.ulVersion
= NCRYPTBUFFER_VERSION
;
428 buffer_desc
.cBuffers
= 1;
429 buffer_desc
.pBuffers
= &buffer
;
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
);
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
;
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
;
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
;
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
;
463 *crtctx
= CertCreateCertificateContext(X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, cert_der
, cert_der_len
);
465 av_log(NULL
, AV_LOG_ERROR
, "CertCreateCertificateContext failed: %lu\n", GetLastError());
466 ret
= AVERROR_EXTERNAL
;
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
;
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
;
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
;
490 if (NCryptDeleteKey(*key
, NCRYPT_SILENT_FLAG
) != ERROR_SUCCESS
)
491 NCryptFreeObject(*key
);
493 CertFreeCertificateContext(*crtctx
);
504 NCryptFreeObject(provider
);
508 static int tls_cert_from_store(void *logctx
, const char *cert_store_name
, const char *cert_subj
, PCCERT_CONTEXT
*crtctx
)
510 HCERTSTORE cert_store
= NULL
;
513 cert_store
= CertOpenStore(CERT_STORE_PROV_SYSTEM_A
, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER
, cert_store_name
);
515 av_log(logctx
, AV_LOG_ERROR
, "Opening user cert store %s failed\n", cert_store_name
);
516 ret
= AVERROR_EXTERNAL
;
520 *crtctx
= CertFindCertificateInStore(cert_store
, X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
, 0, CERT_FIND_SUBJECT_STR_A
, cert_subj
, NULL
);
522 av_log(logctx
, AV_LOG_ERROR
, "Could not find certificate in store\n");
523 ret
= AVERROR_EXTERNAL
;
529 CertCloseStore(cert_store
, 0);
534 static int tls_load_key_cert(char *key_url
, char *cert_url
, NCRYPT_KEY_HANDLE
*key
, PCCERT_CONTEXT
*crtctx
)
536 AVBPrint key_bp
, cert_bp
;
539 av_bprint_init(&key_bp
, 1, MAX_CERTIFICATE_SIZE
);
540 av_bprint_init(&cert_bp
, 1, MAX_CERTIFICATE_SIZE
);
543 ret
= ff_url_read_all(key_url
, &key_bp
);
545 av_log(NULL
, AV_LOG_ERROR
, "Failed to open key file %s\n", key_url
);
549 ret
= ff_url_read_all(cert_url
, &cert_bp
);
551 av_log(NULL
, AV_LOG_ERROR
, "Failed to open cert file %s\n", cert_url
);
555 ret
= tls_import_key_cert(key_bp
.str
, cert_bp
.str
, key
, crtctx
);
560 av_bprint_finalize(&key_bp
, NULL
);
561 av_bprint_finalize(&cert_bp
, NULL
);
566 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
)
568 NCRYPT_KEY_HANDLE key
= 0;
569 PCCERT_CONTEXT crtctx
= NULL
;
571 int ret
= tls_load_key_cert(key_url
, cert_url
, &key
, &crtctx
);
575 ret
= tls_export_key_cert(key
, crtctx
, key_buf
, key_sz
, cert_buf
, cert_sz
, fingerprint
);
581 if (NCryptDeleteKey(key
, NCRYPT_SILENT_FLAG
) != ERROR_SUCCESS
)
582 NCryptFreeObject(key
);
584 CertFreeCertificateContext(crtctx
);
589 typedef struct TLSContext
{
590 TLSShared tls_shared
;
592 char *cert_store_subject
;
593 char *cert_store_name
;
595 CredHandle cred_handle
;
596 TimeStamp cred_timestamp
;
598 CtxtHandle ctxt_handle
;
600 TimeStamp ctxt_timestamp
;
617 SecPkgContext_StreamSizes sizes
;
620 int connection_closed
;
621 int sspi_close_notify
;
624 int ff_tls_set_external_socket(URLContext
*h
, URLContext
*sock
)
626 TLSContext
*c
= h
->priv_data
;
627 TLSShared
*s
= &c
->tls_shared
;
630 c
->tls_shared
.udp
= sock
;
632 c
->tls_shared
.tcp
= sock
;
637 int ff_dtls_export_materials(URLContext
*h
, char *dtls_srtp_materials
, size_t materials_sz
)
639 #if HAVE_SECPKGCONTEXT_KEYINGMATERIALINFO
640 TLSContext
*c
= h
->priv_data
;
642 SecPkgContext_KeyingMaterialInfo keying_info
= { 0 };
643 SecPkgContext_KeyingMaterial keying_material
= { 0 };
645 const char* dst
= "EXTRACTOR-dtls_srtp";
646 SECURITY_STATUS sspi_ret
;
648 if (!c
->have_context
)
649 return AVERROR(EINVAL
);
651 keying_info
.cbLabel
= strlen(dst
) + 1;
652 keying_info
.pszLabel
= (LPSTR
)dst
;
653 keying_info
.cbContextValue
= 0;
654 keying_info
.pbContextValue
= NULL
;
655 keying_info
.cbKeyingMaterial
= materials_sz
;
657 sspi_ret
= SetContextAttributes(&c
->ctxt_handle
, SECPKG_ATTR_KEYING_MATERIAL_INFO
, &keying_info
, sizeof(keying_info
));
658 if (sspi_ret
!= SEC_E_OK
) {
659 av_log(h
, AV_LOG_ERROR
, "Setting keying material info failed: %lx\n", sspi_ret
);
660 return AVERROR_EXTERNAL
;
663 sspi_ret
= QueryContextAttributes(&c
->ctxt_handle
, SECPKG_ATTR_KEYING_MATERIAL
, &keying_material
);
664 if (sspi_ret
!= SEC_E_OK
) {
665 av_log(h
, AV_LOG_ERROR
, "Querying keying material failed: %lx\n", sspi_ret
);
666 return AVERROR_EXTERNAL
;
669 memcpy(dtls_srtp_materials
, keying_material
.pbKeyingMaterial
, FFMIN(materials_sz
, keying_material
.cbKeyingMaterial
));
670 FreeContextBuffer(keying_material
.pbKeyingMaterial
);
672 if (keying_material
.cbKeyingMaterial
> materials_sz
) {
673 av_log(h
, AV_LOG_WARNING
, "Keying material size mismatch: %ld > %zu\n", keying_material
.cbKeyingMaterial
, materials_sz
);
674 return AVERROR(ENOSPC
);
679 return AVERROR(ENOSYS
);
683 static void init_sec_buffer(SecBuffer
*buffer
, unsigned long type
,
684 void *data
, unsigned long size
)
686 buffer
->cbBuffer
= size
;
687 buffer
->BufferType
= type
;
688 buffer
->pvBuffer
= data
;
691 static void init_sec_buffer_desc(SecBufferDesc
*desc
, SecBuffer
*buffers
,
692 unsigned long buffer_count
)
694 desc
->ulVersion
= SECBUFFER_VERSION
;
695 desc
->pBuffers
= buffers
;
696 desc
->cBuffers
= buffer_count
;
699 static int tls_process_send_buffer(URLContext
*h
)
701 TLSContext
*c
= h
->priv_data
;
702 TLSShared
*s
= &c
->tls_shared
;
703 URLContext
*uc
= s
->is_dtls
? s
->udp
: s
->tcp
;
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");
717 c
->send_buf_offset
+= ret
;
719 if (c
->send_buf_offset
< c
->send_buf_size
)
720 return AVERROR(EAGAIN
);
722 av_freep(&c
->send_buf
);
723 c
->send_buf_size
= c
->send_buf_offset
= 0;
728 static int tls_shutdown_client(URLContext
*h
)
730 TLSContext
*c
= h
->priv_data
;
731 TLSShared
*s
= &c
->tls_shared
;
732 URLContext
*uc
= s
->is_dtls
? s
->udp
: s
->tcp
;
736 SecBufferDesc BuffDesc
;
738 SECURITY_STATUS sspi_ret
;
740 SecBufferDesc outbuf_desc
;
742 DWORD dwshut
= SCHANNEL_SHUTDOWN
;
743 init_sec_buffer(&Buffer
, SECBUFFER_TOKEN
, &dwshut
, sizeof(dwshut
));
744 init_sec_buffer_desc(&BuffDesc
, &Buffer
, 1);
746 uc
->flags
&= ~AVIO_FLAG_NONBLOCK
;
747 ret
= tls_process_send_buffer(h
);
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");
755 init_sec_buffer(&outbuf
, SECBUFFER_TOKEN
, NULL
, 0);
756 init_sec_buffer_desc(&outbuf_desc
, &outbuf
, 1);
760 sspi_ret
= AcceptSecurityContext(&c
->cred_handle
, &c
->ctxt_handle
, NULL
, c
->request_flags
, 0,
761 &c
->ctxt_handle
, &outbuf_desc
, &c
->context_flags
,
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
);
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");
774 FreeContextBuffer(outbuf
.pvBuffer
);
777 #ifdef SEC_I_MESSAGE_FRAGMENT
778 sspi_ret
== SEC_I_MESSAGE_FRAGMENT
||
780 sspi_ret
== SEC_I_CONTINUE_NEEDED
);
782 av_log(h
, AV_LOG_DEBUG
, "Close session result: 0x%lx\n", sspi_ret
);
789 static int tls_close(URLContext
*h
)
791 TLSContext
*c
= h
->priv_data
;
792 TLSShared
*s
= &c
->tls_shared
;
794 tls_shutdown_client(h
);
796 DeleteSecurityContext(&c
->ctxt_handle
);
797 FreeCredentialsHandle(&c
->cred_handle
);
799 av_freep(&c
->enc_buf
);
800 c
->enc_buf_size
= c
->enc_buf_offset
= 0;
802 av_freep(&c
->dec_buf
);
803 c
->dec_buf_size
= c
->dec_buf_offset
= 0;
805 av_freep(&c
->send_buf
);
806 c
->send_buf_size
= c
->send_buf_offset
= 0;
809 if (!s
->external_sock
)
810 ffurl_closep(&c
->tls_shared
.udp
);
812 ffurl_closep(&c
->tls_shared
.tcp
);
818 static int tls_handshake_loop(URLContext
*h
, int initial
)
820 TLSContext
*c
= h
->priv_data
;
821 TLSShared
*s
= &c
->tls_shared
;
822 URLContext
*uc
= s
->is_dtls
? s
->udp
: s
->tcp
;
823 SECURITY_STATUS sspi_ret
;
824 SecBuffer outbuf
[3] = { 0 };
825 SecBufferDesc outbuf_desc
;
827 SecBufferDesc inbuf_desc
;
828 struct sockaddr_storage recv_addr
= { 0 };
829 socklen_t recv_addr_len
= 0;
830 int i
, ret
= 0, read_data
= initial
;
832 if (c
->enc_buf
== NULL
) {
833 c
->enc_buf_offset
= 0;
834 ret
= av_reallocp(&c
->enc_buf
, SCHANNEL_INITIAL_BUFFER_SIZE
);
837 c
->enc_buf_size
= SCHANNEL_INITIAL_BUFFER_SIZE
;
840 if (c
->dec_buf
== NULL
) {
841 c
->dec_buf_offset
= 0;
842 ret
= av_reallocp(&c
->dec_buf
, SCHANNEL_INITIAL_BUFFER_SIZE
);
845 c
->dec_buf_size
= SCHANNEL_INITIAL_BUFFER_SIZE
;
848 uc
->flags
&= ~AVIO_FLAG_NONBLOCK
;
851 if (c
->enc_buf_size
- c
->enc_buf_offset
< SCHANNEL_FREE_BUFFER_SIZE
) {
852 c
->enc_buf_size
= c
->enc_buf_offset
+ SCHANNEL_FREE_BUFFER_SIZE
;
853 ret
= av_reallocp(&c
->enc_buf
, c
->enc_buf_size
);
855 c
->enc_buf_size
= c
->enc_buf_offset
= 0;
861 ret
= ffurl_read(uc
, c
->enc_buf
+ c
->enc_buf_offset
, c
->enc_buf_size
- c
->enc_buf_offset
);
863 av_log(h
, AV_LOG_ERROR
, "Failed to read handshake response\n");
866 c
->enc_buf_offset
+= ret
;
867 if (s
->is_dtls
&& !recv_addr_len
) {
868 ff_udp_get_last_recv_addr(uc
, &recv_addr
, &recv_addr_len
);
871 ret
= ff_udp_set_remote_addr(uc
, (struct sockaddr
*)&recv_addr
, recv_addr_len
, 1);
873 av_log(h
, AV_LOG_ERROR
, "Failed connecting udp context\n");
876 av_log(h
, AV_LOG_TRACE
, "Set UDP remote addr on UDP socket, now 'connected'\n");
882 init_sec_buffer(&inbuf
[0], SECBUFFER_TOKEN
, av_malloc(c
->enc_buf_offset
), c
->enc_buf_offset
);
883 init_sec_buffer(&inbuf
[1], SECBUFFER_EMPTY
, NULL
, 0);
884 if (s
->listen
&& s
->is_dtls
) {
885 init_sec_buffer(&inbuf
[2], SECBUFFER_EXTRA
, &recv_addr
, recv_addr_len
);
886 init_sec_buffer_desc(&inbuf_desc
, inbuf
, 3);
888 init_sec_buffer_desc(&inbuf_desc
, inbuf
, 2);
891 if (inbuf
[0].pvBuffer
== NULL
) {
892 av_log(h
, AV_LOG_ERROR
, "Failed to allocate input buffer\n");
893 ret
= AVERROR(ENOMEM
);
897 memcpy(inbuf
[0].pvBuffer
, c
->enc_buf
, c
->enc_buf_offset
);
900 init_sec_buffer(&outbuf
[0], SECBUFFER_TOKEN
, NULL
, 0);
901 init_sec_buffer(&outbuf
[1], SECBUFFER_ALERT
, NULL
, 0);
902 init_sec_buffer(&outbuf
[2], SECBUFFER_EMPTY
, NULL
, 0);
903 init_sec_buffer_desc(&outbuf_desc
, outbuf
, 3);
906 sspi_ret
= AcceptSecurityContext(&c
->cred_handle
, c
->have_context
? &c
->ctxt_handle
: NULL
, &inbuf_desc
,
907 c
->request_flags
, 0, &c
->ctxt_handle
, &outbuf_desc
,
908 &c
->context_flags
, &c
->ctxt_timestamp
);
910 sspi_ret
= InitializeSecurityContext(&c
->cred_handle
, c
->have_context
? &c
->ctxt_handle
: NULL
,
911 s
->host
, c
->request_flags
, 0, 0, &inbuf_desc
, 0, &c
->ctxt_handle
,
912 &outbuf_desc
, &c
->context_flags
, &c
->ctxt_timestamp
);
913 av_freep(&inbuf
[0].pvBuffer
);
915 av_log(h
, AV_LOG_TRACE
, "Handshake res with %d bytes of data: 0x%lx\n", c
->enc_buf_offset
, sspi_ret
);
917 if (sspi_ret
== SEC_E_INCOMPLETE_MESSAGE
) {
918 av_log(h
, AV_LOG_TRACE
, "Received incomplete handshake, need more data\n");
925 /* remote requests a client certificate - attempt to continue without one anyway */
926 if (sspi_ret
== SEC_I_INCOMPLETE_CREDENTIALS
&&
927 !(c
->request_flags
& ISC_REQ_USE_SUPPLIED_CREDS
)) {
928 av_log(h
, AV_LOG_VERBOSE
, "Client certificate has been requested, ignoring\n");
929 c
->request_flags
|= ISC_REQ_USE_SUPPLIED_CREDS
;
934 /* continue handshake */
935 if (sspi_ret
== SEC_I_CONTINUE_NEEDED
||
936 #ifdef SEC_I_MESSAGE_FRAGMENT
937 sspi_ret
== SEC_I_MESSAGE_FRAGMENT
||
939 sspi_ret
== SEC_E_OK
) {
940 for (i
= 0; i
< 3; i
++) {
941 if (outbuf
[i
].BufferType
== SECBUFFER_TOKEN
&& outbuf
[i
].cbBuffer
> 0) {
942 ret
= ffurl_write(uc
, outbuf
[i
].pvBuffer
, outbuf
[i
].cbBuffer
);
943 if (ret
< 0 || ret
!= outbuf
[i
].cbBuffer
) {
944 av_log(h
, AV_LOG_VERBOSE
, "Failed to send handshake data\n");
950 if (outbuf
[i
].pvBuffer
!= NULL
) {
951 FreeContextBuffer(outbuf
[i
].pvBuffer
);
952 outbuf
[i
].pvBuffer
= NULL
;
956 if (sspi_ret
== SEC_E_WRONG_PRINCIPAL
)
957 av_log(h
, AV_LOG_ERROR
, "SNI or certificate check failed\n");
959 av_log(h
, AV_LOG_ERROR
, "Creating security context failed (0x%lx)\n", sspi_ret
);
960 ret
= AVERROR_UNKNOWN
;
964 #ifdef SEC_I_MESSAGE_FRAGMENT
965 if (sspi_ret
== SEC_I_MESSAGE_FRAGMENT
) {
966 av_log(h
, AV_LOG_TRACE
, "Writing fragmented output message part\n");
972 if (inbuf
[1].BufferType
== SECBUFFER_EXTRA
&& inbuf
[1].cbBuffer
> 0) {
973 if (c
->enc_buf_offset
> inbuf
[1].cbBuffer
) {
974 memmove(c
->enc_buf
, (c
->enc_buf
+ c
->enc_buf_offset
) - inbuf
[1].cbBuffer
,
976 c
->enc_buf_offset
= inbuf
[1].cbBuffer
;
977 if (sspi_ret
== SEC_I_CONTINUE_NEEDED
) {
978 av_log(h
, AV_LOG_TRACE
, "Sent reply, handshake continues. %d extra bytes\n", (int)inbuf
[1].cbBuffer
);
984 c
->enc_buf_offset
= 0;
987 if (sspi_ret
== SEC_I_CONTINUE_NEEDED
) {
988 av_log(h
, AV_LOG_TRACE
, "Handshake continues\n");
996 av_log(h
, AV_LOG_TRACE
, "Handshake completed\n");
1001 /* free any remaining output data */
1002 for (i
= 0; i
< 3; i
++) {
1003 if (outbuf
[i
].pvBuffer
!= NULL
) {
1004 FreeContextBuffer(outbuf
[i
].pvBuffer
);
1005 outbuf
[i
].pvBuffer
= NULL
;
1009 av_log(h
, AV_LOG_TRACE
, "Handshake failed\n");
1014 static int tls_client_handshake(URLContext
*h
)
1016 TLSContext
*c
= h
->priv_data
;
1017 TLSShared
*s
= &c
->tls_shared
;
1018 URLContext
*uc
= s
->is_dtls
? s
->udp
: s
->tcp
;
1020 SecBufferDesc outbuf_desc
;
1021 SECURITY_STATUS sspi_ret
;
1024 init_sec_buffer(&outbuf
, SECBUFFER_EMPTY
, NULL
, 0);
1025 init_sec_buffer_desc(&outbuf_desc
, &outbuf
, 1);
1027 c
->request_flags
= ISC_REQ_SEQUENCE_DETECT
| ISC_REQ_REPLAY_DETECT
|
1028 ISC_REQ_CONFIDENTIALITY
| ISC_REQ_ALLOCATE_MEMORY
;
1030 c
->request_flags
|= ISC_REQ_DATAGRAM
;
1032 c
->request_flags
|= ISC_REQ_STREAM
;
1034 sspi_ret
= InitializeSecurityContext(&c
->cred_handle
, NULL
, s
->host
, c
->request_flags
, 0, 0,
1035 NULL
, 0, &c
->ctxt_handle
, &outbuf_desc
, &c
->context_flags
,
1036 &c
->ctxt_timestamp
);
1037 if (sspi_ret
!= SEC_I_CONTINUE_NEEDED
) {
1038 av_log(h
, AV_LOG_ERROR
, "Unable to create initial security context (0x%lx)\n", sspi_ret
);
1039 ret
= AVERROR_UNKNOWN
;
1043 c
->have_context
= 1;
1045 uc
->flags
&= ~AVIO_FLAG_NONBLOCK
;
1046 ret
= ffurl_write(uc
, outbuf
.pvBuffer
, outbuf
.cbBuffer
);
1047 FreeContextBuffer(outbuf
.pvBuffer
);
1048 if (ret
< 0 || ret
!= outbuf
.cbBuffer
) {
1049 av_log(h
, AV_LOG_ERROR
, "Failed to send initial handshake data\n");
1054 return tls_handshake_loop(h
, 1);
1057 DeleteSecurityContext(&c
->ctxt_handle
);
1061 static int tls_server_handshake(URLContext
*h
)
1063 TLSContext
*c
= h
->priv_data
;
1064 TLSShared
*s
= &c
->tls_shared
;
1066 c
->request_flags
= ASC_REQ_SEQUENCE_DETECT
| ASC_REQ_REPLAY_DETECT
|
1067 ASC_REQ_CONFIDENTIALITY
| ASC_REQ_ALLOCATE_MEMORY
;
1069 c
->request_flags
|= ASC_REQ_DATAGRAM
;
1071 c
->request_flags
|= ASC_REQ_STREAM
;
1073 c
->have_context
= 0;
1075 return tls_handshake_loop(h
, 1);
1078 static int tls_handshake(URLContext
*h
)
1080 TLSContext
*c
= h
->priv_data
;
1081 TLSShared
*s
= &c
->tls_shared
;
1082 SECURITY_STATUS sspi_ret
;
1086 ret
= tls_server_handshake(h
);
1088 ret
= tls_client_handshake(h
);
1093 #if CONFIG_DTLS_PROTOCOL
1094 if (s
->is_dtls
&& s
->mtu
> 0) {
1096 sspi_ret
= SetContextAttributes(&c
->ctxt_handle
, SECPKG_ATTR_DTLS_MTU
, &mtu
, sizeof(mtu
));
1097 if (sspi_ret
!= SEC_E_OK
) {
1098 av_log(h
, AV_LOG_ERROR
, "Failed setting DTLS MTU to %d.\n", s
->mtu
);
1099 ret
= AVERROR(EINVAL
);
1102 av_log(h
, AV_LOG_VERBOSE
, "Set DTLS MTU to %d\n", s
->mtu
);
1112 static int tls_open(URLContext
*h
, const char *uri
, int flags
, AVDictionary
**options
)
1114 TLSContext
*c
= h
->priv_data
;
1115 TLSShared
*s
= &c
->tls_shared
;
1116 SECURITY_STATUS sspi_ret
;
1117 SCHANNEL_CRED schannel_cred
= { 0 };
1118 PCCERT_CONTEXT crtctx
= NULL
;
1119 NCRYPT_KEY_HANDLE key
= 0;
1122 if (!s
->external_sock
) {
1123 if ((ret
= ff_tls_open_underlying(s
, h
, uri
, options
)) < 0)
1127 /* SChannel Options */
1128 schannel_cred
.dwVersion
= SCHANNEL_CRED_VERSION
;
1131 if (c
->cert_store_name
&& c
->cert_store_subject
) {
1132 ret
= tls_cert_from_store(h
, c
->cert_store_name
, c
->cert_store_subject
, &crtctx
);
1133 } else if (s
->key_buf
&& s
->cert_buf
) {
1134 ret
= tls_import_key_cert(s
->key_buf
, s
->cert_buf
, &key
, &crtctx
);
1135 } else if (s
->key_file
&& s
->cert_file
) {
1136 ret
= tls_load_key_cert(s
->key_file
, s
->cert_file
, &key
, &crtctx
);
1138 av_log(h
, AV_LOG_VERBOSE
, "No server certificate provided, using self-signed\n");
1139 ret
= tls_gen_self_signed(&key
, &crtctx
);
1145 schannel_cred
.cCreds
= 1;
1146 schannel_cred
.paCred
= &crtctx
;
1148 schannel_cred
.dwFlags
= SCH_CRED_NO_SYSTEM_MAPPER
| SCH_CRED_MANUAL_CRED_VALIDATION
;
1150 #if CONFIG_DTLS_PROTOCOL
1152 schannel_cred
.grbitEnabledProtocols
= SP_PROT_DTLS1_X_SERVER
;
1156 schannel_cred
.dwFlags
= SCH_CRED_AUTO_CRED_VALIDATION
|
1157 SCH_CRED_REVOCATION_CHECK_CHAIN
;
1159 schannel_cred
.dwFlags
= SCH_CRED_MANUAL_CRED_VALIDATION
|
1160 SCH_CRED_IGNORE_NO_REVOCATION_CHECK
|
1161 SCH_CRED_IGNORE_REVOCATION_OFFLINE
;
1163 #if CONFIG_DTLS_PROTOCOL
1165 schannel_cred
.grbitEnabledProtocols
= SP_PROT_DTLS1_X_CLIENT
;
1169 /* Get credential handle */
1170 sspi_ret
= AcquireCredentialsHandle(NULL
, (TCHAR
*)UNISP_NAME
,
1171 s
->listen
? SECPKG_CRED_INBOUND
: SECPKG_CRED_OUTBOUND
,
1172 NULL
, &schannel_cred
, NULL
, NULL
, &c
->cred_handle
,
1173 &c
->cred_timestamp
);
1174 if (sspi_ret
!= SEC_E_OK
) {
1175 av_log(h
, AV_LOG_ERROR
, "Unable to acquire security credentials (0x%lx)\n", sspi_ret
);
1176 ret
= AVERROR_UNKNOWN
;
1180 if (!s
->external_sock
) {
1181 ret
= tls_handshake(h
);
1193 CertFreeCertificateContext(crtctx
);
1195 if (NCryptDeleteKey(key
, NCRYPT_SILENT_FLAG
) != ERROR_SUCCESS
)
1196 NCryptFreeObject(key
);
1201 #if CONFIG_DTLS_PROTOCOL
1202 static int dtls_open(URLContext
*h
, const char *uri
, int flags
, AVDictionary
**options
)
1204 TLSContext
*c
= h
->priv_data
;
1205 TLSShared
*s
= &c
->tls_shared
;
1209 return tls_open(h
, uri
, flags
, options
);
1213 static int tls_read(URLContext
*h
, uint8_t *buf
, int len
)
1215 TLSContext
*c
= h
->priv_data
;
1216 TLSShared
*s
= &c
->tls_shared
;
1217 URLContext
*uc
= s
->is_dtls
? s
->udp
: s
->tcp
;
1218 SECURITY_STATUS sspi_ret
= SEC_E_OK
;
1220 SecBufferDesc inbuf_desc
;
1222 int min_enc_buf_size
= len
+ SCHANNEL_FREE_BUFFER_SIZE
;
1224 /* If we have some left-over data from previous network activity,
1225 * return it first in case it is enough. It may contain
1226 * data that is required to know whether this connection
1227 * is still required or not, esp. in case of HTTP keep-alive
1229 if (c
->dec_buf_offset
> 0)
1232 if (c
->sspi_close_notify
)
1235 if (!c
->connection_closed
) {
1236 size
= c
->enc_buf_size
- c
->enc_buf_offset
;
1237 if (size
< SCHANNEL_FREE_BUFFER_SIZE
|| c
->enc_buf_size
< min_enc_buf_size
) {
1238 c
->enc_buf_size
= c
->enc_buf_offset
+ SCHANNEL_FREE_BUFFER_SIZE
;
1239 if (c
->enc_buf_size
< min_enc_buf_size
)
1240 c
->enc_buf_size
= min_enc_buf_size
;
1241 ret
= av_reallocp(&c
->enc_buf
, c
->enc_buf_size
);
1243 c
->enc_buf_size
= c
->enc_buf_offset
= 0;
1248 uc
->flags
&= ~AVIO_FLAG_NONBLOCK
;
1249 uc
->flags
|= h
->flags
& AVIO_FLAG_NONBLOCK
;
1251 ret
= ffurl_read(uc
, c
->enc_buf
+ c
->enc_buf_offset
,
1252 c
->enc_buf_size
- c
->enc_buf_offset
);
1253 if (ret
== AVERROR_EOF
) {
1254 c
->connection_closed
= 1;
1256 } else if (ret
== AVERROR(EAGAIN
)) {
1258 } else if (ret
< 0) {
1259 av_log(h
, AV_LOG_ERROR
, "Unable to read from socket\n");
1263 c
->enc_buf_offset
+= ret
;
1266 while (c
->enc_buf_offset
> 0 && sspi_ret
== SEC_E_OK
) {
1268 init_sec_buffer(&inbuf
[0], SECBUFFER_DATA
, c
->enc_buf
, c
->enc_buf_offset
);
1270 /* additional buffers for possible output */
1271 init_sec_buffer(&inbuf
[1], SECBUFFER_EMPTY
, NULL
, 0);
1272 init_sec_buffer(&inbuf
[2], SECBUFFER_EMPTY
, NULL
, 0);
1273 init_sec_buffer(&inbuf
[3], SECBUFFER_EMPTY
, NULL
, 0);
1274 init_sec_buffer_desc(&inbuf_desc
, inbuf
, 4);
1276 sspi_ret
= DecryptMessage(&c
->ctxt_handle
, &inbuf_desc
, 0, NULL
);
1277 if (sspi_ret
== SEC_E_OK
|| sspi_ret
== SEC_I_RENEGOTIATE
||
1278 sspi_ret
== SEC_I_CONTEXT_EXPIRED
) {
1279 /* handle decrypted data */
1280 if (inbuf
[1].BufferType
== SECBUFFER_DATA
) {
1281 /* grow buffer if needed */
1282 size
= inbuf
[1].cbBuffer
> SCHANNEL_FREE_BUFFER_SIZE
?
1283 inbuf
[1].cbBuffer
: SCHANNEL_FREE_BUFFER_SIZE
;
1284 if (c
->dec_buf_size
- c
->dec_buf_offset
< size
|| c
->dec_buf_size
< len
) {
1285 c
->dec_buf_size
= c
->dec_buf_offset
+ size
;
1286 if (c
->dec_buf_size
< len
)
1287 c
->dec_buf_size
= len
;
1288 ret
= av_reallocp(&c
->dec_buf
, c
->dec_buf_size
);
1290 c
->dec_buf_size
= c
->dec_buf_offset
= 0;
1295 /* copy decrypted data to buffer */
1296 size
= inbuf
[1].cbBuffer
;
1298 memcpy(c
->dec_buf
+ c
->dec_buf_offset
, inbuf
[1].pvBuffer
, size
);
1299 c
->dec_buf_offset
+= size
;
1302 if (inbuf
[3].BufferType
== SECBUFFER_EXTRA
&& inbuf
[3].cbBuffer
> 0) {
1303 if (c
->enc_buf_offset
> inbuf
[3].cbBuffer
) {
1304 memmove(c
->enc_buf
, (c
->enc_buf
+ c
->enc_buf_offset
) - inbuf
[3].cbBuffer
,
1306 c
->enc_buf_offset
= inbuf
[3].cbBuffer
;
1309 c
->enc_buf_offset
= 0;
1311 if (sspi_ret
== SEC_I_RENEGOTIATE
) {
1312 if (c
->enc_buf_offset
) {
1313 av_log(h
, AV_LOG_ERROR
, "Cannot renegotiate, encrypted data buffer not empty\n");
1314 ret
= AVERROR_UNKNOWN
;
1318 av_log(h
, AV_LOG_VERBOSE
, "Re-negotiating security context\n");
1319 ret
= tls_handshake_loop(h
, 0);
1323 sspi_ret
= SEC_E_OK
;
1325 /* if somehow any send data was left, it is now invalid */
1326 av_freep(&c
->send_buf
);
1327 c
->send_buf_size
= c
->send_buf_offset
= 0;
1330 } else if (sspi_ret
== SEC_I_CONTEXT_EXPIRED
) {
1331 c
->sspi_close_notify
= 1;
1332 if (!c
->connection_closed
) {
1333 c
->connection_closed
= 1;
1334 av_log(h
, AV_LOG_VERBOSE
, "Server closed the connection\n");
1339 } else if (sspi_ret
== SEC_E_INCOMPLETE_MESSAGE
) {
1340 ret
= AVERROR(EAGAIN
);
1343 av_log(h
, AV_LOG_ERROR
, "Unable to decrypt message (error 0x%x)\n", (unsigned)sspi_ret
);
1352 size
= FFMIN(len
, c
->dec_buf_offset
);
1354 memcpy(buf
, c
->dec_buf
, size
);
1355 memmove(c
->dec_buf
, c
->dec_buf
+ size
, c
->dec_buf_offset
- size
);
1356 c
->dec_buf_offset
-= size
;
1361 if (ret
== 0 && !c
->connection_closed
)
1362 ret
= AVERROR(EAGAIN
);
1364 return ret
< 0 ? ret
: AVERROR_EOF
;
1367 static int tls_write(URLContext
*h
, const uint8_t *buf
, int len
)
1369 TLSContext
*c
= h
->priv_data
;
1370 TLSShared
*s
= &c
->tls_shared
;
1371 URLContext
*uc
= s
->is_dtls
? s
->udp
: s
->tcp
;
1372 SECURITY_STATUS sspi_ret
;
1373 SecBuffer outbuf
[4];
1374 SecBufferDesc outbuf_desc
;
1377 uc
->flags
&= ~AVIO_FLAG_NONBLOCK
;
1378 uc
->flags
|= h
->flags
& AVIO_FLAG_NONBLOCK
;
1380 ret
= tls_process_send_buffer(h
);
1384 if (c
->sizes
.cbMaximumMessage
== 0) {
1385 sspi_ret
= QueryContextAttributes(&c
->ctxt_handle
, SECPKG_ATTR_STREAM_SIZES
, &c
->sizes
);
1386 if (sspi_ret
!= SEC_E_OK
)
1387 return AVERROR_UNKNOWN
;
1390 /* limit how much data we can consume */
1391 len
= FFMIN(len
, c
->sizes
.cbMaximumMessage
- c
->sizes
.cbHeader
- c
->sizes
.cbTrailer
);
1393 c
->send_buf_size
= c
->sizes
.cbHeader
+ len
+ c
->sizes
.cbTrailer
;
1394 c
->send_buf
= av_malloc(c
->send_buf_size
);
1395 if (c
->send_buf
== NULL
)
1396 return AVERROR(ENOMEM
);
1398 init_sec_buffer(&outbuf
[0], SECBUFFER_STREAM_HEADER
,
1399 c
->send_buf
, c
->sizes
.cbHeader
);
1400 init_sec_buffer(&outbuf
[1], SECBUFFER_DATA
,
1401 c
->send_buf
+ c
->sizes
.cbHeader
, len
);
1402 init_sec_buffer(&outbuf
[2], SECBUFFER_STREAM_TRAILER
,
1403 c
->send_buf
+ c
->sizes
.cbHeader
+ len
,
1404 c
->sizes
.cbTrailer
);
1405 init_sec_buffer(&outbuf
[3], SECBUFFER_EMPTY
, NULL
, 0);
1406 init_sec_buffer_desc(&outbuf_desc
, outbuf
, 4);
1408 memcpy(outbuf
[1].pvBuffer
, buf
, len
);
1410 sspi_ret
= EncryptMessage(&c
->ctxt_handle
, 0, &outbuf_desc
, 0);
1411 if (sspi_ret
!= SEC_E_OK
) {
1412 av_freep(&c
->send_buf
);
1413 av_log(h
, AV_LOG_ERROR
, "Encrypting data failed\n");
1414 if (sspi_ret
== SEC_E_INSUFFICIENT_MEMORY
)
1415 return AVERROR(ENOMEM
);
1416 return AVERROR(EIO
);
1419 c
->send_buf_size
= outbuf
[0].cbBuffer
+ outbuf
[1].cbBuffer
+ outbuf
[2].cbBuffer
;
1420 c
->send_buf_offset
= 0;
1422 ret
= tls_process_send_buffer(h
);
1423 if (ret
== AVERROR(EAGAIN
)) {
1424 /* We always need to signal that we consumed all (encrypted) data since schannel must not
1425 be fed the same data again. Sending will then be completed next call to this function,
1426 and EAGAIN returned until all remaining buffer is sent. */
1427 return outbuf
[1].cbBuffer
;
1428 } else if (ret
< 0) {
1432 return outbuf
[1].cbBuffer
;
1435 static int tls_get_file_handle(URLContext
*h
)
1437 TLSContext
*c
= h
->priv_data
;
1438 TLSShared
*s
= &c
->tls_shared
;
1439 return ffurl_get_file_handle(s
->is_dtls
? s
->udp
: s
->tcp
);
1442 static int tls_get_short_seek(URLContext
*h
)
1444 TLSContext
*c
= h
->priv_data
;
1445 TLSShared
*s
= &c
->tls_shared
;
1446 return ffurl_get_short_seek(s
->is_dtls
? s
->udp
: s
->tcp
);
1449 #define OFFSET(x) offsetof(TLSContext, x)
1450 static const AVOption options
[] = {
1451 TLS_COMMON_OPTIONS(TLSContext
, tls_shared
),
1452 { "cert_store_subject", "Load certificate (and associated key) from users keystore by subject",
1453 OFFSET(cert_store_subject
), AV_OPT_TYPE_STRING
, .flags
= TLS_OPTFL
},
1454 { "cert_store_name", "Name of the specific cert store to search in (for cert_store_subject)",
1455 OFFSET(cert_store_name
), AV_OPT_TYPE_STRING
, { .str
= "MY" }, .flags
= TLS_OPTFL
},
1459 #if CONFIG_TLS_PROTOCOL
1460 static const AVClass tls_class
= {
1461 .class_name
= "tls",
1462 .item_name
= av_default_item_name
,
1464 .version
= LIBAVUTIL_VERSION_INT
,
1467 const URLProtocol ff_tls_protocol
= {
1469 .url_open2
= tls_open
,
1470 .url_read
= tls_read
,
1471 .url_write
= tls_write
,
1472 .url_close
= tls_close
,
1473 .url_get_file_handle
= tls_get_file_handle
,
1474 .url_get_short_seek
= tls_get_short_seek
,
1475 .priv_data_size
= sizeof(TLSContext
),
1476 .flags
= URL_PROTOCOL_FLAG_NETWORK
,
1477 .priv_data_class
= &tls_class
,
1481 #if CONFIG_DTLS_PROTOCOL
1482 static const AVClass dtls_class
= {
1483 .class_name
= "dtls",
1484 .item_name
= av_default_item_name
,
1486 .version
= LIBAVUTIL_VERSION_INT
,
1489 const URLProtocol ff_dtls_protocol
= {
1491 .url_open2
= dtls_open
,
1492 .url_handshake
= tls_handshake
,
1493 .url_close
= tls_close
,
1494 .url_read
= tls_read
,
1495 .url_write
= tls_write
,
1496 .url_get_file_handle
= tls_get_file_handle
,
1497 .url_get_short_seek
= tls_get_short_seek
,
1498 .priv_data_size
= sizeof(TLSContext
),
1499 .flags
= URL_PROTOCOL_FLAG_NETWORK
,
1500 .priv_data_class
= &dtls_class
,