Skip to content

Commit ad8b56e

Browse files
author
Pan
committed
Added keys and key types implementation.
Added exceptions, updated definitions.
1 parent 2db6afb commit ad8b56e

File tree

6 files changed

+403
-9
lines changed

6 files changed

+403
-9
lines changed

ssh/c_ssh.pxd

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -392,15 +392,15 @@ cdef extern from "libssh/libssh.h" nogil:
392392
char **value)
393393
int ssh_options_get_port(ssh_session session, unsigned int * port_target)
394394
int ssh_pcap_file_close(ssh_pcap_file pcap)
395-
ssh_pcap_file_free(ssh_pcap_file pcap)
395+
void ssh_pcap_file_free(ssh_pcap_file pcap)
396396
ssh_pcap_file ssh_pcap_file_new()
397397
int ssh_pcap_file_open(ssh_pcap_file pcap, const char *filename)
398398

399399
ctypedef int (*ssh_auth_callback) (const char *prompt, char *buf, size_t len,
400400
int echo, int verify, void *userdata)
401401

402402
ssh_key ssh_key_new()
403-
ssh_key_free (ssh_key key)
403+
void ssh_key_free (ssh_key key)
404404
ssh_keytypes_e ssh_key_type(const ssh_key key)
405405
const char *ssh_key_type_to_char(ssh_keytypes_e type)
406406
ssh_keytypes_e ssh_key_type_from_name(const char *name)
@@ -452,14 +452,14 @@ cdef extern from "libssh/libssh.h" nogil:
452452

453453
const char *ssh_pki_key_ecdsa_name(const ssh_key key)
454454

455-
ssh_print_hexa(const char *descr, const unsigned char *what, size_t len)
455+
void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len)
456456
int ssh_send_ignore (ssh_session session, const char *data)
457457
int ssh_send_debug (ssh_session session, const char *message, int always_display)
458-
ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds)
458+
void ssh_gssapi_set_creds(ssh_session session, const ssh_gssapi_creds creds)
459459
int ssh_scp_accept_request(ssh_scp scp)
460460
int ssh_scp_close(ssh_scp scp)
461461
int ssh_scp_deny_request(ssh_scp scp, const char *reason)
462-
ssh_scp_free(ssh_scp scp)
462+
void ssh_scp_free(ssh_scp scp)
463463
int ssh_scp_init(ssh_scp scp)
464464
int ssh_scp_leave_directory(ssh_scp scp)
465465
ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location)
@@ -522,11 +522,11 @@ cdef extern from "libssh/libssh.h" nogil:
522522
int ssh_write_knownhost(ssh_session session)
523523
char *ssh_dump_knownhost(ssh_session session)
524524

525-
ssh_string_burn(ssh_string str)
525+
void ssh_string_burn(ssh_string str)
526526
ssh_string ssh_string_copy(ssh_string str)
527527
void *ssh_string_data(ssh_string str)
528528
int ssh_string_fill(ssh_string str, const void *data, size_t len)
529-
ssh_string_free(ssh_string str)
529+
void ssh_string_free(ssh_string str)
530530
ssh_string ssh_string_from_char(const char *what)
531531
size_t ssh_string_len(ssh_string str)
532532
ssh_string ssh_string_new(size_t size)
@@ -548,7 +548,7 @@ cdef extern from "libssh/libssh.h" nogil:
548548
int ssh_event_remove_fd(ssh_event event, socket_t fd)
549549
int ssh_event_remove_session(ssh_event event, ssh_session session)
550550
int ssh_event_remove_connector(ssh_event event, ssh_connector connector)
551-
ssh_event_free(ssh_event event)
551+
void ssh_event_free(ssh_event event)
552552
const char* ssh_get_clientbanner(ssh_session session)
553553
const char* ssh_get_serverbanner(ssh_session session)
554554
const char* ssh_get_kex_algo(ssh_session session)
@@ -557,7 +557,7 @@ cdef extern from "libssh/libssh.h" nogil:
557557
const char* ssh_get_hmac_in(ssh_session session)
558558
const char* ssh_get_hmac_out(ssh_session session)
559559
ssh_buffer ssh_buffer_new()
560-
ssh_buffer_free(ssh_buffer buffer)
560+
void ssh_buffer_free(ssh_buffer buffer)
561561
int ssh_buffer_reinit(ssh_buffer buffer)
562562
int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len)
563563
uint32_t ssh_buffer_get_data(ssh_buffer buffer, void *data, uint32_t requestedlen)

ssh/exceptions.pyx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,16 @@ class AuthenticationDenied(BaseSSHError):
4141

4242
class AuthenticationError(BaseSSHError):
4343
"""Raised on fatal errors authenticating"""
44+
45+
46+
class KeyExportError(BaseSSHError):
47+
"""Raised on errors exporting key"""
48+
49+
50+
class KeyImportError(BaseSSHError):
51+
"""Raised on errors importing key"""
52+
53+
54+
class KeyGenerationError(BaseSSHError):
55+
"""Raised on errors generating key"""
56+

ssh/key.pxd

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# This file is part of ssh-python.
2+
# Copyright (C) 2018 Panos Kittenis
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, version 2.1.
7+
#
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
# Lesser General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU Lesser General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
16+
17+
cimport c_ssh
18+
19+
20+
cdef class SSHKey:
21+
cdef c_ssh.ssh_key _key
22+
23+
@staticmethod
24+
cdef SSHKey from_ptr(c_ssh.ssh_key key)

ssh/key.pyx

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# This file is part of ssh-python.
2+
# Copyright (C) 2018 Panos Kittenis
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, version 2.1.
7+
#
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
# Lesser General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU Lesser General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
16+
17+
from libc.string cimport const_char
18+
19+
from keytypes cimport from_keytype, KeyType
20+
from utils cimport to_str, to_bytes
21+
22+
from .exceptions import KeyExportError, KeyImportError, KeyGenerationError
23+
24+
cimport c_ssh
25+
26+
27+
cdef class SSHKey:
28+
29+
@staticmethod
30+
cdef SSHKey from_ptr(c_ssh.ssh_key key):
31+
cdef SSHKey _key = SSHKey.__new__(SSHKey)
32+
_key._key = key
33+
return _key
34+
35+
def __cinit__(self):
36+
self._key = c_ssh.ssh_key_new()
37+
if self._key is NULL:
38+
raise MemoryError
39+
40+
def __dealloc__(self):
41+
if self._key is not NULL:
42+
c_ssh.ssh_key_free(self._key)
43+
self._key = NULL
44+
45+
def is_private(self):
46+
cdef bint rc
47+
with nogil:
48+
rc = c_ssh.ssh_key_is_private(self._key)
49+
return bool(rc)
50+
51+
def is_public(self):
52+
cdef bint rc
53+
with nogil:
54+
rc = c_ssh.ssh_key_is_public(self._key)
55+
return bool(rc)
56+
57+
def __eq__(self, SSHKey other):
58+
cdef bint is_private
59+
cdef bint equal
60+
with nogil:
61+
is_private = c_ssh.ssh_key_is_private(self._key)
62+
equal = c_ssh.ssh_key_cmp(
63+
self._key, other._key, c_ssh.ssh_keycmp_e.SSH_KEY_CMP_PRIVATE) \
64+
if is_private else \
65+
c_ssh.ssh_key_cmp(
66+
self._key, other._key,
67+
c_ssh.ssh_keycmp_e.SSH_KEY_CMP_PUBLIC)
68+
return bool(equal)
69+
70+
def key_type(self):
71+
cdef c_ssh.ssh_keytypes_e _type
72+
with nogil:
73+
_type = c_ssh.ssh_key_type(self._key)
74+
return from_keytype(_type)
75+
76+
def ecdsa_name(self):
77+
cdef const_char *c_name
78+
cdef bytes b_name
79+
with nogil:
80+
c_name = c_ssh.ssh_pki_key_ecdsa_name(self._key)
81+
b_name = c_name
82+
return to_str(b_name)
83+
84+
def export_privkey_file(self, filepath, passphrase=None):
85+
cdef bytes b_passphrase
86+
cdef bytes b_filepath = to_bytes(filepath)
87+
cdef const_char *c_passphrase = NULL
88+
cdef const_char *c_filepath = b_filepath
89+
cdef int rc
90+
if passphrase is not None:
91+
b_passphrase = to_bytes(passphrase)
92+
c_passphrase = b_passphrase
93+
with nogil:
94+
rc = c_ssh.ssh_pki_export_privkey_file(
95+
self._key, c_passphrase, NULL, NULL, c_filepath)
96+
if rc != c_ssh.SSH_OK:
97+
raise KeyExportError(c_ssh.ssh_get_error(self._key))
98+
99+
def export_privkey_to_pubkey(self):
100+
cdef SSHKey pub_key
101+
cdef c_ssh.ssh_key _pub_key
102+
cdef int rc
103+
with nogil:
104+
rc = c_ssh.ssh_pki_export_privkey_to_pubkey(self._key, &_pub_key)
105+
if rc != c_ssh.SSH_OK:
106+
raise KeyExportError(c_ssh.ssh_get_error(self._key))
107+
pub_key = SSHKey.from_ptr(_pub_key)
108+
return pub_key
109+
110+
def export_pubkey_base64(self):
111+
cdef char *_key
112+
cdef int rc
113+
cdef bytes b_key
114+
cdef size_t key_len
115+
with nogil:
116+
rc = c_ssh.ssh_pki_export_pubkey_base64(self._key, &_key)
117+
if rc != c_ssh.SSH_OK:
118+
with gil:
119+
raise KeyExportError(c_ssh.ssh_get_error(self._key))
120+
b_key = _key
121+
c_ssh.ssh_string_free_char(_key)
122+
return b_key
123+
124+
125+
def generate(KeyType key_type, int bits):
126+
cdef SSHKey key
127+
cdef c_ssh.ssh_key _key
128+
cdef int rc
129+
with nogil:
130+
rc = c_ssh.ssh_pki_generate(key_type._type, bits, &_key)
131+
if rc != c_ssh.SSH_OK:
132+
raise KeyGenerationError(c_ssh.ssh_get_error(_key))
133+
key = SSHKey.from_ptr(_key)
134+
return key
135+
136+
137+
def import_privkey_base64(bytes b64_key, passphrase=None):
138+
cdef const_char *c_key = b64_key
139+
cdef bytes b_passphrase
140+
cdef const_char *c_passphrase = NULL
141+
cdef int rc
142+
cdef SSHKey key
143+
cdef c_ssh.ssh_key _key
144+
if passphrase is not None:
145+
b_passphrase = to_bytes(passphrase)
146+
c_passphrase = b_passphrase
147+
with nogil:
148+
rc = c_ssh.ssh_pki_import_privkey_base64(
149+
c_key, c_passphrase, NULL, NULL, &_key)
150+
if rc != c_ssh.SSH_OK:
151+
raise KeyImportError(c_ssh.ssh_get_error(_key))
152+
key = SSHKey.from_ptr(_key)
153+
return key
154+
155+
156+
def import_privkey_file(filepath, passphrase=None):
157+
cdef bytes b_passphrase
158+
cdef bytes b_filepath = to_bytes(filepath)
159+
cdef const_char *c_passphrase = NULL
160+
cdef const_char *c_filepath = b_filepath
161+
cdef int rc
162+
cdef SSHKey key
163+
cdef c_ssh.ssh_key _key
164+
if passphrase is not None:
165+
b_passphrase = to_bytes(passphrase)
166+
c_passphrase = b_passphrase
167+
with nogil:
168+
rc = c_ssh.ssh_pki_import_privkey_file(
169+
c_filepath, c_passphrase, NULL, NULL, &_key)
170+
if rc != c_ssh.SSH_OK:
171+
raise KeyExportError(c_ssh.ssh_get_error(_key))
172+
key = SSHKey.from_ptr(_key)
173+
return key
174+
175+
176+
def import_pubkey_base64(bytes b64_key, KeyType key_type):
177+
cdef const_char *c_key = b64_key
178+
cdef int rc
179+
cdef SSHKey key
180+
cdef c_ssh.ssh_key _key
181+
with nogil:
182+
rc = c_ssh.ssh_pki_import_pubkey_base64(
183+
c_key, key_type._type, &_key)
184+
if rc != c_ssh.SSH_OK:
185+
raise KeyImportError(c_ssh.ssh_get_error(_key))
186+
key = SSHKey.from_ptr(_key)
187+
return key
188+
189+
190+
def import_pubkey_file(filepath):
191+
cdef bytes b_filepath = to_bytes(filepath)
192+
cdef const_char *c_filepath = b_filepath
193+
cdef int rc
194+
cdef SSHKey key
195+
cdef c_ssh.ssh_key _key
196+
with nogil:
197+
rc = c_ssh.ssh_pki_import_pubkey_file(
198+
c_filepath, &_key)
199+
if rc != c_ssh.SSH_OK:
200+
raise KeyExportError(c_ssh.ssh_get_error(_key))
201+
key = SSHKey.from_ptr(_key)
202+
return key

ssh/keytypes.pxd

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# This file is part of ssh-python.
2+
# Copyright (C) 2018 Panos Kittenis
3+
#
4+
# This library is free software; you can redistribute it and/or
5+
# modify it under the terms of the GNU Lesser General Public
6+
# License as published by the Free Software Foundation, version 2.1.
7+
#
8+
# This library is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+
# Lesser General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU Lesser General Public
14+
# License along with this library; if not, write to the Free Software
15+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
16+
17+
from c_ssh cimport ssh_keytypes_e
18+
19+
20+
cdef class KeyType:
21+
cdef ssh_keytypes_e _type
22+
23+
24+
cdef class DSSKey(KeyType):
25+
pass
26+
27+
28+
cdef class RSAKey(KeyType):
29+
pass
30+
31+
32+
cdef class RSA1Key(KeyType):
33+
pass
34+
35+
36+
cdef class ECDSAKey(KeyType):
37+
pass
38+
39+
40+
cdef class DSSCert01Key(KeyType):
41+
pass
42+
43+
44+
cdef class RSACert01Key(KeyType):
45+
pass
46+
47+
48+
cdef KeyType from_keytype(ssh_keytypes_e _type)

0 commit comments

Comments
 (0)