We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Support other keytypes with SSHKey Token
We would like to import other public key types like ecdsa into the SSHKey token type.

* [x] The UI and the /token/init API needs to allow this.
* [x] We also need to check, if the keytype is saved and returned correctly by GET /authitem


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `privacyidea/lib/tokens/sshkeytoken.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 #  privacyIDEA
4 #  Jul 18, 2014 Cornelius Kölbel
5 #  License:  AGPLv3
6 #  contact:  http://www.privacyidea.org
7 #
8 # This code is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
10 # License as published by the Free Software Foundation; either
11 # version 3 of the License, or any later version.
12 #
13 # This code is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU AFFERO GENERAL PUBLIC LICENSE for more details.
17 #
18 # You should have received a copy of the GNU Affero General Public
19 # License along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 __doc__="""The SSHKeyTokenClass provides a TokenClass that stores the public
22 SSH key and can give the public SSH key via the getotp function.
23 This can be used to manage SSH keys and retrieve the public ssh key
24 to import it to authorized keys files.
25 
26 The code is tested in tests/test_lib_tokens_ssh
27 """
28 
29 import logging
30 from privacyidea.lib import _
31 from privacyidea.api.lib.utils import getParam
32 from privacyidea.lib.log import log_with
33 from privacyidea.lib.tokenclass import TokenClass
34 from privacyidea.lib.policy import SCOPE, ACTION, GROUP
35 
36 log = logging.getLogger(__name__)
37 
38 
39 optional = True
40 required = False
41 
42 
43 ##TODO: We should save a fingerprint of the SSH Key in the encrypted OTP
44 # field, so that we can be sure, that the public ssh key was not changed in
45 # the database!
46 
47 
48 class SSHkeyTokenClass(TokenClass):
49     """
50     The SSHKeyTokenClass provides a TokenClass that stores the public
51     SSH key and can give the public SSH key via the getotp function.
52     This can be used to manage SSH keys and retrieve the public ssh key
53     to import it to authorized keys files.
54     """
55     mode = ['authenticate']
56     using_pin = False
57 
58     def __init__(self, db_token):
59         TokenClass.__init__(self, db_token)
60         self.set_type(u"sshkey")
61 
62     @staticmethod
63     def get_class_type():
64         return "sshkey"
65 
66     @staticmethod
67     def get_class_prefix():
68         return "SSHK"
69 
70     @staticmethod
71     @log_with(log)
72     def get_class_info(key=None, ret='all'):
73         """
74         returns a subtree of the token definition
75 
76         :param key: subsection identifier
77         :type key: string
78         :param ret: default return value, if nothing is found
79         :type ret: user defined
80         :return: subsection if key exists or user defined
81         :rtype: dictionary
82         """
83         res = {'type': 'sshkey',
84                'title': 'SSHkey Token',
85                'description': _('SSH Public Key: The public SSH key.'),
86                'config': {},
87                'user': ['enroll'],
88                # This tokentype is enrollable in the UI for...
89                'ui_enroll': ["admin", "user"],
90                'policy': {
91                    SCOPE.ENROLL: {
92                        ACTION.MAXTOKENUSER: {
93                            'type': 'int',
94                            'desc': _("The user may only have this maximum number of SSH keys assigned."),
95                            'group': GROUP.TOKEN
96                        },
97                        ACTION.MAXACTIVETOKENUSER: {
98                            'type': 'int',
99                            'desc': _(
100                                "The user may only have this maximum number of active SSH keys assigned."),
101                            'group': GROUP.TOKEN
102                        }
103                    }
104                },
105                }
106         if key:
107             ret = res.get(key, {})
108         else:
109             if ret == 'all':
110                 ret = res
111 
112         return ret
113 
114     def update(self, param):
115         """
116         The key holds the public ssh key and this is required
117         
118         The key probably is of the form "ssh-rsa BASE64 comment"
119         """
120         # We need to save the token, so that we can later add the tokeninfo
121         # Otherwise we might not have created the DB entry, yet and we would
122         # be missing the token.id
123         self.token.save()
124 
125         getParam(param, "sshkey", required)
126             
127         key_elem = param.get("sshkey").split(" ", 2)
128         if len(key_elem) != 3 or key_elem[0] != "ssh-rsa":
129             raise Exception("The key must consist of 'ssh-rsa BASE64 comment'")
130 
131         key_type = key_elem[0]
132         key = key_elem[1]
133         key_comment = key_elem[2]
134         
135         # convert key to hex
136         self.add_tokeninfo("ssh_key", key, value_type="password")
137         self.add_tokeninfo("ssh_type", key_type)
138         self.add_tokeninfo("ssh_comment", key_comment)
139 
140         # call the parents function
141         TokenClass.update(self, param)
142         
143     @log_with(log)
144     def get_sshkey(self):
145         """
146         returns the public SSH key
147         
148         :return: SSH pub key
149         :rtype: string
150         """
151         ti = self.get_tokeninfo()
152         key_type = ti.get("ssh_type")
153         key_comment = ti.get("ssh_comment")
154         # get the ssh key directly, otherwise it will not be decrypted
155         sshkey = self.get_tokeninfo("ssh_key")
156         return u"{0!s} {1!s} {2!s}".format(key_type, sshkey, key_comment)
157
```
--- 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()

```

diff --git a/privacyidea/lib/tokens/sshkeytoken.py b/privacyidea/lib/tokens/sshkeytoken.py
--- a/privacyidea/lib/tokens/sshkeytoken.py
+++ b/privacyidea/lib/tokens/sshkeytoken.py
@@ -125,8 +125,10 @@
         getParam(param, "sshkey", required)
             
         key_elem = param.get("sshkey").split(" ", 2)
-        if len(key_elem) != 3 or key_elem[0] != "ssh-rsa":
-            raise Exception("The key must consist of 'ssh-rsa BASE64 comment'")
+        if len(key_elem) != 3:
+            raise Exception("The key must consist of 'ssh-keytype BASE64 comment'")
+        if key_elem[0] not in ["ssh-rsa", "ssh-ed25519", "ecdsa-sha2-nistp256"]:
+            raise Exception("The keytype you specified is not supported.")
 
         key_type = key_elem[0]
         key = key_elem[1]

{"golden_diff": "diff --git a/privacyidea/lib/tokens/sshkeytoken.py b/privacyidea/lib/tokens/sshkeytoken.py\n--- a/privacyidea/lib/tokens/sshkeytoken.py\n+++ b/privacyidea/lib/tokens/sshkeytoken.py\n@@ -125,8 +125,10 @@\n         getParam(param, \"sshkey\", required)\n             \n         key_elem = param.get(\"sshkey\").split(\" \", 2)\n-        if len(key_elem) != 3 or key_elem[0] != \"ssh-rsa\":\n-            raise Exception(\"The key must consist of 'ssh-rsa BASE64 comment'\")\n+        if len(key_elem) != 3:\n+            raise Exception(\"The key must consist of 'ssh-keytype BASE64 comment'\")\n+        if key_elem[0] not in [\"ssh-rsa\", \"ssh-ed25519\", \"ecdsa-sha2-nistp256\"]:\n+            raise Exception(\"The keytype you specified is not supported.\")\n \n         key_type = key_elem[0]\n         key = key_elem[1]\n", "issue": "Support other keytypes with SSHKey Token\nWe would like to import other public key types like ecdsa into the SSHKey token type.\r\n\r\n* [x] The UI and the /token/init API needs to allow this.\r\n* [x] We also need to check, if the keytype is saved and returned correctly by GET /authitem\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n#  privacyIDEA\n#  Jul 18, 2014 Cornelius K\u00f6lbel\n#  License:  AGPLv3\n#  contact:  http://www.privacyidea.org\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\n__doc__=\"\"\"The SSHKeyTokenClass provides a TokenClass that stores the public\nSSH key and can give the public SSH key via the getotp function.\nThis can be used to manage SSH keys and retrieve the public ssh key\nto import it to authorized keys files.\n\nThe code is tested in tests/test_lib_tokens_ssh\n\"\"\"\n\nimport logging\nfrom privacyidea.lib import _\nfrom privacyidea.api.lib.utils import getParam\nfrom privacyidea.lib.log import log_with\nfrom privacyidea.lib.tokenclass import TokenClass\nfrom privacyidea.lib.policy import SCOPE, ACTION, GROUP\n\nlog = logging.getLogger(__name__)\n\n\noptional = True\nrequired = False\n\n\n##TODO: We should save a fingerprint of the SSH Key in the encrypted OTP\n# field, so that we can be sure, that the public ssh key was not changed in\n# the database!\n\n\nclass SSHkeyTokenClass(TokenClass):\n    \"\"\"\n    The SSHKeyTokenClass provides a TokenClass that stores the public\n    SSH key and can give the public SSH key via the getotp function.\n    This can be used to manage SSH keys and retrieve the public ssh key\n    to import it to authorized keys files.\n    \"\"\"\n    mode = ['authenticate']\n    using_pin = False\n\n    def __init__(self, db_token):\n        TokenClass.__init__(self, db_token)\n        self.set_type(u\"sshkey\")\n\n    @staticmethod\n    def get_class_type():\n        return \"sshkey\"\n\n    @staticmethod\n    def get_class_prefix():\n        return \"SSHK\"\n\n    @staticmethod\n    @log_with(log)\n    def get_class_info(key=None, ret='all'):\n        \"\"\"\n        returns a subtree of the token definition\n\n        :param key: subsection identifier\n        :type key: string\n        :param ret: default return value, if nothing is found\n        :type ret: user defined\n        :return: subsection if key exists or user defined\n        :rtype: dictionary\n        \"\"\"\n        res = {'type': 'sshkey',\n               'title': 'SSHkey Token',\n               'description': _('SSH Public Key: The public SSH key.'),\n               'config': {},\n               'user': ['enroll'],\n               # This tokentype is enrollable in the UI for...\n               'ui_enroll': [\"admin\", \"user\"],\n               'policy': {\n                   SCOPE.ENROLL: {\n                       ACTION.MAXTOKENUSER: {\n                           'type': 'int',\n                           'desc': _(\"The user may only have this maximum number of SSH keys assigned.\"),\n                           'group': GROUP.TOKEN\n                       },\n                       ACTION.MAXACTIVETOKENUSER: {\n                           'type': 'int',\n                           'desc': _(\n                               \"The user may only have this maximum number of active SSH keys assigned.\"),\n                           'group': GROUP.TOKEN\n                       }\n                   }\n               },\n               }\n        if key:\n            ret = res.get(key, {})\n        else:\n            if ret == 'all':\n                ret = res\n\n        return ret\n\n    def update(self, param):\n        \"\"\"\n        The key holds the public ssh key and this is required\n        \n        The key probably is of the form \"ssh-rsa BASE64 comment\"\n        \"\"\"\n        # We need to save the token, so that we can later add the tokeninfo\n        # Otherwise we might not have created the DB entry, yet and we would\n        # be missing the token.id\n        self.token.save()\n\n        getParam(param, \"sshkey\", required)\n            \n        key_elem = param.get(\"sshkey\").split(\" \", 2)\n        if len(key_elem) != 3 or key_elem[0] != \"ssh-rsa\":\n            raise Exception(\"The key must consist of 'ssh-rsa BASE64 comment'\")\n\n        key_type = key_elem[0]\n        key = key_elem[1]\n        key_comment = key_elem[2]\n        \n        # convert key to hex\n        self.add_tokeninfo(\"ssh_key\", key, value_type=\"password\")\n        self.add_tokeninfo(\"ssh_type\", key_type)\n        self.add_tokeninfo(\"ssh_comment\", key_comment)\n\n        # call the parents function\n        TokenClass.update(self, param)\n        \n    @log_with(log)\n    def get_sshkey(self):\n        \"\"\"\n        returns the public SSH key\n        \n        :return: SSH pub key\n        :rtype: string\n        \"\"\"\n        ti = self.get_tokeninfo()\n        key_type = ti.get(\"ssh_type\")\n        key_comment = ti.get(\"ssh_comment\")\n        # get the ssh key directly, otherwise it will not be decrypted\n        sshkey = self.get_tokeninfo(\"ssh_key\")\n        return u\"{0!s} {1!s} {2!s}\".format(key_type, sshkey, key_comment)\n", "path": "privacyidea/lib/tokens/sshkeytoken.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n#  privacyIDEA\n#  Jul 18, 2014 Cornelius K\u00f6lbel\n#  License:  AGPLv3\n#  contact:  http://www.privacyidea.org\n#\n# This code is free software; you can redistribute it and/or\n# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE\n# License as published by the Free Software Foundation; either\n# version 3 of the License, or any later version.\n#\n# This code is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU AFFERO GENERAL PUBLIC LICENSE for more details.\n#\n# You should have received a copy of the GNU Affero General Public\n# License along with this program.  If not, see <http://www.gnu.org/licenses/>.\n#\n__doc__=\"\"\"The SSHKeyTokenClass provides a TokenClass that stores the public\nSSH key and can give the public SSH key via the getotp function.\nThis can be used to manage SSH keys and retrieve the public ssh key\nto import it to authorized keys files.\n\nThe code is tested in tests/test_lib_tokens_ssh\n\"\"\"\n\nimport logging\nfrom privacyidea.lib import _\nfrom privacyidea.api.lib.utils import getParam\nfrom privacyidea.lib.log import log_with\nfrom privacyidea.lib.tokenclass import TokenClass\nfrom privacyidea.lib.policy import SCOPE, ACTION, GROUP\n\nlog = logging.getLogger(__name__)\n\n\noptional = True\nrequired = False\n\n\n##TODO: We should save a fingerprint of the SSH Key in the encrypted OTP\n# field, so that we can be sure, that the public ssh key was not changed in\n# the database!\n\n\nclass SSHkeyTokenClass(TokenClass):\n    \"\"\"\n    The SSHKeyTokenClass provides a TokenClass that stores the public\n    SSH key and can give the public SSH key via the getotp function.\n    This can be used to manage SSH keys and retrieve the public ssh key\n    to import it to authorized keys files.\n    \"\"\"\n    mode = ['authenticate']\n    using_pin = False\n\n    def __init__(self, db_token):\n        TokenClass.__init__(self, db_token)\n        self.set_type(u\"sshkey\")\n\n    @staticmethod\n    def get_class_type():\n        return \"sshkey\"\n\n    @staticmethod\n    def get_class_prefix():\n        return \"SSHK\"\n\n    @staticmethod\n    @log_with(log)\n    def get_class_info(key=None, ret='all'):\n        \"\"\"\n        returns a subtree of the token definition\n\n        :param key: subsection identifier\n        :type key: string\n        :param ret: default return value, if nothing is found\n        :type ret: user defined\n        :return: subsection if key exists or user defined\n        :rtype: dictionary\n        \"\"\"\n        res = {'type': 'sshkey',\n               'title': 'SSHkey Token',\n               'description': _('SSH Public Key: The public SSH key.'),\n               'config': {},\n               'user': ['enroll'],\n               # This tokentype is enrollable in the UI for...\n               'ui_enroll': [\"admin\", \"user\"],\n               'policy': {\n                   SCOPE.ENROLL: {\n                       ACTION.MAXTOKENUSER: {\n                           'type': 'int',\n                           'desc': _(\"The user may only have this maximum number of SSH keys assigned.\"),\n                           'group': GROUP.TOKEN\n                       },\n                       ACTION.MAXACTIVETOKENUSER: {\n                           'type': 'int',\n                           'desc': _(\n                               \"The user may only have this maximum number of active SSH keys assigned.\"),\n                           'group': GROUP.TOKEN\n                       }\n                   }\n               },\n               }\n        if key:\n            ret = res.get(key, {})\n        else:\n            if ret == 'all':\n                ret = res\n\n        return ret\n\n    def update(self, param):\n        \"\"\"\n        The key holds the public ssh key and this is required\n        \n        The key probably is of the form \"ssh-rsa BASE64 comment\"\n        \"\"\"\n        # We need to save the token, so that we can later add the tokeninfo\n        # Otherwise we might not have created the DB entry, yet and we would\n        # be missing the token.id\n        self.token.save()\n\n        getParam(param, \"sshkey\", required)\n            \n        key_elem = param.get(\"sshkey\").split(\" \", 2)\n        if len(key_elem) != 3:\n            raise Exception(\"The key must consist of 'ssh-keytype BASE64 comment'\")\n        if key_elem[0] not in [\"ssh-rsa\", \"ssh-ed25519\", \"ecdsa-sha2-nistp256\"]:\n            raise Exception(\"The keytype you specified is not supported.\")\n\n        key_type = key_elem[0]\n        key = key_elem[1]\n        key_comment = key_elem[2]\n        \n        # convert key to hex\n        self.add_tokeninfo(\"ssh_key\", key, value_type=\"password\")\n        self.add_tokeninfo(\"ssh_type\", key_type)\n        self.add_tokeninfo(\"ssh_comment\", key_comment)\n\n        # call the parents function\n        TokenClass.update(self, param)\n        \n    @log_with(log)\n    def get_sshkey(self):\n        \"\"\"\n        returns the public SSH key\n        \n        :return: SSH pub key\n        :rtype: string\n        \"\"\"\n        ti = self.get_tokeninfo()\n        key_type = ti.get(\"ssh_type\")\n        key_comment = ti.get(\"ssh_comment\")\n        # get the ssh key directly, otherwise it will not be decrypted\n        sshkey = self.get_tokeninfo(\"ssh_key\")\n        return u\"{0!s} {1!s} {2!s}\".format(key_type, sshkey, key_comment)\n", "path": "privacyidea/lib/tokens/sshkeytoken.py"}]}