Repository: kjd/idna

Issue:
[Uncaught exception] UnicodeDecodeError when calling decode with arbitrary data
Hey,

I was doing some fuzzing and I found out that the `idna.decode()` method can raise a `UnicodeDecodeError` leading to a crash of the running program.

This could be problematic if users of the library are dealing with untrusted data since this issue will lead to a DoS. This should be detected and an `idna.IDNAError` should be triggered as detailed in the Readme [Exception](https://github.com/kjd/idna#exceptions) section.

# Reproduction

``` python
import idna

idna.decode(b'\x8d\xd2')
```

# Traceback

``` sh
python3 replay_crash.py
Traceback (most recent call last):
  File "replay_crash.py", line 3, in <module>
    idna.decode(b'\x8d\xd2')
  File "/home/scop/.local/lib/python3.8/site-packages/idna/core.py", line 387, in decode
    s = s.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0x8d in position 0: ordinal not in range(128)
```

Happy to help if you have any questions ;)

Discussion:

Patch:
diff --git a/idna/core.py b/idna/core.py
index d605129..871ebd3 100644
--- a/idna/core.py
+++ b/idna/core.py
@@ -383,8 +383,11 @@ def encode(s, strict=False, uts46=False, std3_rules=False, transitional=False):
 
 def decode(s, strict=False, uts46=False, std3_rules=False):
     # type: (Union[str, bytes, bytearray], bool, bool, bool) -> str
-    if isinstance(s, (bytes, bytearray)):
-        s = s.decode('ascii')
+    try:
+        if isinstance(s, (bytes, bytearray)):
+            s = s.decode('ascii')
+    except UnicodeDecodeError:
+        raise IDNAError('Invalid ASCII in A-label')
     if uts46:
         s = uts46_remap(s, std3_rules, False)
     trailing_dot = False


Test patch:
diff --git a/tests/test_idna.py b/tests/test_idna.py
index 9e1d2d9..7ac6057 100755
--- a/tests/test_idna.py
+++ b/tests/test_idna.py
@@ -259,6 +259,7 @@ class IDNATests(unittest.TestCase):
         self.assertRaises(idna.IDNAError, idna.decode, 'XN---------90GGLBAGAAC.AA')
         self.assertRaises(idna.IDNAError, idna.decode, 'xn---------90gglbagaac.aa')
         self.assertRaises(idna.IDNAError, idna.decode, 'xn--')
+        self.assertRaises(idna.IDNAError, idna.decode, b'\x8d\xd2')
 
 if __name__ == '__main__':
     unittest.main()