diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index 7357129b..ac73bc02 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -433,6 +433,11 @@ LIBSSH_API int ssh_key_import_private(ssh_session session, const char *filename, const char *passphrase, ssh_key *pkey); +LIBSSH_API int ssh_pki_import_pubkey_base64(ssh_session session, + const char *b64_key, + enum ssh_keytypes_e type, + ssh_key *pkey); + LIBSSH_API int ssh_userauth_pki_pubkey(ssh_session session, const char *username, ssh_string publickey, ssh_key privatekey); LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len); diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 615b7c0f..49f8a5eb 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -62,6 +62,14 @@ ssh_key pki_private_key_from_base64(ssh_session session, const char *b64_key, const char *passphrase); ssh_key pki_publickey_from_privatekey(ssh_key privkey); +int pki_pubkey_build_dss(ssh_key key, + ssh_string p, + ssh_string q, + ssh_string g, + ssh_string pubkey); +int pki_pubkey_build_rsa(ssh_key key, + ssh_string e, + ssh_string n); struct signature_struct *pki_do_sign(ssh_key privatekey, const unsigned char *hash); diff --git a/src/pki.c b/src/pki.c index e53659b9..73e2edde 100644 --- a/src/pki.c +++ b/src/pki.c @@ -345,6 +345,133 @@ int ssh_pki_import_privkey_base64(ssh_session session, return SSH_OK; } +int ssh_pki_import_pubkey_base64(ssh_session session, + const char *b64_key, + enum ssh_keytypes_e type, + ssh_key *pkey) { + ssh_buffer buffer; + ssh_key key; + int rc; + + key = ssh_key_new(); + if (key == NULL) { + return SSH_ERROR; + } + + key->type = type; + key->type_c = ssh_key_type_to_char(type); + key->flags = SSH_KEY_FLAG_PUBLIC; + + buffer = base64_to_bin(b64_key); + + switch (type) { + case SSH_KEYTYPE_DSS: + { + ssh_string p; + ssh_string q; + ssh_string g; + ssh_string pubkey; + + p = buffer_get_ssh_string(buffer); + if (p == NULL) { + goto fail; + } + q = buffer_get_ssh_string(buffer); + if (q == NULL) { + ssh_string_burn(p); + ssh_string_free(p); + + goto fail; + } + g = buffer_get_ssh_string(buffer); + if (g == NULL) { + ssh_string_burn(p); + ssh_string_free(p); + ssh_string_burn(q); + ssh_string_free(q); + + goto fail; + } + pubkey = buffer_get_ssh_string(buffer); + if (g == NULL) { + ssh_string_burn(p); + ssh_string_free(p); + ssh_string_burn(q); + ssh_string_free(q); + ssh_string_burn(g); + ssh_string_free(g); + + goto fail; + } + + rc = pki_pubkey_build_dss(key, p, q, g, pubkey); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p)); + ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q)); + ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g)); +#endif + ssh_string_burn(p); + ssh_string_free(p); + ssh_string_burn(q); + ssh_string_free(q); + ssh_string_burn(g); + ssh_string_free(g); + if (rc == SSH_ERROR) { + goto fail; + } + } + break; + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + { + ssh_string e; + ssh_string n; + + e = buffer_get_ssh_string(buffer); + if (e == NULL) { + goto fail; + } + n = buffer_get_ssh_string(buffer); + if (n == NULL) { + ssh_string_burn(e); + ssh_string_free(e); + + goto fail; + } + + rc = pki_pubkey_build_rsa(key, e, n); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e)); + ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n)); +#endif + ssh_string_burn(e); + ssh_string_free(e); + ssh_string_burn(n); + ssh_string_free(n); + if (rc == SSH_ERROR) { + goto fail; + } + } + break; + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: + ssh_set_error(session, SSH_FATAL, + "Unknown public key protocol %d", + type); + goto fail; + } + + ssh_buffer_free(buffer); + + *pkey = key; + return SSH_OK; +fail: + ssh_buffer_free(buffer); + ssh_key_free(key); + + return SSH_ERROR; +} + ssh_key ssh_pki_publickey_from_privatekey(ssh_key privkey) { return pki_publickey_from_privatekey(privkey); } diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 2c99daf8..2f95d297 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -36,6 +36,7 @@ #include "libssh/callbacks.h" #include "libssh/pki.h" #include "libssh/keys.h" +#include "libssh/dh.h" static int pem_get_password(char *buf, int size, int rwflag, void *userdata) { ssh_session session = userdata; @@ -162,6 +163,50 @@ fail: return NULL; } +int pki_pubkey_build_dss(ssh_key key, + ssh_string p, + ssh_string q, + ssh_string g, + ssh_string pubkey) { + key->dsa = DSA_new(); + if (key->dsa == NULL) { + return SSH_ERROR; + } + + key->dsa->p = make_string_bn(p); + key->dsa->q = make_string_bn(q); + key->dsa->g = make_string_bn(g); + key->dsa->pub_key = make_string_bn(pubkey); + if (key->dsa->p == NULL || + key->dsa->q == NULL || + key->dsa->g == NULL || + key->dsa->pub_key == NULL) { + DSA_free(key->dsa); + return SSH_ERROR; + } + + return SSH_OK; +} + +int pki_pubkey_build_rsa(ssh_key key, + ssh_string e, + ssh_string n) { + key->rsa = RSA_new(); + if (key->rsa == NULL) { + return SSH_ERROR; + } + + key->rsa->e = make_string_bn(e); + key->rsa->n = make_string_bn(n); + if (key->rsa->e == NULL || + key->rsa->n == NULL) { + RSA_free(key->rsa); + return SSH_ERROR; + } + + return SSH_OK; +} + ssh_key pki_publickey_from_privatekey(ssh_key privkey) { ssh_key pubkey = NULL; diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c index 9c6cd677..9ef51c9e 100644 --- a/src/pki_gcrypt.c +++ b/src/pki_gcrypt.c @@ -700,6 +700,38 @@ fail: return NULL; } +int pki_pubkey_build_dss(ssh_key key, + ssh_string p, + ssh_string q, + ssh_string g, + ssh_string pubkey) { + gcry_sexp_build(&key->dsa, NULL, + "(public-key(dsa(p %b)(q %b)(g %b)(y %b)))", + ssh_string_len(p), ssh_string_data(p), + ssh_string_len(q), ssh_string_data(q), + ssh_string_len(g), ssh_string_data(g), + ssh_string_len(pubkey), ssh_string_data(pubkey)); + if (key->dsa == NULL) { + return SSH_ERROR; + } + + return SSH_OK; +} + +int pki_pubkey_build_rsa(ssh_key key, + ssh_string e, + ssh_string n) { + gcry_sexp_build(&key->rsa, NULL, + "(public-key(rsa(n %b)(e %b)))", + ssh_string_len(n), ssh_string_data(n), + ssh_string_len(e),ssh_string_data(e)); + if (key->rsa == NULL) { + return SSH_ERROR; + } + + return SSH_OK; +} + ssh_key pki_publickey_from_privatekey(ssh_key privkey) { ssh_key pubkey = NULL; gcry_sexp_t sexp;