Using MailKit with TLS with no certificates in VB.net - vb.net

I'm trying to change our code to send emails with MailKit since the old SMTPClient is obsolete.
We connect to our own server and don't need to authenticate. Here is the code:
Using client = New SmtpClient()
Dim values = SQL.EMAIL_SQL.GetSMTPInfo("MailHostOutsideNetwork")
client.Connect(values.Item1, values.Item2, Security.SecureSocketOptions.None)
client.Send(Message)
client.Disconnect(True)
End Using
I have it working and sending emails as long as I don't use TLS or SSL. When I try to use either of them, I get the exception:
An error occurred while attempting to establish an SSL or TLS connection.
The server's SSL certificate could not be validated for the following reasons:
- The server certificate has the following errors:
- A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
So, my first idea was to contact our IT department and ask about the certificates. They told me we've never had any certificates and most likely never will (some licensing bullshit).
The problem is they still want us to use TLS when sending emails and my boss says that there must be a way to do that (which I basically answered with... well yeah if we had our system and certificates in order. She was not vey happy lol).
So, now I'm here asking you if there is any way of doing that. Sending emails using TLS with no certificates. Any ideas?

As Jimi noted, you can set a ServerCertificateValidationCallback method.
If you read the above docs, it may help you devise a better solution than just to return true, but in the simplest case, setting it to a function that always returns true will work for your needs.
Based on the error message, it sounds like there is a certificate chain, it's just that the SMTP server is probably using a self-signed SSL certificate and/or a root certificate that was generated by your company instead of by an official SSL Certificate Authority and therefore the root certificate used by your SMTP server is not trusted by the system sending the emails.
You can also check out MailKit's default behavior here: https://github.com/jstedfast/MailKit/blob/master/MailKit/MailService.cs#L356
Basically, if the problem is just an untrusted root (what it sounds like your issue is), then it falls back on a hard-coded list of trusted mail server certificate details that it checks against:
var cn = certificate.GetNameInfo (X509NameType.SimpleName, false);
var fingerprint = certificate.Thumbprint;
var serial = certificate.SerialNumber;
var issuer = certificate.Issuer;
Obviously you won't know these strings off the top of your head, but if you write a custom function that prints this information out, you could then hard-code those values into a future version of the validation callback function and feel a little safer than just returning true ;-)

Related

Certificate verification when using NoVerifyHTTPAdapter

I have some code that uses Exchangelib to process emails. For various reasons, the certificate validation fails and I have to use the usual NoVerifyHTTPAdapter:
from exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter
# Tell exchangelib to use this adapter class instead of the default
BaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter
This leads me to two questions:
I am now wondering, am I sending and receiving in plain text without encryption? I know that the servers I am using only have port 443 open.
If I am not sending in plain text, is there a way to get the name of the certificate that I am using?
If this question is answered somewhere else, sorry for the inconvenience, it must have slipped in my initial search.
You are not sending in plain text. Your data is still encrypted since you are communicating over HTTPS.
When certificate validation fails, it means that the certificate of the server cannot be validated using any of the root certificates on your local machine that you (or your OS vendor) have chosen to trust, or that the certificate does not match the server that you are communicating with, that the certificate has expired, or any of the other reasons that may cause failure to validate a certificate.
This means that you have no guarantee that the server you are communicating with is in fact the correct server, which leaves you vulnerable to man-in-the-middle attacks and exposing your data to an untrusted server. But the communication channel itself is still encrypted.
There's some more discussion at What are the implications of ignoring SSL certificate verification?
If you absolutely cannot fix the causes of the invalid certificate, your best option is to accept the certificate locally: How to get Python requests to trust a self signed SSL certificate?

How do I disable TLS certificate verification in grafana for user login using OAuth

I am trying to setup Grafana using the Azure AD configuration in its OAuth setting and the only way to get it working is by using a certificate. Which is fine except for the part where they will not accept privately signed certificates. Unsurprisingly, it throws the following exception:
Error getting user info: Get https://: x509: certificate signed by unknown authority
Do you know a work around? Or the right setting to make grafana use a privately signed cert?
You can add tls_skip_verify_insecure = true to the [auth.generic_oauth] block.
I try different solutions and only two works for me:
You can set tls_skip_verify_insecure = true in grafana.ini file, but is not a good solution because is not secure like is said in the documentation of Grafana (https://grafana.com/docs/grafana/latest/auth/generic-oauth/):
"tls_skip_verify_insecure controls whether a client verifies the server’s certificate chain and host name. If it is true, then SSL/TLS accepts any certificate presented by the server and any host name in that certificate. You should only use this for testing, because this mode leaves SSL/TLS susceptible to man-in-the-middle attacks."
The other solution, and the one that I´m currently using, is adding my CA (the one that I use to sign my certificates) to the trusted CA's of Grafana in the /etc/ssl/certs/ca-certificates.crt file (adding it at the end of this file).
I hope this helps you, it works for me, but I´m not sure if it's the best solution.

2 Way SSL - Client Certificate Not Sent To Server

I'm have an application deployed to salesforce on the force.com platform,
which I'm trying to configure a 2 way SSL for.
I.e.
I want that for each request sent to from SF to my server, a client certificate will be sent.
I did the necessary configurations on SF for the certificate to be sent, but I'm still getting 403.7 from the server, which means: forbidden, client certificate required.
I installed wireshark on the server, captured traffic to see the 2 way ssl handshake, and I'm trying to find in the server hello message where it tells the client the trusted CAs from which a client certificate should correspond, but I'm having difficulties finding it.
I suspect that's why the client does not send the certificate.
Can anyone point me to where in the server hello I should look? Or perhaps in another packet capture?
Thanks in advance.
Client Key Exchange record:
Here, the server sends its Certificate Request message and the client sends its Certificate message in response, but that message contains 0 certificates.
Typically, this happens when the client was unable to select a client certificate to use. Either it's not configured properly to make use of any certificate, or it can't find one that is issued by one of the acceptable CAs.
Look at the Certificate Request packet and check its certificate_authorities list. This is a list of the CA Distinguished Names (DNs) that the server is willing to accept.
One way or another, the client will need to find a client certificate with which it can build a chain towards of those DNs. In the simplest case, a client certificate issued by such a DN is available. Otherwise, the client could have to build a chain from a client cert to such a DN, it would need to have the necessary intermediate CA certificates to do so. (How this is done depends on the client's configuration mechanisms.)
If intermediate CA certificates are necessary and not available on the client side, you may need to configure your server to accept them and advertise them in the Certificate Request too.
Added a screenshot of the handshake captures. can you please point me to where I should be looking? –
See packet #31. It contains the Certificate Request. Also packet #33 contains the certificate from the client, so the reason is not the client does not send the certificate, but instead that the server either does not like the certificate because the validation failed or because the certificate is not sufficient as authorization for the requested resource. You might get more information from the servers log.
Not sure if this will help anyone else, but for our case of this issue everything was working when running locally in Visual Studio and in IIS, but when deployed to a real server, we were hitting a certificate issue during 2-way SSL as described above and verified in Wireshark.
Anyway, on that server we have also have a .NET 4.7.2 Console application which was calling the same API and everything was working fine.
But, our .NET 4.7.2 web API calls were failing. It appears that when the same code was running inside IIS the cert was not available during the SSL negotiation. (although it loaded fine)
Our solution at this point was to modify the following call to include the 3rd parameter.
certificate = new X509Certificate2(certificatepath, Password, X509KeyStorageFlags.MachineKeySet);
By default X509Certificate2 uses the UserKeySet option, so perhaps the application pool user or another thread in IIS (?) was having trouble accessing the cert for the negotiation.
Here are a couple of the related pages that I found useful during my research:
https://paulstovell.com/x509certificate2/
https://github.com/dotnet/runtime/issues/23437

SSL connect to MQ using .net mq client SSLV3?

Currently I am having a problem connecting to the server due to the following issue:
When I tried to connect to the server, it returned an error: MQRC_SSL_INITIALIZATION_ERROR
Upon closer analysis via WireShark, I found that the Client is attempting to connect to the server using SSL v2, while the server can only accept SSL V3, thus rejecting the connection.
I checked through the document, but am not able to find any information on
what SSL version the .Net client supports.
I would like to check whether the SSL version is controlled from the .Net MQ
client, and if so, how can we configure to make it connect via SSL v3?
Thanks.
I'm not sure I agree with your conclusion since WMQ has supported SSL V3.0 and TLS V1.0 since at least V6.0 and possibly earlier. This is more likely a mismatch of configurations between the client and server. The procedure I recommend to resolve SSL/TLS issues is as follows:
My method for debugging SSL connections on WMQ is to progress through the following sequence making sure each step works before advancing to the next:
Get the channel running without SSL. This validates that the channel names are spelled correctly, that a network route exists between the endpoints, that the QMgr's listener is running and that the client points to the right port. You'd be surprised how many times someone mis-keys a port or channel name.
Get the channel running with the SVRCONN definition set to SSLCAUTH(OPTIONAL). This performs an anonymous SSL connection similar to what your browser does. The QMgr presents a certificate to the client but the client is not obligated to send one back. This validates that the QMgr can find its certificate and that the client can find its trust store and properly validates the QMgr's cert. (Note: the QMgr will always request the client cert and the client will always send it if one is present. To perform this test, use a copy of the client's keystore that has the signer cert(s) but not the application's personal cert. Copy the keystore and delete the personal cert from the copy. Do NOT delete the original!)
Set the SVRCONN channel to SSLCAUTH(REQUIRED). This now requires the client to find its keystore (in the last step it required only its trust store) and to be able to find its certificate. It also requires the QMgr to be able to validate the client's cert.
Set up SSLPEER or CHLAUTH mapping rules to narrow the population of validated certificates that will be accepted on the channel.
The difference between steps #2 and #3 helps to isolate the problem by testing the SSL credential exchange in only one direction at a time. This allows you to identify whether the problem exists in the personal cert or the public cert and on which side of the channel. Nearly all problems are sorted out in these two steps.
UPDATE
Notes to respond to questions. There are two types of certificate used with SSL/TLS. The personal certificate contains the private key and is the one that doesn't get passed around. The public certificate is the one that contains the public key and can be given out freely. The private key is held in a keystore. The public keys (usually these are the CA's root and intermediate certs) are stored in a trust store. In some cases, these are separate files. For example, in Java and JMS the JSSE provider looks in the environment for variables that point to the keystore and to the trust store. It is possible in Java and JMS that the keystore and trust store variables point to the same file.
In the case of WebSphere MQ servers and clients other than Java, the keystore and trust store are combined into a single location. Often referred to as a kdb file, it is actually a CMS key database comprised of several files of which one is the KDB. In this case "keystore" is actually shorthand for a combined keystore and trust store. For the .Net client, set the keystore location and other SSL properties in the MQEnviornment.
In the SSL/TLS handshake, the server always sends its public certificate in response to a connections request. The client then must validate that certificate by first checking the signature and validity date, then looking in its trust store for the thing that signed the certificate. If the thing that signed the certificate is an intermediate signer cert (it has itself been signed by something) then the search continues up the signer cert chain until the root cert is reached. Assuming that the server is authenticated, the same procedure is applied in reverse by having the client present a cert and the server validating it.
When the process fails in Step #2 we can debug using knowledge of the process above. The QMgr must first find its cert in its keystore and present it to the client. If the QMgr cannot find its cert, the result is errors in the AMQERR01.LOG file stating this. Always look on the QMgr side first when things die in Step #2!
If the QMgr does find its cert then the next step is that client must be able to find its trust store and then within that trust store must find the necessary signer cert chain. If this fails, there should be errors on the client side to indicate that. For example, a common error when setting the client environment is to specify the entire file name, including the .kdb extension. When this happens the QMgr looks for [keystorename].kdb.kdb which doesn't exist. Another common error is that the personal certificate exists in the keystore but with the wrong label. Non-Java WMQ clients look for the certificate by label name constructed from the literal string ibmwebspheremq followed by the user ID in lower case. For example, if my user ID is TRob then my certificate label would be ibmwebspheremqtrob. Note that this is the certificate's label in the keystore and NOT the certificates Common Name or other field in the Distinguished Name.
Depending on the type of client in use, these may be in the Windows error log, local MQ error logs or other location. If you can't find client-side errors, WMQ tracing is also an option.

SSL XML Gateway - SSL Certificate Handshake Error

I am working on a website that exposes an xml gateway that clients can submit an xml request to and get an xml response in return. The website/company has been purchased by a larger organization and has been migrated into their infrastructure. The existing production site is using an ssl certificate by a particular certificate authority but the larger organization uses certificates issued by a different certificate authority. We have tried run a test with one of their clients and they are getting an SSL handshake error. The original developer says that the only way to get it to work is to restore the original SSL certificate and not to use the new ones. I am looking for some guidance or direction to diagnose this issue, so any help would be appreciated.
What the developer says, from the description is sensible to me, but the problem is theirs.
To verify that this is exactly what is happening you can do a wireshark capture and then decode the flow as SSL. If the problem is that the client do not trust the certificate send by the server and reject the connection you will see it in the handshake in the wireshark.
If you use a java client you could run it with -Djavax.net.debug=ssl to see the ssl messages from within java.
If this is indeed the problem then you must configure the client's truststore to have the certificate send by the server (which is the original one).
If this configuration is possible of course... This depends on the application
UPDATE:
Well if you migrated to a new CA, i.e. you deploy a new certificate in your interface, then sorry to say, it is "your" -meaning the server side- error.
IMHO, if it is possible, you should redeploy the old certificate for a prespecified period, communicating to all the stakeholders that you plan to migrate to a new certificate signed by a new CA, so that the clients don't break
Then it is their responsibility, within that period, to "fix" their client apps to be able to accept the new certificate. This can be as simple as configuration i.e. importing the certificate to a truststore, to as "complicated" as to change code and rebuild the client app (e.g. if the new issued certificate does not have extensions that the code is verifying or the CN has changed etc).
If it is not possible to redeploy the old certificate then, you just have to communicate the change to all stakeholders and then, they should "fix" it accordingly (as mentioned above)