Change to self signed certificate results in communication problem? - wcf

I have a C# client that connects to diffrent services like Elastic Search, IdentityService but also a WCF service. All of them are using a certificate to encrypt communication which have been working great. The problem is that I have to revert to a self-signed certificate and the WCF sevice do not like it at all.
When trying to connect to the service I get “This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case”? I changed the
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
to
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
But that did help. I did get a bit further but not much.
The certificate is generated with this command :
openssl req -x509 -newkey rsa:4096 -sha256 -utf8 -days 365 -nodes -config ./config/tiny_openssl.conf -keyout ./certificates/private.key -out ./certificates/certificate.crt
# ./config/tiny_openssl.conf
[CA_default]
copy_extensions = copy
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
[req_distinguished_name]
C = NO
ST = no
L = no
O = no
OU = myservice
emailAddress = myservice#no.com
CN = myservice Services Titan
[v3_ca]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = #alternate_names
[alternate_names]
DNS.1 = 192.168.130.29
DNS.2 = *.192.168.130.29
DNS.3 = app.192.168.130.29
DNS.4 = myservice
DNS.5 = myservice.local
DNS.6 = TITAN.myservice.local
# ...
Why do I get these problems? Is there a way to generate a selfsigned certificate that would be granted by WCF just like the "real" one?
Edit : I have added the private key to the selfsigned certificate with openSSL.

I didn’t know which web server you use to host the WCF service and how to bind the particular certificate to a port. But In a Windows OS, I have to add an Https site binding when I use IIS to host the WCF service with transport security.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-an-iis-hosted-wcf-service-with-ssl
In a console application, I usually bind a certificate to the particular port by the below command.
netsh http add sslcert ipport=0.0.0.0:8000
certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6
appid={00112233-4455-6677-8899-AABBCCDDEEFF}
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
https://learn.microsoft.com/en-us/windows/win32/http/add-sslcert
Or the same error will occur when the client-side try to connect the service over HTTPS protocol.
“This could be due to the fact that the server certificate is not
configured properly with HTTP.SYS…”
Both Powershell and IIS have a tool to generate a certificate. It works for me.
https://learn.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps
Feel free to let me know if there is anything I can help with.

Related

How to share Self-signed TLS certificate between websites

I've two website within same domain example app1.test.local and app2.test.lcaol. Below is the procedure using which I've generated the self-signed certificate.
Create a private key.
openssl genrsa -out tls.key 2048
Edit openssl.conf file and update req_distinguished_name and alt_names contents.
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
countryName = IN
countryName_default = IN
stateOrProvinceName = KA
stateOrProvinceName_default = KA
localityName = Test
localityName_default = Test
organizationalUnitName = test
organizationalUnitName_default = test
commonName = *.test.local
commonName_max = 64
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = #alt_names
[alt_names]
DNS.1 = *.test.local
Create certificate signing request
openssl req -new -out tls.csr -key tls.key -config openssl.cnf
Sign the SSL Certificate.
openssl x509 -req -days 3650 -in tls.csr -signkey tls.key -out tls.crt -extensions v3_req -extfile openssl.cnf
From the view certificate option of browser I can see both SAN and CN has *.test.local as the value. However when I launch application app2 from app1 browser again prompts for trusting the certificate [The certificate is not trusted because it is self-signed.].
Question: How to prevent browser from prompting to Accept the risk and Continue multiple times for the same certificate but from different websites for self-signed certificates.
How to prevent browser from prompting to Accept the risk and Continue multiple times for the same certificate but from different websites for self-signed certificates.
Overriding the warning of a certificate will only affect the currently used domain and not every domain in the certificate. Otherwise somebody could create a certificate for some innocent site but which also includes an SAN of an important site like paypal.com - and later reuse the certificate to impersonate the important site.
To make a certificate trusted for all domains given in the certificate one need to explicitly import the certificate as trusted into the browsers trust store instead of simply ignoring certificate warnings.

iOS 13 TLS issue

I have installed iOS 13 beta version and run my framework which contains a lot of network requests, but I got this error:
2019-09-19 15:01:33.566811+0200 ---[395:25439] Connection 4: default TLS Trust evaluation failed(-9814)
2019-09-19 15:01:33.567022+0200 ---[395:25439] Connection 4: TLS Trust encountered error 3:-9814
2019-09-19 15:01:33.567110+0200 ---[395:25439] Connection 4: encountered error(3:-9814)
2019-09-19 15:01:33.569824+0200 ---[395:25439] Connection 4: unable to determine interface type without an established connection
2019-09-19 15:01:33.584952+0200 ---[395:25439] Task <D97FD611-0B48-4DCE-99C9-6A971E5E6524>.<4> HTTP load failed, 0/0 bytes (error code: -1202 [3:-9814])
I tried to find out what cause that problem with no success. Can anyone help me?
Apple has defined stricter rules for TLS server certificates, starting from iOS 13 and macOS 10.15.
All TLS server certificates must comply with these new security requirements in iOS 13 and macOS 10.15:
TLS server certificates and issuing CAs using RSA keys must use key sizes greater than or equal to 2048 bits. Certificates using RSA key sizes smaller than 2048 bits are no longer trusted for TLS.
TLS server certificates and issuing CAs must use a hash algorithm from the SHA-2 family in the signature algorithm. SHA-1 signed certificates are no longer trusted for TLS.
TLS server certificates must present the DNS name of the server in the Subject Alternative Name extension of the certificate. DNS names in the CommonName of a certificate are no longer trusted.
Additionally, all TLS server certificates issued after July 1, 2019 (as indicated in the NotBefore field of the certificate) must follow these guidelines:
TLS server certificates must contain an ExtendedKeyUsage (EKU) extension containing the id-kp-serverAuth OID.
TLS server certificates must have a validity period of 825 days or fewer (as expressed in the NotBefore and NotAfter fields of the certificate).
And the final note:
Connections to TLS servers violating these new requirements will fail and may cause network failures, apps to fail, and websites to not load in Safari in iOS 13 and macOS 10.15.
I'm going to add some additional information. To check that your certificate is valid you can open it in Keychain Access and check that it contains correct information:
It expires in less than 825 days;
Signature algorithm isn't SHA-1 (SHA-256, probably);
Public key size isn't smaller than 2048 bits;
There's Extended Key Usage extension with "Server Authentication" purpose;
There's Subject Alternative Name extension that contains server's DNS.
Config example for OpenSSL:
[ ca ]
default_ca = CA_default
[ CA_default ]
default_md = sha256
default_days = 825
[ req ]
prompt = no
default_bits = 4096
distinguished_name = req_distinguished_name
x509_extensions = req_ext
[ req_distinguished_name ]
countryName = ...
stateOrProvinceName = ...
localityName = ...
organizationName = ...
commonName = google.com
[ req_ext ]
extendedKeyUsage = serverAuth
subjectAltName = #alt_names
[alt_names]
DNS.1 = google.com
DNS.2 = www.google.com
To generate new key-certificate pair run this command:
openssl req -newkey rsa:4096 -nodes -keyout key.pem -x509 -out certificate.crt -days 825 -config config.cnf

GRPC ssl with self-signed cert

I'm trying to use a self-signed certificate with GRPC. I generated the certificate / key with:
openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
This gave me two files: cert.pem and key.pem.
I have a Kotlin GRPC server that I setup like follows:
val ca = classLoader.getResourceAsStream("cert.pem")
val key = classLoader.getResourceAsStream("key.pem")
ServerBuilder
.forPort(8443)
.useTransportSecurity(ca, key)
.addService(...)
.build()
.start()
This appears to start successfully. I have a flutter client that I setup the following way:
final cert = await rootBundle.load('cert.pem')
final certAsList = cert.buffer
.asUint8List(
cert.offsetInBytes,
cert.lengthInBytes,
)
.map((uint8) => uint8.toInt())
.toList()
final channel = new ClientChannel(
'localhost',
port: 8443,
options: ChannelOptions(
credentials: ChannelCredentials.secure(certificates: certAsList),
),
)
However, using this channel to connect to my service gives the following error:
gRPC Error (14, Error connecting: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: ok(handshake.cc:352)))
What is wrong with this setup?
By default, the certificate presented (in either direction) will be validated in several ways:
Hostname must match the subject Common Name in the certificate
presented.
the certificate must not be revoked, by using CRL or
OCSP to validate
the root CA certificate must be trusted, and no
intermediaries can be revoked
It's likely that you are running into #3, since it's a self-signed certificate (the root is itself and not trusted) and you're already using localhost to connect to it. You could either add this certificate to your trusted CA certificate store or you can programmatically create an insecure certificate validation for your SSL Context. For more details on the Kotlin (Java) side, you can consult the SO here: Disabling certificate check in gRPC TLS
As mentioned in Matt's answer, your CA certificate is not trusted by the device running your Flutter app since it's self-signed.
Now you have 2 options:
Get a valid certificate from a certificate authority like Verisign, or
Disable the certificate verification in your Flutter app itself
Here's how to implement option 2. You simply add a BadCertificateHandler to the ChannelCredentials instance like so:
final cert = await rootBundle.load('cert.pem')
final certAsList = cert.buffer
.asUint8List(
cert.offsetInBytes,
cert.lengthInBytes,
)
.map((uint8) => uint8.toInt())
.toList()
final channel = new ClientChannel(
'localhost',
port: 8443,
options: ChannelOptions(
credentials: ChannelCredentials.secure(
certificates: certAsList,
onBadCertificate: (cert, host) => true, // <--- **** The missing part ****
),
),
)
By having a handler that always returns true, you're basically disabling the certificate verification completely. Now whether you really want to do that or not is up to you ;)

503 error consuming thirdy part Soap webservice using TLS 1.2 and client certificate authentication with WCF

I've got a problem consuming a Soap Web Service(w/att.) and MTOM that requires client certificate authentication (mutual?).
Before writing what i've already tried i show you what i did in order to receive a client certificate:
I've generated a RSA key with openssl command openssl genrssa -out mykey.key 2048
With this key i've generated a CSR: openssl req -new -key mykey.key -out mycsr.csr
I've sent this CSR to the web service owner in order to receive a client certificate, and they gave me a signed certificate: certificate.cer
Now that i've got my client certificate i've added it in my certificate store under Trusted Root Certification Authority.
Now the code:
First of all i created a Test Project in Visual Studio and i added a Service Reference using the WSDL of the service.
Then i wrote few lines of code:
' Setting TLS 1.2 protocol '
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
ServicePointManager.ServerCertificateValidationCallback = Function(sender1, certificate, chain, sslPolicyErrors)
Return True
End Function
'Creating endpoint and binding'
Dim endpoint As EndpointAddress = New EndpointAddress("https://myWebService.it/service-page")
Dim sslBinding As BasicHttpBinding = New BasicHttpBinding(BasicHttpSecurityMode.Transport)
'Setting CredentialType = Certificate'
sslBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate
'Getting the client certificate from the store'
Dim coll = New X509Store(StoreName.My, StoreLocation.CurrentUser)
coll.Open(OpenFlags.ReadOnly)
Dim cert = coll.Certificates.Find(X509FindType.FindByThumbprint, "76DB1454D4B25ACEAF2BAE465C310E3119278792", True)
'Creating the service'
Dim svc As SdITrasmissioneFileClient = New SdITrasmissioneFileClient(sslBinding, endpoint)
'Setting the certificate inside client credentials'
svc.ClientCredentials.ClientCertificate.Certificate = cert(0)
svc.Open()
'Calling the service'
Dim resp As RispostaEsito_Type = svc.Esito(New Esito_Type() With {.IDFile = "4454555"})
svc.Close()
It looks very simple to me, but when i execute my code i get a
System.ServiceModel.Security.MessageSecurityException: 'The HTTP
request was forbidden with client authentication scheme 'Anonymous'.'
Internal Exception: WebException: Remote Server Error: (403) Forbidden
Next i analyzed traffic using Fiddler and Wireshark and i discovered that, during TLS handshake between client and server, the client doesn't send the certificate to the server.
Now i don't understand the reason why, even if i added the certificate to client credentials, it is not sent to the destination.
After a lot of readings, i discovered what i was missing:
The Client Certificate .cer doesn't contain the private key!
What i did:
I converted .cer file in PEM format with the following command:
openssl x509 -inform der -in ClientCert.cer -out ClientCert.pem
I created a .pfx certificate with my private key:
openssl pkcs12 -export -in ClientCert.pem -inkey mykey.key -out ClientCert.pfx
Then installing .pfx certificate everything works like a charm.
I hope somebody find it usefull.

How to create an OpenSSL Self-Signed Certificate using SAN? [duplicate]

This question already has an answer here:
How can I generate a self-signed certificate with SubjectAltName using OpenSSL? [closed]
(1 answer)
Closed 5 years ago.
As of latest Chrome 60+, if there is no SAN, it throws ERROR on HTTPS pages. OpenSSL command line doesn't add these extension.
Nevermind, figured out myself.
OpenSSL CLI allows -subj flag to set up information about the Certificate Authority (CA), but adding the Subject Alternative Names (SAN) cannot be done using the command line. So I had to resort to call -config followed by the file I want to load as simple configuration. For creating Self-Signed Certificates, this should suffice, but not for production:
# ./config/tiny_openssl.conf
[CA_default]
copy_extensions = copy
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
[req_distinguished_name]
C = US
ST = Washington
L = Seattle
O = My Company
OU = IT Department
emailAddress = it#mycompany.com
CN = mycompany.com
[v3_ca]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = #alternate_names
[alternate_names]
DNS.1 = localhost
DNS.2 = *.localhost
DNS.3 = app.localhost
# ...
The [alternate_names] values must match with the url of the site (or sites) served under SSL by the generated certificate. Something like localhost or app.localhost can work. Then, we fire OpenSSL using this config.
$ openssl req -x509 -newkey rsa:4096 -sha256 -utf8 -days 365 -nodes \
-config ./config/tiny_openssl.conf \
-keyout ./certificates/private.key \
-out ./certificates/ssl/certificate.crt
Added this .crt file in Windows 10 as a Trusted Root Certificate Authorities, restarted Chrome and the Web Server, and voilá.
If you are worried for performance in the HTTP transaction, you can change the rsa to 2048 bits.
This may work only for internal testing between a server and a browser. If you need a more complete and reliable solution with 100% valid SSL Certificates, you should make a CA, a CRS and then sign the CRS with that CA, that will come out a a valid self-signed certificate:
https://stackoverflow.com/a/21494483/647490