From 5cc98ed7205ba68b88d24c85753fb8e60296d2f7 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 22 Aug 2011 16:27:38 +0200 Subject: [PATCH] pki: Add ssh_pki_signature_verify_blob(). --- include/libssh/pki.h | 2 ++ include/libssh/pki_priv.h | 5 +++ src/pki.c | 59 ++++++++++++++++++++++++++++++++++ src/pki_crypto.c | 47 ++++++++++++++++++++++++++++ src/pki_gcrypt.c | 66 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 179 insertions(+) diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 29041920..3e908a61 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -68,6 +68,8 @@ int ssh_pki_export_signature_blob(const ssh_signature sign, int ssh_pki_import_signature_blob(const ssh_string sig_blob, const ssh_key pubkey, ssh_signature *psig); +int ssh_pki_signature_verify_blob(ssh_session session, + ssh_string sig_blob); /* SSH Public Key Functions */ ssh_string ssh_pki_export_pubkey_blob(const ssh_key key); diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h index e86a96c4..3e1ef5dc 100644 --- a/include/libssh/pki_priv.h +++ b/include/libssh/pki_priv.h @@ -55,6 +55,11 @@ ssh_string pki_signature_to_blob(const ssh_signature sign); ssh_signature pki_signature_from_blob(const ssh_key pubkey, const ssh_string sig_blob, enum ssh_keytypes_e type); +int pki_signature_verify(ssh_session session, + const ssh_signature sig, + const ssh_key key, + const unsigned char *hash, + size_t len); /* SSH Signing Functions */ struct signature_struct *pki_do_sign(const ssh_key privatekey, diff --git a/src/pki.c b/src/pki.c index f209fe47..84ee97aa 100644 --- a/src/pki.c +++ b/src/pki.c @@ -979,6 +979,65 @@ int ssh_pki_import_signature_blob(const ssh_string sig_blob, return SSH_OK; } +int ssh_pki_signature_verify_blob(ssh_session session, + ssh_string sig_blob) +{ + unsigned char hash[SHA_DIGEST_LEN + 1] = {0}; + ssh_signature sig; + ssh_key key; + int rc; + + rc = ssh_pki_import_pubkey_blob(session->next_crypto->server_pubkey, &key); + if (rc < 0) { + return SSH_ERROR; + } + + if (session->wanted_methods[SSH_HOSTKEYS]) { + if(!ssh_match_group(session->wanted_methods[SSH_HOSTKEYS], + key->type_c)) { + ssh_set_error(session, + SSH_FATAL, + "Public key from server (%s) doesn't match user " + "preference (%s)", + key->type_c, + session->wanted_methods[SSH_HOSTKEYS]); + ssh_key_free(key); + return -1; + } + } + + rc = ssh_pki_import_signature_blob(sig_blob, key, &sig); + if (rc < 0) { + ssh_key_free(key); + return SSH_ERROR; + } + + ssh_log(session, + SSH_LOG_FUNCTIONS, + "Going to verify a %s type signature", + key->type_c); + + + sha1(session->next_crypto->session_id, + session->next_crypto->digest_len, + hash + 1); + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("Hash to be verified with dsa", hash + 1, SHA_DIGEST_LEN); +#endif + + rc = pki_signature_verify(session, + sig, + key, + hash, + SHA_DIGEST_LEN); + session->next_crypto->server_pubkey_type = key->type_c; + ssh_signature_free(sig); + ssh_key_free(key); + + return rc; +} + /* * This function signs the session id (known as H) as a string then * the content of sigbuf */ diff --git a/src/pki_crypto.c b/src/pki_crypto.c index d4f48d3b..386ac997 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -673,6 +673,53 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, return sig; } +int pki_signature_verify(ssh_session session, + const ssh_signature sig, + const ssh_key key, + const unsigned char *hash, + size_t len) +{ + int rc; + + switch(key->type) { + case SSH_KEYTYPE_DSS: + rc = DSA_do_verify(hash + 1, + len, + sig->dsa_sig, + key->dsa); + if (rc < 0) { + ssh_set_error(session, + SSH_FATAL, + "DSA error: %s", + ERR_error_string(ERR_get_error(), NULL)); + return SSH_ERROR; + } + break; + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + rc = RSA_verify(NID_sha1, + hash + 1, + len, + string_data(sig->rsa_sig), + ssh_string_len(sig->rsa_sig), + key->rsa); + if (rc < 0) { + ssh_set_error(session, + SSH_FATAL, + "RSA error: %s", + ERR_error_string(ERR_get_error(), NULL)); + return SSH_ERROR; + } + break; + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: + ssh_set_error(session, SSH_FATAL, "Unknown public key type"); + return SSH_ERROR; + } + + return SSH_OK; +} + struct signature_struct *pki_do_sign(ssh_key privatekey, const unsigned char *hash) { struct signature_struct *sign; diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c index 3f7a4d90..116e5b00 100644 --- a/src/pki_gcrypt.c +++ b/src/pki_gcrypt.c @@ -1313,6 +1313,72 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, return sig; } +int pki_signature_verify(ssh_session session, + const ssh_signature sig, + const ssh_key key, + const unsigned char *hash, + size_t len) +{ + gcry_sexp_t sexp; + gcry_error_t err; + + switch(key->type) { + case SSH_KEYTYPE_DSS: + err = gcry_sexp_build(&sexp, NULL, "%b", len, hash + 1); + if (err) { + ssh_set_error(session, + SSH_FATAL, + "DSA error: %s", gcry_strerror(err)); + return SSH_ERROR; + } + err = gcry_pk_verify(sig->dsa_sig, sexp, key->dsa); + gcry_sexp_release(sexp); + if (err) { + ssh_set_error(session, SSH_FATAL, "Invalid DSA signature"); + if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) { + ssh_set_error(session, + SSH_FATAL, + "DSA verify error: %s", + gcry_strerror(err)); + } + return SSH_ERROR; + } + break; + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + err = gcry_sexp_build(&sexp, + NULL, + "(data(flags pkcs1)(hash sha1 %b))", + len, hash + 1); + if (err) { + ssh_set_error(session, + SSH_FATAL, + "RSA error: %s", + gcry_strerror(err)); + return SSH_ERROR; + } + err = gcry_pk_verify(sig->rsa_sig, sexp, key->rsa); + gcry_sexp_release(sexp); + if (err) { + ssh_set_error(session, SSH_FATAL, "Invalid RSA signature"); + if (gcry_err_code(err) != GPG_ERR_BAD_SIGNATURE) { + ssh_set_error(session, + SSH_FATAL, + "RSA verify error: %s", + gcry_strerror(err)); + } + return SSH_ERROR; + } + break; + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: + ssh_set_error(session, SSH_FATAL, "Unknown public key type"); + return SSH_ERROR; + } + + return SSH_OK; +} + struct signature_struct *pki_do_sign(ssh_key privatekey, const unsigned char *hash) { struct signature_struct *sign;