Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

STARTTLS Failure

by tultalk (Monk)
on May 03, 2018 at 15:23 UTC ( [id://1214007]=perlquestion: print w/replies, xml ) Need Help??

tultalk has asked for the wisdom of the Perl Monks concerning the following question:

Hi: Failure below

Searches turn up <554 Security failure as generalized and revealing nothing.

Any suggestions/pointers appreciated

If I don't send second EHLO and let it go through auth it authenticates the username/password and sends the email.

socket_write("AUTH PLAIN " . encode_base64(join("\0", $ +auth->{user}, $auth->{user}, $auth->{password}), $CRLF) ) || return fail("send AUTH PLAIN failed (lost connect +ion?)"); socket_read() || return fail("AUTH PLAIN failed: $server_reply") +;

Exchange w/server

- trying abc.us - connected to abc.us <220-cp15m2.lowesthosting.com ESMTP Exim 4.89_1 #1 Thu, 03 May 2018 09 +:29:03 -0500 <220-We do not authorize the use of this system to transport unsolicit +ed, <220 and/or bulk e-mail. >EHLO abc.us <250-cp15m2.lowesthosting.com Hello cp15.lowesthosting.com [69.41.190. +211] <250-SIZE 52428800 <250-8BITMIME <250-PIPELINING <250-AUTH PLAIN LOGIN <250-CHUNKING <250-STARTTLS <250 HELP >STARTTLS <220 TLS go ahead >EHLO abc.us <554 Security failure

The code producing this is:

unless ( $connected ) { return fail("connect to $smtp failed ($!) no (more) retries!") }; { local $^W = 0; # don't warn on undefined variables # Add info to log variable $log .= "Server: $smtp Port: $port\n" . "From: $fromaddr\n" . "Subject: $mail{Subject}\n" ; } my($oldfh) = select(S); $| = 1; select($oldfh); socket_read() || return fail("Connection error from $smtp on port $port ($_) +"); socket_write("EHLO $smtp$CRLF") || return fail("send EHLO error (lost connection?)"); my $ehlo = socket_read(); if ($ehlo) { $log .= "socket_read ehlo: $ehlo \n"; # parse EHLO response map { s/^\d+[- ]//; my ($k, $v) = split /\s+/, $_, 2; $esmtp{$k} = $v || 1 if $k; } split(/\n/, $ehlo); if ($port == 587) { #Add STARTTLS code socket_write("STARTTLS$CRLF") || return fail("send STARTTLS failed (lost connection?)") +; socket_read() || return fail(" $server_reply"); socket_write("EHLO $smtp$CRLF") || return fail("send EHLO error (lost connection?)"); $ehlo = ""; $ehlo = socket_read(); if ($ehlo) { $log .= "2nd socket_read ehlo: $ehlo \n"; + warn("parse 2nd EHLO response"); map { s/^\d+[- ]//; my ($k, $v) = split /\s+/, $_, 2; $esmtp{$k} = $v || 1 if $k; } split(/\n/, $ehlo); } } }

Replies are listed 'Best First'.
Re: STARTTLS Failure
by jeffenstein (Hermit) on May 04, 2018 at 09:17 UTC

    I'm working from memory, but I think you are supposed to do a TLS/SSL negotiation after sending the STARTTLS command. It should not accept any plaintext after the STARTTLS command, so the remote server seems to be working correctly.

    Why not use a module like Net::SMTP to do the heavy lifting for you?

      Hi:

      I have already looked at that and several others

      I my have to do that as a fallback, but that ruins my "learning experience". Or perhaps that would be a better learning experience.

      Thanks for suggestion

      When I go through the steps using openssl, after the STARTTLS and the go ahead I send EHLO and the server sends back expected responses the I send the AUTH PLAIN and it is accepted. Perhaps openssl is doing something with negotiations in background of which I am unaware

      RFC 3207 shows a typical exchange:

      S: 250-STARTTLS S: 250 DSN C: STARTTLS S: 220 Go ahead C: <starts TLS negotiation> C & S: <negotiate a TLS session> C & S: <check result of negotiation> C: EHLO mail.example.com S: 250-mail.imc.org touches your hand gently for a moment

      I don't know specifically what these three example communications are: C: <starts TLS negotiation> C & S: <negotiate a TLS session> C & S: <check result of negotiation>.

      Using openssl I go from S: 220 Go ahead to EHLO and it works up to the pint of a cert failure when I send the RCPT TO:

        Hi tultalk:

        I don't know specifically what these three example communications are: C: <starts TLS negotiation> C & S: <negotiate a TLS session> C & S: <check result of negotiation>

        This part would do a public key exchange and negotiate a private key for this session. After this step all data going to the server must be encrypted by openssl before sending, and all data coming from the server must be decrypted by openssl before it is usable

        The IO::Socket::SSL has an example of how to upgrade a socket from plain to SSL, assuming you are using IO::Socket::INET as the base socket. Search for "Talk Plain and SSL With The Same Socket" in the docs. I haven't looked at the code it uses, but I'm assuming that it re-blesses the socket into IO::Socket::SSL, and after that the IO::Socket::SSL module will encrypt any data you write to the socket before sending to the socket, and decrypt any data it reads from the socket before giving it to you.

        In the example above I didn't see any SSL modules, so I assumed you were still writing plaintext directly to the socket. If that's not the case, could you show the part that does the ssl negotiation and adds the layer to encrypt/decrypt?

        If you want a learning experience, Net::SSLeay directly exposes the openssl library's low-level functions to negotiate sessions, and encrypt/decrypt data. I've never used it directly myself, but I would imagine that there are some good examples in the IO::Socket::SSL sources.

Re: STARTTLS Failure
by tultalk (Monk) on May 03, 2018 at 16:08 UTC

    Works using openSSL cmd

    250 HELP ehlo 250-cp15m2.lowesthosting.com Hello [72.168.128.19] 250-SIZE 52428800 250-8BITMIME 250-PIPELINING 250-AUTH PLAIN LOGIN 250 HELP AUTH PLAIN d2VibWFzdGxxxxxxxxbS51cwB3ZWJtYXN0ZXJAYndtamNtLnVzAHdtQDQwO +TEzV00= 235 Authentication succeeded

      First of all, you might want to completely edit out what looks right now like slightly damaged but partially decodable login-password pair, in case you didn't do that already.

      Secondly, when you're using openssl, you are already establishing a TLS connection (so no STARTTLS command is required), but when doing STARTTLS in Perl by hand (like you seem to be trying to), after receiving 220 TLS go ahead you should immediately send TLS Client hello, establish a TLS connection and send EHLO abc.us over that. Judging by your code,

      socket_write("STARTTLS$CRLF") || return fail("send STARTTLS failed (lost connection?)") +; socket_read() || return fail(" $server_reply"); socket_write("EHLO $smtp$CRLF") || return fail("send EHLO error (lost connection?)");
      you are trying to authenticate in plain text, not over TLS (thus defeating the purpose of the command). Since server expects TLS handshake and not a EHLO, it bails.

      Suggested solution: start right away with TLS. This way, you won't have to create a TLS object over an existing TCP connection, thus slightly breaking encapsulation in your application architecture, and bad guys sitting between you and the server and doing a MITM attack won't be able to impersonate the server at all (like they can before you enter STARTTLS).

        Thanks

        chunks removed and some replaced with xxxxx

Re: STARTTLS Failure
by Anonymous Monk on May 03, 2018 at 17:24 UTC
    Youre writing a ssl client?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1214007]
Approved by Sinistral
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (4)
As of 2024-06-23 14:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.