6262#include <mongoc/mongoc-stream-tls-private.h>
6363#include <mongoc/mongoc-stream-tls-secure-channel-private.h>
6464#include <mongoc/mongoc-trace-private.h>
65+ #include <mongoc/mongoc-util-private.h>
6566
6667#include <mongoc/mongoc-log.h>
6768#include <mongoc/mongoc-ssl.h>
6869#include <mongoc/mongoc-stream-tls.h>
6970
7071#include <bson/bson.h>
7172
73+ #include <subauth.h>
74+
7275#undef MONGOC_LOG_DOMAIN
7376#define MONGOC_LOG_DOMAIN "stream-tls-secure-channel"
7477
7578
7679#define SECURITY_WIN32
80+ #define SCHANNEL_USE_BLACKLISTS 1
7781#include <schannel.h>
7882#include <schnlsp.h>
7983#include <security.h>
8791#define SP_PROT_TLS1_2_CLIENT 0x00000800
8892#endif
8993
94+ #ifndef SP_PROT_TLS1_3_CLIENT
95+ #define SP_PROT_TLS1_3_CLIENT 0x00002000
96+ #endif
9097
9198static void
9299_mongoc_stream_tls_secure_channel_destroy (mongoc_stream_t * stream )
@@ -841,40 +848,96 @@ _mongoc_stream_tls_secure_channel_should_retry(mongoc_stream_t *stream)
841848 RETURN (mongoc_stream_should_retry (tls -> base_stream ));
842849}
843850
844- mongoc_secure_channel_cred *
845- mongoc_secure_channel_cred_new (const mongoc_ssl_opt_t * opt )
851+ static DWORD
852+ get_cred_flags (const mongoc_ssl_opt_t * opt )
846853{
847- BSON_ASSERT_PARAM (opt );
848- mongoc_secure_channel_cred * cred = bson_malloc0 (sizeof (mongoc_secure_channel_cred ));
854+ DWORD dwFlags ;
849855
850- cred -> cred .dwVersion = SCHANNEL_CRED_VERSION ;
851-
852- /* SCHANNEL_CRED:
853- * SCH_USE_STRONG_CRYPTO is not available in VS2010
854- * https://msdn.microsoft.com/en-us/library/windows/desktop/aa379810.aspx */
856+ /* SCH_USE_STRONG_CRYPTO is not available in VS2010
857+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa379810.aspx */
855858#ifdef SCH_USE_STRONG_CRYPTO
856- cred -> cred . dwFlags = SCH_USE_STRONG_CRYPTO ;
859+ dwFlags = SCH_USE_STRONG_CRYPTO ;
857860#endif
858861
859862 /* By default, enable soft failing.
860863 * A certificate with no revocation check is a soft failure. */
861- cred -> cred . dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK ;
864+ dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK ;
862865 /* An offline OCSP responder / CRL distribution list is a soft failure. */
863- cred -> cred . dwFlags |= SCH_CRED_IGNORE_REVOCATION_OFFLINE ;
866+ dwFlags |= SCH_CRED_IGNORE_REVOCATION_OFFLINE ;
864867 if (opt -> weak_cert_validation ) {
865- cred -> cred . dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION ;
868+ dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION ;
866869 TRACE ("%s" , "disabled server certificate checks" );
867870 } else {
868- cred -> cred . dwFlags |= SCH_CRED_AUTO_CRED_VALIDATION ;
871+ dwFlags |= SCH_CRED_AUTO_CRED_VALIDATION ;
869872 if (!_mongoc_ssl_opts_disable_certificate_revocation_check (opt )) {
870- cred -> cred . dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN ;
873+ dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN ;
871874 TRACE ("%s" , "enabled server certificate revocation checks" );
872875 }
873876 TRACE ("%s" , "enabled server certificate checks" );
874877 }
875878
876879 if (opt -> allow_invalid_hostname ) {
877- cred -> cred .dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK ;
880+ dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK ;
881+ }
882+
883+ return dwFlags ;
884+ }
885+
886+ #ifdef HAVE_SCH_CREDENTIALS
887+
888+ void *
889+ _mongoc_secure_channel_sch_credentials_new (const mongoc_ssl_opt_t * opt , PCCERT_CONTEXT * cert , DWORD enabled_protocols )
890+ {
891+ SCH_CREDENTIALS * cred = bson_malloc0 (sizeof (SCH_CREDENTIALS ));
892+
893+ cred -> dwVersion = SCH_CREDENTIALS_VERSION ;
894+ cred -> dwFlags = get_cred_flags (opt );
895+
896+ if (* cert ) {
897+ cred -> cCreds = 1 ;
898+ cred -> paCred = cert ;
899+ }
900+
901+ cred -> cTlsParameters = 1 ;
902+ cred -> pTlsParameters = bson_malloc0 (sizeof (TLS_PARAMETERS ));
903+ cred -> pTlsParameters -> grbitDisabledProtocols = (DWORD )~enabled_protocols ;
904+
905+ return (void * )cred ;
906+ }
907+
908+ #endif
909+
910+ void *
911+ _mongoc_secure_channel_schannel_cred_new (const mongoc_ssl_opt_t * opt , PCCERT_CONTEXT * cert , DWORD enabled_protocols )
912+ {
913+ SCHANNEL_CRED * cred = bson_malloc0 (sizeof (SCHANNEL_CRED ));
914+
915+ cred -> dwVersion = SCHANNEL_CRED_VERSION ;
916+ cred -> dwFlags = get_cred_flags (opt );
917+
918+ if (* cert ) {
919+ cred -> cCreds = 1 ;
920+ cred -> paCred = cert ;
921+ }
922+
923+ cred -> grbitEnabledProtocols = enabled_protocols ;
924+
925+ return (void * )cred ;
926+ }
927+
928+ mongoc_secure_channel_cred *
929+ mongoc_secure_channel_cred_new (const mongoc_ssl_opt_t * opt )
930+ {
931+ BSON_ASSERT_PARAM (opt );
932+ mongoc_secure_channel_cred * cred = bson_malloc0 (sizeof (mongoc_secure_channel_cred ));
933+
934+ DWORD enabled_protocols = SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT ;
935+
936+ /* TLS 1.3 is supported on Windows Server 2022 and newer.
937+ * Schannel will not negotiate TLS 1.3 when SCHANNEL_CRED is used. */
938+ if (_mongoc_verify_windows_version (10 , 0 , 20348 , false)) {
939+ // TODO - enable TLS 1.3 once renegotiation is supported.
940+ // enabled_protocols |= SP_PROT_TLS1_3_CLIENT;
878941 }
879942
880943 if (opt -> ca_file ) {
@@ -887,14 +950,22 @@ mongoc_secure_channel_cred_new(const mongoc_ssl_opt_t *opt)
887950
888951 if (opt -> pem_file ) {
889952 cred -> cert = mongoc_secure_channel_setup_certificate (opt );
953+ }
890954
891- if (cred -> cert ) {
892- cred -> cred .cCreds = 1 ;
893- cred -> cred .paCred = & cred -> cert ;
894- }
955+ #ifdef HAVE_SCH_CREDENTIALS
956+ // SCH_CREDENTIALS is supported in Windows 10 1809 / Server 1809 and later
957+ if (_mongoc_verify_windows_version (10 , 0 , 17763 , false)) {
958+ cred -> cred = _mongoc_secure_channel_sch_credentials_new (opt , & cred -> cert , enabled_protocols );
959+ cred -> cred_type = sch_credentials ;
960+ } else {
961+ cred -> cred = _mongoc_secure_channel_schannel_cred_new (opt , & cred -> cert , enabled_protocols );
962+ cred -> cred_type = schannel_cred ;
895963 }
964+ #else
965+ cred -> cred = _mongoc_secure_channel_schannel_cred_new (opt , & cred -> cert , enabled_protocols );
966+ cred -> cred_type = schannel_cred ;
967+ #endif
896968
897- cred -> cred .grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT ;
898969 return cred ;
899970}
900971
@@ -906,6 +977,13 @@ mongoc_secure_channel_cred_deleter(void *cred_void)
906977 return ;
907978 }
908979 CertFreeCertificateContext (cred -> cert );
980+ #ifdef HAVE_SCH_CREDENTIALS
981+ if (cred -> cred_type == sch_credentials ) {
982+ SCH_CREDENTIALS * sch_cred = (SCH_CREDENTIALS * )cred -> cred ;
983+ bson_free (sch_cred -> pTlsParameters );
984+ }
985+ #endif
986+ bson_free (cred -> cred );
909987 bson_free (cred );
910988}
911989
@@ -982,7 +1060,7 @@ mongoc_stream_tls_secure_channel_new_with_creds(mongoc_stream_t *base_stream,
9821060 UNISP_NAME , /* security package */
9831061 SECPKG_CRED_OUTBOUND , /* we are preparing outbound connection */
9841062 NULL , /* Optional logon */
985- & cred -> cred , /* TLS "configuration", "auth data" */
1063+ cred -> cred , /* TLS "configuration", "auth data" */
9861064 NULL , /* unused */
9871065 NULL , /* unused */
9881066 & secure_channel -> cred_handle -> cred_handle , /* credential OUT param */
0 commit comments