Subversion Repositories Kolibri OS

Rev

Rev 9106 | Rev 9987 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;    sshlib_connection.inc - SSH connection
  2. ;
  3. ;    Copyright (C) 2016-2021 Jeffrey Amelynck
  4. ;
  5. ;    This program is free software: you can redistribute it and/or modify
  6. ;    it under the terms of the GNU General Public License as published by
  7. ;    the Free Software Foundation, either version 3 of the License, or
  8. ;    (at your option) any later version.
  9. ;
  10. ;    This program is distributed in the hope that it will be useful,
  11. ;    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ;    GNU General Public License for more details.
  14. ;
  15. ;    You should have received a copy of the GNU General Public License
  16. ;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  
  18. proc sshlib_connect con_ptr, hostname_sz
  19.  
  20. locals
  21.         socketnum       dd ?
  22.         sockaddr        sockaddr_in
  23.         ctx_ptr         dd ?
  24. endl
  25.  
  26.         mov     edi, [con_ptr]
  27.         lea     eax, [edi + sshlib_connection.part_ex_hash_ctx]
  28.         mov     [ctx_ptr], eax
  29.  
  30. ; Set default values in sockaddr struct
  31.         mov     [sockaddr.sin_family], AF_INET4
  32.         mov     [sockaddr.sin_port], 22 shl 8
  33.  
  34. ; Parse hostname_sz
  35. ; Verify length, extract port number if given and copy base url to sshlib_connection struct
  36. ; Port number, if provided, will be written in sockaddr struct.
  37. ; Hostname ends with any character equal to 0x20 or lower
  38.  
  39.         mov     esi, [hostname_sz]
  40.         lea     edi, [edi + sshlib_connection.hostname_sz]
  41.         mov     ecx, MAX_HOSTNAME_LENGTH
  42.   @@:
  43.         dec     ecx
  44.         jz      .err_hostname
  45.         lodsb
  46.         cmp     al, ':'
  47.         je      .do_port
  48.         stosb
  49.         cmp     al, 0x20
  50.         ja      @r
  51.         mov     byte[edi-1], 0
  52.         jmp     .hostname_ok
  53.  
  54.   .do_port:
  55.         xor     eax, eax
  56.         xor     ebx, ebx
  57.         mov     byte[edi-1], 0
  58.   .portloop:
  59.         lodsb
  60.         cmp     al, 0x20
  61.         jbe     .port_done
  62.         sub     al, '0'
  63.         jb      .err_hostname
  64.         cmp     al, 9
  65.         ja      .err_hostname
  66.         lea     ebx, [ebx*4+ebx]
  67.         shl     ebx, 1
  68.         add     ebx, eax
  69.         jmp     .portloop
  70.   .port_done:
  71.         xchg    bl, bh
  72.         mov     [sockaddr.sin_port], bx
  73.  
  74.   .hostname_ok:
  75. ; resolve name
  76.         push    esp     ; reserve stack place
  77.         push    esp
  78.         mov     eax, [con_ptr]
  79.         lea     eax, [eax+sshlib_connection.hostname_sz]
  80.         invoke  getaddrinfo, eax, 0, 0
  81.         pop     esi
  82. ; test for error
  83.         test    eax, eax
  84.         jnz     .err_hostname
  85.  
  86. ; convert IP address to decimal notation
  87.         mov     eax, [esi+addrinfo.ai_addr]
  88.         mov     eax, [eax+sockaddr_in.sin_addr]
  89.         mov     [sockaddr.sin_addr], eax
  90.         invoke  inet_ntoa, eax
  91. ; write result
  92.         stdcall sshlib_callback_connecting, [con_ptr], eax
  93. ; free allocated memory
  94.         invoke  freeaddrinfo, esi
  95.  
  96. ; Create socket
  97.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  98.         cmp     eax, -1
  99.         jz      .err_sock
  100.         mov     [socketnum], eax
  101.         mov     ebx, [con_ptr]
  102.         mov     [ebx + sshlib_connection.socketnum], eax
  103.  
  104. ; Connect
  105.         DEBUGF  2, "Connecting to server\n"
  106.         lea     edx, [sockaddr]
  107.         mcall   connect, [socketnum], , sizeof.sockaddr_in
  108.         test    eax, eax
  109.         jnz     .err_sock
  110.  
  111. ; Start calculating hash
  112.         invoke  sha2_256_init, [ctx_ptr]
  113. ; HASH: string  V_C, the client's version string (CR and NL excluded)
  114.         invoke  sha2_256_update, [ctx_ptr], ssh_ident_ha, ssh_msg_ident.length+4-2
  115.  
  116. ; >> Send our identification string
  117.         DEBUGF  2, "Sending ID string\n"
  118.         mcall   send, [socketnum], ssh_msg_ident, ssh_msg_ident.length, 0
  119.         cmp     eax, -1
  120.         je      .err_sock
  121.  
  122. ; << Check protocol version of server
  123.         mov     edx, [con_ptr]
  124.         lea     edx, [edx + sshlib_connection.rx_buffer + 4]
  125.         mcall   recv, [socketnum], , PACKETSIZE, 0
  126.         cmp     eax, -1
  127.         je      .err_sock
  128.  
  129.         DEBUGF  2, "Received ID string\n"
  130.         cmp     dword[edx], "SSH-"
  131.         jne     .err_proto
  132.         cmp     dword[edx+4], "2.0-"
  133.         jne     .err_proto
  134.  
  135. ; HASH: string  V_S, the server's version string (CR and NL excluded)
  136.         lea     ecx, [eax+2]
  137.         sub     eax, 2
  138.         bswap   eax
  139.         sub     edx, 4
  140.         mov     dword[edx], eax
  141.         invoke  sha2_256_update, [ctx_ptr], edx, ecx
  142.  
  143. ; >> Key Exchange init
  144.         mov     eax, [con_ptr]
  145.         mov     [eax + sshlib_connection.status], SSHLIB_CON_STAT_INIT
  146.  
  147.         mov     [eax + sshlib_connection.algo_kex], SSHLIB_ALGO_NONE
  148.         mov     [eax + sshlib_connection.algo_hostkey], SSHLIB_ALGO_NONE
  149.         mov     [eax + sshlib_connection.algo_crypt_rx], SSHLIB_ALGO_NONE
  150.         mov     [eax + sshlib_connection.algo_crypt_tx], SSHLIB_ALGO_NONE
  151.         mov     [eax + sshlib_connection.algo_mac_rx], SSHLIB_ALGO_NONE
  152.         mov     [eax + sshlib_connection.algo_mac_tx], SSHLIB_ALGO_NONE
  153.         mov     [eax + sshlib_connection.algo_compr_rx], SSHLIB_ALGO_NONE
  154.         mov     [eax + sshlib_connection.algo_compr_tx], SSHLIB_ALGO_NONE
  155.  
  156.         mov     [eax + sshlib_connection.rx_mac_seqnr], 0
  157.         mov     [eax + sshlib_connection.tx_mac_seqnr], 0
  158.         mov     [eax + sshlib_connection.rx_crypt_blocksize], 4             ; minimum blocksize
  159.         mov     [eax + sshlib_connection.tx_crypt_blocksize], 4
  160.         mov     [eax + sshlib_connection.rx_crypt_proc], sshlib_crypt_null
  161.         mov     [eax + sshlib_connection.tx_crypt_proc], sshlib_crypt_null
  162.         mov     [eax + sshlib_connection.rx_mac_proc], 0
  163.         mov     [eax + sshlib_connection.tx_mac_proc], 0
  164.         mov     [eax + sshlib_connection.rx_mac_length], 0
  165.         mov     [eax + sshlib_connection.tx_mac_length], 0
  166.         mov     [eax + sshlib_connection.tx_pad_size], 8
  167.         mov     [eax + sshlib_connection.tx_pad_proc], sshlib_padd_null
  168.  
  169.         DEBUGF  2, "Sending KEX init\n"
  170.         mov     edi, ssh_msg_kex.cookie
  171.         call    MBRandom
  172.         stosd
  173.         call    MBRandom
  174.         stosd
  175.         call    MBRandom
  176.         stosd
  177.         call    MBRandom
  178.         stosd
  179.         stdcall sshlib_send_packet, [con_ptr], ssh_msg_kex, ssh_msg_kex.length, 0
  180.         cmp     eax, -1
  181.         je      .err_sock
  182.  
  183. ; HASH: string  I_C, the payload of the client's SSH_MSG_KEXINIT
  184.         mov     esi, [con_ptr]
  185.         mov     eax, [esi+sshlib_connection.tx_buffer.packet_length]
  186.         bswap   eax
  187.         movzx   ebx, [esi+sshlib_connection.tx_buffer.padding_length]
  188.         sub     eax, ebx
  189.         dec     eax
  190.         lea     edx, [eax+4]
  191.         bswap   eax
  192.         lea     esi, [esi+sshlib_connection.tx_buffer+1]
  193.         mov     dword[esi], eax
  194.         invoke  sha2_256_update, [ctx_ptr], esi, edx
  195.  
  196. ; << Check key exchange init of server
  197.         stdcall sshlib_recv_packet, [con_ptr], 0
  198.         cmp     eax, -1
  199.         je      .err_sock
  200.  
  201.         mov     esi, [con_ptr]
  202.         cmp     [esi + sshlib_connection.rx_buffer.message_code], SSH_MSG_KEXINIT
  203.         jne     .err_proto
  204.         DEBUGF  2, "Received KEX init\n"
  205.  
  206.         lea     esi, [esi + sshlib_connection.rx_buffer + sizeof.ssh_packet_header + 16]
  207.         lodsd
  208.         bswap   eax
  209.         DEBUGF  1, "kex_algorithms: %s\n", esi
  210.         add     esi, eax
  211.         lodsd
  212.         bswap   eax
  213.         DEBUGF  1, "server_host_key_algorithms: %s\n", esi
  214.         add     esi, eax
  215.         lodsd
  216.         bswap   eax
  217.         DEBUGF  1, "encryption_algorithms_client_to_server: %s\n", esi
  218.         add     esi, eax
  219.         lodsd
  220.         bswap   eax
  221.         DEBUGF  1, "encryption_algorithms_server_to_client: %s\n", esi
  222.         add     esi, eax
  223.         lodsd
  224.         bswap   eax
  225.         DEBUGF  1, "mac_algorithms_client_to_server: %s\n", esi
  226.         add     esi, eax
  227.         lodsd
  228.         bswap   eax
  229.         DEBUGF  1, "mac_algorithms_server_to_client: %s\n", esi
  230.         add     esi, eax
  231.         lodsd
  232.         bswap   eax
  233.         DEBUGF  1, "compression_algorithms_client_to_server: %s\n", esi
  234.         add     esi, eax
  235.         lodsd
  236.         bswap   eax
  237.         DEBUGF  1, "compression_algorithms_server_to_client: %s\n", esi
  238.         add     esi, eax
  239.         lodsd
  240.         bswap   eax
  241.         DEBUGF  1, "languages_client_to_server: %s\n", esi
  242.         add     esi, eax
  243.         lodsd
  244.         bswap   eax
  245.         DEBUGF  1, "languages_server_to_client: %s\n", esi
  246.         add     esi, eax
  247.         lodsb
  248.         DEBUGF  1, "KEX First Packet Follows: %u\n", al
  249.  
  250. ; TODO: parse this structure and set algorithm codes accordingly
  251. ; FIXME: hardcoded for now
  252.         mov     esi, [con_ptr]
  253.         mov     [esi+sshlib_connection.algo_kex], SSHLIB_KEX_DH_SHA256
  254.         mov     [esi+sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA
  255.         mov     [esi+sshlib_connection.algo_crypt_rx], SSHLIB_CRYPT_AES256_CTR
  256.         mov     [esi+sshlib_connection.algo_crypt_tx], SSHLIB_CRYPT_AES256_CTR
  257.         mov     [esi+sshlib_connection.algo_mac_rx], SSHLIB_HMAC_SHA2_256
  258.         mov     [esi+sshlib_connection.algo_mac_tx], SSHLIB_HMAC_SHA2_256
  259.         mov     [esi+sshlib_connection.algo_compr_rx], SSHLIB_COMPR_NONE
  260.         mov     [esi+sshlib_connection.algo_compr_tx], SSHLIB_COMPR_NONE
  261.  
  262. ; HASH: string I_S, the payload of the servers's SSH_MSG_KEXINIT
  263.         mov     esi, [con_ptr]
  264.         mov     eax, [esi+sshlib_connection.rx_buffer.packet_length]
  265.         movzx   ebx, [esi+sshlib_connection.rx_buffer.padding_length]
  266.         sub     eax, ebx
  267.         dec     eax
  268.         lea     edx, [eax+4]
  269.         bswap   eax
  270.         lea     esi, [esi+sshlib_connection.rx_buffer+1]
  271.         mov     dword[esi], eax
  272.         invoke  sha2_256_update, [ctx_ptr], esi, edx
  273.  
  274. ; Exchange keys with the server
  275.  
  276.         stdcall sshlib_dh_gex, [con_ptr]
  277.         test    eax, eax
  278.         jnz     .err
  279.  
  280. ; Re-seed RNG for padding bytes
  281.  
  282.         call    create_seed
  283.         call    init_random
  284.  
  285.         xor     eax, eax
  286.         ret
  287.  
  288.   .err_hostname:
  289.         mov     eax, SSHLIB_ERR_HOSTNAME
  290.         ret
  291.  
  292.   .err_sock:
  293.         mov     eax, SSHLIB_ERR_SOCKET
  294.         ret
  295.  
  296.   .err_proto:
  297.         mov     eax, SSHLIB_ERR_PROTOCOL
  298.         ret
  299.  
  300.   .err:
  301.         ret
  302.  
  303. endp
  304.  
  305.  
  306.  
  307.  
  308. ; Handle common messages and return to caller for specific ones
  309. proc sshlib_msg_handler, con_ptr, flags
  310.  
  311.   .recv:
  312. ; Send a window update if advertised window drops below half
  313.         cmp     [ssh_chan.rcv_wnd], BUFFERSIZE/2
  314.         ja      .no_wnd
  315.         mov     eax, BUFFERSIZE
  316.         bswap   eax
  317.         mov     [ssh_msg_channel_window_adjust.wnd], eax
  318.         stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_window_adjust, ssh_msg_channel_window_adjust.length, 0
  319.         mov     [ssh_chan.rcv_wnd], BUFFERSIZE
  320.   .no_wnd:
  321.  
  322. ; Receive 1 SSH packet
  323.         stdcall sshlib_recv_packet, [con_ptr], [flags]
  324.         cmp     eax, 0
  325.         jle     .ret
  326.  
  327.         mov     esi, [con_ptr]
  328.         lea     esi, [esi + sshlib_connection.rx_buffer]
  329.         mov     al, [esi + ssh_packet_header.message_code]
  330.         inc     esi
  331.  
  332.         cmp     al, SSH_MSG_DISCONNECT
  333.         je      .disc
  334.         cmp     al, SSH_MSG_IGNORE
  335.         je      .ign
  336.         cmp     al, SSH_MSG_DEBUG
  337.         je      .dbg
  338.         cmp     al, SSH_MSG_GLOBAL_REQUEST
  339.         je      .glob_req
  340.         cmp     al, SSH_MSG_CHANNEL_WINDOW_ADJUST
  341.         je      .chan_win_adj
  342. ;        cmp     al, SSH_MSG_CHANNEL_REQUEST
  343. ;        je      .chan_req
  344.         cmp     al, SSH_MSG_CHANNEL_EOF
  345.         je      .chan_eof
  346.         cmp     al, SSH_MSG_CHANNEL_CLOSE
  347.         je      .chan_close
  348.  
  349.   .ret:
  350.         ret
  351.  
  352.   .disc:
  353.         DEBUGF  3, "SSH: Disconnect message received\n"
  354.         mov     eax, SSHLIB_ERR_DISCONNECTING
  355.         ret
  356.  
  357.   .ign:
  358.         DEBUGF  3, "SSH: Ignore MSG received\n"
  359.         jmp     .recv
  360.  
  361.   .dbg:
  362.         DEBUGF  3, "SSH: Debug MSG received\n"
  363.         ;TODO
  364.         jmp     .recv
  365.  
  366.   .glob_req:
  367.         DEBUGF  3, "SSH: Global MSG received\n"
  368.         ;TODO
  369.         jmp     .recv
  370.  
  371.   .chan_win_adj:
  372.         mov     eax, dword[esi]
  373.         bswap   eax
  374.         mov     [ssh_chan.snd_wnd], eax
  375.         ; TODO: validate channel number, act accordingly
  376.         DEBUGF  3, "SSH: Channel %u window update received\n", eax
  377.         jmp     .recv
  378.  
  379.   .chan_eof:
  380.         mov     eax, dword[esi]
  381.         bswap   eax
  382.         ; TODO: validate channel number, act accordingly
  383.         DEBUGF  3, "SSH: Channel %u EOF received\n", eax
  384.         jmp     .recv
  385.  
  386.   .chan_close:
  387.         mov     eax, dword[esi]
  388.         bswap   eax
  389.         ; TODO: validate channel number
  390.         DEBUGF  3, "SSH: Channel %u close received\n", eax
  391.         ; Reply with close message
  392.         stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_close, ssh_msg_channel_close.length, 0
  393.         xor     eax, eax
  394.         ret
  395.  
  396. endp
  397.