Develop and Download Open Source Software

Browse Subversion Repository

Diff of /branches/ssh_chacha20poly1305/ttssh2/ttxssh/ssh.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4307 by maya, Tue Feb 15 09:00:01 2011 UTC revision 4314 by maya, Wed Feb 16 15:55:41 2011 UTC
# Line 131  void SSH2_send_kexinit(PTInstVar pvar); Line 131  void SSH2_send_kexinit(PTInstVar pvar);
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);
# Line 3156  void SSH_end(PTInstVar pvar) Line 3157  void SSH_end(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    
# Line 4669  static BOOL handle_SSH2_kexinit(PTInstVa Line 4674  static BOOL handle_SSH2_kexinit(PTInstVa
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;
# Line 4884  error:; Line 4894  error:;
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
# Line 5357  error: Line 5442  error:
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  {  {
# Line 5369  static BOOL handle_SSH2_dh_common_reply( Line 5709  static BOOL handle_SSH2_dh_common_reply(
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;

Legend:
Removed from v.4307  
changed lines
  Added in v.4314

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26