Zabezpieczenie serwisów WCF certyfikatem bez instalowania certyfikatu na komputerze. Klucz prywatny nie występuje w certyfikacie X.509

0

Robię zabezpieczenie/szyfrowanie serwisu WCF certyfikatem. Moje podejście jest trochę inne bo nie instaluję certyfikatu na komputerze tylko czytam go z pliku.
Powinno to zadziałać w sposób, że po stronie klienta będzie certyfikat tylko z kluczem publicznym (.cer) a po stronie serwisu z publicznym i prywatnym (.pfx)
Tymczasem jeżeli umieszczę po stronie klienta certyfikat tylko z kluczem publicznym (.cer) przy próbie odezwania się do serwisu otrzymuję wyjątek: "Klucz prywatny nie występuje w certyfikacie X.509." Dlaczego ? Jest to certyfikat który wygenerowałem sobie sam ale chyba nie powinno mieć to znaczenia. Tak wygląda kod.

KLIENT:

Odzywam się do serwisów poprzez chanellFactory


channelFactory = new ChannelFactory<IMyService>("IMyService", myEndpoint);

using (var stream = Assembly.GetManifestResourceStream("KlientProject.Certificate.Cert.cer"))
{
	byte[] bytes = new byte[stream.Length];
	stream.Read(bytes, 0, bytes.Length);
	channelFactory.Credentials.ClientCertificate.Certificate = new X509Certificate2(bytes, string.Empty);
}

channelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.Custom;
channelFactory.Credentials.ServiceCertificate.Authentication.CustomCertificateValidator = new CustomCertificateValidator(); 

//WALIDATOR I CERTYFIKAT ZNAJDUJĄ SIĘ PO STRONIE KLIENTA

SERWER


var myServiceHost = new ServiceHost(typeof(MyService));

using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MyService.Host.Certificate.Cert.pfx"))
{
	byte[] bytes = new byte[stream.Length];
	stream.Read(bytes, 0, bytes.Length);
	myServiceHost.Credentials.ServiceCertificate.Certificate = new X509Certificate2(bytes, string.Empty);
}

var authentication = myServiceHost.Credentials.ClientCertificate.Authentication;
authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
authentication.CustomCertificateValidator = new CustomCertificateValidator();

myServiceHost.Open();

//WALIDATOR I CERTYFIKAT ZNAJDUJĄ SIĘ PO STRONIE SERWERA

Macie jakieś pomysły dlaczego mam ten błąd? Pomyślałem jeszcze że moooże moooże jak ten certyfikat będzie wydany przez CA to tego błędu nie będzie ale wątpię.

  1. Drugie pytanie dziwi mnie dlaczego to działa w ten sposób że jak robię zapytanie z klienta do serwisu poprzez chanellFactory to wygląda to tak:
  • wywołanie metody z callera
  • wywołanie customCertificateValidator po stronie klienta i tutaj PYTANIE ->** do parametru certificateToValidate w tej metodzie wpada certyfikat z serwisu czyli mogę sobie podejrzeć go. W sumie nie wiem jakie tam są dane przekazane ale zastanawiam się po co jest po stronie klienta CustomCertificateValidator dlaczego nie jest tylko po stronie serwera?**
  • CustomCertificateValidator po stronie serwisu
  • wywołanie metody
1
  1. Drugie pytanie dziwi mnie dlaczego to działa w ten sposób że jak robię zapytanie z klienta do serwisu poprzez chanellFactory to wygląda to tak:
  • wywołanie metody z callera
  • wywołanie customCertificateValidator po stronie klienta i tutaj PYTANIE ->** do parametru certificateToValidate w tej metodzie wpada certyfikat z serwisu czyli mogę sobie podejrzeć go. W sumie nie wiem jakie tam są dane przekazane ale zastanawiam się po co jest po stronie klienta CustomCertificateValidator dlaczego nie jest tylko po stronie serwera?**

Jest po stronie klienta żebyśmy mogli zweryfikować czy ktoś nam nie podmienił serwera chociażby (man-in-the-middle attack), albo czy ciągle certyfikat jest ważny, albo co innego sobie tam wymyślimy w końcu to customowa walidacja. Certyfikat z kluczem publicznym może pochodzić z różnych źródeł np zdalnych i wtedy warto go weryfikować po stronie klienta, jak dołączamy go do aplikacji to już tej weryfikacji nie potrzebujemy.

A odnośnie oryginalnego problemu, to spróbowałbym załadować z pliku a nie z pamięci, i ustawić go za pomocą metody .SetCertificate tak by móc przesłać nazwę domeny pod którą jest serwer jako ostatni parameter, bo podobno samemu wygenerowane certyfikaty właśnie potrzebują mieć ustawiony ten parametr.

0

@neves: dzięki za cenne wskazówki. korzystając z Twojej wiedzy chciałbym zapytać jeszcze o jedną rzecz której do końca nie rozumiem jak działa. Chodzi o tag Identity. Jego zadaniem jest, żeby zweryfikować i odrzuć żądania które są wysyłane do serwisów z innej domeny niż określona. Z tego co wyczytałem Identity może być określone tylko po stronie serwisów i to ma sens.
Hostując serwisy można ustalić tag identity dla każdego serwisu:

<identity>
       <dns value="nazwadomeny.com" />
 </identity>

Zauważyłem że gdy odzywam się do serwisu nie jest brane pod uwagę co wpiszę w <identity> po stronie serwisu. Liczy się tylko to żeby Identity klienta było zgodnę z Identity certyfikatu.
To wszystko dzieje się kiedy odzywam się do serwisu przez chanellFactory (tak jak w 1szym poście)

Ma to sens co pisze?

0

Dowiedziałem się jedną nową rzecz, że po stronie klienta jak i po stronie serwera musi być plik z rozszerzeniem .pfx. czyli certyfikat który ma w sobie zarówno klucz publiczny jak i klucz prywatny. Tylko że mają to być dwa różne certyfikaty.
Zastanawiam się w jaki sposób to ma działać. Jedynym miejscem w całym mechanizmie szyfrowania połączenia certyfikatem gdzie mogę coś popsuć jest klasa CustomCertificateValidator (tam porównuje dwa certyfikaty ze sobą). Czyli tam w jakiś sposób muszę zdecydować czy pozwalam wykonać kod na serwerze czy nie.
Przeczytałem także że jedyną bezpieczną walidacją jest porównanie "Thumbprint" obu certyfikatów.
Skoro mam dwa różne certyfikaty to ich Thumbprint zgadzał się nie będzie.

Znalazłem przykład klasy CustomCertificateValidator i generalnie coś podobnego co zrobiłem ja ale jest w niej jedna rzecz której nie do końca rozumiem mianowicie plik: ServiceCAPublicKey.cer

link: https://blog.kloud.com.au/2015/11/23/implementing-a-wcf-client-with-certificate-based-mutual-authentication-without-using-windows-certificate-store/#comment-262289

Czyli ktoś ma tam 3 pliki i używa ich wszystkich do walidacji certyfikatu

  1. ClientPFX.pfx (czyli to certyfikat z kluczem publicznym i prywatnym)
  2. ServicePublicKey.cer (chyba klucz publiczny z certyfikatu serwisu)
  3. ServiceCAPublicKey.cer (nie wiem)

Rozumiem że klucz publiczny certyfikatu serwisu bedzie u klienta i bede walidowal go z kluczem publicznym certyfikatu który dostałem od serwisu. Ale po co to ServiceCAPublicKey.cer i co to jest to nie wiem. No bo chyba wszystkie certyfikaty powinny być od CA skoro mówimy tu o produkcji.

Wiece jak to powinno działać ? Dodam że mówię tu o środowisku produkcyjnym więc ręcznie podpisany certyfikat nie wchodzi w grę. Domyślam się że ten 3ci certyfikat tworzony jest na podstawie któregoś innego?

1 użytkowników online, w tym zalogowanych: 0, gości: 1