Default .Net LdapConnection SSL validation - c#

When looking for a way to implement server certificate validation when accessing AD using LDAP with SSL, I have come across the following answer to one of the questions here on Stack Overflow - https://stackoverflow.com/a/41013779/6179181.
In the answer it is stated that:
You should not write validation yourself. Certificate validation is tricky business, and it's already done for you. Use the built-in stuff...
Is my understanding correct that there is a default algorithm for validating server SSL certificates? For example, will the following code perform implicit validation of the server's SSL certificate? If so, where I could read more about it (I did not find much information on MSDN)?
LdapConnection _connection = new LdapConnection(new LdapDirectoryIdentifier(m_DomainName, m_PortNo));
_connection.AuthType = AuthType.Basic;
_connection.Credential = new NetworkCredential(m_UserName, m_Password);
_connection.SessionOptions.SecureSocketLayer = true;
_connection.Bind();
EDIT:
Is the root CA that issued the certificate to the server validated against trusted root CAs in the local certificates store implicitly in the code above?

Related

RabbitMq Broker not accepting PFX

After having a working solution of RabbitMq over SSL using the certs generated by OpenSSL, I was given a requirement from our client that we cannot use OpenSSL to generate the certs. The server admin went and created the certificate chain via IIS.
We did the following to the certs after creation:
exported the server certs to a PFX and extracted cert.pem and cert.key
exported the client cert to a PFX and extracted cert.pem and cert.key
exported the Root CA to rootca.pem
updated the config file for RabbitMq
To test the connections and certificates were created properly, we went through the Troubleshooting Steps here.
Everything passed fine. We are able to connect using openssl s_client on port 5671 as expected using the client's cert.pem and cert.key generated from client.pfx. We can see the connection made in management console, as well as in the logs, and they communicate back and forth.
Now, using the client.pfx in the .NET client, we are getting an error about the certificate validation:
MassTransit.RabbitMqTransport.RabbitMqConnectionException: Connect failed: admin#mitvs-atm01:5671/ ---> RabbitMQ.Client.Exceptions.BrokerUnreachableException: None of the specified endpoints were reachable ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
How can I be getting an error using the client.pfx but not get an error when using the cert.pem and cert.key that I extracted from it?
This error message means that client can't validate server certificate. Your problem is likely to do with rootca.pem not being trusted on your client's machine. Follow the appropriate OS guide to make the root CA certificate trusted.
When testing the connections through OpenSSL using s_client, it performs no or very basic verification and .NET apps can provide a function that applies any logic. The most common verification type is matching certificate's CN against server's hostname but it really can be anything.
So, even on a trusted Root CA, the CN still needs to match the hostname, which isn't picked up using OpenSSL commands.
Regenerating the cert and amending that fixed the problem.
Also, you could effectively add the code below and it will disregard this error:
h.UseSsl(s =>
{
s.ServerName = SslHostName;
s.CertificatePath = SslFileLocation;
s.CertificatePassphrase = SslPassphrase;
// The below allows the Root CA's CN to be different than the others, but adds vulnerability
s.AllowPolicyErrors(System.Net.Security.SslPolicyErrors.RemoteCertificateNameMismatch);
});
Please note - Ignoring errors carries the risk of exposing your system to MITM attacks (unless you implement your own verification logic that's not based on CN/hostname matching, of course).

How to validate server SSL certificate for LDAP+SSL connection

Our application works with Active Directory users and groups. We are using LDAP on port 389 for Active Directory operations. Now, one of our clients want us add an option for using LDAP + SSL for Active Directory communication.
They told us that they have a local CA installed on their domain and using self signed certificate for LDAPS. They also told us that they will provide the certificate, no mutual-trust needed and we should use Windows certificate store.
I have developed a test application for LDAP+SSL operations and saw that server sends its certificate when a client initiates an LDAP+SSL connection. I can establish the connection only by returning true from the server certificate verification method.
The questions are;
- Which certificate (root, the ceritificate used for LDAP+SSL...) should the customer give us?
What should be the format of the certificate for working on .Net environment?
How should I verify the server's certificate when connecting the server?
What they mean by "we should use Windows certificate store"? Do they want us add the server's certificate automatically to trusted certificate store of the local machine?
Sample code I used for LDAP+SSL connection,
LdapConnection _connection = new LdapConnection(new LdapDirectoryIdentifier(m_DomainName, m_PortNo));
_connection.Timeout = TimeSpan.FromMinutes(10);
_connection.AuthType = AuthType.Basic;
_connection.Credential = new NetworkCredential(m_UserName, m_Password);
_connection.SessionOptions.ProtocolVersion = 3;
_connection.SessionOptions.SecureSocketLayer = true;
_connection.SessionOptions.VerifyServerCertificate = (ldapCon, serverCertificate) =>
{
//TODO: Verify server certificate
return true;
};
_connection.SessionOptions.QueryClientCertificate = (con, trustedCAs) => null;
_connection.Bind();
Which certificate (root, the ceritificate used for LDAP+SSL...) should the customer give us?
The root certificate that signed the LDAP server cert. They can also give you the whole chain in advance, but that will be sent during TLS handshake anyway. You only need to have the root cert in advance.
What should be the format of the certificate for working on .Net environment?
Anything that you can import into certmgr.msc. Pfx is the usual choice on Windows.
How should I verify the server's certificate when connecting the server?
You should not write validation yourself. Certificate validation is tricky business, and it's already done for you. Use the built-in stuff (also see below).
What they mean by "we should use Windows certificate store"? Do they want us add the server's certificate automatically to trusted certificate store of the local machine?
Yes. They send you the root cert they used for signing the ldap server cert, which you can then import as a trusted root. Once this is done, you don't need to do any manual validation, it will just work™ :) with valid certificates and will not work with invalid ones.
Note that once you add their root cert as trusted, they can forge any server certificate for the client their root is installed on, and anything they sign will be considered valid on that client.
Bonus: adding semi-custom validation and debugging certificate errors
One problem that you may face is that error messages are not very helpful. If the certificate cannot be validated, you will get a very generic error message that has no hint about the actual problem. You may want to hook into the validation process for other reasons too.
For this purpose, you can define your own validation:
private bool VerifyServerCertificate(LdapConnection ldapConnection, X509Certificate certificate)
{
X509Certificate2 certificate2 = new X509Certificate2( certificate );
return certificate2.Verify();
}
And then add it to the ldap connection:
_connection.SessionOptions.VerifyServerCertificate =
new VerifyServerCertificateCallback( VerifyServerCertificate );
This way you can catch exceptions on Verify() etc. But again, if the certificate is valid (can be verified by the client), this is not strictly needed, it's done automatically anyway. You only need this if you want something not implemented, like for example you could just return true in VerifyServerCertificate to accept any cert including the invalid ones (this would be a Bad Idea and makes a secure connection useless, but may be good for debugging, etc).
Another thing you could implement in this method is certificate pinning for additional security, but that's beyond the scope of this answer.
BTW: Since introduction of the StartTLS extended operation for LDAP v3 in May 2000 (RFC 2830) LDAPS (made for LDAP v2) is deprecated.

How to Connect to a Web-service that has a faulty security certificate [duplicate]

We are setting up a new SharePoint for which we don't have a valid SSL certificate yet. I would like to call the Lists web service on it to retrieve some meta data about the setup. However, when I try to do this, I get the exception:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
The nested exception contains the error message:
The remote certificate is invalid according to the validation procedure.
This is correct since we are using a temporary certificate.
My question is: how can I tell the .Net web service client (SoapHttpClientProtocol) to ignore these errors?
Alternatively you can register a call back delegate which ignores the certification error:
...
ServicePointManager.ServerCertificateValidationCallback = MyCertHandler;
...
static bool MyCertHandler(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors error)
{
// Ignore errors
return true;
}
Like Jason S's answer:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
I put this in my Main and look to my app.config and test if (ConfigurationManager.AppSettings["IgnoreSSLCertificates"] == "True") before calling that line of code.
I solved it this way:
Call the following just before calling your ssl webservice that cause that error:
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
/// <summary>
/// solution for exception
/// 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.
/// </summary>
public static void BypassCertificateError()
{
ServicePointManager.ServerCertificateValidationCallback +=
delegate(
Object sender1,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
};
}
The approach I used when faced with this problem was to add the signer of the temporary certificate to the trusted authorities list on the computer in question.
I normally do testing with certificates created with CACERT, and adding them to my trusted authorities list worked swimmingly.
Doing it this way means you don't have to add any custom code to your application and it properly simulates what will happen when your application is deployed. As such, I think this is a superior solution to turning off the check programmatically.
I was having same error using DownloadString; and was able to make it works as below with suggestions on this page
System.Net.WebClient client = new System.Net.WebClient();
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
string sHttpResonse = client.DownloadString(sUrl);
ServicePointManager.ServerCertificateValidationCallback +=
(mender, certificate, chain, sslPolicyErrors) => true;
will bypass invaild ssl . Write it to your web service constructor.
For newbies,
you can extend your partial service class in a separate cs file and add the code the code provided by "imanabidi" to get it integrated
To further expand on Simon Johnsons post - Ideally you want a solution that will simulate the conditions you will see in production and modifying your code won't do that and could be dangerous if you forget to take the code out before you deploy it.
You will need a self-signed certificate of some sort. If you're using IIS Express you will have one of these already, you'll just have to find it. Open Firefox or whatever browser you like and go to your dev website. You should be able to view the certificate information from the URL bar and depending on your browser you should be able to export the certificate to a file.
Next, open MMC.exe, and add the Certificate snap-in. Import your certificate file into the Trusted Root Certificate Authorities store and that's all you should need. It's important to make sure it goes into that store and not some other store like 'Personal'. If you're unfamiliar with MMC or certificates, there are numerous websites with information how to do this.
Now, your computer as a whole will implicitly trust any certificates that it has generated itself and you won't need to add code to handle this specially. When you move to production it will continue to work provided you have a proper valid certificate installed there. Don't do this on a production server - that would be bad and it won't work for any other clients other than those on the server itself.

SSL Socket between .Net and Java with client authentication

I am trying to create an SSL Socket Server/Client between .NET and Java. In this case, my SSL Socket Server will run in .net and the client runs in Java under Linux. My problem is that the connection fails during the handshaking, specifically when the server request a certificate from the client, the client is unable to send something back and the connection fails.
In .net I am using sslStream to establish the connection and on Java I am using the standard SSLSocket. Some code snippets are below, but this is what I have so far:
On the server side (Windows), I have a private certificate in the Personal/Certificates folders under MMC. I have a public certificate from the client in the Trusted People/Certificates. Both certificates were issued by the same CA. The certificate chain for both certificates have multiple levels, but it is the same for both. The root level certificate in the chain is also installed in the trusted Certification Authorities/Certificates folder.
On the client side (Linux), I have a keystore that contains the private certificate that matches the public certificate installed at the server. I have a trust store that contains the public certificate from the server, matching the server's private one.
On the server side (.net) I am using a Socket that does an asynchronous read and then it gets wrapped into an SSLStream, the code snippet is like this:
NetworkStream ns = new NetworkStream(socket, false);
SslStream ssl = new SslStream(ns, true);
ssl.AuthenticateAsServer(serverCertificate, true, SslProtocols.Default, true);
The client code is pretty much standard code:
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
InetAddress addr = InetAddress.getByName(servername);
SSLSocket socket = (SSLSocket) factory.createSocket(addr,port);
socket.setUseClientMode(true);
socket.setNeedClientAuth(true);
socket.setWantClientAuth(true);
socket.startHandshake();
os = new DataOutputStream(socket.getOutputStream());
is = new DataInputStream(socket.getInputStream());
byte[] outBuf = new byte[50];
os.write("SEND SOMETHING".getBytes("UTF-8"));
is.read(outBuf);
In java I have set the proper varialbes to point to the trust and key store with their password.
Now, following the standard SSL Handshake, this is what happens:
ClientHello
ServerHello
Server sends public certificate
Client matches the public certificate with the one on the trust store
Server sends the Certificate request
With the certificate request the server sends a list of valid CAs, on this list only the my root CA is sent (among a long list of other well known CAs.).
Client certificate is null.
Server receives a null certificate from the client, thus closes the connection.
And that is it, the client won't send a valid certificate back to the server. I have some questions on this:
Has anybody experienced something like this?
Regarding that list of CAs sent by the server (Windows), How does .net determine what to send to the client? Is there a way to modify that list?
Do I need to send the all the authorities in the chain used to sign my certificate in that list of CAs? or is the Root one enough?
Am I missing something on either side of my code?
Any help will be greatly appreciated it.
In
The following two statements are useless on the client side (although they shouldn't hurt):
socket.setNeedClientAuth(true);
socket.setWantClientAuth(true);
The fact that you see the Certificate Request message and the Client Certificate message shows that the server is configured properly.
The most likely cause that comes to mind for the absence of certificate in the client certificate message is that the keystore (on the client side) might not be configured properly. You may be interested in this answer to make sure that your client key store is configured properly. More specifically, you need to make sure that the private key for your client certificate was imported in the same alias as the certificate chain (and that it's the chain going back to a CA advertised in the Certificate Request message).
(Regarding the rest of your question, I'm not sure how to modify the CA list sent by the server when using SslStream in C#. This earlier question would seem to suggest there is no solution, although newer versions of .Net may have addresses the issue since this question was asked. I haven't been able to find anything that would do it by looking at the SslStream API documentation and related classes, but this doesn't mean it doesn't exist.)

Accessing Securised Web Service

I need to connect to a provider's web service with a Windows Form application. He gives me a certificate to access it but I have a security problem.
I have done these following steps :
Add certificate to personal store (on IE & Firefox)
Generate a proxy with the remote wsdl (no problem)
Use this code to call a method :
`using (service1.MessagesService m = new service1.MessagesService())
{
X509Certificate crt = new X509Certificate(#"C:\OpenSSL\bin\thecert.p12",string.Empty);
m.ClientCertificates.Add(crt);
var result = m.AuthoriseTransaction(aut);
this.textBox1.AppendText(result.id.ToString());
}`
I have the following error :
The underlying connection was closed: Could not establish trust relationship for the channel SSL / TLS.
Thanks for your help
Your connection isn't being authorised correctly, is the webservice over https? You may need to create a custom implementation of CertificatePolicy. See this article for an example.

Categories

Resources