2017-12-20 269 views
18

Mam następujący kod C#, konstruując wywołanie https z certyfikatem niestandardowym. Podczas korzystania z Tls 1.1, połączenie działa poprawnie. Podczas korzystania z Tls 1.2 połączenie jest przerywane. Używam curl, używając TLC 1.2 również działa dobrze.C# i dotnet 4.7.1 nie dodawanie niestandardowego certyfikatu dla wywołań TLS 1.2

C# Kod:

X509Certificate2Collection collection = new X509Certificate2Collection(); 
collection.Import("C:\\SomePath\\MyCertificate.pfx", "MyPassword", X509KeyStorageFlags.PersistKeySet); 
var cert = collection[0]; 

ServicePointManager.SecurityProtocol = ...; 

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) => true; 
HttpClientHandler handler = new HttpClientHandler(); 
handler.ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true; 
handler.ClientCertificates.Add(cert); 

var content = new ByteArrayContent(Encoding.GetEncoding("latin1").GetBytes("Hello world")); 
HttpClient client = new HttpClient(handler); 
var resp = client.PostAsync(requestUri: url, content: content).Result.Content.ReadAsStringAsync().Result; 

Działa z:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11; 

Błąd:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 

komunikat .Net: SocketException: Istniejące połączenie zostało gwałtownie zamknięte przez zdalny host

wersja .Net: 4.7.1

OS: Windows 10 w wersji 1703 (obsługiwane lista szyfr: https://msdn.microsoft.com/en-us/library/windows/desktop/mt808163(v=vs.85).aspx) - i serwer określa TLS_RSA_WITH_AES_256_GCM_SHA384 być używany, który jest jednym z obsługiwanych szyfrów.

W wireshark widzę, że przy połączeniach roboczych (C#/Tls 1.1 i Curl Tls 1.2) certyfikat jest wysyłany na serwer. Oto zrzut Wireshark dla C# tls 1.1 rozmowy:

Wireshark dump - Csharp tls 1.1

Jednak również w Wireshark, widzę, że z C#/TLS 1.2 nie ma certyfikat wysyłane od klienta do serwera. Oto zrzut Wireshark dla C# tls 1.2 rozmowy:

enter image description here

Czy ktoś może zobaczyć, co ja tu brakuje?

UPDATE

Wydaje się, że certyfikat ma podpisu md5, który nie jest obsługiwany przez Schannel w oknach w połączeniu z TLS 1.2. Nasz dostawca utworzył dla nas kolejny certyfikat jako rozwiązanie.

natknąłem tej losowej wątku, który omawia problem: https://community.qualys.com/thread/15498

+0

Miałem podobny problem z aplikacją klient/serwer .Net Core 2.0. Rozwiązałem, wymuszając na serwerze TLS 1.2. W ten sposób klient właściwie negocjuje protokół i certyfikat. Możesz spróbować połączyć się z serwerem, który jest zmuszony tylko do TLS 1.2 i zobaczyć, czy masz takie samo zachowanie w .NET Framework. – Ghigo

+0

Dobrze to zmienić na serwerze, tak naprawdę nie jest tu opcja, ponieważ serwer należy do dostawcy. I nie ma znaczenia, czy dodaję tls 1.1 razem. Dopóki tls 1.2 jest tylko jednym z dozwolonych protokołów, ten problem ma miejsce. Muszę wiedzieć, dlaczego .net zachowuje się w ten sposób, gdy curl działa dobrze. I potrzebuję włączonej funkcji tls 1.2, ponieważ jest to ustawienie statyczne, a inne połączenia zależą od tls 1.2 w tej samej aplikacji. Gdybym mógł zmienić tls 1.3 dla tego pojedynczego połączenia, zrobiłby to. Ale ustawienie protokołów na obiekcie obsługi powoduje zgłoszenie wyjątku informującego, że nie jest to możliwe w bieżącym env. –

+1

Wygląda trochę jak duplikat tego pytania https://stackoverflow.com/questions/44751179/tls-1-2-not-negotiated-in-net-4-7- bez -explicit-servicepointmanager-security –

Odpowiedz

0

Wierzę, że ten kod jest maskowanie jakiś rodzaj błędu certyfikatu przez zawsze ślepo powrocie prawda:

polecam mieć funkcję naprawdę analizować wyniki arg4. To są błędy zasad SSL. Zaloguj się, a otrzymasz odpowiedź. W moim przykładzie piszę do konsoli, ale możesz pisać do śladu lub pliku. Otrzymasz numer, który zostanie powiązany z wartością wyliczenia SslPolicyErrors. Na podstawie wyników możesz potrzebować sprawdzić swój arg3, który jest twoim łańcuchem.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => { 

SslPolicyErrors errs = sslPolicyErrors; 
Console.WriteLine("Policy Errors " + sslPolicyErrors.ToString());   
return true;}; 
+0

Po pierwsze, dziękuję za komentowanie! Jednak funkcja wywołania zwrotnego nigdy nie jest wywoływana. Właśnie dodałem ciało do funkcji z punktem przerwania i wywołaniem zapisu na konsolę i nic z tego nie zostanie pobite. –

+0

Ctznkane w rzeczywistości, mimo że nie jest wywoływane podczas korzystania z tls 1.2, jest rzeczywiście wywoływane podczas używania tls 1.1 i określa typ błędu "System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors". Metoda zwraca wartość true, pozwalając na wywołanie w tls 1.1, ale może tls 1.2 na to nie zezwoli w ogóle ze względu na wyższe standardy bezpieczeństwa? Najlepszym rozwiązaniem jest dowiedzieć się, dlaczego błędy łańcucha występują w tls 1.1, a następnie naprawić błąd i spróbować ponownie z Tls 1.2. Wrócę z wynikiem. –

+0

Po niewielkim wykopaniu obiektów udowodnionych dla metody wywołania zwrotnego, znalazłem tę wiadomość w głąb: "Łańcuch certyfikatów przetworzony, ale zakończony certyfikatem głównym, który nie jest zaufany przez dostawcę zaufania." - Pojadę google specjalnie po ten błąd. –

0

Nie powinieneś określać właściwości usługi obsługi SslProtocols?

Spróbuj dodać ten wiersz po hander definicję:

handler.SslProtocols = SslProtocols.Tls12; 
1

Jesteś tuż przy głównej przyczyny tego problemu: Domyślnie klienci SCHANNEL oparte oferują SHA1, SHA256, SHA384 i SHA512 (na Win10/Server 2016). Dlatego też serwery TLS 1.2 nie powinny wysyłać swoich certyfikatów MD5 do tych klientów.

Klient (HttpClient) nie wyświetla MD5 w rozszerzeniu signature_algorithms, więc uzgadnianie TLS 1.2 kończy się niepowodzeniem. Poprawka polega na użyciu certyfikatu bezpiecznego serwera.