Subversion Repositories Kolibri OS

Rev

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

  1. ;    ssh.asm - SSH client for KolibriOS
  2. ;
  3. ;    Copyright (C) 2015-2016 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. format binary as ""
  19.  
  20. __DEBUG__       = 1
  21. __DEBUG_LEVEL__ = 1
  22.  
  23. BUFFERSIZE      = 4096
  24. MAX_BITS        = 8192
  25.  
  26. DH_PRIVATE_KEY_SIZE     = 256
  27.  
  28. use32
  29.  
  30.         db      'MENUET01'      ; signature
  31.         dd      1               ; header version
  32.         dd      start           ; entry point
  33.         dd      i_end           ; initialized size
  34.         dd      mem+4096        ; required memory
  35.         dd      mem+4096        ; stack pointer
  36.         dd      hostname        ; parameters
  37.         dd      0               ; path
  38.  
  39. include '../../macros.inc'
  40. purge mov,add,sub
  41. include '../../proc32.inc'
  42. include '../../dll.inc'
  43. include '../../debug-fdo.inc'
  44. include '../../network.inc'
  45. ;include '../../develop/libraries/libcrash/trunk/libcrash.inc'
  46.  
  47. include 'mcodes.inc'
  48. include 'ssh_transport.inc'
  49. include 'dh_gex.inc'
  50.  
  51. include 'mpint.inc'
  52. include 'random.inc'
  53. include 'aes256.inc'
  54. include 'aes256-ctr.inc'
  55. include 'aes256-cbc.inc'
  56. include '../../fs/kfar/trunk/kfar_arc/sha256.inc'
  57.  
  58. ; macros for network byte order
  59. macro dd_n op {
  60.    dd 0 or (((op) and 0FF000000h) shr 24) or \
  61.            (((op) and 000FF0000h) shr  8) or \
  62.            (((op) and 00000FF00h) shl  8) or \
  63.            (((op) and 0000000FFh) shl 24)
  64. }
  65.  
  66. macro dw_n op {
  67.    dw 0 or (((op) and 0FF00h) shr 8) or \
  68.            (((op) and 000FFh) shl 8)
  69. }
  70.  
  71. start:
  72.         mcall   68, 11          ; Init heap
  73.  
  74.         DEBUGF  1, "SSH: Loading libraries\n"
  75.         stdcall dll.Load, @IMPORT
  76.         test    eax, eax
  77.         jnz     exit
  78.  
  79.         DEBUGF  1, "SSH: Init PRNG\n"
  80.         call    init_random
  81.  
  82.         DEBUGF  1, "SSH: Init Console\n"
  83.         invoke  con_start, 1
  84.         invoke  con_init, 80, 25, 80, 25, title
  85.  
  86. ; Check for parameters
  87.         cmp     byte[hostname], 0
  88.         jne     resolve
  89.  
  90. main:
  91.         invoke  con_cls
  92. ; Welcome user
  93.         invoke  con_write_asciiz, str1
  94.  
  95. prompt:
  96. ; write prompt
  97.         invoke  con_write_asciiz, str2
  98. ; read string
  99.         mov     esi, hostname
  100.         invoke  con_gets, esi, 256
  101. ; check for exit
  102.         test    eax, eax
  103.         jz      done
  104.         cmp     byte[esi], 10
  105.         jz      done
  106.  
  107. resolve:
  108.         mov     [sockaddr1.port], 22 shl 8
  109.  
  110. ; delete terminating '\n'
  111.         mov     esi, hostname
  112.   @@:
  113.         lodsb
  114.         cmp     al, ':'
  115.         je      .do_port
  116.         cmp     al, 0x20
  117.         ja      @r
  118.         mov     byte[esi-1], 0
  119.         jmp     .done
  120.  
  121.   .do_port:
  122.         xor     eax, eax
  123.         xor     ebx, ebx
  124.         mov     byte[esi-1], 0
  125.   .portloop:
  126.         lodsb
  127.         cmp     al, 0x20
  128.         jbe     .port_done
  129.         sub     al, '0'
  130.         jb      hostname_error
  131.         cmp     al, 9
  132.         ja      hostname_error
  133.         lea     ebx, [ebx*4 + ebx]
  134.         shl     ebx, 1
  135.         add     ebx, eax
  136.         jmp     .portloop
  137.  
  138.   .port_done:
  139.         xchg    bl, bh
  140.         mov     [sockaddr1.port], bx
  141.  
  142.   .done:
  143.  
  144. ; resolve name
  145.         push    esp     ; reserve stack place
  146.         push    esp
  147.         invoke  getaddrinfo, hostname, 0, 0
  148.         pop     esi
  149. ; test for error
  150.         test    eax, eax
  151.         jnz     dns_error
  152.  
  153.         invoke  con_cls
  154.         invoke  con_write_asciiz, str3
  155.         invoke  con_write_asciiz, hostname
  156.  
  157. ; write results
  158.         invoke  con_write_asciiz, str8
  159.  
  160. ; convert IP address to decimal notation
  161.         mov     eax, [esi+addrinfo.ai_addr]
  162.         mov     eax, [eax+sockaddr_in.sin_addr]
  163.         mov     [sockaddr1.ip], eax
  164.         invoke  inet_ntoa, eax
  165. ; write result
  166.         invoke  con_write_asciiz, eax
  167. ; free allocated memory
  168.         invoke  freeaddrinfo, esi
  169.  
  170.         invoke  con_write_asciiz, str9
  171.  
  172.         mcall   40, EVM_STACK + EVM_KEY
  173.         invoke  con_cls
  174.  
  175. ; Create socket
  176.         mcall   socket, AF_INET4, SOCK_STREAM, 0
  177.         cmp     eax, -1
  178.         jz      socket_err
  179.         mov     [socketnum], eax
  180.  
  181. ; Connect
  182.         mcall   connect, [socketnum], sockaddr1, 18
  183.         test    eax, eax
  184.         jnz     socket_err
  185.  
  186. ; Start calculating hash meanwhile
  187.         call    sha256_init
  188. ; HASH: string  V_C, the client's version string (CR and NL excluded)
  189.         mov     esi, ssh_ident_ha
  190.         mov     edx, ssh_ident.length+4-2
  191.         call    sha256_update
  192.  
  193. ; Send our identification string
  194.         DEBUGF  1, "Sending ID string\n"
  195.         mcall   send, [socketnum], ssh_ident, ssh_ident.length, 0
  196.         cmp     eax, -1
  197.         je      socket_err
  198.  
  199. ; Check protocol version of server
  200.         mcall   recv, [socketnum], rx_buffer, BUFFERSIZE, 0
  201.         cmp     eax, -1
  202.         je      socket_err
  203.  
  204.         DEBUGF  1, "Received ID string\n"
  205.         cmp     dword[rx_buffer], "SSH-"
  206.         jne     proto_err
  207.         cmp     dword[rx_buffer+4], "2.0-"
  208.         jne     proto_err
  209.  
  210. ; HASH: string  V_S, the server's version string (CR and NL excluded)
  211.         lea     edx, [eax+2]
  212.         sub     eax, 2
  213.         bswap   eax
  214.         mov     [rx_buffer-4], eax
  215.         mov     esi, rx_buffer-4
  216.         call    sha256_update
  217.  
  218. ; Key Exchange init
  219.         DEBUGF  1, "Sending KEX init\n"
  220.         mov     edi, ssh_kex.cookie
  221.         call    MBRandom
  222.         stosd
  223.         call    MBRandom
  224.         stosd
  225.         call    MBRandom
  226.         stosd
  227.         call    MBRandom
  228.         stosd
  229.         stdcall ssh_send_packet, [socketnum], ssh_kex, ssh_kex.length, 0
  230.         cmp     eax, -1
  231.         je      socket_err
  232.  
  233. ; HASH: string  I_C, the payload of the client's SSH_MSG_KEXINIT
  234.         mov     eax, [tx_buffer+ssh_header.length]
  235.         bswap   eax
  236.         movzx   ebx, [tx_buffer+ssh_header.padding]
  237.         sub     eax, ebx
  238.         dec     eax
  239.         lea     edx, [eax+4]
  240.         bswap   eax
  241.         mov     [tx_buffer+1], eax
  242.         mov     esi, tx_buffer+1
  243.         call    sha256_update
  244.  
  245. ; Check key exchange init of server
  246.         stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
  247.         cmp     eax, -1
  248.         je      socket_err
  249.  
  250.         cmp     [rx_buffer+ssh_header.message_code], SSH_MSG_KEXINIT
  251.         jne     proto_err
  252.         DEBUGF  1, "Received KEX init\n"
  253.  
  254.         lea     esi, [rx_buffer+sizeof.ssh_header+16]
  255.         lodsd
  256.         bswap   eax
  257.         DEBUGF  1, "kex_algorithms: %s\n", esi
  258.         add     esi, eax
  259.         lodsd
  260.         bswap   eax
  261.         DEBUGF  1, "server_host_key_algorithms: %s\n", esi
  262.         add     esi, eax
  263.         lodsd
  264.         bswap   eax
  265.         DEBUGF  1, "encryption_algorithms_client_to_server: %s\n", esi
  266.         add     esi, eax
  267.         lodsd
  268.         bswap   eax
  269.         DEBUGF  1, "encryption_algorithms_server_to_client: %s\n", esi
  270.         add     esi, eax
  271.         lodsd
  272.         bswap   eax
  273.         DEBUGF  1, "mac_algorithms_client_to_server: %s\n", esi
  274.         add     esi, eax
  275.         lodsd
  276.         bswap   eax
  277.         DEBUGF  1, "mac_algorithms_server_to_client: %s\n", esi
  278.         add     esi, eax
  279.         lodsd
  280.         bswap   eax
  281.         DEBUGF  1, "compression_algorithms_client_to_server: %s\n", esi
  282.         add     esi, eax
  283.         lodsd
  284.         bswap   eax
  285.         DEBUGF  1, "compression_algorithms_server_to_client: %s\n", esi
  286.         add     esi, eax
  287.         lodsd
  288.         bswap   eax
  289.         DEBUGF  1, "languages_client_to_server: %s\n", esi
  290.         add     esi, eax
  291.         lodsd
  292.         bswap   eax
  293.         DEBUGF  1, "languages_server_to_client: %s\n", esi
  294.         add     esi, eax
  295.         lodsb
  296.         DEBUGF  1, "KEX First Packet Follows: %u\n", al
  297.  
  298.         ; TODO
  299.  
  300. ; HASH: string I_S, the payload of the servers's SSH_MSG_KEXINIT
  301.         mov     eax, [rx_buffer+ssh_header.length]
  302.         movzx   ebx, [rx_buffer+ssh_header.padding]
  303.         sub     eax, ebx
  304.         dec     eax
  305.         lea     edx, [eax+4]
  306.         bswap   eax
  307.         mov     [rx_buffer+sizeof.ssh_header-5], eax
  308.         mov     esi, rx_buffer+sizeof.ssh_header-5
  309.         call    sha256_update
  310.  
  311. ; Exchange keys with the server
  312.         stdcall dh_gex
  313.         test    eax, eax
  314.         jnz     exit
  315.  
  316. ; Set keys
  317.         DEBUGF  1, "SSH: Init encryption\n"
  318.         stdcall aes256_cbc_init, rx_iv
  319.         mov     [rx_context], eax
  320.         stdcall aes256_set_encrypt_key, [rx_context], rx_enc_key
  321.         mov     [decrypt_proc], aes256_cbc_decrypt
  322.         mov     [rx_blocksize], 32
  323.  
  324.         DEBUGF  1, "SSH: Init decryption\n"
  325.         stdcall aes256_cbc_init, tx_iv
  326.         mov     [tx_context], eax
  327.         stdcall aes256_set_decrypt_key, [tx_context], tx_enc_key
  328.         mov     [encrypt_proc], aes256_cbc_encrypt
  329.         mov     [tx_blocksize], 32
  330.  
  331. ; Launch network thread
  332.         mcall   18, 7
  333.         push    eax
  334.         mcall   51, 1, thread, mem - 2048
  335.         pop     ecx
  336.         mcall   18, 3
  337.  
  338. mainloop:
  339.         call    [con_get_flags]
  340.         test    eax, 0x200                      ; con window closed?
  341.         jnz     exit
  342.  
  343.         stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
  344.         cmp     eax, -1
  345.         je      closed
  346.  
  347.         DEBUGF  1, 'SSH: got %u bytes of data !\n', eax
  348.  
  349.         mov     esi, rx_buffer
  350.         mov     ecx, eax
  351.         pusha
  352. @@:
  353.         lodsb
  354.         DEBUGF  1, "%x ", eax:2
  355.         dec     ecx
  356.         jnz     @r
  357.         popa
  358.         lea     edi, [esi + eax]
  359.         mov     byte [edi], 0
  360.         invoke  con_write_asciiz, esi
  361.         jmp     mainloop
  362.  
  363. proto_err:
  364.         DEBUGF  1, "SSH: protocol error\n"
  365.         invoke  con_write_asciiz, str7
  366.         jmp     prompt
  367.  
  368. socket_err:
  369.         DEBUGF  1, "SSH: socket error %d\n", ebx
  370.         invoke  con_write_asciiz, str6
  371.         jmp     prompt
  372.  
  373. dns_error:
  374.         DEBUGF  1, "SSH: DNS error %d\n", eax
  375.         invoke  con_write_asciiz, str5
  376.         jmp     prompt
  377.  
  378. hostname_error:
  379.         invoke  con_write_asciiz, str10
  380.         jmp     prompt
  381.  
  382. closed:
  383.         invoke  con_write_asciiz, str11
  384.         jmp     prompt
  385.  
  386. done:
  387.         invoke  con_exit, 1
  388. exit:
  389.         DEBUGF  1, "SSH: Exiting\n"
  390.         mcall   close, [socketnum]
  391.         mcall   -1
  392.  
  393.  
  394. thread:
  395.         mcall   40, 0
  396.   .loop:
  397.         invoke  con_getch2
  398.         mov     [send_data], ax
  399.         xor     esi, esi
  400.         inc     esi
  401.         test    al, al
  402.         jnz     @f
  403.         inc     esi
  404.   @@:
  405.         stdcall ssh_send_packet, [socketnum], send_data, 0
  406.  
  407.         invoke  con_get_flags
  408.         test    eax, 0x200                      ; con window closed?
  409.         jz      .loop
  410.         mcall   -1
  411.  
  412. ; data
  413. title   db      'Secure Shell',0
  414. str1    db      'SSH client for KolibriOS',10,10,\
  415.                 'Please enter URL of SSH server (host:port)',10,10,0
  416. str2    db      '> ',0
  417. str3    db      'Connecting to ',0
  418. str4    db      10,0
  419. str5    db      'Name resolution failed.',10,10,0
  420. str6    db      'A socket error occured.',10,10,0
  421. str7    db      'A protocol error occured.',10,10,0
  422. str8    db      ' (',0
  423. str9    db      ')',10,0
  424. str10   db      'Invalid hostname.',10,10,0
  425. str11   db      10,'Remote host closed the connection.',10,10,0
  426.  
  427. sockaddr1:
  428.         dw AF_INET4
  429.   .port dw 0
  430.   .ip   dd 0
  431.         rb 10
  432.  
  433. ssh_ident_ha:
  434.         dd_n (ssh_ident.length-2)
  435. ssh_ident:
  436.         db "SSH-2.0-KolibriOS_SSH_0.01",13,10
  437.   .length = $ - ssh_ident
  438.  
  439. ssh_kex:
  440.         db SSH_MSG_KEXINIT
  441.   .cookie:
  442.         rd 4
  443.   .kex_algorithms:
  444.         dd_n .server_host_key_algorithms - .kex_algorithms - 4
  445.         db "diffie-hellman-group-exchange-sha256" ; diffie-hellman-group-exchange-sha1
  446.   .server_host_key_algorithms:
  447.         dd_n .encryption_algorithms_client_to_server - .server_host_key_algorithms - 4
  448.         db "ssh-rsa"                    ;,ssh-dss
  449.   .encryption_algorithms_client_to_server:
  450.         dd_n .encryption_algorithms_server_to_client - .encryption_algorithms_client_to_server - 4
  451.         db "aes256-cbc"                 ;,aes256-ctr,aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-ctr,aes192-cbc,aes128-ctr,aes128-cbc,blowfish-ctr,blowfish-cbc,3des-ctr,3des-cbc,arcfour256,arcfour128"
  452.   .encryption_algorithms_server_to_client:
  453.         dd_n .mac_algorithms_client_to_server - .encryption_algorithms_server_to_client - 4
  454.         db "aes256-cbc"                 ;,aes256-ctr,aes256-cbc,rijndael-cbc@lysator.liu.se,aes192-ctr,aes192-cbc,aes128-ctr,aes128-cbc,blowfish-ctr,blowfish-cbc,3des-ctr,3des-cbc,arcfour256,arcfour128"
  455.   .mac_algorithms_client_to_server:
  456.         dd_n .mac_algorithms_server_to_client - .mac_algorithms_client_to_server - 4
  457.         db "hmac-sha2-256"              ;,hmac-sha1,hmac-sha1-96,hmac-md5"
  458.   .mac_algorithms_server_to_client:
  459.         dd_n .compression_algorithms_client_to_server - .mac_algorithms_server_to_client - 4
  460.         db "hmac-sha2-256"              ;,hmac-sha1,hmac-sha1-96,hmac-md5"
  461.   .compression_algorithms_client_to_server:
  462.         dd_n .compression_algorithms_server_to_client - .compression_algorithms_client_to_server - 4
  463.         db "none"                       ;,zlib"
  464.   .compression_algorithms_server_to_client:
  465.         dd_n .languages_client_to_server - .compression_algorithms_server_to_client - 4
  466.         db "none"                       ;,zlib"
  467.   .languages_client_to_server:
  468.         dd_n .languages_server_to_client - .languages_client_to_server - 4
  469.         db ""
  470.   .languages_server_to_client:
  471.         dd_n .first_kex_packet_follows - .languages_server_to_client - 4
  472.         db ""
  473.   .first_kex_packet_follows:
  474.         db 0
  475.   .reserved:
  476.         dd_n 0
  477.   .length = $ - ssh_kex
  478.  
  479.  
  480. ssh_gex_req:
  481.         db SSH_MSG_KEX_DH_GEX_REQUEST
  482.         dd_n 128                ; DH GEX min
  483.         dd_n 256                ; DH GEX number of bits
  484.         dd_n 512                ; DH GEX Max
  485.   .length = $ - ssh_gex_req
  486.  
  487.  
  488. ssh_new_keys:
  489.         db SSH_MSG_NEWKEYS
  490.   .length = $ - ssh_new_keys
  491.  
  492.  
  493. include_debug_strings
  494.  
  495.  
  496. ; import
  497. align 4
  498. @IMPORT:
  499.  
  500. library network, 'network.obj', \
  501.         console, 'console.obj';, \
  502. ;        libcrash, 'libcrash.obj'
  503.  
  504. import  network, \
  505.         getaddrinfo, 'getaddrinfo', \
  506.         freeaddrinfo, 'freeaddrinfo', \
  507.         inet_ntoa, 'inet_ntoa'
  508.  
  509. import  console, \
  510.         con_start, 'START', \
  511.         con_init, 'con_init', \
  512.         con_write_asciiz, 'con_write_asciiz', \
  513.         con_exit, 'con_exit', \
  514.         con_gets, 'con_gets', \
  515.         con_cls, 'con_cls', \
  516.         con_getch2, 'con_getch2', \
  517.         con_set_cursor_pos, 'con_set_cursor_pos', \
  518.         con_write_string, 'con_write_string', \
  519.         con_get_flags,  'con_get_flags'
  520.  
  521. ;import  libcrash, \
  522. ;        crash.hash, 'crash_hash'
  523.  
  524. IncludeIGlobals
  525.  
  526. i_end:
  527.  
  528. decrypt_proc    dd dummy_encrypt
  529. encrypt_proc    dd dummy_encrypt
  530. rx_blocksize    dd 4
  531. tx_blocksize    dd 4
  532. rx_context      dd ?
  533. tx_context      dd ?
  534.  
  535. IncludeUGlobals
  536.  
  537. socketnum       dd ?
  538. rx_packet_length dd ?   ;;;;;
  539. rx_buffer:      rb BUFFERSIZE+1
  540. tx_buffer:      rb BUFFERSIZE+1
  541.  
  542. send_data       dw ?
  543.  
  544. hostname        rb 1024
  545.  
  546. ; Diffie Hellman variables
  547. dh_p            dd ?
  548.                 rb MAX_BITS/8
  549. dh_g            dd ?
  550.                 rb MAX_BITS/8
  551. dh_x            dd ?
  552.                 rb MAX_BITS/8
  553. dh_e            dd ?
  554.                 rb MAX_BITS/8
  555. dh_f            dd ?
  556.                 rb MAX_BITS/8
  557.  
  558. dh_signature    dd ?
  559.                 rb MAX_BITS/8
  560.  
  561. ; Output from key exchange
  562. dh_K            dd ?            ; Shared Secret (Big endian)
  563.                 rb MAX_BITS/8
  564.   .length       dd ?            ; Length in little endian
  565.  
  566. dh_H            rb 32           ; Exchange Hash
  567. session_id      rb 32
  568. rx_iv           rb 32           ; Rx initialisation vector
  569. tx_iv           rb 32           ; Tx initialisation vector
  570. rx_enc_key      rb 32           ; Rx encryption key
  571. tx_enc_key      rb 32           ; Tx encryption key
  572. rx_int_key      rb 32           ; Rx integrity key
  573. tx_int_key      rb 32           ; Tx integrity key
  574.  
  575. ; Temporary values      ; To be removed
  576. mpint_tmp       rb MPINT_MAX_LEN+4
  577.  
  578. mem:
  579.