2015-07-03 37 views
21

Pracuję nad usługą WCF, która ma być używana przez klienta, który nie został opracowany przeze mnie, a także nie jest .NET (być może Java).Wzajemne uwierzytelnianie SSL za pomocą WCF: brak certyfikatu CertificateRequest i certyfikatu Potwierdź w fazie uzgadniania

W każdym przypadku usługa powinna obsługiwać wzajemne uwierzytelnianie SSL, gdy zarówno usługa, jak i klient uwierzytelniają się certyfikatami X.509 w warstwie transportowej. Certyfikaty zostały wymieniane między stronami w odpowiednim momencie.

Mój problem polega na tym, że nie mogę uzyskać odpowiedniej konfiguracji WCF, tak aby uwierzytelnianie certyfikatu klienta działało poprawnie. Co się spodziewać, że w ramach uzgadniania TLS, serwer zawiera również Certificate Request, jak widać poniżej:

enter image description here

Następnie, klient powinien odpowiedzieć z `Certyfikat Sprawdź” między innymi:

enter image description here

The (najnowsza) konfiguracja usługi jest ten jeden. Używam niestandardowego powiązania z trybem uwierzytelniania ustawionym na MutualSslNegotiated.

<bindings> 
    <customBinding> 
    <binding name="CarShareSecureHttpBindingCustom"> 
     <textMessageEncoding messageVersion="Soap11" /> 
     <security authenticationMode="MutualSslNegotiated"/> 
     <httpsTransport requireClientCertificate="true" /> 
    </binding> 
    </customBinding> 
</bindings> 

... 

<serviceBehaviors> 
    <behavior name="ServiceBehavior"> 
    <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" /> 
    <serviceDebug includeExceptionDetailInFaults="false" httpHelpPageEnabled="false" /> 
    <serviceCredentials> 
     <serviceCertificate findValue="..." storeLocation="LocalMachine" x509FindType="FindByIssuerName" storeName="My" /> 
     <clientCertificate> 
     <certificate findValue="..." storeName="My" storeLocation="LocalMachine" x509FindType="FindByIssuerName"/> 
     </clientCertificate> 
    </serviceCredentials> 
    </behavior> 
</serviceBehaviors> 

Cześć przywitania serwera wygląda tak w przypadku wszystkich konfiguracji usług, które próbowałem, bez certyfikatu CertificateRequest. enter image description here

Inne rzeczy powinienem wymienić:

  • Usługa jest własny serwer i nasłuchuje na porcie niż domyślny (nie 443). Certyfikat SSL serwera został powiązany z tym portem.
  • Próbowałem również basicHttpBinding i wsHttpBidning z trybem zabezpieczeń ustawionym na Transport i ustawieniem uwierzytelniania klienta na Certificate, bez wyników (w rzeczywistości wyniki są takie same).

Wszelkie pomysły będą mile widziane.

+0

Próbowałeś włączyć WCF śledzenie i sprawdzić, czy są jakieś szczegółowe błędy w środku? – UserControl

+0

@UserControl: Tak, śledzenie jest włączone, ale niestety nie ma żadnych powiązanych błędów. –

+0

Dzikie uderzenie - jest szansa, że ​​po stronie serwera brakuje certyfikatów głównych z łańcucha zaufania klienta? Oznacza to, że masz certyfikat klienta, ale brakuje niektórych certyfikatów root w swoim łańcuchu ...? –

Odpowiedz

11

OK, po kilku kolejnych próbach wymyśliłem to. Publikowanie tego na wypadek, gdyby inni napotkali ten sam problem.

Powinienem kontynuować, wspominając, że to zachowanie naprawdę musi być wymienione gdzieś w MSDN, w miejscu, które jest naprawdę widoczne dla każdego, kto szuka informacji bezpieczeństwa WCF, a nie zakopane głęboko w dokumentacji jakiegoś narzędzia.

Platformy, na których udało mi się odtworzyć i naprawić: Windows 8.1 x64 i Windows Server 2008 R2 Standard.

Jak już wspomniałem, moim problemem było to, że nie mogłem skonfigurować zabezpieczeń WCF tak, że usługa wymagałaby certyfikatów klienta. Wspólnym zamieszaniem, które zauważyłem podczas poszukiwania rozwiązania, jest to, że wiele osób uważa, że ​​klient może wysłać certyfikat, jeśli go posiada, bez żadnych zastrzeżeń. Nie ma to oczywiście miejsca - serwer musi najpierw o to poprosić, a ponadto określić, które urzędy certyfikacji są dozwolone: ​​through a CertificateRequest reply.

Podsumowując, moja sytuacja była:

  • Usługa jest self-hosted.
  • Usługa działa na HTTPS, na niestandardowym porcie (nie 443, ale 9000).

To oznaczało, że musiałem utworzyć certyfikat SSL wiążący dla portu 9000 przy użyciu netsh.exe http add sslcert. Wiązanie zostało stworzone, ale był haczyk. Znalazłem tylko problem po uruchomieniu netsh http show sslcert po prostu sprawdzić na moim oprawa:

IP:port      : 0.0.0.0:9000 
Certificate Hash    : ... 
Application ID    : ... 
Certificate Store Name  : MY 
Verify Client Certificate Revocation : Enabled 
Verify Revocation Using Cached Client Certificate Only : Disabled 
Usage Check     : Enabled 
Revocation Freshness Time : 0 
URL Retrieval Timeout  : 0 
Ctl Identifier    : (null) 
Ctl Store Name    : (null) 
DS Mapper Usage    : Disabled 
-->Negotiate Client Certificate : Disabled 

Sprawca był ostatnią właściwość wiązania, „Negocjuj certyfikat klienta”, udokumentowany here. Wygląda na to, że ta właściwość jest domyślnie wyłączona. Musisz go włączyć jawnie podczas tworzenia wiązania.

Odtworzenie wiążące się ze stwierdzeniem poniżej rozwiązał problem:

netsh.exe http add sslcert ipport=0.0.0.0:9000 certhash=... appid=... certstorename=MY verifyclientcertrevocation=Enable VerifyRevocationWithCachedClientCertOnly=Disable UsageCheck=Enable clientcertnegotiation=Enable 

Przed sprawdzenie powiązań próbowałem gospodarzem prostą usługę WCF w IIS i włączyć uwierzytelnianie certyfikatu klienta stamtąd. Był bardzo ciekawy, że chociaż nie wydano żadnego numeru, to jednak nie udało się uzyskać 403,7. Nawet usługi IIS nie utworzyły powiązania z odpowiednimi parametrami.

W każdym razie teraz działa i tak można to naprawić.

Nie zapomnieć, konfigurację usługi zmieniło, jak również (zabezpieczenie wiązanie), w celu umożliwienia negocjacji certyfikatu:

<customBinding> 
    <binding name="CustomHttpBindingCustom" receiveTimeout="01:00:00"> 
    <textMessageEncoding messageVersion="Soap11" /> 
    <security authenticationMode="SecureConversation" requireSecurityContextCancellation="true"> 
     <secureConversationBootstrap allowInsecureTransport="false" authenticationMode="MutualSslNegotiated" requireSecurityContextCancellation="true"></secureConversationBootstrap> 
    </security> 
    <httpsTransport requireClientCertificate="true" /> 
    </binding> 
</customBinding>