Azure web role - Multiple ssl certs pointing to a single endpoint - ssl

Is there a way I can have multiple ssl certificates point to a single inputendpoint in a service definition? For example, lets say I have two url's.
service.foo.net/Service.svc
service.doo.net/Service.svc
I want both of these addresses to resolve to my windows azure service, but I'm not sure how to configure this in the service definition.
<Certificates>
<Certificate name="service.foo.net" storeLocation="LocalMachine" storeName="My" />
<Certificate name="service.doo.net" storeLocation="LocalMachine" storeName="My" />
</Certificates>
<Endpoints>
<InputEndpoint name="HttpsIn" protocol="https" port="443" certificate="service.foo.net" />
</Endpoints>
According to this MSDN article, each input endpoint must have a unique port. Is there any way to specify more than once certificate for this endpoint?

Unfortunately this is not possible. Azure is re-exposing an SSL limitation. The SSL limitation is interesting, and the reason you can't use v-hosts over SSL. Lets walk through an example:
You connect to https://ig2600.blogspot.com
That resolves to some ip address - say 8.8.8.8
Your browser now connects to 8.8.8.8
8.8.8.8 must preset a certificate before your browser will send any data
the browser verifies the ceritificate presented is for ig2600.blogspot.com
You send the http request, which contains your domain name.
Since the server needs to present a certificate before you tell it the host name you want to talk to, the server can't know which certificate to use if multiple are present, thus you can only have a single cert.

"Oliver Bock"'s answer may work for you and "Igor Dvorkin"'s answer is not valid anymore since IIS 8 with Windows Server 2012 supports SNI, which enables you to add a "hostheader" to HTTPS bindings and having multiple SSL certificates to different domains listening to the same HTTPS port.
You need to automate the process of installing the certificates on the machine and add HTTPS bindings to IIS.
I'm a Microsoft Technical Evangelist and I have posted a detailed explanation and a sample "plug & play" source-code at:
http://www.vic.ms/microsoft/windows-azure/multiples-ssl-certificates-on-windows-azure-cloud-services/

This post indicates you will need a "multi domain certificate", which seems to be a certificate that can match multiple DNS names in step 5 of Igor's answer. I have not tried it, but presumably this certificate can be uploaded to Azure in the usual way.

Related

Client certificate based authentication HAProxy and a general questions

I want to add to a Tomcat servlet (which is behind a HAProxy server) client based authentication so what I did was
I've updated Tomcat configuration by adding
<Connector port="18443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="want" sslProtocol="TLS"
keystoreFile="conf/cert/server-keystore.jks"
keystorePass="changeit"
truststoreFile="conf/cert/server-truststore.jks"
truststorePass="changeit" />
P.S more info on https://docs.bmc.com/docs/rsso1908/configuring-the-tomcat-server-for-certificate-based-authentication-907302408.html
I also updated my HAProxy configuration by updating several lines, i.e
listen VIP
bind 172.16.200.85:443 transparent ssl crt /etc/haproxy/cert/server.pem ca-file /etc/haproxy/cert/ca.crt verify required crl-file /etc/haproxy/cert/root_crl.pem
P.S more info on https://www.loadbalancer.org/blog/client-certificate-authentication-with-haproxy/
and when I navigate to a page I get prompted for a certificate immediately, and I don't want that. What I want is a specific path, i.e /login/me to prompt for a certificate to choose. Basically, I want the same solution for client certificate authentication as on
https://secure.login.gov/
--> select "Sign in with your government employee ID"
--> click on the button "Insert your PIV/CAC" [you get a certificate list to choose from]
My questions:
How they are able to to accomplish client certificate based authentication via (it seems) a path "/login/piv_cac"?
I'm asking this, because I've found answers on a stackoverflow configure tomcat for client authentication only for specific URL patterns that this is not possible to accomplish. I've also tried my self, but I get always prompted for a client certificate upon connecting to a Tomcat instance (before navigating to an authentication url)
Is it doable with two Tomcat instances behind a HAProxy?
If so, what would be a general HAProxy configuration [or steps] for this?
If not, what do I need to make it happen?
Do I need one Tomcat instance for "casual" human beings and other Tomcat instance for "certified" human beings?

Tomcat 9.x.x Client Authentication using X.509 Certificates

I’m using Tomcat 9.0.19 and trying to enable X.509 cert.-based client authentication (AKA I&A) for a particular Web application.
In summary, the Tomcat works for an application that has basic I&A enabled over one-way TLS. When accessing the Web application that has certificate-based I&A, Tomcat does not seem to request a client certificate as part of the Server Hello message, prior to sending Server Hello Done and it later fails the authentication check:
02-Jan-2020 13:00:40.371 FINE [https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate Looking up certificates
02-Jan-2020 13:00:40.830 FINE [https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate No certificates included with this request
Traced the TLS flow in Wireshark and saw the TLS 1.2 handshake. Shortly after encrypted data is exchanged, the Tomcat sends an “Encrypted Alert” message and the socket is closed. Trying to contact the Tomcat from the browser, doing a GET. The browser does not prompt me to select a certificate, which also seems to point to Tomcat not requesting it from the browser.
Any help will be greatly appreciated!
More Details:
We have a set of certificates for the Tomcat and the client, issued by an Intermediate CA, which is signed (issued) by a Root CA. The trust stores have been setup on both sides (client and server) as well as key stores with the right certs/keys in them. The Web application is setup to require certificate I&A (web.xml):
<security-constraint>
<web-resource-collection>
<web-resource-name>All by default</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>OTService</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>certificate</realm-name>
</login-config>
The OTService role is setup in the Tomcat-Users.xml, along with a single user account:
Now, the Connector in server.xml is configured as follows:
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="100" SSLEnabled="true" scheme="https" secure="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="/apache-tomcat-9.0.19/conf/km/keyStore.jks"
certificateKeystorePassword="PASSWORD"
certificateKeyAlias="tomcat"
type="RSA" />
truststoreFile="/apache-tomcat-9.0.19/conf/km/trust_store.jks"
truststorePass="PASSWORD"
truststoreType="JKS"
certificateVerification="required"
clientAuth="true"
protocols="TLSv1.2"
</SSLHostConfig>
</Connector>
Any ideas why Tomcat would not request a client certificate?
The first issue that I discovered was that Tomcat ignored the Connector->SSLHostConfig settings for the trust store and used the JRE default trust store anyway. The way I discovered it was to have a browser save the negotiated TLS session key to a file (Google SSLKEYLOGFILE), then configured the Wireshark to use that file, captured the browser-Tomcat session and then was able to see every message in plaintext.
Next, I discovered that Tomcat was actually asking for a client cert., but the list of accepted Root CAs it was sending was from the default JRE cacerts file, not from the file specified by the truststoreFile attribute. Can have Tomcat use a different file across the board by adding a setenv.sh file to the Tomcat bin directory with Java properties to override default trust store location.
Now, I was in business, the browser was able to complete the TLS handshake, but then the authentication and authorization steps were failing. I finally determinate that the proper way to provide the cert. subject field in tomcat_users.xml file was not "CN=OU Client, OU=Control Systems, O=IoTOY, L=Scottsdale, S=AZ, C=US", but "CN=OU Client, OU=Control Systems, O=IoTOY, L=Scottsdale, ST=AZ, C=US". Finally, I had 2-way TLS working.
One thing to keep in mind is if anything running on the Tomcat attempts to connect over TLS to another system that uses commercial CA certs, it will fail because the truststore you're using now does not have commercial Root CAs' certs. One way to remediate it is to make a copy of the default JRE cacerts file and add your system-specific CA cert(s) to it and point to it from the setenv.sh file noted above.
When you have:
<Connector ...>
<SSLHostConfig>
<Certificate A=1 B=2 C=3 />
D=4 E=5 F=6
</SSLHostConfig>
</Connector>
then A,B,C are attributes of the Certificate object but D,E,F are NOT attributes of the SSLHostConfig object -- they are XML content which is different. Attributes need to be put IN THE TAG:
<Connector ... >
<SSLHostConfig certificateVerification="required" truststoreFile=... >
<Certificate ...keystore... />
</SSLHostConfig>
</Connector>
and that does cert-request on the initial handshake as desired (for me, tested on tomcat 9.0.14).

BizTalk WCF-BasicHttp Identity Editor field clarification

I'm trying to make it so my Send Port which is of type WCF-BasicHttp, will send a client certificate that will be accepted by the IIS server of the WCF service.
So far, as far as I can tell, the Client Cert is being attached (because when I put the wrong thumbprint value in there, I get a "Client Cert not found error"). However, now I'm getting an error as such
System.Net.WebException: The underlying connection was closed: Could
not establish trust relationship for the SSL/TLS secure channel. --->
System.Security.Authentication.AuthenticationException: The remote
certificate is invalid according to the validation procedure.
Which to me, sounds like something in processing the IIS SSL certificate is not working.
This service
works fine when being called from another Winforms application, using
the same Client Cert.
is set to Require SSL
is set to Require Client Certificates
Have a look at the image below...the only way I was able to the WCF to recognize a client cert was being attached was through configuring the send port as such:
My question is, does this look correct? Notice the highlighted field, what is supposed to go in there? Is this the reason I'm getting the SSL/TLS error?
EDIT Or, do I have it all wrong, and the lower Certificate Reference area is not supposed to contain the Client Certficate?
So, it turns out, that in order to get it to work, I had to provide the Service's identity in the top portion. I noticed that putting anything in the Endpoint Identity dialog, after saving, a nice little bit of XML is written to the WCF-BasicHttp dialog after.
<identity>
<dns value="myserver.mydomain.ca" />
<certificateReference storeName="My" storeLocation="LocalMachine" x509FindType="FindByThumbprint" findValue="[thumbprint]" isChainIncluded="False" />
</identity>
with only the lower portion filled out as in my question above, it provides the <certificateReference> portion, but the <dns value="myserver.mydomain.ca" /> does not show up until you provide something in one of the textboxes in the "General" section. It worked when I provided either the DNS, or the Base64 of the server certificate.
So, I guess the answer is, once you fill out one of the sections, both are required, the send port is not going to automatically guess on the endpoint based on the address.

How do I implement Client Certificate authentication the right way?

WCF is extremely extensible and has a lot of ready-to-use features, however I continue struggling with some topics and the more documentation I read, the more I get confused.
I hope to get some answers from the community. Feedback on any assumption or question is extremely welcome.
For the record: to really accept a single answer I should divide this post in multiple questions but it would lead to even more confusion.
I am pretty sure there are some real WCF experts online who can answer the few questions in this document all at once so I can accept a single answer as the real deal to setup clientcertificate authentication using IIS the right way.
Let me sketch the situation and partner request:
1: The partner requirement and the question to use a client certificate.
Partner X needs to call an API on my backend and they have the clear requirement to use Clientcertificate authentication.
They created the clientcertificate and provided us the certificate with only the public key since it seems only logic they keep the private key actually private and in their own system(s).
The certificate was imported on the local computer account and looking at the certification path this is valid. All intermediate certification authorities and in the end the root certification authority are trusted.
2: Our WCF serverside configuration
I have a serviceBehavior configured as such:
<behavior name="ClientCertificateBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceCredentials>
<serviceCertificate findValue="<serialnumber here>" x509FindType="FindBySerialNumber" />
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" />
</clientCertificate>
</serviceCredentials>
</behavior>
I guess I made a first mistake here and should use ChainTrust to actually validate the certificate using its certification path. What do you think?
The service is configured as such:
<service behaviorConfiguration="ClientCertificateBehavior" name="<Full service namespace and servicename>">
<endpoint binding="basicHttpBinding" bindingConfiguration="Soap11CertificateBasicHttpBinding"
contract="<The interface>"></endpoint>
</service>
The binding looks like this:
It is a basicHttpBinding to force SOAP1.1 (according to the partner's specifications).
<binding name="Soap11CertificateBasicHttpBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
3: Hosting the WCF service in IIS and the IIS configuration
We host our WCF services in IIS7.
We configured the folder in which the services reside to require SSL and to accept Client certificates.
Authentication-wise anonymous authentication is enabled.
The thing is that communication from the partner works and we were confident that everything was OK, however toggling the IIS-setting to 'require' client certificate shows us that all of a sudden it is no longer possible to successfully call our service.
Am I correct to assume that following things are not done correctly:
The serviceCerticate in the serviceBehavior is not really necessary. This is a setting used by the client. Or is it necessary to provide this certificate information for the service endpoint to match the certificate that's being send by the client?
For clientcertificate authentication to really work in IIS the certificate needs to be mapped to a user. This user should be granted permissions on the folder containing the services and all authentication mechanisms (anonymous, windows,...) should be disabled.
This way IIS will handle the actual handshake and validate the servicecommunication.
Or is it more a matter of extra security mapping the certificate to a user?
By setting 'Accept' on IIS we bypass the actual certificate validation between client and server.
All authentication mechanisms like 'anonymous' and 'windows' have to be disabled on IIS for the folder which holds the services.
In your scenario, you don't need to configure certificates in WCF, IIS handles those for you. You can clear the entire <serviceCredentials> block, because:
The <serviceCertificate> of <serviceCredentials> specifies an X.509 certificate that will be used to authenticate the service to clients using Message security mode, which you do not use, and the <clientCertificate> of <serviceCredentials> defines an X.509 certificate used to sign and encrypt messages to a client form a service in a duplex communication pattern.
See here how to map client certificates to user accounts.

How to set user principal name of service identity of an STS issuer for a ws-federation binding by config?

How can I specify the service identity principal name in the WCF client config for the issuer STS when binding using WS-Federation?
I have an application pool running under a domain account on a front end server trying to authenticate using federation to backend services on an app server (running under domain accnts) using an STS also running on the app server and under a domain account.
In order to use Kerberos correctly I need to set the userprincipal name of the STS on the frontend client. I can't see how to do that.
I am experiencing a connected problem, which is that fallback to NTLM does not work when the issuer is specified using FQDN, and Kerberos fails (SSPI negotiation failed) I think because I have no issuer principal name in the config. If I set the issuer using IP address instead, then authentication to STS succeeds using NTLM, I think, so I have a workaround.
The STS is issuing tokens on the basis of Windows auth on that endpoint. It has other endpoints for forms-type auth and so on.
Possibly a related problem on our network is that silverlight clients that call back to web services are not working without the servers being manually added to Local Intranet zone in IE. Seems as though for some reason the app servers are not considered as being on same domain. Any clues much appreciated!
I found the solution regarding setting the user principal name of the STS. I just needed to set it in the issuer element of the federation binding:
OK, don't know why I couldn't find this before, but first thing Monday morning the answer pops up immediately:
http://msdn.microsoft.com/en-us/library/aa347735.aspx
The issuer element of the wsfederation is an endpoint config that allows you to set the user principal name within it.
The schema from the link above is here:
<issuer address="Uri" >
<headers>
<add name="String"
namespace="String" />
</headers>
<identity>
<certificate encodedValue="String"/>
<certificateReference findValue="String"
isChainIncluded="Boolean"
storeName="AddressBook/AuthRoot/CertificateAuthority/Disallowed/My/Root/TrustedPeople/TrustedPublisher"
storeLocation="LocalMachine/CurrentUser"
x509FindType=System.Security.Cryptography.X509certificates.X509findtype/>
<dns value="String"/>
<rsa value="String"/>
<servicePrincipalName value="String"/>
<usePrincipalName value="String"/>
</identity>
</issuer>
Regarding the network issues, this was a DNS problem. PTR used instead of aliases.