smtp problem: x509: certificate signed by unknown authority

7,059 views
Skip to first unread message

Lars Pensjö

unread,
Dec 8, 2012, 5:40:13 AM12/8/12
to golan...@googlegroups.com
When I use smtp.SendMail, I get the error message "x509: certificate signed by unknown authority". What does that mean?

I am using  smtp.PlainAuth("", smtpusername, smtppassword, smtphost) as authentication, using a user name and password given by my mail supplier.

Dave Cheney

unread,
Dec 8, 2012, 5:43:27 AM12/8/12
to Lars Pensjö, golan...@googlegroups.com
That usually means that the host you are trying to connect to is
returning a certificate that is signed by a CA root that your computer
does not know about. This could be a self signed certificate, a
misconfiguration on the remote end, or something nasty doing SSL man
in the middle.
>t is > --
>
>

Lars Pensjö

unread,
Dec 8, 2012, 5:51:43 AM12/8/12
to golan...@googlegroups.com, Lars Pensjö
If I decide to trust it anyway, how can I make smtp.SendMail() accept it?

I don't know much about certificates, and how they are involved in the SMTP protocol.

Phil Pennock

unread,
Dec 10, 2012, 7:32:56 PM12/10/12
to Lars Pensjö, golan...@googlegroups.com
On 2012-12-08 at 02:51 -0800, Lars Pensjö wrote:
> If I decide to trust it anyway, how can I make smtp.SendMail() accept it?
>
> I don't know much about certificates, and how they are involved in the SMTP
> protocol.

Badly.

There are two distinct modes of using SMTP. Mode 1 is "delivery to MX
for a domain", mode 2 is "initial submission of a message by the
author".

Mode 2 usage _should_ be happening on port 587 (instead of 25) and the
mail server operator should be using a certificate from an authority
trusted by all their users. In this case, SMTP usage of certificates is
very much like any normal application's usage of TLS certificates.
There's no problem, beyond server mis-configuration.

The mode 1 usage has protocol-level issues about choosing a trustworthy
name for verification. In the typical case, these names are not
verified at all, which means that SMTP/TLS is vulnerable to
man-in-the-middle attacks.

For Go, you create a TLS config and set the InsecureSkipVerify bool to
true. Promoting a rawConn connection might be done with:

cfg := &tls.Config{ServerName: "mx.example.org", InsecureSkipVerify: true}
tlsConn := tls.Client(rawConn, cfg)

If you're interested, then:

http://tools.ietf.org/html/draft-fanf-dane-smtp

is the only current proposal for fixing the TLS naming issue for SMTP on
the MX port; it requires DNSSEC and use of TLSA records.

-Phil

Lars Pensjö

unread,
Dec 12, 2012, 6:54:08 AM12/12/12
to golan...@googlegroups.com, Lars Pensjö
Thanks Phil!

I am using port 587. If I understand you correctly, you say I should modify the smtp package to get what I want?

Looking into smtp.SendMail, there are a couple of lines:
   230		if ok, _ := c.Extension("STARTTLS"); ok {
   231			if err = c.StartTLS(nil); err != nil {
   232				return err
   233			}
   234		}
The Client.StartTls will send command "STARTTLS" and do c.conn = tls.Client(c.conn, config) (adding a crypt layer I think). Instead, from your proposal, I should modify SendMail to do:

if ok, _ := c.Extension("STARTTLS"); ok {
    cfg := &tls.Config{ServerName: addr, InsecureSkipVerify: true} // 'addr' is the server address
    c.conn = tls.Client(rawConn, cfg)
}

Is that what you propose? The c.conn is a private field, which means I can't do my own version of the SendMail() function, I will need to make my own version of the smtp package.

A follow-up question, given the problem I have: Is the bug in my mail provider, in smtp, or in some local configuration in my application/computer?

/Lars

agl

unread,
Dec 12, 2012, 9:43:58 AM12/12/12
to golan...@googlegroups.com, Lars Pensjö
On Wednesday, December 12, 2012 6:54:08 AM UTC-5, Lars Pensjö wrote:
A follow-up question, given the problem I have: Is the bug in my mail provider, in smtp, or in some local configuration in my application/computer?

What's the hostname:port of the server in question? I can take a look at the certificate chain.


Cheers

AGL

agl

unread,
Dec 12, 2012, 9:54:01 AM12/12/12
to golan...@googlegroups.com, Lars Pensjö
On Wednesday, December 12, 2012 9:43:58 AM UTC-5, agl wrote:
What's the hostname:port of the server in question? I can take a look at the certificate chain.

The reporter provided the hostname to me privately and I can confirm that it's a self-signed certificate: i.e. it's clearly invalid and intended to be so.

So this really is a question of how to handle this case, not a problem with crypto/x509 finding the system root certificates etc.

One other thing caught my eye above:

&tls.Config{ServerName: addr, InsecureSkipVerify: true} // 'addr' is the server address

ServerName should be just the hostname, but |addr| suggests that it might contain the port number too. Just a drive-by comment.


Cheers

AGL 

Lars Pensjö

unread,
Dec 12, 2012, 5:03:08 PM12/12/12
to golan...@googlegroups.com, Lars Pensjö
Thanks!

To my understanding, I still can't use the current net/smtp package without modifying it myself?

So I changed smtp.SendMail (the bold font) as follows:

func SendMail(addr string, a smtp.Auth, from string, to []string, msg []byte) error {
    c, err := Dial(addr)
    if err != nil {
        return err
    }
    if ok, _ := c.Extension("STARTTLS"); ok {
        cfg := &tls.Config{ServerName: c.serverName, InsecureSkipVerify: true}
        c.conn = tls.Client(c.conn, cfg)
        c.Text = textproto.NewConn(c.conn)
        c.tls = true
    }
    if a != nil && c.ext != nil {
        if _, ok := c.ext["AUTH"]; ok {
            if err = c.Auth(a); err != nil {
                return err
            }
        }
    }

Now, a proper EHLO is generated, followed by "AUTH PLAIN xxxxxxxxx" with a correct hash. However, the c.Auth() call returns the error "local error: unexpected message". I don't know the reason for that failure. When I test the protocol manually (with telnet), it works fine.

Anthony Martin

unread,
Dec 12, 2012, 9:18:06 PM12/12/12
to Lars Pensjö, golan...@googlegroups.com
Lars Pensjö <lars....@gmail.com> once said:
> Now, a proper EHLO is generated, followed by "AUTH PLAIN xxxxxxxxx" with a
> correct hash. However, the c.Auth() call returns the error "local error:
> unexpected message". I don't know the reason for that failure. When I test
> the protocol manually (with telnet), it works fine.

You have to call the StartTLS method with your TLS config.
It sends the actual STARTTLS command and waits for a 220
response. Also, you shouldn't modify the SendMail function
in net/smtp. Just copy the code into your program and
modify it to suit your needs.

Here's a diff that will do what you want:

--- a.go 2012-02-21 18:08:04.000000000 -0800
+++ b.go 2012-12-12 18:14:29.839858458 -0800
@@ -228,12 +228,17 @@
return err
}
if ok, _ := c.Extension("STARTTLS"); ok {
- if err = c.StartTLS(nil); err != nil {
+ host, _, _ := net.SplitHostPort(addr)
+ config = &tls.Config{
+ InsecureSkipVerify: true,
+ ServerName: host,
+ }
+ if err = c.StartTLS(config); err != nil {
return err
}
}
- if a != nil && c.ext != nil {
- if _, ok := c.ext["AUTH"]; ok {
+ if a != nil {
+ if ok, _ := c.Extension("AUTH"); ok {
if err = c.Auth(a); err != nil {
return err
}

Cheers,
Anthony

Lars Pensjö

unread,
Dec 13, 2012, 10:24:17 AM12/13/12
to golan...@googlegroups.com
Thanks, now it works! And calling StartTLS() means I don't need access to private fields.
Reply all
Reply to author
Forward
0 new messages