Subversion Repositories Kolibri OS

Rev

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