Tomcat as Clients communicating with multiple separated Servers via SSL - sockets

Here is the scenario:
I have multiple application servers running locally for now (should be running in different host) --> each is listening on different port (at localhost).
I have a single client application running on Tomcat.
When startup Tomcat, login with different user's details with connect to different (above) servers remotely.
My problem is:
First, I startup Tomcat and logged in as userA, it then connected successfully to serverA(localhost:1000).
Then I logged out.
Logged in again as userB, it did NOT connect to serverB(localhost:1001) as expected; instead, it gave exception
"javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown"
However, if I restart Tomcat, and login as userB first, it then connects successfully to serverB.
Does anyone know what the problem is?
I really appreciate any suggestion :)
Code for client Tomcat:
SetupClientKeystore();
SetupServerKeystore();
SSLContext context = SetupSSLContext();
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket(hostname, portNo);
GZIPOutputStream gZipOut = new GZIPOutputStream(socket.getOutputStream()); // no trust certificate found throws here
Code for serverA and B:
setupClientKeyStore();
setupServerKeystore();
setupSSLContext();
server = new ServerSocket(portNo);
SSLServerSocketFactory socketFactory = sslContext.getServerSocketFactory();
serverSocket = (SSLServerSocket) socketFactory.createServerSocket(portNo);
serverSocket.setNeedClientAuth(true);
while ( true )
{
Socket client = serverSocket.accept();
inStream = client.getInputStream();
BufferedInputStream bufferedIn = new BufferedInputStream(inStream); //unknown_certificate throws here
//do something here.....
}

"javax.net.ssl.SSLHandshakeException: Received fatal alert:
certificate_unknown"
This usually indicates that the server's certificate is not trusted.
Could it be that when you log-in as userA you load the trusted certificate of serverA and connect, and then when you try to connect to serverB you try to authenticate serverB using the certificate of ServerA (loaded when you logged in as userA)?
As a result the SSL handshake fails.
So when you restart and login as userB the appropriate certificate (i.e. of ServerB) is loaded and the connection is succesfull?
You have no code in your post but if you do it as I say, this explains the exception.

Related

MailKit gets an SslHandshakeException with LetsEncrypt SSL certificates

I have a server (Centos 7) setup to be used as mail server. Using postfix/dovecot/opendkim/opendmarc..
It works as it should, users are able to connect their emails using gmail for example. Able to send and receive mail.
Also when I use MailKit and test my .NET Core application from my home pc MailKit connects fine and the emails are send.
However, when I deploy the application to my server MailKit fails to connect.
If I look in the logs I see the following
postfix/submission/smtpd[4486]: match_hostname: unknown ~? 127.0.0.1/32
postfix/submission/smtpd[4486]: match_hostaddr: MY_SERVER_IP ~? 127.0.0.1/32
postfix/submission/smtpd[4486]: match_hostname: unknown ~? MY_SERVER_IP/32
postfix/submission/smtpd[4486]: match_hostaddr: MY_SERVER_IP ~? MY_SERVER_IP/32
postfix/submission/smtpd[4486]: lost connection after STARTTLS from unknown[MY_SERVER_IP]
But if I look a bit higher in the logs I see
Anonymous TLS connection established from unknown[MY_SERVER_IP]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
My MailKit (which works fine from outside of the server):
using (SmtpClient emailClient = new SmtpClient())
{
await emailClient.ConnectAsync(emailConfiguration.SmtpServer, emailConfiguration.SmtpPort, SecureSocketOptions.StartTls);
emailClient.AuthenticationMechanisms.Remove("XOAUTH2");
await emailClient.AuthenticateAsync(emailConfiguration.SmtpUsername, emailConfiguration.SmtpPassword);
await emailClient.SendAsync(message);
await emailClient.DisconnectAsync(true);
}
edit:
The exception from MailKit (certificate is proper and not self-signed):
MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection.
May 19 16:07:37 domain.com NETCoreApp[4452]: The server's SSL certificate could not be validated for the following reasons:
May 19 16:07:37 domain.com NETCoreApp[4452]: • The server certificate has the following errors:
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get certificate CRL
May 19 16:07:37 domain.com NETCoreApp[4452]: • The root certificate has the following errors:
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get certificate CRL
May 19 16:07:37 domain.com NETCoreApp[4452]: • unable to get local issuer certificate
May 19 16:07:37 domain.com NETCoreApp[4452]: ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
The unable to get certificate CRL error sounds like SslStream was unable to get the CRL, perhaps because the CRL server is unreachable for some reason.
You could try adding emailClient.CheckCertificateRevocation = false; before the ConnectAsync to check if that's the issue.
The other error, unable to get local issuer certificate, might be because the server that MailKit is running on doesn't have the Root CA certificate in its X509Store but your home PC does.
Update:
The problem is that LetsEncrypt SSL certificates do not include a CRL location which means that certificate revocation checks will fail.
To bypass this, you need to set client.CheckCertificateRevocation = false; before connecting.
I found an answer which works but isn't my preferred method since I wanted to be able to use MailKit for more that just my own server (make it configurable from within the app itself)
I came to the solution because I thought it had to do with some internal traffic going wrong..
By using the old SmtpClient from System.Net.Mail I was able to use the DefaultCredentials.
using (SmtpClient client = new SmtpClient("127.0.0.1"))
{
client.UseDefaultCredentials = true;
MailAddress from = new MailAddress(emailMessage.FromAddress.Address, emailMessage.FromAddress.Name);
foreach (IEmailAddress emailAddress in emailMessage.ToAddresses)
{
MailAddress to = new MailAddress(emailAddress.Address, emailAddress.Name);
MailMessage email = new MailMessage(from, to)
{
Subject = emailMessage.Subject,
Body = emailMessage.Content
};
await client.SendMailAsync(email);
}
}
I have the same problem on ubuntu 20.04 with .NET core 3.1
and after 3 hours of trial and error, I finally found the solution.
I've just ignored the Certificate Validation CallBack.
using var client = new SmtpClient(new ProtocolLogger("smtp.log"));
client.CheckCertificateRevocation = false;
client.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
client.Connect("your.smtp.host", 587, SecureSocketOptions.StartTls);
I hope this would be helpful :)

Getting "Client was not authenticated to send anonymous mail during MAIL FROM" error from Exchange SMTP using Rust lettre library

I am writing a Rust application that will send email through an Exchange server with SMTP functionality enabled. According to Microsoft's webpage, the settings that are required are:
Server address smtp.office365.com
Port 587
StartTLS Enabled
Credentials for mail account login
These are corroborated by the POP/IMAP settings of the webmail service.
Here is my code (with some censoring):
extern crate lettre;
use self::lettre::email::EmailBuilder;
use self::lettre::transport::smtp::{SecurityLevel, SmtpTransportBuilder, SUBMISSION_PORT};
use self::lettre::transport::smtp::authentication::Mechanism;
use self::lettre::transport::EmailTransport;
pub fn send_mail() {
let email = EmailBuilder::new()
.from("my email")
.to("destination email")
.body("testing")
.subject("testing")
.build()
.unwrap();
// Connect to SMTP server
let mut transport = SmtpTransportBuilder::new(("smtp.office365.com", SUBMISSION_PORT))
.expect("Failed to create email transport")
.encrypt()
.smtp_utf8(true)
.credentials("my email", "my password")
.authentication_mechanism(Mechanism::Login)
.build();
println!("Mail transport built");
println!("{:?}", transport.send(email.clone()));
}
When I compile and run the code,it gives me this error:
Err(Permanent(Response { code: Code { severity:
PermanentNegativeCompletion, category: Unspecified3, detail: 0 },
message: ["5.7.57 SMTP; Client was not authenticated to send anonymous
mail during MAIL FROM [SYXPR01CA0106.ausprd01.prod.outlook.com]"] }))
Why is this happening?
The closest I've come in my research is an issue on GitHub in relation to the lettre library not supporting the Login authentication mechanism (which Office 365 uses); however, the codebase was updated to support Login and I am using the master branch directly from GitHub so theoretically my application should support the Login mechanism.
Edit: Forgot to mention that I attempted an EHLO to the server, but it returned a (Client:(Connection closed)) error.
I used telnet and openssl to try connecting directly to my SMTP server, where I found that AUTH LOGIN requires 3 commands; one to send the AUTH LOGIN code, one to send the username and another to send the password. I found that the lettre library implements all its AUTH commands as single commands, so this wasn't working with the server. I downloaded the source code for the library, changed the send function to do the three separate commands, recompiled my code and everything worked fine :)
My addition to the lettre code:
if (accepted_mechanisms[0] == Mechanism::Login) &&
(accepted_mechanisms.capacity() == 1) {
try_smtp!(self.client.command("AUTH LOGIN"), self);
try_smtp!(self.client.command(base64::encode_config(
&username.as_bytes(),
base64::STANDARD).as_str()), self);
try_smtp!(self.client.command(base64::encode_config(
&password.as_bytes(),
base64::STANDARD).as_str()), self);

smack is connecting to ejabberd server

Here is my smack code to connect ejabberd server
XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
builder.setUsernameAndPassword("admin#manish-lenovo-g510", "admin");
builder.setServiceName("manish-lenovo-g510");
builder.setHost("192.168.1.2");
builder.setPort(5280);
XMPPTCPConnectionConfiguration build = builder.build();
AbstractXMPPConnection conn1 = new XMPPTCPConnection(build);
conn1.connect();
I am getting this error:
Exception in thread "main" org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). Used filter: No filter used or filter was 'null'.
at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackException.java:106)
at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackException.java:85)
at org.jivesoftware.smack.SynchronizationPoint.checkForResponse(SynchronizationPoint.java:253)
at org.jivesoftware.smack.SynchronizationPoint.checkIfSuccessOrWait(SynchronizationPoint.java:146)
at org.jivesoftware.smack.SynchronizationPoint.checkIfSuccessOrWaitOrThrow(SynchronizationPoint.java:125)
at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:837)
at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.java:365)
if i open admin interface of ejabberd its opening so Why this code is not working. One more thing how to find the service name as i guess that might be the issue as i dont know the service name, i have given it randomly.
I think port should be the standard XMPP port which is 5222. 5280 is the port for web admin, which speaks HTTP, not XMPP.

Fiddler Error Connecting to HTTPS Applications !SecureClientPipeDirect failed

Fiddler Error Connecting to HTTPS Applications
Fiddler Log:
!SecureClientPipeDirect failed: Authentication failed because the remote party has closed the transport stream. on pipe to (CN=services.bigpond.com, O=DO_NOT_TRUST_BC, OU=Created by http://www.fiddler2.com)
I have followed other posts but no answers
The typical explanation for this message, as documented in many places, is that the client application has not been configured to trust Fiddler's root certificate. As such, the client closes the connection to Fiddler when it sees the untrusted certificate.
http://fiddler2.com/documentation/Configure-Fiddler/Tasks/TrustFiddlerRootCert
In Kestrel I'm using an SSL cert.
I 'downgraded' the TLS protocol in order to get this to work.
This is not something you'd do in production - but in production you shouldn't be using kestrel. I'm not saying this is the best overall config, but this is mainly to show the SslProtocols option.
WebHost.CreateDefaultBuilder(args)
.UseKestrel(options =>
{
options.Listen(IPAddress.Any, 5000); // http:localhost:5000
options.Listen(IPAddress.Any, 44300, listenOptions =>
{
// https://dotnetthoughts.net/enable-http2-on-kestrel/
//listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
listenOptions.UseHttps(#"S:\WORK\SSL\example.com.pfx", "cert-password", httpsOptions =>
{
httpsOptions.SslProtocols = System.Security.Authentication.SslProtocols.Tls;
});
});
})
.UseStartup<Startup>();

SASL authorization failing while connecting to XMPP server

I am trying to connect to gmail using SMACK API through XMPP server. but getting the
error : SASL authentication failed using mechanism PLAIN
you can check a glimpse of code. I got it from net only
ConnectionConfiguration connConfig = new ConnectionConfiguration("talk.google.com", 5222, "gmail.com");
connection = new XMPPConnection(connConfig);
connection.connect();
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
I checked in the smack debug window. it says in XML :
< invalid-authzid />
I am already having account on gmail and my gtalk is also running.
You need to set the authentication before you connect viz
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
must appear before connection.connect().
See my blog.
ConnectionConfiguration cc = new ConnectionConfiguration(
"vietnam.agilemobile.com", 5222, vietnam.agilemobile.com");
XMPPConnection connection = new XMPPConnection(cc);
try {
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
connection.connect();
Log.e("LOGIN", "" + 111);
// You have to put this code before you login
Log.e("LOGIN", "" + 222);
// You have to specify your gmail addres WITH #gmail.com at the end
connection.login("nemodo", "123456", "resource");
Log.e("LOGIN", "" + 333);
// See if you are authenticated
System.out.println(connection.isAuthenticated());
} catch (XMPPException e1) {
e1.printStackTrace();
}
I also get this mistake, but i can not work.
For anyone looking for possible solutions to this many years after this was originally asked and answered, I recently was able to get past this authentication error by explicitly setting the authzid value on the XMPPTCPConnectionConfiguration.
I was running into an issue where my connection configuration worked fine for some client XMPP servers, but not for others, even though they were all using SASL PLAIN authentication. After some troubleshooting, I learned that the ones that were failing were expecting an authzid value. After adjusting my code to set this, it works in both the environments that were working before, as well as the environments that were failing.
Here is how I am building my connection configuration:
XMPPTCPConnectionConfiguration.builder()
.setHost(XMPP_DOMAIN)
.setXmppDomain(XMPP_DOMAIN)
.setPort(XMPP_PORT)
.setCompressionEnabled(true) // optional, not all servers will support this
.setUsernameAndPassword(XMPP_USER, XMPP_PASSWORD)
.setResource(XMPP_RESOURCE)
.setAuthzid(JidCreate.entityBareFrom(String.format("%s#%s", XMPP_USER, XMPP_DOMAIN))) // <-- this was the change I needed
.build();
Specifically I needed to add this line:
.setAuthzid(JidCreate.entityBareFrom(String.format("%s#%s", XMPP_USER, XMPP_DOMAIN)))