Skip to content

Commit 7706b33

Browse files
committed
Fix base64-url parsing errors in email headers
1 parent acefb97 commit 7706b33

File tree

4 files changed

+23
-6
lines changed

4 files changed

+23
-6
lines changed

Lib/email/_encoded_words.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,22 @@ def decode_b(encoded):
113113
# The non-alphabet characters are ignored as far as padding
114114
# goes, but we don't know how many there are. So try without adding
115115
# padding to see if it works.
116+
#
117+
# We use urlsafe_b64decode here because some mailers apparently use the
118+
# urlsafe b64 alphabet, and urlsafe_b64decode will correctly decode
119+
# both the urlsafe and regular alphabets.
120+
116121
try:
117122
return (
118-
base64.b64decode(encoded, validate=False),
123+
base64.urlsafe_b64decode(encoded),
119124
[errors.InvalidBase64CharactersDefect()],
120125
)
121126
except binascii.Error:
122127
# Add as much padding as could possibly be necessary (extra padding
123128
# is ignored).
124129
try:
125130
return (
126-
base64.b64decode(encoded + b'==', validate=False),
131+
base64.urlsafe_b64decode(encoded + b'=='),
127132
[errors.InvalidBase64CharactersDefect(),
128133
errors.InvalidBase64PaddingDefect()],
129134
)

Lib/email/base64mime.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
]
3535

3636

37-
from base64 import b64encode
38-
from binascii import b2a_base64, a2b_base64
37+
from base64 import b64encode, urlsafe_b64decode
38+
from binascii import b2a_base64
3939

4040
CRLF = '\r\n'
4141
NL = '\n'
@@ -102,12 +102,15 @@ def decode(string):
102102
base64 (like =?iso-8859-1?b?bmloISBuaWgh?=) -- please use the high
103103
level email.header class for that functionality.
104104
"""
105+
# We use urlsafe_b64decode here because some mailers apparently use the
106+
# urlsafe b64 alphabet, and urlsafe_b64decode will correctly decode both
107+
# the urlsafe and regular alphabets.
105108
if not string:
106109
return bytes()
107110
elif isinstance(string, str):
108-
return a2b_base64(string.encode('raw-unicode-escape'))
111+
return urlsafe_b64decode(string.encode('raw-unicode-escape'))
109112
else:
110-
return a2b_base64(string)
113+
return urlsafe_b64decode(string)
111114

112115

113116
# For convenience and backwards compatibility w/ standard base64 module

Lib/test/test_email/test__encoded_words.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ def test_missing_padding(self):
3838
# 2 missing padding characters
3939
self._test(b'dg', b'v', [errors.InvalidBase64PaddingDefect])
4040

41+
def test_urlsafe_alphabet(self):
42+
self._test(
43+
b'QW5tZWxkdW5nIE5ldHphbnNjaGx1c3MgU_xkcmluZzNwLmpwZw==',
44+
b'Anmeldung Netzanschluss S\xfcdring3p.jpg',
45+
[errors.InvalidBase64CharactersDefect])
46+
4147
def test_invalid_character(self):
4248
self._test(b'dm\x01k===', b'vi', [errors.InvalidBase64CharactersDefect])
4349

Lib/test/test_email/test_email.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4663,6 +4663,9 @@ def test_decode(self):
46634663
eq = self.assertEqual
46644664
eq(base64mime.decode(''), b'')
46654665
eq(base64mime.decode('aGVsbG8='), b'hello')
4666+
eq(base64mime.decode(
4667+
'QW5tZWxkdW5nIE5ldHphbnNjaGx1c3MgU_xkcmluZzNwLmpwZw=='),
4668+
b'Anmeldung Netzanschluss S\xfcdring3p.jpg')
46664669

46674670
def test_encode(self):
46684671
eq = self.assertEqual

0 commit comments

Comments
 (0)