@@ -926,11 +926,15 @@ def _auth_cram_md5(self, arg=None):
926926 except ValueError as e :
927927 self .push ('535 Splitting response {!r} into user and password '
928928 'failed: {}' .format (logpass , e ))
929- return False
930- valid_hashed_pass = hmac .HMAC (
931- sim_auth [1 ].encode ('ascii' ),
932- self ._decode_base64 (sim_cram_md5_challenge ).encode ('ascii' ),
933- 'md5' ).hexdigest ()
929+ return
930+
931+ pwd = sim_auth [1 ].encode ('ascii' )
932+ msg = self ._decode_base64 (sim_cram_md5_challenge ).encode ('ascii' )
933+ try :
934+ valid_hashed_pass = hmac .HMAC (pwd , msg , 'md5' ).hexdigest ()
935+ except ValueError :
936+ self .push ('504 CRAM-MD5 is not supported' )
937+ return
934938 self ._authenticated (user , hashed_pass == valid_hashed_pass )
935939 # end AUTH related stuff.
936940
@@ -1031,6 +1035,7 @@ def handle_error(self):
10311035class SMTPSimTests (unittest .TestCase ):
10321036
10331037 def setUp (self ):
1038+ smtplib ._have_cram_md5_support .cache_clear ()
10341039 self .thread_key = threading_helper .threading_setup ()
10351040 self .real_getfqdn = socket .getfqdn
10361041 socket .getfqdn = mock_socket .getfqdn
@@ -1181,6 +1186,29 @@ def testAUTH_CRAM_MD5(self):
11811186 self .assertEqual (resp , (235 , b'Authentication Succeeded' ))
11821187 smtp .close ()
11831188
1189+ @hashlib_helper .block_algorithm ('md5' )
1190+ def testAUTH_CRAM_MD5_blocked (self ):
1191+ # CRAM-MD5 is the only "known" method by the server,
1192+ # but it is not supported by the client. In particular,
1193+ # no challenge will ever be sent.
1194+ self .serv .add_feature ("AUTH CRAM-MD5" )
1195+ smtp = smtplib .SMTP (HOST , self .port , local_hostname = 'localhost' ,
1196+ timeout = support .LOOPBACK_TIMEOUT )
1197+ self .addCleanup (smtp .close )
1198+ msg = re .escape ("No suitable authentication method found." )
1199+ with self .assertRaisesRegex (smtplib .SMTPException , msg ):
1200+ smtp .login (sim_auth [0 ], sim_auth [1 ])
1201+
1202+ @hashlib_helper .block_algorithm ('md5' )
1203+ def testAUTH_CRAM_MD5_blocked_and_fallback (self ):
1204+ # Test that PLAIN is tried after CRAM-MD5 failed
1205+ self .serv .add_feature ("AUTH CRAM-MD5 PLAIN" )
1206+ smtp = smtplib .SMTP (HOST , self .port , local_hostname = 'localhost' ,
1207+ timeout = support .LOOPBACK_TIMEOUT )
1208+ self .addCleanup (smtp .close )
1209+ resp = smtp .login (sim_auth [0 ], sim_auth [1 ])
1210+ self .assertEqual (resp , (235 , b'Authentication Succeeded' ))
1211+
11841212 @hashlib_helper .requires_hashdigest ('md5' , openssl = True )
11851213 def testAUTH_multiple (self ):
11861214 # Test that multiple authentication methods are tried.
0 commit comments