svnno****@sourc*****
svnno****@sourc*****
2011年 2月 19日 (土) 16:41:41 JST
Revision: 4321 http://sourceforge.jp/projects/ttssh2/svn/view?view=rev&revision=4321 Author: maya Date: 2011-02-19 16:41:41 +0900 (Sat, 19 Feb 2011) Log Message: ----------- SSH2 ã® ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521 ãã¹ãéµæ¹å¼ããµãã¼ããã Modified Paths: -------------- trunk/doc/en/html/about/history.html trunk/doc/ja/html/about/history.html trunk/ttssh2/ttxssh/hosts.c trunk/ttssh2/ttxssh/key.c trunk/ttssh2/ttxssh/key.h trunk/ttssh2/ttxssh/ssh.c trunk/ttssh2/ttxssh/ssh.h trunk/ttssh2/ttxssh/ttxssh.c -------------- next part -------------- Modified: trunk/doc/en/html/about/history.html =================================================================== --- trunk/doc/en/html/about/history.html 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/doc/en/html/about/history.html 2011-02-19 07:41:41 UTC (rev 4321) @@ -1635,6 +1635,7 @@ <ul> <li>added support for confirming agent-forwarding request.</li> <!--li>SSH2 Ì diffie-hellman-group-exchange-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521 ®ð·vgRðT|[gµ½B</li--> + <!--li>SSH2 Ì ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521 zXg®û®ðT|[gµ½B</li--> </ul> </li> Modified: trunk/doc/ja/html/about/history.html =================================================================== --- trunk/doc/ja/html/about/history.html 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/doc/ja/html/about/history.html 2011-02-19 07:41:41 UTC (rev 4321) @@ -1636,6 +1636,7 @@ <ul> <li>SSHG[WFg]ðv³ê½Æ«ÉAó¯üêé©Ç¤©[UÉmF·é@\ðÇÁµ½B</li> <li>SSH2 Ì diffie-hellman-group-exchange-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521 ®ð·vgRðT|[gµ½B</li> + <li>SSH2 Ì ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521 zXg®û®ðT|[gµ½B</li> </ul> </li> Modified: trunk/ttssh2/ttxssh/hosts.c =================================================================== --- trunk/ttssh2/ttxssh/hosts.c 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/ttssh2/ttxssh/hosts.c 2011-02-19 07:41:41 UTC (rev 4321) @@ -642,6 +642,7 @@ pvar->hosts_state.hostkey.type = key->type; pvar->hosts_state.hostkey.dsa = key->dsa; pvar->hosts_state.hostkey.rsa = key->rsa; + pvar->hosts_state.hostkey.ecdsa = key->ecdsa; index += eat_base64(data + index); index += eat_spaces(data + index); @@ -791,8 +792,11 @@ int bits; unsigned char FAR * exp; unsigned char FAR * mod; + const EC_GROUP *group; + const EC_POINT *pa, *pb; - if (key->type == KEY_RSA1) { // SSH1 host public key + switch (key->type) { + case KEY_RSA1: // SSH1 host public key bits = key->bits; exp = key->exp; mod = key->mod; @@ -805,22 +809,30 @@ && equal_mp_ints(mod, pvar->hosts_state.key_mod); */ - } else if (key->type == KEY_RSA) { // SSH2 RSA host public key - + case KEY_RSA: // SSH2 RSA host public key return key->rsa != NULL && pvar->hosts_state.hostkey.rsa != NULL && BN_cmp(key->rsa->e, pvar->hosts_state.hostkey.rsa->e) == 0 && BN_cmp(key->rsa->n, pvar->hosts_state.hostkey.rsa->n) == 0; - } else if (key->type == KEY_DSA) { // SSH2 DSA host public key - + case KEY_DSA: // SSH2 DSA host public key return key->dsa != NULL && pvar->hosts_state.hostkey.dsa && BN_cmp(key->dsa->p, pvar->hosts_state.hostkey.dsa->p) == 0 && BN_cmp(key->dsa->q, pvar->hosts_state.hostkey.dsa->q) == 0 && BN_cmp(key->dsa->g, pvar->hosts_state.hostkey.dsa->g) == 0 && BN_cmp(key->dsa->pub_key, pvar->hosts_state.hostkey.dsa->pub_key) == 0; - } - else { + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: + if (key->ecdsa == NULL || pvar->hosts_state.hostkey.ecdsa == NULL) { + return FALSE; + } + group = EC_KEY_get0_group(key->ecdsa); + pa = EC_KEY_get0_public_key(key->ecdsa), + pb = EC_KEY_get0_public_key(pvar->hosts_state.hostkey.ecdsa); + return EC_POINT_cmp(group, pa, pb, NULL) == 0; + + default: return FALSE; } @@ -894,7 +906,9 @@ int index; enum ssh_keytype type = pvar->hosts_state.hostkey.type; - if (type == KEY_RSA1) { + switch (type) { + case KEY_RSA1: + { int result_len = host_len + 50 + 8 + get_ushort16_MSBfirst(pvar->hosts_state.hostkey.exp) / 3 + get_ushort16_MSBfirst(pvar->hosts_state.hostkey.mod) / 3; @@ -920,7 +934,15 @@ index += print_mp_int(result + index, pvar->hosts_state.hostkey.mod); strncpy_s(result + index, result_len - index, " \r\n", _TRUNCATE); - } else if (type == KEY_RSA || type == KEY_DSA) { + break; + } + + case KEY_RSA: + case KEY_DSA: + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: + { Key *key = &pvar->hosts_state.hostkey; char *blob = NULL; int blen, uulen, msize; @@ -961,7 +983,10 @@ if (uu != NULL) free(uu); - } else { + break; + } + + default: return NULL; } @@ -1082,17 +1107,27 @@ } // Ú±ÌT[oÌL[ðÇÝÞ - if (pvar->hosts_state.hostkey.type == KEY_RSA1) { // SSH1 + switch (pvar->hosts_state.hostkey.type) { + case KEY_RSA1: // SSH1 key.type = KEY_RSA1; key.bits = pvar->hosts_state.hostkey.bits; key.exp = copy_mp_int(pvar->hosts_state.hostkey.exp); key.mod = copy_mp_int(pvar->hosts_state.hostkey.mod); - } else if (pvar->hosts_state.hostkey.type == KEY_RSA) { // SSH2 RSA + break; + case KEY_RSA: // SSH2 RSA key.type = KEY_RSA; key.rsa = duplicate_RSA(pvar->hosts_state.hostkey.rsa); - } else { // SSH2 DSA + break; + case KEY_DSA: // SSH2 DSA key.type = KEY_DSA; key.dsa = duplicate_DSA(pvar->hosts_state.hostkey.dsa); + break; + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: + key.type = pvar->hosts_state.hostkey.type; + key.ecdsa = EC_KEY_dup(pvar->hosts_state.hostkey.ecdsa); + break; } // t@C©çÇÝÞ @@ -1532,17 +1567,23 @@ // known_hosts ɶݵȢL[Í ÆÅt@CÖ«Þ½ßÉA±±ÅÛ¶µÄ¨B pvar->hosts_state.hostkey.type = key->type; - if (key->type == KEY_RSA1) { // SSH1 + switch (key->type) { + case KEY_RSA1: // SSH1 pvar->hosts_state.hostkey.bits = key->bits; pvar->hosts_state.hostkey.exp = copy_mp_int(key->exp); pvar->hosts_state.hostkey.mod = copy_mp_int(key->mod); - - } else if (key->type == KEY_RSA) { // SSH2 RSA + break; + case KEY_RSA: // SSH2 RSA pvar->hosts_state.hostkey.rsa = duplicate_RSA(key->rsa); - - } else { // SSH2 DSA + break; + case KEY_DSA: // SSH2 DSA pvar->hosts_state.hostkey.dsa = duplicate_DSA(key->dsa); - + break; + case KEY_ECDSA256: // SSH2 ECDSA + case KEY_ECDSA384: + case KEY_ECDSA521: + pvar->hosts_state.hostkey.ecdsa = EC_KEY_dup(key->ecdsa); + break; } free(pvar->hosts_state.prefetched_hostname); pvar->hosts_state.prefetched_hostname = _strdup(hostname); Modified: trunk/ttssh2/ttxssh/key.c =================================================================== --- trunk/ttssh2/ttxssh/key.c 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/ttssh2/ttxssh/key.c 2011-02-19 07:41:41 UTC (rev 4321) @@ -26,11 +26,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "ttxssh.h" #include "key.h" +#include "kex.h" #include <openssl/rsa.h> #include <openssl/dsa.h> +#include <openssl/ecdsa.h> #define INTBLOB_LEN 20 #define SIGBLOB_LEN (2*INTBLOB_LEN) @@ -287,21 +288,98 @@ return ret; } +int ssh_ecdsa_verify(EC_KEY *key, enum ssh_keytype keytype, + u_char *signature, u_int signaturelen, + u_char *data, u_int datalen) +{ + ECDSA_SIG *sig; + const EVP_MD *evp_md; + EVP_MD_CTX md; + unsigned char digest[EVP_MAX_MD_SIZE], *sigblob; + unsigned int len, dlen; + int ret, nid = NID_undef; + char *ptr; + + OpenSSL_add_all_digests(); + + if (key == NULL) { + return -2; + } + + ptr = signature; + + len = get_uint32_MSBfirst(ptr); + ptr += 4; + if (strncmp(get_sshname_from_keytype(keytype), ptr, len) != 0) { + return -3; + } + ptr += len; + + len = get_uint32_MSBfirst(ptr); + ptr += 4; + sigblob = ptr; + ptr += len; + + /* parse signature */ + if ((sig = ECDSA_SIG_new()) == NULL) + return -4; + if ((sig->r = BN_new()) == NULL) + return -5; + if ((sig->s = BN_new()) == NULL) + return -6; + + buffer_get_bignum2(&sigblob, sig->r); + buffer_get_bignum2(&sigblob, sig->s); + if (sigblob != ptr) { + return -7; + } + + /* hash the data */ + switch (keytype) { + case KEY_ECDSA256: + nid = NID_sha256; + break; + case KEY_ECDSA384: + nid = NID_sha384; + break; + case KEY_ECDSA521: + nid = NID_sha512; + break; + } + if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { + return -8; + } + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, &dlen); + + ret = ECDSA_do_verify(digest, dlen, sig, key); + memset(digest, 'd', sizeof(digest)); + + ECDSA_SIG_free(sig); + + return ret; +} + int key_verify(Key *key, unsigned char *signature, unsigned int signaturelen, unsigned char *data, unsigned int datalen) { int ret = 0; - if (key->type == KEY_RSA) { + switch (key->type) { + case KEY_RSA: ret = ssh_rsa_verify(key->rsa, signature, signaturelen, data, datalen); - - } - else if (key->type == KEY_DSA) { + break; + case KEY_DSA: ret = ssh_dss_verify(key->dsa, signature, signaturelen, data, datalen); - - } - else { + break; + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: + ret = ssh_ecdsa_verify(key->ecdsa, key->type, signature, signaturelen, data, datalen); + break; + default: return -1; } @@ -399,6 +477,9 @@ case KEY_DSA: case KEY_RSA: + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: key_to_blob(k, &blob, &len); break; @@ -438,6 +519,10 @@ return "RSA"; case KEY_DSA: return "DSA"; + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: + return "ECDSA"; } return "unknown"; } @@ -453,6 +538,12 @@ return BN_num_bits(k->rsa->n); case KEY_DSA: return BN_num_bits(k->dsa->p); + case KEY_ECDSA256: + return 256; + case KEY_ECDSA384: + return 384; + case KEY_ECDSA521: + return 521; } return 0; } @@ -587,6 +678,10 @@ // void key_free(Key *key) { + if (key == NULL) { + return; + } + switch (key->type) { case KEY_RSA1: case KEY_RSA: @@ -600,6 +695,14 @@ DSA_free(key->dsa); key->dsa = NULL; break; + + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: + if (key->ecdsa != NULL) + EC_KEY_free(key->ecdsa); + key->ecdsa = NULL; + break; } free(key); } @@ -607,18 +710,27 @@ // // L[©ç¶ñðÔp·é // -char *get_sshname_from_key(Key *key) +char *get_sshname_from_keytype(enum ssh_keytype type) { - if (key->type == KEY_RSA) { + if (type == KEY_RSA) { return "ssh-rsa"; - } else if (key->type == KEY_DSA) { + } else if (type == KEY_DSA) { return "ssh-dss"; + } else if (type == KEY_ECDSA256) { + return "ecdsa-sha2-nistp256"; + } else if (type == KEY_ECDSA384) { + return "ecdsa-sha2-nistp384"; + } else if (type == KEY_ECDSA521) { + return "ecdsa-sha2-nistp521"; } else { return "ssh-unknown"; } } +char *get_sshname_from_key(Key *key) +{ + return get_sshname_from_keytype(key->type); +} - // // L[¶ñ©çíÊð»è·é // @@ -634,11 +746,45 @@ return KEY_RSA; } else if (strcmp(name, "ssh-dss") == 0) { return KEY_DSA; + } else if (strcmp(name, "ecdsa-sha2-nistp256") == 0) { + return KEY_ECDSA256; + } else if (strcmp(name, "ecdsa-sha2-nistp384") == 0) { + return KEY_ECDSA384; + } else if (strcmp(name, "ecdsa-sha2-nistp521") == 0) { + return KEY_ECDSA521; } return KEY_UNSPEC; } +enum ssh_keytype key_curve_name_to_keytype(char *name) +{ + if (strcmp(name, "nistp256") == 0) { + return KEY_ECDSA256; + } else if (strcmp(name, "nistp384") == 0) { + return KEY_ECDSA384; + } else if (strcmp(name, "nistp521") == 0) { + return KEY_ECDSA521; + } + return KEY_UNSPEC; +} + +char *curve_keytype_to_name(enum ssh_keytype type) +{ + switch (type) { + case KEY_ECDSA256: + return "nistp256"; + break; + case KEY_ECDSA384: + return "nistp384"; + break; + case KEY_ECDSA521: + return "nistp521"; + break; + } + return NULL; +} + // // L[îñ©çobt@ÖÏ··é (for SSH2) // NOTE: @@ -646,29 +792,39 @@ int key_to_blob(Key *key, char **blobp, int *lenp) { buffer_t *b; - char *sshname; + char *sshname, *tmp; int len; int ret = 1; // success b = buffer_init(); sshname = get_sshname_from_key(key); - if (key->type == KEY_RSA) { + switch (key->type) { + case KEY_RSA: buffer_put_string(b, sshname, strlen(sshname)); buffer_put_bignum2(b, key->rsa->e); buffer_put_bignum2(b, key->rsa->n); - - } else if (key->type == KEY_DSA) { + break; + case KEY_DSA: buffer_put_string(b, sshname, strlen(sshname)); buffer_put_bignum2(b, key->dsa->p); buffer_put_bignum2(b, key->dsa->q); buffer_put_bignum2(b, key->dsa->g); buffer_put_bignum2(b, key->dsa->pub_key); + break; + case KEY_ECDSA256: + case KEY_ECDSA384: + case KEY_ECDSA521: + buffer_put_string(b, sshname, strlen(sshname)); + tmp = curve_keytype_to_name(key->type); + buffer_put_string(b, tmp, strlen(tmp)); + buffer_put_ecpoint(b, EC_KEY_get0_group(key->ecdsa), + EC_KEY_get0_public_key(key->ecdsa)); + break; - } else { + default: ret = 0; goto error; - } len = buffer_len(b); @@ -700,6 +856,9 @@ char key[128]; RSA *rsa = NULL; DSA *dsa = NULL; + EC_KEY *ecdsa = NULL; + EC_POINT *q = NULL; + char *curve = NULL; Key *hostkey; // hostkey enum ssh_keytype type; @@ -720,7 +879,8 @@ type = get_keytype_from_name(key); - if (type == KEY_RSA) { // RSA key + switch (type) { + case KEY_RSA: // RSA key rsa = RSA_new(); if (rsa == NULL) { goto error; @@ -736,9 +896,9 @@ hostkey->type = type; hostkey->rsa = rsa; + break; - } - else if (type == KEY_DSA) { // DSA key + case KEY_DSA: // DSA key dsa = DSA_new(); if (dsa == NULL) { goto error; @@ -761,11 +921,53 @@ hostkey->type = type; hostkey->dsa = dsa; + break; - } else { - // unknown key + case KEY_ECDSA256: // ECDSA + case KEY_ECDSA384: + case KEY_ECDSA521: + curve = buffer_get_string(&data, NULL); + if (type != key_curve_name_to_keytype(curve)) { + goto error; + } + + switch (type) { + case KEY_ECDSA256: + ecdsa = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + break; + case KEY_ECDSA384: + ecdsa = EC_KEY_new_by_curve_name(NID_secp384r1); + break; + case KEY_ECDSA521: + ecdsa = EC_KEY_new_by_curve_name(NID_secp521r1); + break; + default: + goto error; + } + if (ecdsa == NULL) { + goto error; + } + + q = EC_POINT_new(EC_KEY_get0_group(ecdsa)); + if (q == NULL) { + goto error; + } + + buffer_get_ecpoint(&data, EC_KEY_get0_group(ecdsa), q); + if (key_ec_validate_public(EC_KEY_get0_group(ecdsa), q) == -1) { + goto error; + } + + if (EC_KEY_set_public_key(ecdsa, q) != 1) { + goto error; + } + + hostkey->type = type; + hostkey->ecdsa = ecdsa; + break; + + default: // unknown key goto error; - } return (hostkey); @@ -775,6 +977,8 @@ RSA_free(rsa); if (dsa != NULL) DSA_free(dsa); + if (ecdsa != NULL) + EC_KEY_free(ecdsa); return NULL; } Modified: trunk/ttssh2/ttxssh/key.h =================================================================== --- trunk/ttssh2/ttxssh/key.h 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/ttssh2/ttxssh/key.h 2011-02-19 07:41:41 UTC (rev 4321) @@ -38,6 +38,7 @@ char *key_fingerprint(Key *key, enum fp_rep dgst_rep); const char *key_type(const Key *k); +char *get_sshname_from_keytype(enum ssh_keytype type); char *get_sshname_from_key(Key *key); enum hostkey_type get_keytype_from_name(char *name); Modified: trunk/ttssh2/ttxssh/ssh.c =================================================================== --- trunk/ttssh2/ttxssh/ssh.c 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/ttssh2/ttxssh/ssh.c 2011-02-19 07:41:41 UTC (rev 4321) @@ -4428,7 +4428,7 @@ int offset = 0; char *msg = NULL; char tmp[1024+512]; - char str_keytype[10]; + char str_keytype[20]; notify_verbose_message(pvar, "SSH2_MSG_KEXINIT was received.", LOG_LEVEL_VERBOSE); @@ -4512,7 +4512,7 @@ } buf[i] = 0; offset += size; - pvar->hostkey_type = -1; + pvar->hostkey_type = KEY_UNSPEC; choose_SSH2_proposal(buf, myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], str_keytype, sizeof(str_keytype)); if (strlen(str_keytype) == 0) { // not match strncpy_s(tmp, sizeof(tmp), "unknown host KEY type: ", _TRUNCATE); Modified: trunk/ttssh2/ttxssh/ssh.h =================================================================== --- trunk/ttssh2/ttxssh/ssh.h 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/ttssh2/ttxssh/ssh.h 2011-02-19 07:41:41 UTC (rev 4321) @@ -201,6 +201,9 @@ KEY_RSA1, KEY_RSA, KEY_DSA, + KEY_ECDSA256, + KEY_ECDSA384, + KEY_ECDSA521, KEY_UNSPEC, }; @@ -211,7 +214,10 @@ "diffie-hellman-group-exchange-sha1," \ "diffie-hellman-group14-sha1," \ "diffie-hellman-group1-sha1" -#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" +#define KEX_DEFAULT_PK_ALG "ecdsa-sha2-nistp256," \ + "ecdsa-sha2-nistp384," \ + "ecdsa-sha2-nistp521," \ + "ssh-rsa,ssh-dss" // use the setting of pvar.CipherOrder. #define KEX_DEFAULT_ENCRYPT "" #define KEX_DEFAULT_MAC "hmac-sha1,hmac-md5" @@ -423,6 +429,8 @@ RSA *rsa; // SSH2 DSA DSA *dsa; + // SSH2 ECDSA + EC_KEY *ecdsa; // SSH1 RSA int bits; unsigned char *exp; Modified: trunk/ttssh2/ttxssh/ttxssh.c =================================================================== --- trunk/ttssh2/ttxssh/ttxssh.c 2011-02-19 05:09:33 UTC (rev 4320) +++ trunk/ttssh2/ttxssh/ttxssh.c 2011-02-19 07:41:41 UTC (rev 4321) @@ -76,6 +76,7 @@ #include "buffer.h" #include "cipher.h" +#include "key.h" #include "sftp.h" @@ -2238,11 +2239,7 @@ append_about_text(dlg, "KEX:", ssh2_kex_algorithms[pvar->kex_type].name); - if (pvar->hostkey_type == KEY_DSA) { - strncpy_s(buf, sizeof(buf), "ssh-dss", _TRUNCATE); - } else { - strncpy_s(buf, sizeof(buf), "ssh-rsa", _TRUNCATE); - } + strncpy_s(buf, sizeof(buf), get_sshname_from_keytype(pvar->hostkey_type), _TRUNCATE); UTIL_get_lang_msg("DLG_ABOUT_HOSTKEY", pvar, "Host Key:"); append_about_text(dlg, pvar->ts->UIMsg, buf);