| 131 |
static BOOL handle_SSH2_kexinit(PTInstVar pvar); |
static BOOL handle_SSH2_kexinit(PTInstVar pvar); |
| 132 |
static void SSH2_dh_kex_init(PTInstVar pvar); |
static void SSH2_dh_kex_init(PTInstVar pvar); |
| 133 |
static void SSH2_dh_gex_kex_init(PTInstVar pvar); |
static void SSH2_dh_gex_kex_init(PTInstVar pvar); |
| 134 |
|
static void SSH2_ecdh_kex_init(PTInstVar pvar); |
| 135 |
static BOOL handle_SSH2_dh_common_reply(PTInstVar pvar); |
static BOOL handle_SSH2_dh_common_reply(PTInstVar pvar); |
| 136 |
static BOOL handle_SSH2_dh_gex_reply(PTInstVar pvar); |
static BOOL handle_SSH2_dh_gex_reply(PTInstVar pvar); |
| 137 |
static BOOL handle_SSH2_newkeys(PTInstVar pvar); |
static BOOL handle_SSH2_newkeys(PTInstVar pvar); |
| 3157 |
DH_free(pvar->kexdh); |
DH_free(pvar->kexdh); |
| 3158 |
pvar->kexdh = NULL; |
pvar->kexdh = NULL; |
| 3159 |
} |
} |
| 3160 |
|
if (pvar->ecdh_client_key) { |
| 3161 |
|
EC_KEY_free(pvar->ecdh_client_key); |
| 3162 |
|
pvar->ecdh_client_key = NULL; |
| 3163 |
|
} |
| 3164 |
memset(pvar->server_version_string, 0, sizeof(pvar->server_version_string)); |
memset(pvar->server_version_string, 0, sizeof(pvar->server_version_string)); |
| 3165 |
memset(pvar->client_version_string, 0, sizeof(pvar->client_version_string)); |
memset(pvar->client_version_string, 0, sizeof(pvar->client_version_string)); |
| 3166 |
|
|
| 4674 |
case KEX_DH_GEX_SHA256: |
case KEX_DH_GEX_SHA256: |
| 4675 |
SSH2_dh_gex_kex_init(pvar); |
SSH2_dh_gex_kex_init(pvar); |
| 4676 |
break; |
break; |
| 4677 |
|
case KEX_ECDH_SHA2_256: |
| 4678 |
|
case KEX_ECDH_SHA2_384: |
| 4679 |
|
case KEX_ECDH_SHA2_521: |
| 4680 |
|
SSH2_ecdh_kex_init(pvar); |
| 4681 |
|
break; |
| 4682 |
default: |
default: |
| 4683 |
// TODO |
// TODO |
| 4684 |
break; |
break; |
| 4894 |
} |
} |
| 4895 |
|
|
| 4896 |
|
|
| 4897 |
|
// |
| 4898 |
|
// KEX_ECDH_SHA2_256 or KEX_ECDH_SHA2_384 or KEX_ECDH_SHA2_521 |
| 4899 |
|
// |
| 4900 |
|
|
| 4901 |
|
static void SSH2_ecdh_kex_init(PTInstVar pvar) |
| 4902 |
|
{ |
| 4903 |
|
EC_KEY *client_key = NULL; |
| 4904 |
|
const EC_GROUP *group; |
| 4905 |
|
buffer_t *msg = NULL; |
| 4906 |
|
unsigned char *outmsg; |
| 4907 |
|
int len; |
| 4908 |
|
|
| 4909 |
|
client_key = EC_KEY_new(); |
| 4910 |
|
if (client_key == NULL) { |
| 4911 |
|
goto error; |
| 4912 |
|
} |
| 4913 |
|
switch (pvar->kex_type) { |
| 4914 |
|
case KEX_ECDH_SHA2_256: |
| 4915 |
|
client_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); |
| 4916 |
|
break; |
| 4917 |
|
case KEX_ECDH_SHA2_384: |
| 4918 |
|
client_key = EC_KEY_new_by_curve_name(NID_secp384r1); |
| 4919 |
|
break; |
| 4920 |
|
case KEX_ECDH_SHA2_521: |
| 4921 |
|
client_key = EC_KEY_new_by_curve_name(NID_secp521r1); |
| 4922 |
|
break; |
| 4923 |
|
default: |
| 4924 |
|
goto error; |
| 4925 |
|
} |
| 4926 |
|
if (client_key == NULL) { |
| 4927 |
|
goto error; |
| 4928 |
|
} |
| 4929 |
|
if (EC_KEY_generate_key(client_key) != 1) { |
| 4930 |
|
goto error; |
| 4931 |
|
} |
| 4932 |
|
group = EC_KEY_get0_group(client_key); |
| 4933 |
|
|
| 4934 |
|
|
| 4935 |
|
msg = buffer_init(); |
| 4936 |
|
if (msg == NULL) { |
| 4937 |
|
// TODO: error check |
| 4938 |
|
return; |
| 4939 |
|
} |
| 4940 |
|
|
| 4941 |
|
buffer_put_ecpoint(msg, group, EC_KEY_get0_public_key(client_key)); |
| 4942 |
|
|
| 4943 |
|
len = buffer_len(msg); |
| 4944 |
|
outmsg = begin_send_packet(pvar, SSH2_MSG_KEX_ECDH_INIT, len); |
| 4945 |
|
memcpy(outmsg, buffer_ptr(msg), len); |
| 4946 |
|
finish_send_packet(pvar); |
| 4947 |
|
|
| 4948 |
|
// ここで作成した鍵は、あとでハッシュ計算に使うため取っておく。 |
| 4949 |
|
if (pvar->ecdh_client_key) { |
| 4950 |
|
EC_KEY_free(pvar->ecdh_client_key); |
| 4951 |
|
} |
| 4952 |
|
pvar->ecdh_client_key = client_key; |
| 4953 |
|
|
| 4954 |
|
SSH2_dispatch_init(2); |
| 4955 |
|
SSH2_dispatch_add_message(SSH2_MSG_KEX_ECDH_REPLY); |
| 4956 |
|
SSH2_dispatch_add_message(SSH2_MSG_IGNORE); // XXX: Tru64 UNIX workaround (2005.3.5 yutaka) |
| 4957 |
|
|
| 4958 |
|
buffer_free(msg); |
| 4959 |
|
|
| 4960 |
|
notify_verbose_message(pvar, "SSH2_MSG_KEX_ECDH_INIT was sent at SSH2_ecdh_kex_init().", LOG_LEVEL_VERBOSE); |
| 4961 |
|
|
| 4962 |
|
return; |
| 4963 |
|
|
| 4964 |
|
error:; |
| 4965 |
|
EC_KEY_free(client_key); |
| 4966 |
|
buffer_free(msg); |
| 4967 |
|
|
| 4968 |
|
notify_fatal_error(pvar, "error occurred @ SSH2_ecdh_kex_init()"); |
| 4969 |
|
} |
| 4970 |
|
|
| 4971 |
|
|
| 4972 |
static void ssh2_set_newkeys(PTInstVar pvar, int mode) |
static void ssh2_set_newkeys(PTInstVar pvar, int mode) |
| 4973 |
{ |
{ |
| 4974 |
#if 1 |
#if 1 |
| 5442 |
} |
} |
| 5443 |
|
|
| 5444 |
|
|
| 5445 |
|
// |
| 5446 |
|
// Elliptic Curv Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEX_ECDH_REPLY:31) |
| 5447 |
|
// |
| 5448 |
|
static BOOL handle_SSH2_ecdh_kex_reply(PTInstVar pvar) |
| 5449 |
|
{ |
| 5450 |
|
char *data; |
| 5451 |
|
int len; |
| 5452 |
|
int offset = 0; |
| 5453 |
|
char *server_host_key_blob; |
| 5454 |
|
int bloblen, siglen; |
| 5455 |
|
EC_POINT *server_public = NULL; |
| 5456 |
|
const EC_GROUP *group; |
| 5457 |
|
char *signature; |
| 5458 |
|
int ecdh_len; |
| 5459 |
|
char *ecdh_buf = NULL; |
| 5460 |
|
BIGNUM *share_key = NULL; |
| 5461 |
|
char *hash; |
| 5462 |
|
char *emsg, emsg_tmp[1024]; // error message |
| 5463 |
|
int ret, hashlen; |
| 5464 |
|
Key *hostkey = NULL; // hostkey |
| 5465 |
|
|
| 5466 |
|
notify_verbose_message(pvar, "SSH2_MSG_KEX_ECDH_REPLY was received.", LOG_LEVEL_VERBOSE); |
| 5467 |
|
|
| 5468 |
|
memset(&hostkey, 0, sizeof(hostkey)); |
| 5469 |
|
|
| 5470 |
|
// TODO: buffer overrun check |
| 5471 |
|
|
| 5472 |
|
// 6byte(サイズ+パディング+タイプ)を取り除いた以降のペイロード |
| 5473 |
|
data = pvar->ssh_state.payload; |
| 5474 |
|
// パケットサイズ - (パディングサイズ+1);真のパケットサイズ |
| 5475 |
|
len = pvar->ssh_state.payloadlen; |
| 5476 |
|
|
| 5477 |
|
// for debug |
| 5478 |
|
push_memdump("KEX_ECDH_REPLY", "key exchange: receiving", data, len); |
| 5479 |
|
|
| 5480 |
|
bloblen = get_uint32_MSBfirst(data); |
| 5481 |
|
data += 4; |
| 5482 |
|
server_host_key_blob = data; // for hash |
| 5483 |
|
|
| 5484 |
|
push_memdump("DH_GEX_REPLY", "server_host_key_blob", server_host_key_blob, bloblen); |
| 5485 |
|
|
| 5486 |
|
hostkey = key_from_blob(data, bloblen); |
| 5487 |
|
if (hostkey == NULL) { |
| 5488 |
|
emsg = "key_from_blob error @ handle_SSH2_ecdh_kex_reply()"; |
| 5489 |
|
goto error; |
| 5490 |
|
} |
| 5491 |
|
data += bloblen; |
| 5492 |
|
|
| 5493 |
|
// known_hosts対応 (2006.3.20 yutaka) |
| 5494 |
|
if (hostkey->type != pvar->hostkey_type) { // ホストキーの種別比較 |
| 5495 |
|
_snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, |
| 5496 |
|
"type mismatch for decoded server_host_key_blob @ %s", __FUNCTION__); |
| 5497 |
|
emsg = emsg_tmp; |
| 5498 |
|
goto error; |
| 5499 |
|
} |
| 5500 |
|
HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, hostkey); |
| 5501 |
|
if (pvar->socket == INVALID_SOCKET) { |
| 5502 |
|
emsg = "Server disconnected @ handle_SSH2_ecdh_kex_reply()"; |
| 5503 |
|
goto error; |
| 5504 |
|
} |
| 5505 |
|
|
| 5506 |
|
/* Q_S, server public key */ |
| 5507 |
|
group = EC_KEY_get0_group(pvar->ecdh_client_key); |
| 5508 |
|
server_public = EC_POINT_new(group); |
| 5509 |
|
if (server_public == NULL) { |
| 5510 |
|
emsg = "Out of memory1 @ handle_SSH2_ecdh_kex_reply()"; |
| 5511 |
|
goto error; |
| 5512 |
|
} |
| 5513 |
|
|
| 5514 |
|
buffer_get_ecpoint(&data, group, server_public); |
| 5515 |
|
|
| 5516 |
|
siglen = get_uint32_MSBfirst(data); |
| 5517 |
|
data += 4; |
| 5518 |
|
signature = data; |
| 5519 |
|
data += siglen; |
| 5520 |
|
|
| 5521 |
|
push_memdump("KEX_ECDH_REPLY", "signature", signature, siglen); |
| 5522 |
|
|
| 5523 |
|
// check public key |
| 5524 |
|
if (key_ec_validate_public(group, server_public) != 0) { |
| 5525 |
|
emsg = "ECDH invalid server public key @ handle_SSH2_ecdh_kex_reply()"; |
| 5526 |
|
goto error; |
| 5527 |
|
} |
| 5528 |
|
// 共通鍵の生成 |
| 5529 |
|
ecdh_len = (EC_GROUP_get_degree(group) + 7) / 8; |
| 5530 |
|
ecdh_buf = malloc(ecdh_len); |
| 5531 |
|
if (ecdh_buf == NULL) { |
| 5532 |
|
emsg = "Out of memory2 @ handle_SSH2_ecdh_kex_reply()"; |
| 5533 |
|
goto error; |
| 5534 |
|
} |
| 5535 |
|
if (ECDH_compute_key(ecdh_buf, ecdh_len, server_public, |
| 5536 |
|
pvar->ecdh_client_key, NULL) != (int)ecdh_len) { |
| 5537 |
|
emsg = "Out of memory2 @ handle_SSH2_ecdh_kex_reply()"; |
| 5538 |
|
goto error; |
| 5539 |
|
} |
| 5540 |
|
share_key = BN_new(); |
| 5541 |
|
if (share_key == NULL) { |
| 5542 |
|
emsg = "Out of memory3 @ handle_SSH2_ecdh_kex_reply()"; |
| 5543 |
|
goto error; |
| 5544 |
|
} |
| 5545 |
|
// 'share_key'がサーバとクライアントで共有する鍵(G^A×B mod P)となる。 |
| 5546 |
|
BN_bin2bn(ecdh_buf, ecdh_len, share_key); |
| 5547 |
|
//debug_print(40, ecdh_buf, ecdh_len); |
| 5548 |
|
|
| 5549 |
|
// ハッシュの計算 |
| 5550 |
|
/* calc and verify H */ |
| 5551 |
|
hash = kex_ecdh_hash(ssh2_kex_algorithms[pvar->kex_type].evp_md(), |
| 5552 |
|
group, |
| 5553 |
|
pvar->client_version_string, |
| 5554 |
|
pvar->server_version_string, |
| 5555 |
|
buffer_ptr(pvar->my_kex), buffer_len(pvar->my_kex), |
| 5556 |
|
buffer_ptr(pvar->peer_kex), buffer_len(pvar->peer_kex), |
| 5557 |
|
server_host_key_blob, bloblen, |
| 5558 |
|
EC_KEY_get0_public_key(pvar->ecdh_client_key), |
| 5559 |
|
server_public, |
| 5560 |
|
share_key, |
| 5561 |
|
&hashlen); |
| 5562 |
|
|
| 5563 |
|
{ |
| 5564 |
|
push_memdump("KEX_ECDH_REPLY ecdh_kex_reply", "my_kex", buffer_ptr(pvar->my_kex), buffer_len(pvar->my_kex)); |
| 5565 |
|
push_memdump("KEX_ECDH_REPLY ecdh_kex_reply", "peer_kex", buffer_ptr(pvar->peer_kex), buffer_len(pvar->peer_kex)); |
| 5566 |
|
|
| 5567 |
|
push_bignum_memdump("KEX_ECDH_REPLY ecdh_kex_reply", "share_key", share_key); |
| 5568 |
|
|
| 5569 |
|
push_memdump("KEX_ECDH_REPLY ecdh_kex_reply", "hash", hash, hashlen); |
| 5570 |
|
} |
| 5571 |
|
|
| 5572 |
|
//debug_print(30, hash, hashlen); |
| 5573 |
|
//debug_print(31, pvar->client_version_string, strlen(pvar->client_version_string)); |
| 5574 |
|
//debug_print(32, pvar->server_version_string, strlen(pvar->server_version_string)); |
| 5575 |
|
//debug_print(33, buffer_ptr(pvar->my_kex), buffer_len(pvar->my_kex)); |
| 5576 |
|
//debug_print(34, buffer_ptr(pvar->peer_kex), buffer_len(pvar->peer_kex)); |
| 5577 |
|
//debug_print(35, server_host_key_blob, bloblen); |
| 5578 |
|
|
| 5579 |
|
// session idの保存(初回接続時のみ) |
| 5580 |
|
if (pvar->session_id == NULL) { |
| 5581 |
|
pvar->session_id_len = hashlen; |
| 5582 |
|
pvar->session_id = malloc(pvar->session_id_len); |
| 5583 |
|
if (pvar->session_id != NULL) { |
| 5584 |
|
memcpy(pvar->session_id, hash, pvar->session_id_len); |
| 5585 |
|
} else { |
| 5586 |
|
// TODO: |
| 5587 |
|
} |
| 5588 |
|
} |
| 5589 |
|
|
| 5590 |
|
if ((ret = key_verify(hostkey, signature, siglen, hash, hashlen)) != 1) { |
| 5591 |
|
if (ret == -3 && hostkey->type == KEY_RSA) { |
| 5592 |
|
if (!pvar->settings.EnableRsaShortKeyServer) { |
| 5593 |
|
_snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, |
| 5594 |
|
"key verify error(remote rsa key length is too short %d-bit) " |
| 5595 |
|
"@ handle_SSH2_ecdh_kex_reply()", BN_num_bits(hostkey->rsa->n)); |
| 5596 |
|
} |
| 5597 |
|
else { |
| 5598 |
|
goto cont; |
| 5599 |
|
} |
| 5600 |
|
} |
| 5601 |
|
else { |
| 5602 |
|
_snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, |
| 5603 |
|
"key verify error(%d) @ handle_SSH2_ecdh_kex_reply()\r\n%s", ret, SENDTOME); |
| 5604 |
|
} |
| 5605 |
|
emsg = emsg_tmp; |
| 5606 |
|
save_memdump(LOGDUMP); |
| 5607 |
|
goto error; |
| 5608 |
|
} |
| 5609 |
|
|
| 5610 |
|
cont: |
| 5611 |
|
kex_derive_keys(pvar, pvar->we_need, hash, share_key, pvar->session_id, pvar->session_id_len); |
| 5612 |
|
|
| 5613 |
|
// KEX finish |
| 5614 |
|
begin_send_packet(pvar, SSH2_MSG_NEWKEYS, 0); |
| 5615 |
|
finish_send_packet(pvar); |
| 5616 |
|
|
| 5617 |
|
notify_verbose_message(pvar, "SSH2_MSG_NEWKEYS was sent at handle_SSH2_ecdh_kex_reply().", LOG_LEVEL_VERBOSE); |
| 5618 |
|
|
| 5619 |
|
// SSH2_MSG_NEWKEYSを送り終わったあとにキーの設定および再設定を行う |
| 5620 |
|
// 送信用の暗号鍵は SSH2_MSG_NEWKEYS の送信後に、受信用のは SSH2_MSG_NEWKEYS の |
| 5621 |
|
// 受信後に再設定を行う。 |
| 5622 |
|
if (pvar->rekeying == 1) { // キーの再設定 |
| 5623 |
|
// まず、送信用だけ設定する。 |
| 5624 |
|
ssh2_set_newkeys(pvar, MODE_OUT); |
| 5625 |
|
pvar->ssh2_keys[MODE_OUT].mac.enabled = 1; |
| 5626 |
|
pvar->ssh2_keys[MODE_OUT].comp.enabled = 1; |
| 5627 |
|
enable_send_compression(pvar); |
| 5628 |
|
if (!CRYPT_start_encryption(pvar, 1, 0)) { |
| 5629 |
|
// TODO: error |
| 5630 |
|
} |
| 5631 |
|
|
| 5632 |
|
} else { |
| 5633 |
|
// 初回接続の場合は実際に暗号ルーチンが設定されるのは、あとになってから |
| 5634 |
|
// なので(CRYPT_start_encryption関数)、ここで鍵の設定をしてしまってもよい。 |
| 5635 |
|
ssh2_set_newkeys(pvar, MODE_IN); |
| 5636 |
|
ssh2_set_newkeys(pvar, MODE_OUT); |
| 5637 |
|
|
| 5638 |
|
// SSH2_MSG_NEWKEYSを送信した時点で、MACを有効にする。(2006.10.30 yutaka) |
| 5639 |
|
pvar->ssh2_keys[MODE_OUT].mac.enabled = 1; |
| 5640 |
|
pvar->ssh2_keys[MODE_OUT].comp.enabled = 1; |
| 5641 |
|
|
| 5642 |
|
// パケット圧縮が有効なら初期化する。(2005.7.9 yutaka) |
| 5643 |
|
// SSH2_MSG_NEWKEYSの受信より前なのでここだけでよい。(2006.10.30 maya) |
| 5644 |
|
prep_compression(pvar); |
| 5645 |
|
enable_compression(pvar); |
| 5646 |
|
} |
| 5647 |
|
|
| 5648 |
|
// TTSSHバージョン情報に表示するキービット数を求めておく |
| 5649 |
|
{ |
| 5650 |
|
int bits; |
| 5651 |
|
BIGNUM *order = BN_new(); |
| 5652 |
|
EC_GROUP_get_order(group, order, NULL); |
| 5653 |
|
bits = BN_num_bits(order); |
| 5654 |
|
pvar->client_key_bits = bits; |
| 5655 |
|
pvar->server_key_bits = bits; |
| 5656 |
|
BN_free(order); |
| 5657 |
|
} |
| 5658 |
|
#if 0 |
| 5659 |
|
{ |
| 5660 |
|
BN_CTX *ctx; |
| 5661 |
|
BIGNUM *pub_key = NULL; |
| 5662 |
|
int bits; |
| 5663 |
|
ctx = BN_CTX_new(); |
| 5664 |
|
|
| 5665 |
|
pub_key = EC_POINT_point2bn(group, server_public, POINT_CONVERSION_UNCOMPRESSED, NULL, ctx); |
| 5666 |
|
bits = BN_num_bits(pub_key); |
| 5667 |
|
printf("%d\n", bits); |
| 5668 |
|
|
| 5669 |
|
pub_key = EC_POINT_point2bn(group, EC_KEY_get0_public_key(pvar->ecdh_client_key), POINT_CONVERSION_UNCOMPRESSED, NULL, ctx); |
| 5670 |
|
bits = BN_num_bits(pub_key); |
| 5671 |
|
printf("%d\n", bits); |
| 5672 |
|
|
| 5673 |
|
BN_CTX_free(ctx); |
| 5674 |
|
} |
| 5675 |
|
#endif |
| 5676 |
|
|
| 5677 |
|
SSH2_dispatch_init(3); |
| 5678 |
|
SSH2_dispatch_add_message(SSH2_MSG_NEWKEYS); |
| 5679 |
|
SSH2_dispatch_add_message(SSH2_MSG_IGNORE); // XXX: Tru64 UNIX workaround (2005.3.5 yutaka) |
| 5680 |
|
|
| 5681 |
|
EC_POINT_clear_free(server_public); |
| 5682 |
|
key_free(hostkey); |
| 5683 |
|
EC_KEY_free(pvar->ecdh_client_key); pvar->ecdh_client_key = NULL; |
| 5684 |
|
free(ecdh_buf); |
| 5685 |
|
return TRUE; |
| 5686 |
|
|
| 5687 |
|
error: |
| 5688 |
|
EC_KEY_free(pvar->ecdh_client_key); pvar->ecdh_client_key = NULL; |
| 5689 |
|
key_free(hostkey); |
| 5690 |
|
EC_POINT_clear_free(server_public); |
| 5691 |
|
free(ecdh_buf); |
| 5692 |
|
BN_free(share_key); |
| 5693 |
|
|
| 5694 |
|
notify_fatal_error(pvar, emsg); |
| 5695 |
|
|
| 5696 |
|
return FALSE; |
| 5697 |
|
} |
| 5698 |
|
|
| 5699 |
|
|
| 5700 |
// KEXにおいてサーバから返ってくる 31 番メッセージに対するハンドラ |
// KEXにおいてサーバから返ってくる 31 番メッセージに対するハンドラ |
| 5701 |
static BOOL handle_SSH2_dh_common_reply(PTInstVar pvar) |
static BOOL handle_SSH2_dh_common_reply(PTInstVar pvar) |
| 5702 |
{ |
{ |
| 5709 |
case KEX_DH_GEX_SHA256: |
case KEX_DH_GEX_SHA256: |
| 5710 |
handle_SSH2_dh_gex_group(pvar); |
handle_SSH2_dh_gex_group(pvar); |
| 5711 |
break; |
break; |
| 5712 |
|
case KEX_ECDH_SHA2_256: |
| 5713 |
|
case KEX_ECDH_SHA2_384: |
| 5714 |
|
case KEX_ECDH_SHA2_521: |
| 5715 |
|
handle_SSH2_ecdh_kex_reply(pvar); |
| 5716 |
|
break; |
| 5717 |
default: |
default: |
| 5718 |
// TODO |
// TODO |
| 5719 |
break; |
break; |