prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Add support for loading DSA OpenSSH public keys
  Should be straightforward to add support to the existing code.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/cryptography/hazmat/primitives/serialization.py`
  Content:
  ```
  1 # This file is dual licensed under the terms of the Apache License, Version
  2 # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3 # for complete details.
  4 
  5 from __future__ import absolute_import, division, print_function
  6 
  7 import base64
  8 import struct
  9 import warnings
  10 
  11 from cryptography import utils
  12 from cryptography.exceptions import UnsupportedAlgorithm
  13 from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
  14 
  15 
  16 def load_pem_traditional_openssl_private_key(data, password, backend):
  17     warnings.warn(
  18         "load_pem_traditional_openssl_private_key is deprecated and will be "
  19         "removed in a future version, use load_pem_private_key instead.",
  20         utils.DeprecatedIn06,
  21         stacklevel=2
  22     )
  23 
  24     return backend.load_traditional_openssl_pem_private_key(
  25         data, password
  26     )
  27 
  28 
  29 def load_pem_pkcs8_private_key(data, password, backend):
  30     warnings.warn(
  31         "load_pem_pkcs8_private_key is deprecated and will be removed in a "
  32         "future version, use load_pem_private_key instead.",
  33         utils.DeprecatedIn06,
  34         stacklevel=2
  35     )
  36 
  37     return backend.load_pkcs8_pem_private_key(data, password)
  38 
  39 
  40 def load_pem_private_key(data, password, backend):
  41     return backend.load_pem_private_key(data, password)
  42 
  43 
  44 def load_pem_public_key(data, backend):
  45     return backend.load_pem_public_key(data)
  46 
  47 
  48 def load_ssh_public_key(data, backend):
  49     key_parts = data.split(b' ')
  50 
  51     if len(key_parts) != 2 and len(key_parts) != 3:
  52         raise ValueError(
  53             'Key is not in the proper format or contains extra data.')
  54 
  55     key_type = key_parts[0]
  56     key_body = key_parts[1]
  57 
  58     if not key_type.startswith(b'ssh-'):
  59         raise ValueError('SSH-formatted keys must begin with \'ssh-\'.')
  60 
  61     if not key_type.startswith(b'ssh-rsa'):
  62         raise UnsupportedAlgorithm('Only RSA keys are currently supported.')
  63 
  64     return _load_ssh_rsa_public_key(key_body, backend)
  65 
  66 
  67 def _load_ssh_rsa_public_key(key_body, backend):
  68     data = base64.b64decode(key_body)
  69 
  70     key_type, rest = _read_next_string(data)
  71     e, rest = _read_next_mpint(rest)
  72     n, rest = _read_next_mpint(rest)
  73 
  74     if key_type != b'ssh-rsa':
  75         raise ValueError(
  76             'Key header and key body contain different key type values.')
  77 
  78     if rest:
  79         raise ValueError('Key body contains extra bytes.')
  80 
  81     return backend.load_rsa_public_numbers(RSAPublicNumbers(e, n))
  82 
  83 
  84 def _read_next_string(data):
  85     """Retrieves the next RFC 4251 string value from the data."""
  86     str_len, = struct.unpack('>I', data[:4])
  87     return data[4:4 + str_len], data[4 + str_len:]
  88 
  89 
  90 def _read_next_mpint(data):
  91     """
  92     Reads the next mpint from the data.
  93 
  94     Currently, all mpints are interpreted as unsigned.
  95     """
  96     mpint_data, rest = _read_next_string(data)
  97 
  98     return _int_from_bytes(mpint_data, byteorder='big', signed=False), rest
  99 
  100 
  101 if hasattr(int, "from_bytes"):
  102     _int_from_bytes = int.from_bytes
  103 else:
  104     def _int_from_bytes(data, byteorder, signed=False):
  105         assert byteorder == 'big'
  106         assert not signed
  107 
  108         if len(data) % 4 != 0:
  109             data = (b'\x00' * (4 - (len(data) % 4))) + data
  110 
  111         result = 0
  112 
  113         while len(data) > 0:
  114             digit, = struct.unpack('>I', data[:4])
  115             result = (result << 32) + digit
  116             data = data[4:]
  117 
  118         return result
  119
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py
  --- a/src/cryptography/hazmat/primitives/serialization.py
  +++ b/src/cryptography/hazmat/primitives/serialization.py
  @@ -10,6 +10,9 @@
   
   from cryptography import utils
   from cryptography.exceptions import UnsupportedAlgorithm
  +from cryptography.hazmat.primitives.asymmetric.dsa import (
  +    DSAParameterNumbers, DSAPublicNumbers
  +)
   from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
   
   
  @@ -55,19 +58,23 @@
       key_type = key_parts[0]
       key_body = key_parts[1]
   
  -    if not key_type.startswith(b'ssh-'):
  -        raise ValueError('SSH-formatted keys must begin with \'ssh-\'.')
  +    try:
  +        decoded_data = base64.b64decode(key_body)
  +    except TypeError:
  +        raise ValueError('Key is not in the proper format.')
   
  -    if not key_type.startswith(b'ssh-rsa'):
  -        raise UnsupportedAlgorithm('Only RSA keys are currently supported.')
  +    if key_type == b'ssh-rsa':
  +        return _load_ssh_rsa_public_key(decoded_data, backend)
  +    elif key_type == b'ssh-dss':
  +        return _load_ssh_dss_public_key(decoded_data, backend)
  +    else:
  +        raise UnsupportedAlgorithm(
  +            'Only RSA and DSA keys are currently supported.'
  +        )
   
  -    return _load_ssh_rsa_public_key(key_body, backend)
   
  -
  -def _load_ssh_rsa_public_key(key_body, backend):
  -    data = base64.b64decode(key_body)
  -
  -    key_type, rest = _read_next_string(data)
  +def _load_ssh_rsa_public_key(decoded_data, backend):
  +    key_type, rest = _read_next_string(decoded_data)
       e, rest = _read_next_mpint(rest)
       n, rest = _read_next_mpint(rest)
   
  @@ -81,6 +88,26 @@
       return backend.load_rsa_public_numbers(RSAPublicNumbers(e, n))
   
   
  +def _load_ssh_dss_public_key(decoded_data, backend):
  +    key_type, rest = _read_next_string(decoded_data)
  +    p, rest = _read_next_mpint(rest)
  +    q, rest = _read_next_mpint(rest)
  +    g, rest = _read_next_mpint(rest)
  +    y, rest = _read_next_mpint(rest)
  +
  +    if key_type != b'ssh-dss':
  +        raise ValueError(
  +            'Key header and key body contain different key type values.')
  +
  +    if rest:
  +        raise ValueError('Key body contains extra bytes.')
  +
  +    parameter_numbers = DSAParameterNumbers(p, q, g)
  +    public_numbers = DSAPublicNumbers(y, parameter_numbers)
  +
  +    return backend.load_dsa_public_numbers(public_numbers)
  +
  +
   def _read_next_string(data):
       """Retrieves the next RFC 4251 string value from the data."""
       str_len, = struct.unpack('>I', data[:4])
  
verification_info: {"golden_diff": "diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py\n--- a/src/cryptography/hazmat/primitives/serialization.py\n+++ b/src/cryptography/hazmat/primitives/serialization.py\n@@ -10,6 +10,9 @@\n \n from cryptography import utils\n from cryptography.exceptions import UnsupportedAlgorithm\n+from cryptography.hazmat.primitives.asymmetric.dsa import (\n+    DSAParameterNumbers, DSAPublicNumbers\n+)\n from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers\n \n \n@@ -55,19 +58,23 @@\n     key_type = key_parts[0]\n     key_body = key_parts[1]\n \n-    if not key_type.startswith(b'ssh-'):\n-        raise ValueError('SSH-formatted keys must begin with \\'ssh-\\'.')\n+    try:\n+        decoded_data = base64.b64decode(key_body)\n+    except TypeError:\n+        raise ValueError('Key is not in the proper format.')\n \n-    if not key_type.startswith(b'ssh-rsa'):\n-        raise UnsupportedAlgorithm('Only RSA keys are currently supported.')\n+    if key_type == b'ssh-rsa':\n+        return _load_ssh_rsa_public_key(decoded_data, backend)\n+    elif key_type == b'ssh-dss':\n+        return _load_ssh_dss_public_key(decoded_data, backend)\n+    else:\n+        raise UnsupportedAlgorithm(\n+            'Only RSA and DSA keys are currently supported.'\n+        )\n \n-    return _load_ssh_rsa_public_key(key_body, backend)\n \n-\n-def _load_ssh_rsa_public_key(key_body, backend):\n-    data = base64.b64decode(key_body)\n-\n-    key_type, rest = _read_next_string(data)\n+def _load_ssh_rsa_public_key(decoded_data, backend):\n+    key_type, rest = _read_next_string(decoded_data)\n     e, rest = _read_next_mpint(rest)\n     n, rest = _read_next_mpint(rest)\n \n@@ -81,6 +88,26 @@\n     return backend.load_rsa_public_numbers(RSAPublicNumbers(e, n))\n \n \n+def _load_ssh_dss_public_key(decoded_data, backend):\n+    key_type, rest = _read_next_string(decoded_data)\n+    p, rest = _read_next_mpint(rest)\n+    q, rest = _read_next_mpint(rest)\n+    g, rest = _read_next_mpint(rest)\n+    y, rest = _read_next_mpint(rest)\n+\n+    if key_type != b'ssh-dss':\n+        raise ValueError(\n+            'Key header and key body contain different key type values.')\n+\n+    if rest:\n+        raise ValueError('Key body contains extra bytes.')\n+\n+    parameter_numbers = DSAParameterNumbers(p, q, g)\n+    public_numbers = DSAPublicNumbers(y, parameter_numbers)\n+\n+    return backend.load_dsa_public_numbers(public_numbers)\n+\n+\n def _read_next_string(data):\n     \"\"\"Retrieves the next RFC 4251 string value from the data.\"\"\"\n     str_len, = struct.unpack('>I', data[:4])\n", "issue": "Add support for loading DSA OpenSSH public keys\nShould be straightforward to add support to the existing code.\n\n", "before_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport base64\nimport struct\nimport warnings\n\nfrom cryptography import utils\nfrom cryptography.exceptions import UnsupportedAlgorithm\nfrom cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers\n\n\ndef load_pem_traditional_openssl_private_key(data, password, backend):\n    warnings.warn(\n        \"load_pem_traditional_openssl_private_key is deprecated and will be \"\n        \"removed in a future version, use load_pem_private_key instead.\",\n        utils.DeprecatedIn06,\n        stacklevel=2\n    )\n\n    return backend.load_traditional_openssl_pem_private_key(\n        data, password\n    )\n\n\ndef load_pem_pkcs8_private_key(data, password, backend):\n    warnings.warn(\n        \"load_pem_pkcs8_private_key is deprecated and will be removed in a \"\n        \"future version, use load_pem_private_key instead.\",\n        utils.DeprecatedIn06,\n        stacklevel=2\n    )\n\n    return backend.load_pkcs8_pem_private_key(data, password)\n\n\ndef load_pem_private_key(data, password, backend):\n    return backend.load_pem_private_key(data, password)\n\n\ndef load_pem_public_key(data, backend):\n    return backend.load_pem_public_key(data)\n\n\ndef load_ssh_public_key(data, backend):\n    key_parts = data.split(b' ')\n\n    if len(key_parts) != 2 and len(key_parts) != 3:\n        raise ValueError(\n            'Key is not in the proper format or contains extra data.')\n\n    key_type = key_parts[0]\n    key_body = key_parts[1]\n\n    if not key_type.startswith(b'ssh-'):\n        raise ValueError('SSH-formatted keys must begin with \\'ssh-\\'.')\n\n    if not key_type.startswith(b'ssh-rsa'):\n        raise UnsupportedAlgorithm('Only RSA keys are currently supported.')\n\n    return _load_ssh_rsa_public_key(key_body, backend)\n\n\ndef _load_ssh_rsa_public_key(key_body, backend):\n    data = base64.b64decode(key_body)\n\n    key_type, rest = _read_next_string(data)\n    e, rest = _read_next_mpint(rest)\n    n, rest = _read_next_mpint(rest)\n\n    if key_type != b'ssh-rsa':\n        raise ValueError(\n            'Key header and key body contain different key type values.')\n\n    if rest:\n        raise ValueError('Key body contains extra bytes.')\n\n    return backend.load_rsa_public_numbers(RSAPublicNumbers(e, n))\n\n\ndef _read_next_string(data):\n    \"\"\"Retrieves the next RFC 4251 string value from the data.\"\"\"\n    str_len, = struct.unpack('>I', data[:4])\n    return data[4:4 + str_len], data[4 + str_len:]\n\n\ndef _read_next_mpint(data):\n    \"\"\"\n    Reads the next mpint from the data.\n\n    Currently, all mpints are interpreted as unsigned.\n    \"\"\"\n    mpint_data, rest = _read_next_string(data)\n\n    return _int_from_bytes(mpint_data, byteorder='big', signed=False), rest\n\n\nif hasattr(int, \"from_bytes\"):\n    _int_from_bytes = int.from_bytes\nelse:\n    def _int_from_bytes(data, byteorder, signed=False):\n        assert byteorder == 'big'\n        assert not signed\n\n        if len(data) % 4 != 0:\n            data = (b'\\x00' * (4 - (len(data) % 4))) + data\n\n        result = 0\n\n        while len(data) > 0:\n            digit, = struct.unpack('>I', data[:4])\n            result = (result << 32) + digit\n            data = data[4:]\n\n        return result\n", "path": "src/cryptography/hazmat/primitives/serialization.py"}], "after_files": [{"content": "# This file is dual licensed under the terms of the Apache License, Version\n# 2.0, and the BSD License. See the LICENSE file in the root of this repository\n# for complete details.\n\nfrom __future__ import absolute_import, division, print_function\n\nimport base64\nimport struct\nimport warnings\n\nfrom cryptography import utils\nfrom cryptography.exceptions import UnsupportedAlgorithm\nfrom cryptography.hazmat.primitives.asymmetric.dsa import (\n    DSAParameterNumbers, DSAPublicNumbers\n)\nfrom cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers\n\n\ndef load_pem_traditional_openssl_private_key(data, password, backend):\n    warnings.warn(\n        \"load_pem_traditional_openssl_private_key is deprecated and will be \"\n        \"removed in a future version, use load_pem_private_key instead.\",\n        utils.DeprecatedIn06,\n        stacklevel=2\n    )\n\n    return backend.load_traditional_openssl_pem_private_key(\n        data, password\n    )\n\n\ndef load_pem_pkcs8_private_key(data, password, backend):\n    warnings.warn(\n        \"load_pem_pkcs8_private_key is deprecated and will be removed in a \"\n        \"future version, use load_pem_private_key instead.\",\n        utils.DeprecatedIn06,\n        stacklevel=2\n    )\n\n    return backend.load_pkcs8_pem_private_key(data, password)\n\n\ndef load_pem_private_key(data, password, backend):\n    return backend.load_pem_private_key(data, password)\n\n\ndef load_pem_public_key(data, backend):\n    return backend.load_pem_public_key(data)\n\n\ndef load_ssh_public_key(data, backend):\n    key_parts = data.split(b' ')\n\n    if len(key_parts) != 2 and len(key_parts) != 3:\n        raise ValueError(\n            'Key is not in the proper format or contains extra data.')\n\n    key_type = key_parts[0]\n    key_body = key_parts[1]\n\n    try:\n        decoded_data = base64.b64decode(key_body)\n    except TypeError:\n        raise ValueError('Key is not in the proper format.')\n\n    if key_type == b'ssh-rsa':\n        return _load_ssh_rsa_public_key(decoded_data, backend)\n    elif key_type == b'ssh-dss':\n        return _load_ssh_dss_public_key(decoded_data, backend)\n    else:\n        raise UnsupportedAlgorithm(\n            'Only RSA and DSA keys are currently supported.'\n        )\n\n\ndef _load_ssh_rsa_public_key(decoded_data, backend):\n    key_type, rest = _read_next_string(decoded_data)\n    e, rest = _read_next_mpint(rest)\n    n, rest = _read_next_mpint(rest)\n\n    if key_type != b'ssh-rsa':\n        raise ValueError(\n            'Key header and key body contain different key type values.')\n\n    if rest:\n        raise ValueError('Key body contains extra bytes.')\n\n    return backend.load_rsa_public_numbers(RSAPublicNumbers(e, n))\n\n\ndef _load_ssh_dss_public_key(decoded_data, backend):\n    key_type, rest = _read_next_string(decoded_data)\n    p, rest = _read_next_mpint(rest)\n    q, rest = _read_next_mpint(rest)\n    g, rest = _read_next_mpint(rest)\n    y, rest = _read_next_mpint(rest)\n\n    if key_type != b'ssh-dss':\n        raise ValueError(\n            'Key header and key body contain different key type values.')\n\n    if rest:\n        raise ValueError('Key body contains extra bytes.')\n\n    parameter_numbers = DSAParameterNumbers(p, q, g)\n    public_numbers = DSAPublicNumbers(y, parameter_numbers)\n\n    return backend.load_dsa_public_numbers(public_numbers)\n\n\ndef _read_next_string(data):\n    \"\"\"Retrieves the next RFC 4251 string value from the data.\"\"\"\n    str_len, = struct.unpack('>I', data[:4])\n    return data[4:4 + str_len], data[4 + str_len:]\n\n\ndef _read_next_mpint(data):\n    \"\"\"\n    Reads the next mpint from the data.\n\n    Currently, all mpints are interpreted as unsigned.\n    \"\"\"\n    mpint_data, rest = _read_next_string(data)\n\n    return _int_from_bytes(mpint_data, byteorder='big', signed=False), rest\n\n\nif hasattr(int, \"from_bytes\"):\n    _int_from_bytes = int.from_bytes\nelse:\n    def _int_from_bytes(data, byteorder, signed=False):\n        assert byteorder == 'big'\n        assert not signed\n\n        if len(data) % 4 != 0:\n            data = (b'\\x00' * (4 - (len(data) % 4))) + data\n\n        result = 0\n\n        while len(data) > 0:\n            digit, = struct.unpack('>I', data[:4])\n            result = (result << 32) + digit\n            data = data[4:]\n\n        return result\n", "path": "src/cryptography/hazmat/primitives/serialization.py"}]}