@@ -109,7 +109,7 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
109109 # check and log bin size
110110 binary_file = os .path .join (dut .app .binary_path , 'https_server.bin' )
111111 bin_size = os .path .getsize (binary_file )
112- logging .info ('https_server_simple_bin_size : {}KB' . format ( bin_size // 1024 ) )
112+ logging .info (f 'https_server_simple_bin_size : { bin_size // 1024 } KB' )
113113 # start test
114114 logging .info ('Waiting to connect with AP' )
115115 if dut .app .sdkconfig .get ('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN' ) is True :
@@ -125,8 +125,8 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
125125
126126 # Expected logs
127127
128- logging .info ('Got IP : {}' . format ( got_ip ) )
129- logging .info ('Got Port : {}' . format ( got_port ) )
128+ logging .info (f 'Got IP : { got_ip } ' )
129+ logging .info (f 'Got Port : { got_port } ' )
130130
131131 logging .info ('Performing GET request over an SSL connection with the server' )
132132
@@ -156,7 +156,7 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
156156
157157 if dut .app .sdkconfig .get ('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK' ) is True :
158158 current_cipher = dut .expect (r'Current Ciphersuite(.*)' , timeout = 5 )[0 ]
159- logging .info ('Current Ciphersuite {}' . format ( current_cipher ) )
159+ logging .info (f 'Current Ciphersuite { current_cipher } ' )
160160
161161 logging .info ('Checking user callback: Obtaining client certificate...' )
162162
@@ -166,9 +166,9 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
166166 1
167167 ].decode ()
168168
169- logging .info ('Serial No. {}' . format ( serial_number ) )
170- logging .info ('Issuer Name {}' . format ( issuer_name ) )
171- logging .info ('Expires on {}' . format ( expiry ) )
169+ logging .info (f 'Serial No. { serial_number } ' )
170+ logging .info (f 'Issuer Name { issuer_name } ' )
171+ logging .info (f 'Expires on { expiry } ' )
172172
173173 # Close the connection
174174 conn .close ()
@@ -203,8 +203,8 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None
203203
204204 # Expected logs
205205
206- logging .info ('Got IP : {}' . format ( got_ip ) )
207- logging .info ('Got Port : {}' . format ( got_port ) )
206+ logging .info (f 'Got IP : { got_ip } ' )
207+ logging .info (f 'Got Port : { got_port } ' )
208208
209209 logging .info ('Performing GET request over an SSL connection with the server' )
210210
@@ -233,7 +233,7 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None
233233
234234 if dut .app .sdkconfig .get ('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK' ) is True :
235235 current_cipher = dut .expect (r'Current Ciphersuite(.*)' , timeout = 5 )[0 ]
236- logging .info ('Current Ciphersuite {}' . format ( current_cipher ) )
236+ logging .info (f 'Current Ciphersuite { current_cipher } ' )
237237
238238 logging .info ('Checking user callback: Obtaining client certificate...' )
239239
@@ -243,9 +243,9 @@ def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None
243243 1
244244 ].decode ()
245245
246- logging .info ('Serial No. : {}' . format ( serial_number ) )
247- logging .info ('Issuer Name : {}' . format ( issuer_name ) )
248- logging .info ('Expires on : {}' . format ( expiry ) )
246+ logging .info (f 'Serial No. : { serial_number } ' )
247+ logging .info (f 'Issuer Name : { issuer_name } ' )
248+ logging .info (f 'Expires on : { expiry } ' )
249249
250250 # Close the connection
251251 conn .close ()
@@ -277,8 +277,8 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
277277
278278 # Expected logs
279279
280- logging .info ('Got IP : {}' . format ( got_ip ) )
281- logging .info ('Got Port : {}' . format ( got_port ) )
280+ logging .info (f 'Got IP : { got_ip } ' )
281+ logging .info (f 'Got Port : { got_port } ' )
282282 logging .info ('Performing GET request over an SSL connection with the server using TLSv1.3' )
283283
284284 CLIENT_CERT_FILE = 'client_cert.pem'
@@ -288,14 +288,136 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
288288 cert .write (client_cert_pem )
289289 key .write (client_key_pem )
290290
291+ # First try with TLSv1.2 and that should fail
292+ ssl_context = ssl .SSLContext (ssl .PROTOCOL_TLS_CLIENT )
293+ ssl_context .minimum_version = ssl .TLSVersion .TLSv1_2
294+ ssl_context .maximum_version = ssl .TLSVersion .TLSv1_2
295+ ssl_context .verify_mode = ssl .CERT_REQUIRED
296+ ssl_context .check_hostname = False
297+ ssl_context .load_verify_locations (cadata = server_cert_pem )
298+ ssl_context .load_cert_chain (certfile = CLIENT_CERT_FILE , keyfile = CLIENT_KEY_FILE )
299+ conn = http .client .HTTPSConnection (got_ip , got_port , context = ssl_context )
300+ try :
301+ conn .request ('GET' , '/' )
302+ except ssl .SSLError as e :
303+ logging .info (f'SSL handshake failed with TLSv1.2: { e } ' )
304+ else :
305+ logging .info ('SSL handshake succeeded with TLSv1.2' )
306+ raise RuntimeError ('This should have failed' )
307+
308+ ssl_context .minimum_version = ssl .TLSVersion .TLSv1_3
309+ ssl_context .maximum_version = ssl .TLSVersion .TLSv1_3
310+
311+ os .remove (CLIENT_CERT_FILE )
312+ os .remove (CLIENT_KEY_FILE )
313+
314+ conn = http .client .HTTPSConnection (got_ip , got_port , context = ssl_context )
315+ logging .info ('Performing SSL handshake with the server' )
316+ conn .request ('GET' , '/' )
317+ resp = conn .getresponse ()
318+ dut .expect ('performing session handshake' )
319+ got_resp = resp .read ().decode ('utf-8' )
320+ if got_resp != success_response :
321+ logging .info ('Response obtained does not match with correct response' )
322+ raise RuntimeError ('Failed to test SSL connection' )
323+
324+ if dut .app .sdkconfig .get ('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK' ) is True :
325+ current_cipher = dut .expect (r'Current Ciphersuite(.*)' , timeout = 5 )[0 ]
326+ logging .info (f'Current Ciphersuite { current_cipher } ' )
327+
328+ logging .info ('Checking user callback: Obtaining client certificate...' )
329+
330+ serial_number = dut .expect (r'serial number\s*:([^\n]*)' , timeout = 5 )[0 ]
331+ issuer_name = dut .expect (r'issuer name\s*:([^\n]*)' , timeout = 5 )[0 ]
332+ expiry = dut .expect (
333+ r'expires on\s*:((.*)\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])*)' ,
334+ timeout = 5 ,
335+ )[1 ].decode ()
336+
337+ logging .info (f'Serial No. : { serial_number } ' )
338+ logging .info (f'Issuer Name : { issuer_name } ' )
339+ logging .info (f'Expires on : { expiry } ' )
340+
341+ # Close the connection
342+ conn .close ()
343+ logging .info ('Correct response obtained' )
344+ logging .info ('SSL connection test successful\n Closing the connection' )
345+
346+
347+ @pytest .mark .wifi_router
348+ @pytest .mark .parametrize (
349+ 'config' ,
350+ [
351+ 'tls1_2_only' ,
352+ ],
353+ indirect = True ,
354+ )
355+ @idf_parametrize ('target' , ['esp32' , 'esp32c3' , 'esp32s3' ], indirect = ['target' ])
356+ def test_examples_protocol_https_server_tls1_2_only (dut : Dut ) -> None :
357+ logging .info ('Waiting to connect with AP' )
358+ if dut .app .sdkconfig .get ('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN' ) is True :
359+ dut .expect ('Please input ssid password:' )
360+ env_name = 'wifi_router'
361+ ap_ssid = get_env_config_variable (env_name , 'ap_ssid' )
362+ ap_password = get_env_config_variable (env_name , 'ap_password' )
363+ dut .write (f'{ ap_ssid } { ap_password } ' )
364+ # Parse IP address and port of the server
365+ dut .expect (r'Starting server' )
366+ got_port = int (dut .expect (r'Server listening on port (\d+)' , timeout = 30 )[1 ].decode ())
367+ got_ip = dut .expect (r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]' , timeout = 30 )[1 ].decode ()
368+
369+ # Expected logs
370+ logging .info (f'Got IP : { got_ip } ' )
371+ logging .info (f'Got Port : { got_port } ' )
372+ logging .info ('Performing GET request over an SSL connection with the server using TLSv1.2' )
373+
374+ CLIENT_CERT_FILE = 'client_cert.pem'
375+ CLIENT_KEY_FILE = 'client_key.pem'
376+
377+ with open (CLIENT_CERT_FILE , 'w' , encoding = 'utf-8' ) as cert , open (CLIENT_KEY_FILE , 'w' , encoding = 'utf-8' ) as key :
378+ cert .write (client_cert_pem )
379+ key .write (client_key_pem )
380+
381+ # First try with TLSv1.3 and that should fail
291382 ssl_context = ssl .SSLContext (ssl .PROTOCOL_TLS_CLIENT )
292383 ssl_context .minimum_version = ssl .TLSVersion .TLSv1_3
293384 ssl_context .maximum_version = ssl .TLSVersion .TLSv1_3
294385 ssl_context .verify_mode = ssl .CERT_REQUIRED
295386 ssl_context .check_hostname = False
296387 ssl_context .load_verify_locations (cadata = server_cert_pem )
297-
298388 ssl_context .load_cert_chain (certfile = CLIENT_CERT_FILE , keyfile = CLIENT_KEY_FILE )
389+ conn = http .client .HTTPSConnection (got_ip , got_port , context = ssl_context )
390+ try :
391+ conn .request ('GET' , '/' )
392+ except ssl .SSLError as e :
393+ logging .info (f'SSL handshake failed with TLSv1.3: { e } ' )
394+ else :
395+ logging .info ('SSL handshake succeeded with TLSv1.3' )
396+ raise RuntimeError ('This should have failed' )
397+
398+ ssl_context .minimum_version = ssl .TLSVersion .TLSv1_2
399+ ssl_context .maximum_version = ssl .TLSVersion .TLSv1_2
400+
401+ # Also now with TLS1.2, try with a non matching ciphersuite and that should fail
402+ # Server only accepts: DHE-RSA-AES128-SHA256, DHE-RSA-AES256-SHA256,
403+ # ECDHE-RSA-AES256-SHA384, ECDHE-RSA-AES128-SHA256
404+ # Try AES128-GCM-SHA256 which is NOT in the list
405+ ssl_context .set_ciphers ('AES128-GCM-SHA256' )
406+
407+ conn = http .client .HTTPSConnection (got_ip , got_port , context = ssl_context )
408+ try :
409+ logging .info ('Trying SSL handshake with non-matching ciphersuite (should fail)' )
410+ conn .request ('GET' , '/' )
411+ except ssl .SSLError as e :
412+ logging .info (f'SSL handshake failed with non-matching ciphersuite (expected): { e } ' )
413+ else :
414+ logging .info ('SSL handshake succeeded with non-matching ciphersuite' )
415+ raise RuntimeError ('This should have failed - custom ciphersuites not enforced' )
416+ finally :
417+ conn .close ()
418+
419+ # Now try with the matching ciphersuite
420+ ssl_context .set_ciphers ('DHE-RSA-AES128-SHA256' )
299421
300422 os .remove (CLIENT_CERT_FILE )
301423 os .remove (CLIENT_KEY_FILE )
@@ -312,7 +434,7 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
312434
313435 if dut .app .sdkconfig .get ('CONFIG_EXAMPLE_ENABLE_HTTPS_USER_CALLBACK' ) is True :
314436 current_cipher = dut .expect (r'Current Ciphersuite(.*)' , timeout = 5 )[0 ]
315- logging .info ('Current Ciphersuite {}' . format ( current_cipher ) )
437+ logging .info (f 'Current Ciphersuite { current_cipher } ' )
316438
317439 logging .info ('Checking user callback: Obtaining client certificate...' )
318440
@@ -323,9 +445,9 @@ def test_examples_protocol_https_server_tls1_3(dut: Dut) -> None:
323445 timeout = 5 ,
324446 )[1 ].decode ()
325447
326- logging .info ('Serial No. : {}' . format ( serial_number ) )
327- logging .info ('Issuer Name : {}' . format ( issuer_name ) )
328- logging .info ('Expires on : {}' . format ( expiry ) )
448+ logging .info (f 'Serial No. : { serial_number } ' )
449+ logging .info (f 'Issuer Name : { issuer_name } ' )
450+ logging .info (f 'Expires on : { expiry } ' )
329451
330452 # Close the connection
331453 conn .close ()
0 commit comments