Develop and Download Open Source Software

Browse Subversion Repository

Diff of /trunk/ttssh2/ttxssh/pkt.c

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

revision 6969 by doda, Thu Nov 2 11:37:41 2017 UTC revision 9048 by nmaya, Wed Dec 16 12:24:13 2020 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (c) 1998-2001, Robert O'Callahan   * Copyright (c) 1998-2001, Robert O'Callahan
3   * (C) 2004-2017 TeraTerm Project   * (C) 2004- TeraTerm Project
4   * All rights reserved.   * All rights reserved.
5   *   *
6   * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
# Line 88  static int recv_data(PTInstVar pvar, uns Line 88  static int recv_data(PTInstVar pvar, uns
88          return amount_read;          return amount_read;
89  }  }
90    
   
91  // 改行コードが出てくるまで読む  // 改行コードが出てくるまで読む
92  static int recv_line_data(PTInstVar pvar)  static int recv_line_data(PTInstVar pvar)
93  {  {
# Line 128  static int recv_line_data(PTInstVar pvar Line 127  static int recv_line_data(PTInstVar pvar
127          return amount_read;          return amount_read;
128  }  }
129    
   
130  /* This function does two things:  /* This function does two things:
131     -- reads data from the sshd and feeds the SSH protocol packets to ssh.c     -- reads data from the sshd and feeds the SSH protocol packets to ssh.c
132     -- copies any available decrypted session data into the application buffer     -- copies any available decrypted session data into the application buffer
# Line 176  int PKT_recv(PTInstVar pvar, char *buf, Line 174  int PKT_recv(PTInstVar pvar, char *buf,
174                          pvar->pkt_state.datastart += i;                          pvar->pkt_state.datastart += i;
175                          pvar->pkt_state.datalen -= i;                          pvar->pkt_state.datalen -= i;
176                  }                  }
177                  else if (pvar->pkt_state.seen_server_ID && pvar->pkt_state.datalen >= (unsigned int) SSH_get_min_packet_size(pvar)) {                  else if (pvar->pkt_state.seen_server_ID && pvar->pkt_state.datalen >= SSH_get_min_packet_size(pvar)) {
178                          char *data = pvar->pkt_state.buf + pvar->pkt_state.datastart;                          char *data = pvar->pkt_state.buf + pvar->pkt_state.datastart;
179                          uint32 padding;                          uint32 padding;
180                          uint32 pktsize;                          uint32 pktsize;
181                          uint32 total_packet_size;                          uint32 total_packet_size;
182                          struct Mac *mac = &pvar->ssh2_keys[MODE_IN].mac;                          struct Mac *mac = &pvar->ssh2_keys[MODE_IN].mac;
183                          int etm;                          struct Enc *enc = &pvar->ssh2_keys[MODE_IN].enc;
184                            int aadlen;
185    
186                          etm = mac && mac->enabled && mac->etm;                          /*
187                             * aadlen: Additional Authenticated Data Length
188                             *   - 暗号化しないが MAC や AEAD での認証の対象となるデータの長さ
189                             *
190                             * EtM 方式の MAC や、AEAD な暗号ではパケットの先頭のパケット長部分は暗号化されず
191                             * 認証のみが行われる。パケット長は uint32 (4バイト) で格納されている。
192                             * 通常の MAC 方式 (E&M) で、かつ AEAD でない暗号方式ではパケット長部分も暗号化
193                             * されるので aadlen は 0 となる。
194                             */
195                            if (SSHv2(pvar) && ((mac && mac->etm) || (enc && enc->auth_len > 0))) {
196                                    aadlen = 4;
197                            }
198                            else {
199                                    aadlen = 0;
200                            }
201    
202                          // 暗号化パケットの一部を復号化する。                          /*
203                          if (!pvar->pkt_state.predecrypted_packet && !etm) {                           * aadlen が 0 の時はパケット長部分が暗号化されている。パケット全体を受信してから
204                                  SSH_predecrpyt_packet(pvar, data);                           * 後段の処理を行う為にパケット長を知る必要が有る為、先頭の 1 ブロックを復号する。
205                             */
206                            if (SSHv2(pvar) && !pvar->pkt_state.predecrypted_packet && aadlen == 0) {
207                                    SSH_predecrypt_packet(pvar, data);
208                                  pvar->pkt_state.predecrypted_packet = TRUE;                                  pvar->pkt_state.predecrypted_packet = TRUE;
209                          }                          }
210    
211                            // パケットの先頭に uint32 (4バイト) のパケット長が来る
212                            pktsize = get_uint32_MSBfirst(data);
213    
214                          if (SSHv1(pvar)) {                          if (SSHv1(pvar)) {
215                                  uint32 realpktsize = get_uint32_MSBfirst(data);                                  // SSH1 ではパケット長の値には padding の長さが含まれていない。
216                                    // また padding の長さの情報もパケット上には無いので、パケット長の値から計算する。
217                                    padding = 8 - (pktsize % 8);
218    
219                                  padding = 8 - (realpktsize % 8);                                  // 以降の処理は pktsize に padding の値が含まれている事が前提となっている。
220                                  pktsize = realpktsize + padding;                                  pktsize += padding;
                         } else {  
                                 // SSH2のパケットは先頭に packet-size(4)+padding(1)+type(1) が続く。  
                                 pktsize = get_uint32_MSBfirst(data);  
                                 if (etm) {  
                                         padding = 0;  
                                 }  
                                 else {  
                                         padding = (unsigned char) data[4];  
                                 }  
221                          }                          }
222    
223                          // パケット(TCPペイロード)の全体のサイズは、SSHペイロード+4(+MAC)となる。                          // パケット(TCPペイロード)の全体のサイズは、SSHペイロード+4(+MAC)となる。
224                          // +4は、SSHペイロードのサイズを格納している部分(int型)。                          // +4は、SSHペイロードのサイズを格納している部分(int型)。
225                          total_packet_size = pktsize + 4 + SSH_get_clear_MAC_size(pvar);                          total_packet_size = pktsize + 4 + SSH_get_authdata_size(pvar, MODE_IN);
226    
227                          if (total_packet_size <= pvar->pkt_state.datalen) {                          if (total_packet_size <= pvar->pkt_state.datalen) {
228                                  /* the data must be 4 byte aligned. */                                  // 受信済みデータが十分有る場合はパケットの実処理を行う
229                                  if (SSHv1(pvar)) {                                  if (SSHv1(pvar)) {
230                                          SSH_handle_packet1(pvar, data, pktsize, padding);                                          // SSH1 は EtM 非対応 (そもそも MAC ではなく CRC を使う)
231                                            SSH1_handle_packet(pvar, data, pktsize, padding);
232                                  }                                  }
233                                  else {                                  else {
234                                          SSH_handle_packet2(pvar, data, pktsize, padding, etm);                                          // SSH2 ではこの時点では padding 長部分が復号されていない場合があるので、
235                                            // padding 長は渡さずに、必要になった時に内部で取得する。
236                                            SSH2_handle_packet(pvar, data, pktsize, aadlen, enc->auth_len);
237                                  }                                  }
                                 pvar->pkt_state.predecrypted_packet = FALSE;  
238    
239                                    pvar->pkt_state.predecrypted_packet = FALSE;
240                                  pvar->pkt_state.datastart += total_packet_size;                                  pvar->pkt_state.datastart += total_packet_size;
241                                  pvar->pkt_state.datalen -= total_packet_size;                                  pvar->pkt_state.datalen -= total_packet_size;
242    
243                          } else if (total_packet_size > PACKET_MAX_SIZE) {                          }
244                                  // 4MBを超える巨大なパケットが届いたら、異常終了する。                          else if (total_packet_size > PACKET_MAX_SIZE) {
245                                  // 実際にはデータ化けで復号失敗時に、誤認識することが多い。                                  // パケット長が大きすぎる場合は異常終了する。
246                                    // 実際には何らかの要因で復号失敗⇒パケット長部分が壊れている事が多い。
247                                  UTIL_get_lang_msg("MSG_PKT_OVERSIZED_ERROR", pvar,                                  UTIL_get_lang_msg("MSG_PKT_OVERSIZED_ERROR", pvar,
248                                                    "Oversized packet received from server; connection will close.");                                                    "Oversized packet received from server; connection will close.");
249                                  notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE);                                  notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE);
250                          } else {                          }
251                            else {
252                                  int amount_read = recv_data(pvar, max(total_packet_size, READAMOUNT));                                  int amount_read = recv_data(pvar, max(total_packet_size, READAMOUNT));
253    
254                                  if (amount_read == SOCKET_ERROR) {                                  if (amount_read == SOCKET_ERROR) {

Legend:
Removed from v.6969  
changed lines
  Added in v.9048

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