From a4b2518761c6b68b8a28ea250d58e7257bce6554 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Sun, 21 Aug 2011 11:03:53 +0200 Subject: pki: Add ssh_pki_import_signature_blob(). --- include/libssh/pki.h | 6 +++ src/pki.c | 60 +++++++++++++++++++++++++++++ src/pki_crypto.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/pki_gcrypt.c | 80 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+) diff --git a/include/libssh/pki.h b/include/libssh/pki.h index dd090d6..b0f682b 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -93,6 +93,9 @@ ssh_string ssh_pki_export_pubkey_blob(const ssh_key key); int ssh_pki_export_signature_blob(const ssh_signature sign, ssh_string *sign_blob); +int ssh_pki_import_signature_blob(const ssh_string sig_blob, + const ssh_key pubkey, + ssh_signature *psig); ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, ssh_key privatekey); @@ -107,6 +110,9 @@ ssh_key pki_private_key_from_base64(const char *b64_key, void *auth_data); 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); struct signature_struct *pki_do_sign(const ssh_key privatekey, const unsigned char *hash); diff --git a/src/pki.c b/src/pki.c index f776938..542bede 100644 --- a/src/pki.c +++ b/src/pki.c @@ -913,6 +913,66 @@ int ssh_pki_export_signature_blob(const ssh_signature sig, return SSH_OK; } +int ssh_pki_import_signature_blob(const ssh_string sig_blob, + const ssh_key pubkey, + ssh_signature *psig) +{ + ssh_signature sig; + enum ssh_keytypes_e type; + ssh_string str; + ssh_buffer buf; + char *type_c; + int rc; + + if (sig_blob == NULL || psig == NULL) { + return SSH_ERROR; + } + + buf = ssh_buffer_new(); + if (buf == NULL) { + return SSH_ERROR; + } + + rc = buffer_add_data(buf, + ssh_string_data(sig_blob), + ssh_string_len(sig_blob)); + if (rc < 0) { + ssh_buffer_free(buf); + return SSH_ERROR; + } + + str = buffer_get_ssh_string(buf); + if (str == NULL) { + ssh_buffer_free(buf); + return SSH_ERROR; + } + + type_c = ssh_string_to_char(str); + ssh_string_free(str); + if (type_c == NULL) { + ssh_buffer_free(buf); + return SSH_ERROR; + } + + type = ssh_key_type_from_name(type_c); + SAFE_FREE(type_c); + + str = buffer_get_ssh_string(buf); + ssh_buffer_free(buf); + if (str == NULL) { + return SSH_ERROR; + } + + sig = pki_signature_from_blob(pubkey, str, type); + ssh_string_free(str); + if (sig == NULL) { + return SSH_ERROR; + } + + *psig = sig; + return SSH_OK; +} + /* * 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 0dafd22..f71c22b 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -561,6 +561,110 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) return sig_blob; } +ssh_signature pki_signature_from_blob(const ssh_key pubkey, + const ssh_string sig_blob, + enum ssh_keytypes_e type) +{ + ssh_signature sig; + ssh_string r; + ssh_string s; + size_t len; + size_t rsalen; + + sig = ssh_signature_new(); + if (sig == NULL) { + return NULL; + } + + sig->type = type; + + len = ssh_string_len(sig_blob); + + switch(type) { + case SSH_KEYTYPE_DSS: + /* 40 is the dual signature blob len. */ + if (len != 40) { + ssh_pki_log("Signature has wrong size: %lu", + (unsigned long)len); + ssh_signature_free(sig); + return NULL; + } + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("r", ssh_string_data(str), 20); + ssh_print_hexa("s", (unsigned char *)ssh_string_data(rs) + 20, 20); +#endif + + sig->dsa_sig = DSA_SIG_new(); + if (sig->dsa_sig == NULL) { + ssh_signature_free(sig); + return NULL; + } + + r = ssh_string_new(20); + if (r == NULL) { + ssh_signature_free(sig); + return NULL; + } + ssh_string_fill(r, ssh_string_data(sig_blob), 20); + + sig->dsa_sig->r = make_string_bn(r); + ssh_string_free(r); + if (sig->dsa_sig->r == NULL) { + ssh_signature_free(sig); + return NULL; + } + + s = ssh_string_new(20); + if (s == NULL) { + ssh_signature_free(sig); + return NULL; + } + ssh_string_fill(s, (char *)ssh_string_data(sig_blob) + 20, 20); + + sig->dsa_sig->s = make_string_bn(s); + ssh_string_free(s); + if (sig->dsa_sig->s == NULL) { + ssh_signature_free(sig); + return NULL; + } + + break; + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + rsalen = RSA_size(pubkey->rsa); + + if (len > rsalen) { + ssh_pki_log("Signature is to big size: %lu", + (unsigned long)len); + ssh_signature_free(sig); + return NULL; + } + + if (len < rsalen) { + ssh_pki_log("RSA signature len %lu < %lu", + (unsigned long)len, (unsigned long)rsalen); + } + +#ifdef DEBUG_CRYPTO + ssh_pki_log("RSA signature len: %lu", (unsigned long)len); + ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len); +#endif + sig->rsa_sig = string_copy(sig_blob); + if (sig->rsa_sig == NULL) { + ssh_signature_free(sig); + return NULL; + } + break; + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: + ssh_pki_log("Unknown signature type"); + return NULL; + } + + return sig; +} + 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 2a6a120..3317514 100644 --- a/src/pki_gcrypt.c +++ b/src/pki_gcrypt.c @@ -1224,6 +1224,86 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) return sig_blob; } +ssh_signature pki_signature_from_blob(const ssh_key pubkey, + const ssh_string sig_blob, + enum ssh_keytypes_e type) +{ + ssh_signature sig; + gcry_error_t err; + size_t len; + size_t rsalen; + + sig = ssh_signature_new(); + if (sig == NULL) { + return NULL; + } + + sig->type = type; + + len = ssh_string_len(sig_blob); + + switch(type) { + case SSH_KEYTYPE_DSS: + /* 40 is the dual signature blob len. */ + if (len != 40) { + ssh_pki_log("Signature has wrong size: %lu", + (unsigned long)len); + ssh_signature_free(sig); + return NULL; + } + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("r", ssh_string_data(str), 20); + ssh_print_hexa("s", (unsigned char *)ssh_string_data(rs) + 20, 20); +#endif + + err = gcry_sexp_build(&sig->dsa_sig, + NULL, + "(sig-val(dsa(r %b)(s %b)))", + 20, + ssh_string_data(sig_blob), + 20, + (unsigned char *)ssh_string_data(sig_blob) + 20); + if (err) { + ssh_signature_free(sig); + return NULL; + } + break; + case SSH_KEYTYPE_RSA: + case SSH_KEYTYPE_RSA1: + rsalen = (gcry_pk_get_nbits(pubkey->rsa) + 7) / 8; + + if (len > rsalen) { + ssh_pki_log("Signature is to big size: %lu", + (unsigned long)len); + ssh_signature_free(sig); + return NULL; + } + + if (len < rsalen) { + ssh_pki_log("RSA signature len %lu < %lu", + (unsigned long)len, (unsigned long)rsalen); + } + +#ifdef DEBUG_CRYPTO + ssh_pki_log("RSA signature len: %lu", (unsigned long)len); + ssh_print_hexa("RSA signature", ssh_string_data(sig_blob), len); +#endif + + if (gcry_sexp_build(&sig->rsa_sig, NULL, "(sig-val(rsa(s %b)))", + ssh_string_len(sig_blob), ssh_string_data(sig_blob))) { + ssh_signature_free(sig); + return NULL; + } + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: + ssh_pki_log("Unknown signature type"); + return NULL; + } + + return sig; +} + struct signature_struct *pki_do_sign(ssh_key privatekey, const unsigned char *hash) { struct signature_struct *sign; -- cgit