Is there a way to call a Web Service with Client and Service Certificates in powershell?

644 views Asked by At

I'm working on a Powershell script, that needs to call a web service, with a Client and Service Certificate. I have the connect semi-working in C# .Net. In .Net app.config i have these configurations:

...
<security mode="TransportWithMessageCredential">
            <message clientCredentialType="Certificate" negotiateServiceCredential="false" establishSecurityContext="false"/>
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CertificateAuthenticationBehavior">
          <clientCredentials>
            <clientCertificate findValue="Capital Market FIONAsi" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
            <serviceCertificate>
              <defaultCertificate findValue="example.dk" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
              <authentication certificateValidationMode="PeerTrust" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>

The .net code.

var stinaProxy = new StinaServiceProxy("StinaService");
var stinaHandshakeResponse = stinaProxy.HandShake(testValueArgument);

This seems to get me passed certificate validation in .net

But as mentioned, I actually need this to work for me in powershell. I don't know how to call a webservice and suppy both the client and the service certificate.

Here is what I got so far in powershell, but it ends in timeout, witch I believe is a certificate problem.

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    $ClientCertificate = Get-ChildItem Cert:\LocalMachine\My\af4269b1d7190be23f1e48001fc345011f7ade80
    $defaultCertificate = Get-ChildItem Cert:\LocalMachine\My\42097f29a5bd2fb4d9960e74f67654d369b7a2e3
    $url = "https://example.dk/StinaService.svc?wsdl"
    $webserviceex = New-WebServiceProxy -Uri $url -Namespace WebServiceProxy 
    $webserviceex.Timeout = 5000
    $webserviceex.ClientCertificates.Add($ClientCertificate)
    $webserviceex.ClientCertificates.Add($defaultCertificate)
    $handshakeResult = $webserviceex.HandShake("1234!")

Any help is appreciated :)

1

There are 1 answers

2
Cpt.Whale On

I doubt the ServiceCertificate is going to be the cause of your issues since only the client should care. Have you tried setting your $webserviceex with only the $ClientCertificate added? Usually, you would only add additional certificates if you had a chain and needed CA certificates too.


I did find how to add service certificates in powershell. You didn't include the classes you used, but I was able to use [System.ServiceModel.ServiceHost] to create something similar to what you have. here is a powershell example of a webservice using client and server certificates.

[URI]$URI = 'https://example.dk/StinaService.svc'

# WSHttpBinding
$binding = New-Object System.ServiceModel.WSHttpBinding
$binding.Security.Mode = [System.ServiceModel.SecurityMode]::TransportWithMessageCredential
$binding.Security.Transport.ClientCredentialType = [System.ServiceModel.HttpClientCredentialType]::Certificate
$binding.Security.Message.ClientCredentialType   = [System.ServiceModel.MessageCredentialType]::Certificate

# Create service host
$ServiceHost = [System.ServiceModel.ServiceHost]::new([StinaService], $URI)
    $ServiceHost.AddServiceEndpoint([IStinaService], $binding,"")

    # Add Service Certificate (authenticate the server)
    $ServiceHost.Credentials.ServiceCertificate.SetCertificate(
        [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine,
        [System.Security.Cryptography.X509Certificates.StoreName]::My,
        [System.Security.Cryptography.X509Certificates.X509FindType]::FindBySubjectName,
        'example.dk'
    )
    # Add Client Certificate (authenticate the client)
    $ServiceHost.Credentials.ClientCertificate.SetCertificate(
        [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine,
        [System.Security.Cryptography.X509Certificates.StoreName]::My,
        [System.Security.Cryptography.X509Certificates.X509FindType]::FindBySubjectName,
        'Capital Market FIONAsi' 
    )

# Open the service
$ServiceHost.Open()

# Close the service.
$ServiceHost.Close()

I based this off of the example .net WCF code in this MS how-to, and defined the [StinaService] ServiceContract using the definitions from Chrissy Lemaire in her powershell tcp service proof-of-concept.


Note that you can probably ignore this example - just copy your existing .Net code, format it to powershell like this, and import the same app.config you are already using.

[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "$dllPath.config")
$null = [Reflection.Assembly]::LoadFrom($dllPath)

Copied from https://stackoverflow.com/a/33927024/7411885.