Subversion Repositories Kolibri OS

Rev

Rev 9990 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;    sshlib_dh_gex.inc - Diffie Hellman Group exchange
  2. ;
  3. ;    Copyright (C) 2015-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. ; https://www.ietf.org/rfc/rfc4419.txt
  19.  
  20. proc sshlib_dh_gex con_ptr
  21.  
  22. locals
  23.  
  24.         mpint_tmp               dd ?
  25.  
  26.         mpint_p                 dd ?
  27.         mpint_g                 dd ?
  28.         mpint_x                 dd ?
  29.         mpint_e                 dd ?
  30.         mpint_f                 dd ?
  31.         mpint_K_big             dd ?
  32.  
  33.         k_h_ctx                 dd ?
  34.         temp_ctx                dd ?
  35.  
  36.         H                       dd ?    ; exchange hash
  37.         K_length                dd ?
  38.  
  39.         session_id_x            rb SHA2_256_LEN+1
  40.  
  41.         str_K_S                 dd ?    ; server public host key and certificates (K_S)
  42.         mpint_f_big             dd ?    ; pointer to original
  43.         str_s_of_H              dd ?    ; signature of H
  44.  
  45. endl
  46.  
  47. ; Allocate memory for temp variables
  48.  
  49.         mov     ecx, 7*(MAX_BITS/8+4) + 2*LIBCRASH_CTX_LEN + 1*SHA2_256_LEN
  50.         mcall   68, 12
  51.         test    eax, eax
  52.         jz      .err_nomem
  53.  
  54. ; Init pointers for temp variables
  55.  
  56.         mov     [mpint_tmp], eax
  57.         add     eax, (MAX_BITS/8+4)
  58.         mov     [mpint_p], eax
  59.         add     eax, (MAX_BITS/8+4)
  60.         mov     [mpint_g], eax
  61.         add     eax, (MAX_BITS/8+4)
  62.         mov     [mpint_x], eax
  63.         add     eax, (MAX_BITS/8+4)
  64.         mov     [mpint_e], eax
  65.         add     eax, (MAX_BITS/8+4)
  66.         mov     [mpint_f], eax
  67.         add     eax, (MAX_BITS/8+4)
  68.         mov     [mpint_K_big], eax
  69.         add     eax, (MAX_BITS/8+4)
  70.  
  71.         mov     [k_h_ctx], eax
  72.         add     eax, LIBCRASH_CTX_LEN
  73.         mov     [temp_ctx], eax
  74.         add     eax, LIBCRASH_CTX_LEN
  75.  
  76.         mov     [H], eax
  77.         add     eax, SHA2_256_LEN
  78.  
  79. ; Copy the partial exchange hash to our temporary one
  80.  
  81.         mov     esi, [con_ptr]
  82.         lea     esi, [esi+sshlib_connection.part_ex_hash_ctx]
  83.         mov     edi, [temp_ctx]
  84.         mov     ecx, LIBCRASH_CTX_LEN/4
  85.         rep movsd
  86.  
  87. ;----------------------------------------------
  88. ; >> Send Diffie-Hellman Group Exchange Request
  89.  
  90.         DEBUGF  2, "Sending DH group exchange request\n"
  91.         stdcall sshlib_send_packet, [con_ptr], ssh_msg_gex_req, ssh_msg_gex_req.length, 0
  92.         cmp     eax, 0
  93.         jl      .err
  94.  
  95. ;---------------------------------------------
  96. ; << Parse Diffie-Hellman Group Exchange Group
  97.  
  98.         stdcall sshlib_recv_packet, [con_ptr], 0
  99.         cmp     eax, 0
  100.         jl      .err
  101.  
  102.         mov     ebx, [con_ptr]
  103.         cmp     [ebx + sshlib_connection.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_GROUP
  104.         jne     .err_proto
  105.         DEBUGF  2, "Received DH group\n"
  106.  
  107.         lea     esi, [ebx + sshlib_connection.rx_buffer + sizeof.ssh_packet_header]
  108.         stdcall mpint_to_little_endian, [mpint_p], esi
  109.         add     esi, 4
  110.         add     esi, eax
  111.         DEBUGM  1, "DH modulus (p): ", [mpint_p]
  112.  
  113.         stdcall mpint_to_little_endian, [mpint_g], esi
  114.         add     esi, 4
  115.         add     esi, eax
  116.         DEBUGM  1, "DH base (g): ", [mpint_g]
  117.  
  118. ;-------------------------------------------
  119. ; >> Send Diffie-Hellman Group Exchange Init
  120.  
  121. ; generate a random number x, where 1 < x < (p-1)/2
  122.         mov     edi, [mpint_x]
  123.         mov     dword[edi], DH_PRIVATE_KEY_SIZE/8
  124.         add     edi, 4
  125.         mov     ecx, DH_PRIVATE_KEY_SIZE/8/4
  126.   @@:
  127.         push    ecx
  128.         call    MBRandom
  129.         pop     ecx
  130.         stosd
  131.         dec     ecx
  132.         jnz     @r
  133.  
  134. ; If the highest bit is set, add a zero byte
  135.         shl     eax, 1
  136.         jnc     @f
  137.         mov     byte[edi], 0
  138.         mov     eax, [mpint_x]
  139.         inc     dword[eax]
  140.   @@:
  141.         DEBUGM  1, "DH private key (x): ", [mpint_x]
  142.  
  143. ; Compute e = g^x mod p
  144.         stdcall mpint_modexp, [mpint_e], [mpint_g], [mpint_x], [mpint_p]
  145.         stdcall mpint_shrink, [mpint_e]
  146.         DEBUGM  1, "DH public key (e): ", [mpint_e]
  147.  
  148. ; Create group exchange init packet
  149.         mov     byte[ebx + sshlib_connection.tx_buffer.message_code], SSH_MSG_KEX_DH_GEX_INIT
  150.         lea     edi, [ebx + sshlib_connection.tx_buffer.message_code+1]
  151.         stdcall mpint_to_big_endian, edi, [mpint_e]
  152.  
  153.         DEBUGF  2, "Sending GEX init\n"
  154.         mov     ecx, dword[ebx + sshlib_connection.tx_buffer.message_code+1]
  155.         bswap   ecx
  156.         add     ecx, 5
  157.         lea     esi, [ebx + sshlib_connection.tx_buffer.message_code]
  158.         stdcall sshlib_send_packet, [con_ptr], esi, ecx, 0
  159.         cmp     eax, 0
  160.         jl      .err
  161.  
  162. ;---------------------------------------------
  163. ; << Parse Diffie-Hellman Group Exchange Reply
  164.  
  165.         stdcall sshlib_recv_packet, [con_ptr], 0
  166.         cmp     eax, 0
  167.         jl      .err
  168.  
  169.         mov     ebx, [con_ptr]
  170.         cmp     [ebx + sshlib_connection.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_REPLY
  171.         jne     .err_proto
  172.  
  173.         DEBUGF  2, "Received GEX Reply\n"
  174.  
  175. ;--------------------------------
  176. ; HASH: string K_S, the host key
  177.         lea     esi, [ebx + sshlib_connection.rx_buffer + sizeof.ssh_packet_header]
  178.         mov     [str_K_S], esi
  179.         mov     edx, [esi]
  180.         bswap   edx
  181.         add     edx, 4
  182.         lea     eax, [esi+edx]
  183.         mov     [mpint_f_big], eax
  184.         invoke  sha2_256.update, [temp_ctx], esi, edx
  185.  
  186. ;--------------------------------------------------------------------------
  187. ; HASH: uint32 min, minimal size in bits of an acceptable group
  188. ;       uint32 n, preferred size in bits of the group the server will send
  189. ;       uint32 max, maximal size in bits of an acceptable group
  190.         invoke  sha2_256.update, [temp_ctx], ssh_msg_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12
  191.  
  192. ;----------------------------
  193. ; HASH: mpint p, safe prime
  194.         stdcall mpint_shrink, [mpint_p]
  195.         stdcall mpint_to_big_endian, [mpint_tmp], [mpint_p]
  196.         add     eax, 4
  197.         invoke  sha2_256.update, [temp_ctx], [mpint_tmp], eax
  198.  
  199. ;----------------------------------------
  200. ; HASH: mpint g, generator for subgroup
  201.         stdcall mpint_shrink, [mpint_g]
  202.         stdcall mpint_to_big_endian, [mpint_tmp], [mpint_g]
  203.         add     eax, 4
  204.         invoke  sha2_256.update, [temp_ctx], [mpint_tmp], eax
  205.  
  206. ;---------------------------------------------------
  207. ; HASH: mpint e, exchange value sent by the client
  208.         mov     ebx, [con_ptr]
  209.         lea     esi, [ebx + sshlib_connection.tx_buffer + sizeof.ssh_packet_header]
  210.         mov     edx, [esi]
  211.         bswap   edx
  212.         add     edx, 4
  213.         invoke  sha2_256.update, [temp_ctx], esi, edx
  214.  
  215. ;---------------------------------------------------
  216. ; HASH: mpint f, exchange value sent by the server
  217.         mov     esi, [mpint_f_big]
  218.         mov     edx, [esi]
  219.         bswap   edx
  220.         add     edx, 4
  221.         invoke  sha2_256.update, [temp_ctx], esi, edx
  222.  
  223.         stdcall mpint_to_little_endian, [mpint_f], [mpint_f_big]
  224.         mov     esi, [mpint_f_big]
  225.         add     esi, eax
  226.         add     esi, 4
  227.         mov     [str_s_of_H], esi
  228.         DEBUGM  1, "DH exchange value (f): ", [mpint_f]
  229.  
  230. ;--------------------------------------
  231. ; Calculate shared secret K = f^x mod p
  232.         stdcall mpint_modexp, [mpint_tmp], [mpint_f], [mpint_x], [mpint_p]
  233.         stdcall mpint_shrink, [mpint_tmp]
  234.         DEBUGM  1, "DH shared secret (K): ", [mpint_tmp]
  235.  
  236. ; We always need it in big endian order, so store it as such.
  237.         stdcall mpint_to_big_endian, [mpint_K_big], [mpint_tmp]
  238.         mov     [K_length], eax
  239.  
  240. ;-----------------------------------
  241. ; HASH: mpint K, the shared secret
  242.         add     eax, 4
  243.         invoke  sha2_256.update, [temp_ctx], [mpint_K_big], eax
  244.  
  245. ;-------------------------------
  246. ; Finalize the exchange hash (H)
  247.         invoke  sha2_256.finish, [temp_ctx]
  248.         mov     esi, [temp_ctx]
  249.         mov     edi, [H]
  250.         mov     ecx, SHA2_256_LEN/4
  251.         rep movsd
  252.  
  253.         DEBUGF  1, "Exchange hash H: "
  254.         stdcall dump_hex, [H], SHA2_256_LEN/4
  255.  
  256. ;--------------------------
  257. ; Set or get the session id
  258.  
  259.         mov     eax, [con_ptr]
  260.         cmp     [eax + sshlib_connection.status], SSHLIB_CON_STAT_KEX_DONE
  261.         jae     @f
  262.  
  263. ; If first KEX, verify host public key
  264.         stdcall sshlib_host_verify, [con_ptr], [str_K_S], [str_s_of_H], [H], SHA2_256_LEN
  265.         test    eax, eax
  266.         jnz     .err_hostkey_verification
  267.  
  268.         mov     eax, [con_ptr]
  269.         mov     esi, [H]
  270.         lea     edi, [eax + sshlib_connection.session_id]
  271.         mov     ecx, SHA2_256_LEN/4
  272.         rep movsd
  273.   @@:
  274.  
  275.         lea     esi, [eax + sshlib_connection.session_id]
  276.         lea     edi, [session_id_x+1]
  277.         mov     ecx, SHA2_256_LEN/4
  278.         rep movsd
  279.  
  280. ;-------------------------------------
  281. ; << Parse Diffie-Hellman New Keys MSG
  282.  
  283.         DEBUGF  2, "Expecting New Keys message\n"
  284.  
  285.         stdcall sshlib_recv_packet, [con_ptr], 0
  286.         cmp     eax, 0
  287.         jl      .err
  288.  
  289.         mov     ebx, [con_ptr]
  290.         cmp     [ebx + sshlib_connection.rx_buffer.message_code], SSH_MSG_NEWKEYS
  291.         jne     .err_proto
  292.  
  293.         DEBUGF  2, "Received New Keys\n"
  294.  
  295. ;----------------------------------------------------
  296. ; >> Reply with New Keys message (Using the old keys)
  297.  
  298.         stdcall sshlib_send_packet, [con_ptr], ssh_msg_new_keys, ssh_msg_new_keys.length, 0
  299.         cmp     eax, 0
  300.         jl      .err
  301.  
  302. ;---------------
  303. ; Calculate keys
  304.  
  305. ; First, calculate partial hash of K and H so we can re-use it for every key.
  306.  
  307.         invoke  sha2_256.init, [k_h_ctx]
  308.  
  309.         mov     ecx, [K_length]
  310.         add     ecx, 4
  311.         invoke  sha2_256.update, [k_h_ctx], [mpint_K_big], ecx
  312.         invoke  sha2_256.update, [k_h_ctx], [H], SHA2_256_LEN
  313.  
  314. ;---------------------------------------------------------------
  315. ; Initial IV client to server: HASH(K || H || "A" || session_id)
  316.  
  317.         mov     esi, [k_h_ctx]
  318.         mov     edi, [temp_ctx]
  319.         mov     ecx, LIBCRASH_CTX_LEN/4
  320.         rep movsd
  321.         lea     edx, [session_id_x]
  322.         mov     byte[edx], 'A'
  323.         invoke  sha2_256.update, [temp_ctx], edx, SHA2_256_LEN+1
  324.         invoke  sha2_256.finish, [temp_ctx]
  325.         mov     ebx, [con_ptr]
  326.         lea     edi, [ebx + sshlib_connection.tx_iv]
  327.         mov     esi, [temp_ctx]
  328.         mov     ecx, SHA2_256_LEN/4
  329.         rep movsd
  330.  
  331. ;---------------------------------------------------------------
  332. ; Initial IV server to client: HASH(K || H || "B" || session_id)
  333.  
  334.         mov     esi, [k_h_ctx]
  335.         mov     edi, [temp_ctx]
  336.         mov     ecx, LIBCRASH_CTX_LEN/4
  337.         rep movsd
  338.         lea     edx, [session_id_x]
  339.         mov     byte[edx], 'B'
  340.         invoke  sha2_256.update, [temp_ctx], edx, SHA2_256_LEN+1
  341.         invoke  sha2_256.finish, [temp_ctx]
  342.         mov     ebx, [con_ptr]
  343.         lea     edi, [ebx + sshlib_connection.rx_iv]
  344.         mov     esi, [temp_ctx]
  345.         mov     ecx, SHA2_256_LEN/4
  346.         rep movsd
  347.  
  348. ;-------------------------------------------------------------------
  349. ; Encryption key client to server: HASH(K || H || "C" || session_id)
  350.  
  351.         mov     esi, [k_h_ctx]
  352.         mov     edi, [temp_ctx]
  353.         mov     ecx, LIBCRASH_CTX_LEN/4
  354.         rep movsd
  355.         lea     edx, [session_id_x]
  356.         mov     byte[edx], 'C'
  357.         invoke  sha2_256.update, [temp_ctx], edx, SHA2_256_LEN+1
  358.         invoke  sha2_256.finish, [temp_ctx]
  359.  
  360.         mov     ebx, [con_ptr]
  361.         lea     edi, [ebx+sshlib_connection.tx_enc_key]
  362.         mov     esi, [temp_ctx]
  363.         mov     ecx, SHA2_256_LEN/4
  364.         rep movsd
  365.  
  366.         mov     esi, [k_h_ctx]
  367.         mov     edi, [temp_ctx]
  368.         mov     ecx, LIBCRASH_CTX_LEN/4
  369.         rep movsd
  370.         mov     ebx, [con_ptr]
  371.         lea     edi, [ebx+sshlib_connection.tx_enc_key]
  372.         invoke  sha2_256.update, [temp_ctx], edi, SHA2_256_LEN
  373.         invoke  sha2_256.finish, [temp_ctx]
  374.  
  375.         mov     ebx, [con_ptr]
  376.         add     edi, 256/8
  377.         mov     esi, [temp_ctx]
  378.         mov     ecx, SHA2_256_LEN/4
  379.         rep movsd
  380.  
  381. ;-------------------------------------------------------------------
  382. ; Encryption key server to client: HASH(K || H || "D" || session_id)
  383.  
  384.         mov     esi, [k_h_ctx]
  385.         mov     edi, [temp_ctx]
  386.         mov     ecx, LIBCRASH_CTX_LEN/4
  387.         rep movsd
  388.         lea     edx, [session_id_x]
  389.         mov     byte[edx], 'D'
  390.         invoke  sha2_256.update, [temp_ctx], edx, SHA2_256_LEN+1
  391.         invoke  sha2_256.finish, [temp_ctx]
  392.  
  393.         mov     ebx, [con_ptr]
  394.         lea     edi, [ebx+sshlib_connection.rx_enc_key]
  395.         mov     esi, [temp_ctx]
  396.         mov     ecx, SHA2_256_LEN/4
  397.         rep movsd
  398.  
  399.         mov     esi, [k_h_ctx]
  400.         mov     edi, [temp_ctx]
  401.         mov     ecx, LIBCRASH_CTX_LEN/4
  402.         rep movsd
  403.         mov     ebx, [con_ptr]
  404.         lea     edi, [ebx+sshlib_connection.rx_enc_key]
  405.         invoke  sha2_256.update, [temp_ctx], edi, SHA2_256_LEN
  406.         invoke  sha2_256.finish, [temp_ctx]
  407.  
  408.         mov     ebx, [con_ptr]
  409.         add     edi, 256/8
  410.         mov     esi, [temp_ctx]
  411.         mov     ecx, SHA2_256_LEN/4
  412.         rep movsd
  413.  
  414. ;------------------------------------------------------------------
  415. ; Integrity key client to server: HASH(K || H || "E" || session_id)
  416.  
  417.         mov     esi, [k_h_ctx]
  418.         mov     edi, [temp_ctx]
  419.         mov     ecx, LIBCRASH_CTX_LEN/4
  420.         rep movsd
  421.         lea     edx, [session_id_x]
  422.         mov     byte[edx], 'E'
  423.         invoke  sha2_256.update, [temp_ctx], edx, SHA2_256_LEN+1
  424.         invoke  sha2_256.finish, [temp_ctx]
  425.         mov     ebx, [con_ptr]
  426.         lea     edi, [ebx + sshlib_connection.tx_int_key]
  427.         mov     esi, [temp_ctx]
  428.         mov     ecx, SHA2_256_LEN/4
  429.         rep movsd
  430.  
  431. ;------------------------------------------------------------------
  432. ; Integrity key server to client: HASH(K || H || "F" || session_id)
  433.  
  434.         mov     esi, [k_h_ctx]
  435.         mov     edi, [temp_ctx]
  436.         mov     ecx, LIBCRASH_CTX_LEN/4
  437.         rep movsd
  438.         lea     edx, [session_id_x]
  439.         mov     byte[edx], 'F'
  440.         invoke  sha2_256.update, [temp_ctx], edx, SHA2_256_LEN+1
  441.         invoke  sha2_256.finish, [temp_ctx]
  442.         mov     ebx, [con_ptr]
  443.         lea     edi, [ebx + sshlib_connection.rx_int_key]
  444.         mov     esi, [temp_ctx]
  445.         mov     ecx, SHA2_256_LEN/4
  446.         rep movsd
  447.  
  448.         mov     ebx, [con_ptr]
  449.         mov     [ebx + sshlib_connection.status], SSHLIB_CON_STAT_KEX_DONE
  450.         xor     eax, eax
  451.  
  452.   .err:
  453.         push    eax
  454.         xor     eax, eax
  455.         mov     ecx, (7*(MAX_BITS/8+4) + 2*LIBCRASH_CTX_LEN + 1*SHA2_256_LEN )/4
  456.         mov     edi, [mpint_tmp]
  457.         rep stosd
  458.  
  459.         mcall   68, 13, [mpint_tmp]
  460.         pop     eax
  461.         ret
  462.  
  463.   .err_hostkey_verification:
  464.         DEBUGF  3, "Hostkey verification failed!\n"
  465.         jmp     .err
  466.  
  467.   .err_nomem:
  468.         DEBUGF  3, "Out of memory during key exchange!\n"
  469.         mov     eax, SSHLIB_ERR_NOMEM
  470.         ret
  471.  
  472.   .err_proto:
  473.         DEBUGF  3, "Protocol error during key exchange!\n"
  474.         mov     eax, SSHLIB_ERR_PROTOCOL
  475.         jmp     .err
  476.  
  477. endp
  478.