From 2b61418128a6a9401d42f452a9e1acb5fe29cbb0 Mon Sep 17 00:00:00 2001 From: milo Date: Thu, 17 Mar 2011 10:05:59 +0100 Subject: [pki] added ssh_pki_do_sign() function --- include/libssh/keys.h | 4 ++ include/libssh/pki.h | 2 + src/keys.c | 4 +- src/pki.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 2 deletions(-) diff --git a/include/libssh/keys.h b/include/libssh/keys.h index e38cf9c..e6354a9 100644 --- a/include/libssh/keys.h +++ b/include/libssh/keys.h @@ -71,6 +71,10 @@ ssh_private_key privatekey_make_rsa(ssh_session session, ssh_buffer buffer, ssh_public_key publickey_make_dss(ssh_session session, ssh_buffer buffer); ssh_public_key publickey_make_rsa(ssh_session session, ssh_buffer buffer, int type); ssh_public_key publickey_from_string(ssh_session session, ssh_string pubkey_s); +ssh_string signature_to_string(SIGNATURE *sign); +#if defined HAVE_LIBCRYPTO +ssh_string RSA_do_sign(const unsigned char *payload, int len, RSA *privkey); +#endif SIGNATURE *signature_from_string(ssh_session session, ssh_string signature,ssh_public_key pubkey,int needed_type); void signature_free(SIGNATURE *sign); ssh_string ssh_do_sign_with_agent(struct ssh_session_struct *session, diff --git a/include/libssh/pki.h b/include/libssh/pki.h index fe83fc5..7aed09a 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -48,6 +48,8 @@ int ssh_key_import_private(ssh_key key, ssh_session session, const char *filename, const char *passphrase); ssh_key ssh_pki_publickey_from_privatekey(ssh_key privkey); +ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, + ssh_key privatekey); /* temporary functions, to be removed after migration to ssh_key */ ssh_key ssh_pki_convert_privatekey_to_key(ssh_private_key priv); diff --git a/src/keys.c b/src/keys.c index 7512e9a..7ea824e 100644 --- a/src/keys.c +++ b/src/keys.c @@ -725,7 +725,7 @@ error: } /* Signature decoding functions */ -static ssh_string signature_to_string(SIGNATURE *sign) { +ssh_string signature_to_string(SIGNATURE *sign) { unsigned char buffer[40] = {0}; ssh_buffer tmpbuf = NULL; ssh_string str = NULL; @@ -1093,7 +1093,7 @@ void signature_free(SIGNATURE *sign) { * I think now, maybe it's a bad idea to name it has it should have be * named in libcrypto */ -static ssh_string RSA_do_sign(const unsigned char *payload, int len, RSA *privkey) { +ssh_string RSA_do_sign(const unsigned char *payload, int len, RSA *privkey) { ssh_string sign = NULL; unsigned char *buffer = NULL; unsigned int size; diff --git a/src/pki.c b/src/pki.c index 1742073..acf0aeb 100644 --- a/src/pki.c +++ b/src/pki.c @@ -31,9 +31,11 @@ */ #include "libssh/libssh.h" +#include "libssh/session.h" #include "libssh/priv.h" #include "libssh/pki.h" #include "libssh/keys.h" +#include "libssh/buffer.h" /** * @brief creates a new empty SSH key @@ -409,6 +411,116 @@ error: return NULL; } +/* + * This function signs the session id (known as H) as a string then + * the content of sigbuf */ +ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, + ssh_key privatekey) { + struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto : + session->next_crypto; + unsigned char hash[SHA_DIGEST_LEN + 1] = {0}; + ssh_string session_str = NULL; + ssh_string signature = NULL; + SIGNATURE *sign = NULL; + SHACTX ctx = NULL; +#ifdef HAVE_LIBGCRYPT + gcry_sexp_t gcryhash; +#endif + + if(privatekey == NULL || !ssh_key_is_private(privatekey)) { + return NULL; + } + + session_str = ssh_string_new(SHA_DIGEST_LEN); + if (session_str == NULL) { + return NULL; + } + ssh_string_fill(session_str, crypto->session_id, SHA_DIGEST_LEN); + + ctx = sha1_init(); + if (ctx == NULL) { + ssh_string_free(session_str); + return NULL; + } + + sha1_update(ctx, session_str, ssh_string_len(session_str) + 4); + ssh_string_free(session_str); + sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf)); + sha1_final(hash + 1,ctx); + hash[0] = 0; + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("Hash being signed with dsa", hash + 1, SHA_DIGEST_LEN); +#endif + + sign = malloc(sizeof(SIGNATURE)); + if (sign == NULL) { + return NULL; + } + + switch(privatekey->type) { + case SSH_KEYTYPE_DSS: +#ifdef HAVE_LIBGCRYPT + if (gcry_sexp_build(&gcryhash, NULL, "%b", SHA_DIGEST_LEN + 1, hash) || + gcry_pk_sign(&sign->dsa_sign, gcryhash, privatekey->dsa)) { + ssh_set_error(session, SSH_FATAL, "Signing: libcrypt error"); + gcry_sexp_release(gcryhash); + signature_free(sign); + return NULL; + } +#elif defined HAVE_LIBCRYPTO + sign->dsa_sign = DSA_do_sign(hash + 1, SHA_DIGEST_LEN, + privatekey->dsa); + if (sign->dsa_sign == NULL) { + ssh_set_error(session, SSH_FATAL, "Signing: openssl error"); + signature_free(sign); + return NULL; + } +#ifdef DEBUG_CRYPTO + ssh_print_bignum("r", sign->dsa_sign->r); + ssh_print_bignum("s", sign->dsa_sign->s); +#endif +#endif /* HAVE_LIBCRYPTO */ + sign->rsa_sign = NULL; + break; + case SSH_KEYTYPE_RSA: +#ifdef HAVE_LIBGCRYPT + if (gcry_sexp_build(&gcryhash, NULL, "(data(flags pkcs1)(hash sha1 %b))", + SHA_DIGEST_LEN, hash + 1) || + gcry_pk_sign(&sign->rsa_sign, gcryhash, privatekey->rsa)) { + ssh_set_error(session, SSH_FATAL, "Signing: libcrypt error"); + gcry_sexp_release(gcryhash); + signature_free(sign); + return NULL; + } +#elif defined HAVE_LIBCRYPTO + sign->rsa_sign = RSA_do_sign(hash + 1, SHA_DIGEST_LEN, + privatekey->rsa); + if (sign->rsa_sign == NULL) { + ssh_set_error(session, SSH_FATAL, "Signing: openssl error"); + signature_free(sign); + return NULL; + } +#endif + sign->dsa_sign = NULL; + break; + default: + signature_free(sign); + return NULL; + } +#ifdef HAVE_LIBGCRYPT + gcry_sexp_release(gcryhash); +#endif + + sign->type = privatekey->type; + + signature = signature_to_string(sign); + signature_free(sign); + + return signature; +} + + /** * @} */ -- cgit v1.2.3