certificate problems trying to send email with libcurl - email

This is my libcurl code. I am trying to send email to my own email domain in linux.
This is my sample libcurl code.
curl_easy_setopt(curl, CURLOPT_USERNAME, "username#mydomain.com");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "mypassword");
curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.mydomain.com:25");
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
recipients = curl_slist_append(recipients, TO);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fileBuf_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &file_upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //Dont display Curl Connection data Change 1L to 0
res = curl_easy_perform(curl);
When I run this code, I am getting the below error.
* Rebuilt URL to: smtp://mail.mydomain.com:25/
* Hostname was NOT found in DNS cache
* Trying <My mail domain Ip address>...
* Connected to mail.mydomain.com (<My mail domain Ip address>) port 25 (#0)
< 220 mail.mydomain.com ESMTP
> EHLO client6
< 250-mail.mydomain.com
< 250-PIPELINING
< 250-SIZE 20480000
< 250-VRFY
< 250-ETRN
< 250-STARTTLS
< 250-AUTH PLAIN LOGIN
< 250-ENHANCEDSTATUSCODES
< 250-8BITMIME
< 250 DSN
> STARTTLS
< 220 2.0.0 Ready to start TLS
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* SSL certificate problem: self signed certificate
* Closing connection 0
curl_easy_perform() failed: Peer certificate cannot be authenticated with given CA certificates

Your issue is that your server is providing a self-signed certificate so curl is not able to verify its provenance. You have several options:
The best option is to get a server certificate that is signed by a well-known certificate authority. Some CAs will issue a certificate you can use for free; search for "free ssl certificate". You will need to be able to provide some proof that you control the domain.
You can install your self-signed certificate to the list of trusted CAs on the computer(s) that run your libcurl code. The procedure to do this depends on your OS (even different distributions of Linux may do this differently). This link is a decent starting point for Linux.
Your program can tell libcurl to verify with the self-signed certificate. See Adding self-signed SSL certificate for libcurl.
You can create your own certificate authority and use either of the previous two approaches. The advantage of this over self-signing is it decouples the signing and the signed certificates. If you want to change the server certificate (e.g. if it expires or the host name changes) you don't necessarily need to reconfigure all the clients.
For completeness, you could disable verification by setting CURLOPT_SSL_VERIFYPEER to 0. This is highly discouraged, however, as it makes the access insecure. You should only do this for testing purposes, or in the rare case that the network between client and server is guaranteed to be secure.

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 :)

Outlook Mailcow wrong ssl certificate

Recently I set up a mail server (mailcow) with help of the following tutorial. I tried to login with Outlook, but Outlook says that the certificate can not be verified. Why is the value of the issued to field mail.example.org and not to xxx.xxx.xx?
mailcow.conf:
MAILCOW_HOSTNAME=xxx.xxx.xx
HTTP_PORT=8080
HTTP_BIND=0.0.0.0
HTTPS_PORT=8443
HTTPS_BIND=0.0.0.0
SMTP_PORT=25
SMTPS_PORT=465
SUBMISSION_PORT=587
IMAP_PORT=143
IMAPS_PORT=993
POP_PORT=110
POPS_PORT=995
SIEVE_PORT=4190
DOVEADM_PORT=127.0.0.1:19991
SQL_PORT=127.0.0.1:13306
ADDITIONAL_SAN=
# Skip running ACME (acme-mailcow, Let's Encrypt certs) - y/n
SKIP_LETS_ENCRYPT=n
# Skip IPv4 check in ACME container - y/n
SKIP_IP_CHECK=n
# Skip HTTP verification in ACME container - y/n
SKIP_HTTP_VERIFICATION=n
In the configuration file I set SKIP_LETS_ENCRYPT = y and generated the ssl certificate with letsencrypt myself. Look here.

Trust self-signed certificate for Email::Sender::Transport::SMTPS in perl

Trying to use Email::Sender::Transport::SMTPS for sending email. My transport is:
my $transport = Email::Sender::Transport::SMTPS->new({
host => $smtpserver,
ssl => 'starttls',
sasl_username => $smtpuser,
sasl_password => $smtppassword,
debug => 1,
});
When trying send the email, the debug says:
Net::SMTPS=GLOB(0x7f893b2b00f0)<<< 250-SIZE 52428800
Net::SMTPS=GLOB(0x7f893b2b00f0)<<< 250-8BITMIME
Net::SMTPS=GLOB(0x7f893b2b00f0)<<< 250-PIPELINING
Net::SMTPS=GLOB(0x7f893b2b00f0)<<< 250-STARTTLS
Net::SMTPS=GLOB(0x7f893b2b00f0)<<< 250 HELP
Net::SMTPS=GLOB(0x7f893b2b00f0)>>> STARTTLS
Net::SMTPS=GLOB(0x7f893b2b00f0)<<< 220 TLS go ahead
DEBUG: .../IO/Socket/SSL.pm:735: local error: SSL connect attempt failed error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
DEBUG: .../IO/Socket/SSL.pm:738: fatal SSL error: SSL connect attempt failed error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed
unable to establish SMTP connection
Probably because the server using self-signed certificate. (When using the same setting in the Thunderbird it is needed to add the "trust this certificate" setting.)
The question is: How to add the "trust this certificate" for the Email::Sender::Transport::SMTPS - thus allow sending email.
There is no direct way to give Email::Sender::Transport::SMTPS SSL specific arguments. But, since ultimately IO:Socket::SSL is used you can hack your way around this limitation. From the man page:
This is a list of typical errors seen with the use of IO::Socket::SSL:. ....
Make SSL settings inacessible by the user, together with bad builtin settings.
Some modules use IO::Socket::SSL, but don't make the SSL settings available to the user. This is often combined with bad builtin settings or defaults (like switching verification off). Thus the user needs to hack around these restrictions by using set_args_filter_hack or similar.
Thus what you could do is
IO::Socket::SSL::set_args_filter_hack( sub {
my ($is_server,$args) = #_;
$args->{SSL_fingerprint} = 'sha1$437104....'
});
With this option you could make certificate pinning trust a certificate as long as it's fingerprint matches the given one. You can get the fingerprint for instance with:
openssl s_client -connect mail.example.org:25 -starttls smtp |\
openssl x509 -fingerprint -noout
Alternative ways would be to use the certificate as trusted with the SSL_ca_file option. You could also set SSL_verify_mode to 0 (SSL_VERFY_NONE) but since this disables any kind of validation you should only use this for testing.
Please note that set_args_filter_hack is global, that is it affects all IO::Socket::SSL objects in your program. Thus depending on the program you should only set it directly before you establish the connection with Email::Sender::Transport::SMTPS and reset it immediately afterwards.
For more information about these options please read the documentation of IO::Socket::SSL.
You can control the SSL usage with the options of new() constructor method
"SSL_verify_mode"=>'SSL_VERIFY_NONE'
IN Email/Sender/Transport/SMTPS.pm
# compatible
my $ssl = $self->ssl;
$ssl = 'ssl' if $self->ssl and $self->ssl ne 'starttls';
return (
$self->host,
Port => $self->port,
Timeout => $self->timeout,
defined $ssl ? (doSSL => $ssl) : (),
defined $self->helo ? (Hello => $self->helo) : (),
defined $self->localaddr ? (LocalAddr => $self->localaddr) : (),
defined $self->localport ? (LocalPort => $self->localport) : (),
defined $self->debug ? (Debug => $self->debug) : (),
"SSL_verify_mode"=>'SSL_VERIFY_NONE',#ADDED LINE
);
EDIT: This is really bad, because as per comments you trust everything. Instead if on linux/*nix
cat tobetrusted.crt >> /etc/ssl/cert.pem

How configure roundcube to work with imaps?

I recently installed Postfix, Dovecot to setup a mail server on my own VPS ( using this tutorial: Email with Postfix, Dovecot, Mysql)
Imaps server uses port 993 for Authentication, and Postfix uses port 25 to send mails.
In this tutorial, users stored in a Database ( so imaps use mysql to authenticate users).
i'm sure every thing works fine with imaps and postfix , because few days ago i installed Kmail client (on my linux) and receive mails from my server. sending mails also works fine, i sent a mail to Gmail and google received it without a problem (in my "Gmail inbox" not spam folder)
So to get to my Emails from a web mail client, i installed Roundcube on /var/www/mail directory.
I configured Roundcube many times. but each time it gives me this Error:
IMAP Error: Login failed for [me#mydomain] from X.x.X.x . Empty
startup greeting (localhost:993) in
/var/www/mm/program/lib/Roundcube/rcube_imap.php on line 184 (POST
/mm/?_task=login?_task=login&_action=login)
When i do log in from roundcube, imap server says ( in /var/log/mail.log ):
May 20 07:05:16 my-server dovecot: imap-login: Disconnected (no auth
attempts): rip=::1, lip=::1, TLS handshaking: Disconnected
Here is my roundcube config file :
$config['db_dsnw'] = 'mysql://roundcubeuser:myPassword#localhost/roundcubemail';
// ----------------------------------
// IMAP
// ----------------------------------
$config['debug_level'] = 13;
$config['default_host'] = 'ssl://127.0.0.1';
$config['default_port'] = 993;
// ----------------------------------
// SMTP
// ----------------------------------
$config['smtp_server'] = 'ssl://localhost';
What's the problem? i really have no idea what is happening !
Thank you.
I'm using postfix + dovecot + roundcube a few months now and it's working for me. In my configuration, postfix rejects plaintext sessions, so roundcube has to connect with ssl - and it's working.
This is from my main.inc.php. I don't remember editing anything here, it's just the initial config created during the installation.
Now that I'm looking at it, default_port doesn't make any sense, I think it's just ignored.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// Supported replacement variables:
// %n - http hostname ($_SERVER['SERVER_NAME'])
// %d - domain (http hostname without the first part)
// %s - domain name after the '#' from e-mail address provided at login screen
// For example %n = mail.domain.tld, %d = domain.tld
// TCP port used for IMAP connections
$rcmail_config['default_port'] = 143;
$rcmail_config['default_host'] = array("ssl://localhost:993");
// TCP port used for IMAP connections
$rcmail_config['default_port'] = 143;
In case the other answer does not work, this is what worked for me. My config.inc.php now contains:
$config['default_host'] = 'ssl://localhost';
$config['default_port'] = 993;
NOTE: using tls://localhost did not work for me. I had to specify ssl:// as the URI scheme.
Via PhpMyAdmin, I also ran this SQL command (all my user accounts are on the same machine that runs RoundCube):
UPDATE `rc_users` SET `mail_host`='ssl://localhost'
I got the port number 993 from running sudo netstat -tulnp in order to determine the port on which Dovecot was listening.

Postfix SMTP relay: client does not offer TLS client certificate to the server?

I have two machines, one running Ubuntu and one runing Debian, both running Postfix. The intent is that machine#2 becomes a SMTP relay/smarthost for machine#1. I have created a CA and issued certificates for both of the machines: a server certificate for #2 and a client certificate for #1.
When sending e-mail from #1 (by having the MUA talk to Postfix on localhost:25 with the intent that it relays e-mail to #2), the basic things work fine: the machines can talk to each other and an attempt to relay is actually made. The idea is to allow relaying on #2 if a valid client-side SSL/TLS certificate is presented from #1.
The relevant configuration for #2 is:
smtpd_tls_received_header = yes
smtpd_tls_loglevel = 2
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/ssl/private/cert2.pem
smtpd_tls_key_file = /etc/ssl/private/key2-d.pem
smtpd_tls_CAfile = /etc/ssl/certs/cacert.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_mandatory_protocols = SSLv3, TLSv1
smtpd_tls_mandatory_ciphers = medium
smtpd_tls_auth_only = yes
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination permit_tls_all_clientcerts
The configuration on #1 is:
smtp_tls_CAfile = /etc/ssl/certs/cacert.pem
smtp_tls_cert_file = /etc/ssl/private/cert1.pem
smtp_tls_key_file = /etc/ssl/private/key1-d.pem
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_security_level = verify
smtp_tls_loglevel = 2
Machine#1 connects to #2, enables STARTTLS, the log files show that it successfuly verifies the certificate from #2, and attempts to relay the message. However, it appears not to send the client certificate to #2, and #2 refuses to relay the message.
Log entries from #1:
Apr 17 01:18:14 mail1 postfix/smtp[30250]: Verified TLS connection established to mail2[x.x.x.x]:25: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Apr 17 01:18:14 mail1 postfix/smtp[30244]: 8A2328BDB4: to=<addr#gmail.com>, relay=mail2[x.x.x.x]:25, delay=3488, delays=3486/0.41/0.85/0.19, dsn=4.7.1, status=deferred (host mail2[x.x.x.x] said: 454 4.7.1 <addr#gmail.com>: Relay access denied (in reply to RCPT TO command))
Log entries from #2:
Apr 17 01:18:13 mail2 postfix/smtpd[28798]: Anonymous TLS connection established from unknown[y.y.y.y]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Apr 17 01:18:13 mail2 postfix/smtpd[28798]: NOQUEUE: reject: RCPT from unknown[y.y.y.y]: 454 4.7.1 <addr#gmail.com>: Relay access denied; from=<addr#mail1> to=<addr#gmail.com> proto=ESMTP helo=<mail1>
Any ideas? I'm basing my assumption that #1 didn't send its client cert on the "Anonymous TLS connection established" part in the logs from mail2.
A TLS server must request a certificate from the client, the client will not send it by its own. Try to add
smtpd_tls_ask_ccert=yes
on the server side
add your server adress ( server1.domaine.com ) in the postfix conf file main.cf
mynetworks = 127.0.0.1/8