Open jepler opened 1 year ago
I've seen SSL related hardfault on QtPy with ESP32-S2, trying to connect to a MQTT broker on port 8883 with TLS. When I Ctrl-C'd the program, it sometimes resulted in hard fault. Even though I had no time to isolate this further, the problem could be related to this issue.
I've been trying to do SMTP with STARTTLS in which you start with a non-ssl socket and upgrade to an ssl socket during the transactions, and I think it triggers this same problem. If I wrap_socket()
, the next recv will make the ESP32S3 (and S2) crash to safe mode. With 8.0.4 and 8.1.0-beta0. The code works perfectly on the pico-w though, 8.0.4.
I made a basic program that illustrates this, I think. If I try the fix mentioned above of doing a connect()
after the wrap_socket()
I'll get OSError: Failed SSL handshake
# STARTTLS example that crashes ESP32S3 into safe mode but works on pico-w
import wifi
import ssl
import socketpool
import time
STARTUP_WAIT = 5
HOST = "smtp.gmail.com"
PORT = 587
MAXBUF = 4096
buf = bytearray(MAXBUF)
def send_smtp_command(cmd: bytearray):
"""Quick function to send a command"""
print("Sending",cmd)
sock.send(cmd)
def receive_smtp_response(expect: bytearray):
"""Quick and inefficient function to read an smtp response"""
more = True
response = b""
while more:
sock.recv_into(buf,3)
code = buf[:3]
if code != expect:
print("Expected code ",expect," got ",code)
raise ConnectionError
sock.recv_into(buf,1)
if buf[:1] != b'-':
more = False
while True:
sock.recv_into(buf,1)
bin = buf[:1]
if bin == b"\n":
break
response += bin
return code,response
print("short wait for startup")
time.sleep(STARTUP_WAIT)
if wifi.radio.ipv4_address is None:
print("connecting to wifi")
wifi.radio.connect("my ssid","my password")
print(f"local address {wifi.radio.ipv4_address}")
pool = socketpool.SocketPool(wifi.radio)
ssl_context = ssl.create_default_context()
sock = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
print("Connecting to socket")
sock.connect((HOST,PORT))
c,r = receive_smtp_response(b"220")
print("Got code:",c,"\nresponse:",r)
send_smtp_command(b"EHLO 127.0.0.1\r\n")
c,r = receive_smtp_response(b"250")
print("Got code:",c,"\nresponse:",r)
if b"STARTTLS" not in r:
print("Couldn't find STARTTLS in response")
raise ConnectionError
send_smtp_command(b"STARTTLS\r\n")
c,r = receive_smtp_response(b"220")
print("Got code:",c,"\nresponse:",r)
print("Wrapping Socket")
sock = ssl_context.wrap_socket(sock=sock)
# This command works on pico-w but not ESP32s2/s3
send_smtp_command(b"EHLO 127.0.0.1\r\n")
c,r = receive_smtp_response(b"250")
print("Got code:",c,"\nresponse:",r)
send_smtp_command(b"QUIT\r\n")
sock.close()
On pico-w:
...
Sending b'STARTTLS\r\n'
Got code: bytearray(b'220')
response: b'2.0.0 Ready to start TLS\r'
Wrapping Socket
Sending b'EHLO 127.0.0.1\r\n'
Got code: bytearray(b'250')
response: b'smtp.gmail.com at your service, [174.118.230.138]\rSIZE 35882577\r8BITMIME\rAUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH\rENHANCEDSTATUSCODES\rPIPELINING\rCHUNKING\rSMTPUTF8\r'
Sending b'QUIT\r\n'
On ESP32S3:
...
Sending b'STARTTLS\r\n'
Got code: bytearray(b'220')
response: b'2.0.0 Ready to start TLS\r'
Wrapping Socket
Sending b'EHLO 127.0.0.1\r\n'
(Crash to safe mode)
Thanks for that info -- it's a good point that this functionality is required for protocols that use STARTTLS. On a practical note you might check whether you can use port 465 instead, which depends on what the server accepts. https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#cite_note-tcp465-86
I was able to make my smtp work using port 465 and doing ssl right from the initial connection no problem. I was trying to cover the starttls case when I noticed this crash come up.
It wouldn't hurt to re-test this after idf5 but it's probably our bug.
CircuitPython version
Code/REPL
Behavior
When the
send
call is reached, the following happens:Description
No response
Additional information
The correct sequence is apparently correct, and does work: