Kitura / Swift-SMTP

Swift SMTP client
Apache License 2.0
261 stars 63 forks source link

Connecting to Amazon SES #22

Closed collinhundley closed 7 years ago

collinhundley commented 7 years ago

Hey @quanvo87, I've been having a hard time connecting to Amazon SES. Here's how I'm connecting:

let smtp = SMTP(hostname: "email-smtp.us-west-2.amazonaws.com",
                email: MY_SES_USERNAME,
                password: MY_SES_PASSWORD,
                port: 587)

With port 587, I get this error:

530 Must issue a STARTTLS command first

If I change the port to 465 (TLS Wrapper instead of STARTTLS), it just times out instead of connecting.

Any ideas? Everything works from the command line, so it's not a firewall issue. Thanks!

quanvo87 commented 7 years ago

@collinhundley tomorrow is a holiday for me so I'll be able to look into the issue a little then. But I will definitely take a deep dive Wednesday!

Some initial ideas are--it looks like Amazon SES requires an encrypted connection. So you will need to provide information to initialize an SSL instance and include that in the SMTP struct. If you haven't already, this blog post goes more into detail about that whole process. Though based on the error you're getting, it could also be an issue with Swift-SMTP not handling certain SMTP server's connection processes correctly. I will look into it and update you.

collinhundley commented 7 years ago

@quanvo87 thanks for taking the time to look into this!

I also tried initializing an SSL with a self-signed cert, but this is the output when trying to connect:

[2017-07-03T23:08:37.488-06:00] [VERBOSE] [SMTPSocket.swift:86 readFromSocket()] 220 email-smtp.amazonaws.com ESMTP SimpleEmailService-2108164273 N74k6fuCDMXGVO4FzTuF

[2017-07-03T23:08:37.489-06:00] [VERBOSE] [SMTPSocket.swift:65 write] EHLO localhost
[2017-07-03T23:08:37.529-06:00] [VERBOSE] [SMTPSocket.swift:86 readFromSocket()] 250-email-smtp.amazonaws.com
250-8BITMIME
250-SIZE 10485760
250-STARTTLS
250-AUTH PLAIN LOGIN
250 Ok

[2017-07-03T23:08:37.530-06:00] [VERBOSE] [SMTPSocket.swift:65 write] STARTTLS
[2017-07-03T23:08:37.570-06:00] [VERBOSE] [SMTPSocket.swift:86 readFromSocket()] 220 Ready to start TLS

Error code: -25264(0x-62B0), ERROR: SecPKCS12Import, code: -25264, reason: Could not determine error reason.

I can't seem to pinpoint the issue, so hopefully you have a better idea.

I should also point out that attempting to connect to SES on port 465 (or any of the other SMTPS ports) just hangs forever, until it eventually times out. I'm pretty confused on this one, as Amazon specifically supports this protocol and I have no problem connecting from Terminal via telnet or openssl. Thanks again!

quanvo87 commented 7 years ago

When you created your self-signed cert, did you add a password to it? If not, try creating a new one with a password, and provide your SSL instance with that password.

Also, are you using an SSL instance that is supported on your OS? On this documentation page, the first 3 are supported on Linux, and the 4th on macOS.

As for certain ports hanging, this does sound familiar, and I tried to add safeguards around this (by connecting on a different thread so that we could timeout on the main thread). I'm not sure why certain ports hang in the first place, I think it has something to do with some SMTP servers being finicky and/or the the BlueSocket package Swift-SMTP uses to read/write data from a socket.

I'll keep looking into it.

collinhundley commented 7 years ago

Hey @quanvo87, your suggestion to add the password did the trick! Seems to be working now on macOS, so I'll test Linux soon.

As a side note, it looks like SMTPSocket is logging a large amount of information. Probably useful for debugging, but maybe it could be throttled back a bit for production? I've found that Kitura's logging in verbose mode strikes a good balance between useful information and brevity.

quanvo87 commented 7 years ago

Good to hear! I'm going to update the docs to include information like this--and make passwords not optional for now (and raise an issue in the BlueSSLService package as well).

I'll look into throttling logging for production, too.

collinhundley commented 7 years ago

Thanks for your help on this.

I do have one question regarding SSL certs: can you explain why a certificate is necessary on the client side? It seems like the server (in this case SES) should present a certificate when we make a connection, rather than the client. Along with that, are there any security concerns with using self-signed certs for SMTP? The encryption is the same, so it seems like it should be ok as long as the server accepts it.

Thanks!

youming-lin commented 7 years ago

@collinhundley Client cert is needed as part of the TLS handshake:

SMTP TLS Handshake

I think it's OK to use self-signed cert in client (not server). WARNING: I'm not a security expert, please do not do this in your production app without first consulting someone who is one.

quanvo87 commented 7 years ago

@collinhundley We are meeting with our security expert tomorrow and will have more information on this soon.

collinhundley commented 7 years ago

@quanvo87 that's great, I'd love to hear more about the certificates.

My understanding is that self-signed certs offer the same security as the ones from CAs; they just can't be trusted by browsers. But for an email server (my own server connecting to AWS), it seems like self-signed certs should be fine, since I know that I can trust my own certificate.

If you find out otherwise please share!

youming-lin commented 7 years ago

@collinhundley After talking with @gtaban, our security expert, turns out I was wrong in my understanding of the TLS handshake.

Whether or not a client certificate is needed depends on the SMTP server; the certificate is only used for authentication purposes, and is only needed when the server demands client authentication via certificate.

We'll update Kitura-SMTP and make client certificate optional.

collinhundley commented 7 years ago

@youming-lin thanks for following up. I'll be watching out for an update.

gtaban commented 7 years ago

Hi @collinhundley , I haven't worked with SMTP security too much so hopefully I won't say too many wrong things. I'll start with some background that you probably know already!

There are two main levels of security involved with SMTP:

SMTP itself doesn't specify transport level security though most servers use STARTTLS protocol which basically just opportunistically tries to upgrade the channel to secure. But this is mostly secrecy secure (meaning encryption of the data) and not end point authentication. For secrecy, certificates are not necessary in general. It really depends on the validation requirements of the other party. So server certificate would get validated by the client and vice versa.

In general, authenticating the server endpoint is much more critical than the client endpoint as the server is obviously more privileged. Currently there does not seem to be a set endpoint authentication standard although SMTP STS is being drafted which requires the server cert to be signed by a valid CA. However I don't think there is any specifications on the client cert. What this also means is that depending on how the server is setup, the client can:

I think long term what we would want to have is an SMTP client that supports all three. But again which to use is dependent on the certificate validation requirements of the server.

Let me know if the above doesn't answer your question.