Domanda Autenticazione SSL reciproca con WCF: no CertificateRequest e CertificateVerify nella fase di handshake


Sto lavorando a un servizio WCF che deve essere utilizzato da un client che non è stato sviluppato da me e che non è .NET (forse Java).

In ogni caso, il servizio deve supportare l'autenticazione SSL reciproca, in cui sia il servizio che il client autenticano con certificati X.509 certificati al livello di trasporto. I certificati sono stati scambiati tra le parti in un momento precedente.

Il mio problema è che non riesco a ottenere la corretta configurazione di WCF in modo tale che l'autenticazione del certificato client funzioni correttamente. Quello che mi aspetto è che, come parte dell'handshake TLS, il server includa anche un Certificate Request, come visto di seguito:

enter image description here

A seguito di ciò, il client dovrebbe rispondere con un "Certificate Verify" tra le altre cose:

enter image description here

La (ultima) configurazione del servizio è questa. Sto usando un'associazione personalizzata, con la modalità di autenticazione impostata su 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>

La parte Server di Hello Handshake è simile a questa per tutte le configurazioni di servizio che ho provato, senza CertificateRequest. enter image description here

Altre cose che dovrei menzionare:

  • Il servizio è auto-ospitato e in ascolto su una porta non predefinita (non 443). Il certificato SSL del server è stato associato a questa porta.
  • Ho provato anche a basicHttpBinding e a wsHttpBidning con la modalità di sicurezza impostata su Transport e l'autenticazione del client impostata su Certificate, senza risultati (lo stesso risultato in realtà).

Qualsiasi idea sarebbe apprezzata.


22
2017-07-03 06:49


origine


risposte:


OK, dopo qualche altro tentativo l'ho capito. Pubblicando questo nel caso in cui altri si imbattono nello stesso problema.

Dovrei continuare dicendo che questo comportamento deve essere menzionato da qualche parte su MSDN, in una posizione che è davvero visibile per chiunque sia alla ricerca di informazioni sulla sicurezza della WCF e non sepolta in profondità nella documentazione di alcuni strumenti.

Le piattaforme in cui sono stato in grado di riprodurre e correggere questo: Windows 8.1 x64 e Windows Server 2008 R2 Standard.

Come ho detto, il mio problema era che non potevo configurare la sicurezza della WCF in modo tale che il servizio richiedesse i certificati client. Una comune confusione che ho notato mentre cercavo una soluzione è che molte persone credono che il client possa inviare il certificato, se così fosse, senza essere contestato. Questo, ovviamente, non è il caso: il server deve prima chiederglielo e, inoltre, specificare quali CA sono consentite attraverso a CertificateRequest rispondere.

Per riassumere, la mia situazione era:

  • Il servizio è auto-ospitato.
  • Il servizio viene eseguito su HTTPS, su una porta non standard (non 443 ma 9000).

Ciò significava che dovevo creare un bind certificato SSL per la porta 9000 usando netsh.exe http add sslcert. Bene, il legame era stato creato ma c'era un problema. Ho trovato il problema solo dopo l'esecuzione netsh http show sslcert solo per verificare la mia associazione:

 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

Il colpevole era l'ultima proprietà del legame, "Negozia cliente certificato"documentato Qui. Apparentemente, per impostazione predefinita, questa proprietà è disabilitata. È necessario attivarlo esplicitamente durante la creazione del binding.

La rilegatura vincolante con la seguente affermazione ha risolto il problema:

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

Prima di controllare i binding, ho provato a ospitare un semplice servizio WCF in IIS e ad abilitare l'autenticazione del certificato client da lì. Era molto curioso vedere che anche se non c'era CertificateRequest rilasciato da IIS, ha ancora fallito con a 403.7. Anche IIS non ha creato l'associazione con i parametri appropriati.

Ad ogni modo, ora funziona e questo è il modo in cui puoi aggiustarlo.

Per non dimenticare, anche la configurazione del servizio è stata modificata (la sicurezza vincolante) per consentire la negoziazione dei certificati:

<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>

12
2017-07-06 19:05