@@ -926,11 +926,15 @@ def _auth_cram_md5(self, arg=None):
926
926
except ValueError as e :
927
927
self .push ('535 Splitting response {!r} into user and password '
928
928
'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
934
938
self ._authenticated (user , hashed_pass == valid_hashed_pass )
935
939
# end AUTH related stuff.
936
940
@@ -1031,6 +1035,7 @@ def handle_error(self):
1031
1035
class SMTPSimTests (unittest .TestCase ):
1032
1036
1033
1037
def setUp (self ):
1038
+ smtplib ._have_cram_md5_support .cache_clear ()
1034
1039
self .thread_key = threading_helper .threading_setup ()
1035
1040
self .real_getfqdn = socket .getfqdn
1036
1041
socket .getfqdn = mock_socket .getfqdn
@@ -1181,6 +1186,29 @@ def testAUTH_CRAM_MD5(self):
1181
1186
self .assertEqual (resp , (235 , b'Authentication Succeeded' ))
1182
1187
smtp .close ()
1183
1188
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
+
1184
1212
@hashlib_helper .requires_hashdigest ('md5' , openssl = True )
1185
1213
def testAUTH_multiple (self ):
1186
1214
# Test that multiple authentication methods are tried.
0 commit comments