Subversion Repositories Kolibri OS

Rev

Rev 9070 | Blame | Last modification | View Log | Download | RSS feed

  1. ;    ssh_transport.inc - SSH transport layer
  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.  
  19. struct  ssh_packet_header
  20.         packet_length   dd ?    ; The length of the packet in bytes, not including 'mac' or the
  21.                                 ; 'packet_length' field itself.
  22.         padding_length  db ?    ; Length of 'random padding' (bytes).
  23.  
  24.         message_code    db ?    ; First byte of payload
  25. ends
  26.  
  27. proc padding_zero
  28.  
  29.         xor     eax, eax
  30.         ret
  31.  
  32. endp
  33.  
  34. proc ssh_recv_packet connection, flags
  35.  
  36. locals
  37.         data_length     dd ?    ; Total length of packet without MAC
  38.         socket_error    dd ?
  39. endl
  40.  
  41.         DEBUGF  2, "> "
  42. ; Receive first block (Read length, padding length, message code)
  43.         mov     ebx, [connection]
  44.         mov     ecx, [ebx+ssh_connection.socketnum]
  45.         mov     esi, [ebx+ssh_connection.rx_crypt_blocksize]
  46.         lea     edx, [ebx+ssh_connection.rx_buffer]
  47.         mov     edi, [flags]
  48.         mcall   recv
  49.         mov     [socket_error], ebx
  50.         DEBUGF  1, "chunk = %u ", eax
  51.         mov     ebx, [connection]
  52.         cmp     eax, [ebx+ssh_connection.rx_crypt_blocksize]
  53.         jne     .fail
  54.  
  55. ; Decrypt first block
  56.         cmp     [ebx+ssh_connection.rx_crypt_proc], 0
  57.         je      @f
  58.         pusha
  59.         lea     esi, [ebx+ssh_connection.rx_buffer]
  60.         stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
  61.         popa
  62.   @@:
  63.  
  64. ; Check data length
  65.         mov     esi, [ebx+ssh_connection.rx_buffer.packet_length]
  66.         bswap   esi                                             ; convert length to little endian
  67.         mov     [ebx+ssh_connection.rx_buffer.packet_length], esi
  68.         DEBUGF  1, "packet length=%u ", esi
  69.         cmp     esi, BUFFERSIZE
  70.         ja      .fail                                           ; packet is too large
  71.  
  72. ; Calculate amount of remaining data
  73.         add     esi, 4                                          ; Packet length field itself is not included in the count
  74.         sub     esi, [ebx+ssh_connection.rx_crypt_blocksize]    ; Already received this amount of data
  75.         add     esi, [ebx+ssh_connection.rx_mac_length]
  76.         jz      .got_all_data
  77.  
  78. ; Receive remaining data
  79.         lea     edx, [ebx+ssh_connection.rx_buffer]
  80.         add     edx, [ebx+ssh_connection.rx_crypt_blocksize]
  81.         mov     ecx, [ebx+ssh_connection.socketnum]
  82.         mov     edi, [flags]
  83.   .receive_loop:
  84.         mcall   recv
  85.         DEBUGF  1, "chunk = %u ", eax
  86.         cmp     eax, 0
  87.         jbe     .fail
  88.         add     edx, eax
  89.         sub     esi, eax
  90.         jnz     .receive_loop
  91.  
  92. ; Decrypt data
  93.         mov     ebx, [connection]
  94.         cmp     [ebx+ssh_connection.rx_crypt_proc], 0
  95.         je      .decrypt_complete
  96.         mov     ecx, [ebx+ssh_connection.rx_buffer.packet_length]
  97.         add     ecx, 4                                          ; Packet_length field itself
  98.         sub     ecx, [ebx+ssh_connection.rx_crypt_blocksize]    ; Already decrypted this amount of data
  99.         jz      .decrypt_complete
  100.  
  101.         lea     esi, [ebx+ssh_connection.rx_buffer]
  102.         add     esi, [ebx+ssh_connection.rx_crypt_blocksize]
  103.   .decrypt_loop:
  104.         pusha
  105.         stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
  106.         popa
  107.         add     esi, [ebx+ssh_connection.rx_crypt_blocksize]
  108.         sub     ecx, [ebx+ssh_connection.rx_crypt_blocksize]
  109.         jnz     .decrypt_loop
  110.   .decrypt_complete:
  111.  
  112. ; Authenticate message
  113.         cmp     [ebx+ssh_connection.rx_mac_proc], 0
  114.         je      .mac_complete
  115.         lea     esi, [ebx+ssh_connection.rx_seq]
  116.         mov     ecx, [ebx+ssh_connection.rx_buffer.packet_length]
  117.         add     ecx, 8                                          ; packet_length field itself + sequence number
  118.         lea     eax, [ebx+ssh_connection.rx_mac_ctx]
  119.         mov     edx, [ebx+ssh_connection.rx_buffer.packet_length]
  120.         bswap   edx                                             ; convert length to big endian
  121.         mov     [ebx+ssh_connection.rx_buffer.packet_length], edx
  122.         stdcall [ebx+ssh_connection.rx_mac_proc], eax, esi, ecx
  123.         mov     edx, [ebx+ssh_connection.rx_buffer.packet_length]
  124.         bswap   edx                                             ; convert length to little endian
  125.         mov     [ebx+ssh_connection.rx_buffer.packet_length], edx
  126.  
  127.         lea     esi, [ebx+ssh_connection.rx_mac_ctx]
  128.         lea     edi, [ebx+ssh_connection.rx_buffer]
  129.         add     edi, [ebx+ssh_connection.rx_buffer.packet_length]
  130.         add     edi, 4
  131.         mov     ecx, [ebx+ssh_connection.rx_mac_length]
  132.         shr     ecx, 2
  133.         repe cmpsd
  134.         jne     .mac_failed
  135.   .mac_complete:
  136.         add     byte[ebx+ssh_connection.rx_seq+3], 1            ; Update sequence counter
  137.         adc     byte[ebx+ssh_connection.rx_seq+2], 0
  138.         adc     byte[ebx+ssh_connection.rx_seq+1], 0
  139.         adc     byte[ebx+ssh_connection.rx_seq+0], 0
  140.  
  141. ; Return useful data length to the caller via eax register
  142.   .got_all_data:
  143.         mov     eax, [ebx+ssh_connection.rx_buffer.packet_length]
  144.         movzx   ebx, [ebx+ssh_connection.rx_buffer.padding_length]
  145.         sub     eax, ebx
  146.         DEBUGF  1, "useful data length=%u\n", eax
  147.         ret
  148.  
  149.   .fail:
  150.         DEBUGF  3, "ssh_recv_packet failed!\n"
  151.         mov     eax, -1
  152.         mov     ebx, [socket_error]
  153.         ret
  154.  
  155.   .mac_failed:
  156.         DEBUGF  3, "ssh_recv_packet MAC failed!\n"
  157.         mov     eax, -2
  158.         mov     ebx, [socket_error]
  159.         ret
  160.  
  161. endp
  162.  
  163.  
  164. proc ssh_send_packet connection, buf, payload_size, flags
  165.  
  166. locals
  167.         packet_size    dd ?
  168. endl
  169.         DEBUGF  2, "< "
  170.  
  171. ; Check how many bytes we should pad
  172.         mov     eax, [payload_size]
  173.         inc     eax                     ; padding length byte
  174.         lea     edx, [eax+4]            ; total packet size (without padding and MAC)
  175.         mov     [packet_size], edx
  176.  
  177.         mov     ecx, [connection]
  178.         mov     ebx, [ecx+ssh_connection.tx_pad_size]
  179.         dec     ebx
  180.         and     edx, ebx
  181.         neg     edx
  182.         add     edx, [ecx+ssh_connection.tx_pad_size]
  183.         add     edx, [ecx+ssh_connection.tx_pad_size]
  184.         DEBUGF  1, "padding %u bytes ", edx
  185.         add     [packet_size], edx      ; total packet size with padding
  186.  
  187. ; Start building the packet
  188. ; First comes the packet length, in network byte order ofcourse.
  189.         add     eax, edx
  190.         DEBUGF  1, "total size: %u ", eax
  191.         bswap   eax
  192.         lea     edi, [ecx+ssh_connection.tx_buffer]
  193.         stosd
  194. ; Then the padding length
  195.         mov     al, dl
  196.         stosb
  197. ; And the actual payload bytes
  198.         mov     esi, [buf]
  199.         mov     ecx, [payload_size]
  200.         rep movsb
  201.  
  202. ; Append the packet with #edx padding bytes.
  203. ; Since we must pad at least 8 bytes, we can always use DWORD writes.
  204. ; First do an (unaligned) write exactly following the data
  205.         dec     edx
  206.         mov     esi, edx
  207.         shr     esi, 2          ; number dwords
  208.         mov     ebx, edx
  209.         and     ebx, 3
  210.         inc     ebx             ; number bytes in first write (1-4)
  211.         mov     edx, [connection]
  212.         call    [edx+ssh_connection.tx_pad_proc]
  213.         mov     dword[edi], eax
  214.         add     edi, ebx
  215. ; Then, do as many aligned writes as nescessary
  216.         mov     ebx, [connection]
  217.   @@:
  218.         call    [ebx+ssh_connection.tx_pad_proc]
  219.         stosd
  220.         dec     esi
  221.         jnz     @r
  222.  
  223. ; Append the packet with Message Authentication Code
  224.         mov     edx, [connection]
  225.         cmp     [edx+ssh_connection.tx_mac_proc], 0
  226.         je      .mac_complete
  227.         DEBUGF  1, "MAC sequence number: 0x%x\n", [edx+ssh_connection.tx_seq]
  228.         lea     esi, [edx+ssh_connection.tx_seq]
  229.         mov     ecx, [packet_size]
  230.         add     ecx, 4                                          ; Sequence number length
  231.         lea     eax, [edx+ssh_connection.tx_mac_ctx]
  232.         stdcall [edx+ssh_connection.tx_mac_proc], eax, esi, ecx
  233.  
  234.         lea     esi, [edx+ssh_connection.tx_mac_ctx]
  235.         lea     edi, [edx+ssh_connection.tx_buffer]
  236.         add     edi, [packet_size]
  237.         mov     ecx, [edx+ssh_connection.tx_mac_length]
  238.         shr     ecx, 2
  239.         rep movsd
  240.   .mac_complete:
  241.         add     byte[edx+ssh_connection.tx_seq+3], 1            ; Update sequence counter
  242.         adc     byte[edx+ssh_connection.tx_seq+2], 0
  243.         adc     byte[edx+ssh_connection.tx_seq+1], 0
  244.         adc     byte[edx+ssh_connection.tx_seq+0], 0
  245.  
  246. ; Now, encrypt everything but MAC
  247.         cmp     [edx+ssh_connection.tx_crypt_proc], 0
  248.         je      .encrypt_complete
  249.         lea     esi, [edx+ssh_connection.tx_buffer]
  250.         mov     ecx, [packet_size]
  251.   .encrypt_loop:
  252.         pusha
  253.         stdcall [edx+ssh_connection.tx_crypt_proc], [edx+ssh_connection.tx_crypt_ctx_ptr], esi, esi
  254.         popa
  255.         add     esi, [edx+ssh_connection.tx_crypt_blocksize]
  256.         sub     ecx, [edx+ssh_connection.tx_crypt_blocksize]
  257.         jnz     .encrypt_loop
  258.   .encrypt_complete:
  259.  
  260. ; Send the packet
  261.         mov     ebx, [connection]
  262.         mov     ecx, [ebx+ssh_connection.socketnum]
  263.         lea     edx, [ebx+ssh_connection.tx_buffer]
  264.         mov     esi, [packet_size]
  265.         add     esi, [ebx+ssh_connection.tx_mac_length]
  266.         mov     edi, [flags]
  267.         mcall   send
  268.  
  269.         DEBUGF  1, "\n"
  270.  
  271.         ret
  272.  
  273. endp
  274.  
  275.