Currently, I am setting up CA authentication for a java application using qpid jms.
I am happy to say I have gotten everything to work with the connection itself, and the passing of authorized messages between two applications.
Because of future application features, I need the userId to be present in every message that is sent over the connection. The problem is that because I am using certifications and keystores and such, the username field of the connection is never filled in, as the broker simply uses the certificate information to authorize the messages.
I am wondering if there is some way for me to specify keystore info in the broker connection url, without username:password, and have the username from the certificate added to each message sent across the connection. (The userId would populate if I set up the connection with a username, but because only a cert is used for verification, that field is null). For security reasons, I dont want to hardcode the cert's username as the connection username, but pull it from the cert and get it there. I have gotten code to work with manually loading the keystore and parsing the string for the username, but I am scared this solution might not work in the long run, as well as being relatively inefficient. (Looking for say a method in the connection class that will take the keystore info it used in the URL and give me back the username set in the cert in said keystore).
I am using:
Qpid JMS AMQP 0-x 6.4.0
broker: QPID c++ 1.39.0
Related
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 ;-)
I am using EPP (Extensible Provisioning Protocol) to perform domain registration operations.
Everything works fine but when I use a certificate, the login request fails.
Let us say I have certificate in C:\Folder\epp.crt and using the following code:
var tcpTransport = new TcpTransport(url, port, new X509Certificate("C:\Folder\epp.crt"), true);
var service = new Service(tcpTransport);
service.Connect();
This code executes just fine and service is connected. That means connection to URL is established using certificate. Now, I try to login with:
service.Execute(logingCmd);
But this gives me "Server requires Client certificate validation, no client certificate provided".
Why? Should there be any flag for certificate in login command?
Per RFC5734, EPP uses TLS, not TCP. This RFC also mandates use of client certificates.
Your question lacks details about the content of epp.crt (where is the associated key?) or the language you use. The TLS negotiation, including validation of client certificate happens before the EPP login, but the exact moment may be hidden by the library you use to connect.
So to answer your "Should there be any flag for certificate in Login Command?", no there should not as the certificate handling is part of the transport setup, not the EPP commands. Your problem is probably more around your use of TcpTransport.
You can use a network sniffer to see exactly what happens. Registries are probably not offering TLS1.3 for now so you should still be able to see the TLS exchanges, including your client providing a certificate.
Also the registry you connect to should be able to help you.
I've been reading and trying to comprehend the differences in browser side security. From what I gather, SSL is used to keep people from sniffing the traffic you send to the server. This allows you to send a password to a server in clear text...right? As long as you are in an SSL encrypted session you don't have to worry about hashing the password first or anything weird, just send it straight to the server along with the username. After the user authenticates you send them back a JWT and then all future requests to the server should include this JWT assuming they are trying to access a secured area. This allows the server to not even have to check the password, all the server does is verify the signature and that's all the server cares about. As long as the signature is verified you give the client whatever info they are requesting. Have I missed something?
You are correct. "This allows the server not to even have to check the password." Why would you have to check a password on each request?
A JWT is a means of verifying authentication. It is generated upon a successful authentication request and hence forth passed with each request to let the server know this user is authenticated.
It can be used to store arbitrary values such as user_id or api_key but they are not very secure so don't store any valuable information here.
Be wary though, if a plain JWT is intercepted by a third party, it can assume this user's session and possible data.
SSL is a lower level form of security, encrypting every request from and to the server to prevent interception and retains integrity.
SSL is achieved by (purchasing) an SSL certificate and installing it on your server. Basically an SSL certificate is a small data file that binds a cryptographic key to an 'organisation'. Once installed succesfully, HTTPS requests (on port 443 by default) are possible.
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
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.