Subversion Repositories Kolibri OS

Rev

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

  1. ;    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. ; TODO: dont convert mpints to little endian immediately.
  21. ; Or maybe even better, not at all.
  22.  
  23. proc dh_gex
  24.  
  25. locals
  26.         dh_f_big        dd ?
  27. endl
  28.  
  29. ;----------------------------------------------
  30. ; >> Send Diffie-Hellman Group Exchange Request
  31.  
  32.         DEBUGF  2, "Sending GEX\n"
  33.         stdcall ssh_send_packet, con, ssh_gex_req, ssh_gex_req.length, 0
  34.         cmp     eax, -1
  35.         je      .socket_err
  36.  
  37. ;---------------------------------------------
  38. ; << Parse Diffie-Hellman Group Exchange Group
  39.  
  40.         stdcall ssh_recv_packet, con, 0
  41.         cmp     eax, -1
  42.         je      .socket_err
  43.  
  44.         cmp     [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_GROUP
  45.         jne     proto_err
  46.         DEBUGF  2, "Received GEX group\n"
  47.  
  48.         mov     esi, con.rx_buffer+sizeof.ssh_packet_header
  49.         DEBUGF  1, "DH modulus (p): "
  50.         stdcall mpint_to_little_endian, con.dh_p, esi
  51.         add     esi, 4
  52.         add     esi, eax
  53.         stdcall mpint_print, con.dh_p
  54.  
  55.         DEBUGF  1, "DH base (g): "
  56.         stdcall mpint_to_little_endian, con.dh_g, esi
  57.         add     esi, 4
  58.         add     esi, eax
  59.         stdcall mpint_print, con.dh_g
  60.  
  61. ;-------------------------------------------
  62. ; >> Send Diffie-Hellman Group Exchange Init
  63.  
  64. ; generate a random number x, where 1 < x < (p-1)/2
  65.         mov     edi, con.dh_x+4
  66.         mov     [con.dh_x], DH_PRIVATE_KEY_SIZE/8
  67.         mov     ecx, DH_PRIVATE_KEY_SIZE/8/4
  68.   @@:
  69.         push    ecx
  70.         call    MBRandom
  71.         pop     ecx
  72.         stosd
  73.         dec     ecx
  74.         jnz     @r
  75.  
  76. ; If the highest bit is set, add a zero byte
  77.         shl     eax, 1
  78.         jnc     @f
  79.         mov     byte[edi], 0
  80.         inc     dword[con.dh_x]
  81.   @@:
  82.  
  83.         DEBUGF  1, "DH x: "
  84.         stdcall mpint_print, con.dh_x
  85.  
  86. ; Compute e = g^x mod p
  87.         stdcall mpint_modexp, con.dh_e, con.dh_g, con.dh_x, con.dh_p
  88.         stdcall mpint_shrink, con.dh_e
  89.  
  90.         DEBUGF  1, "DH e: "
  91.         stdcall mpint_print, con.dh_e
  92.  
  93. ; Create group exchange init packet
  94.         mov     edi, con.tx_buffer.message_code
  95.         mov     al, SSH_MSG_KEX_DH_GEX_INIT
  96.         stosb
  97.         stdcall mpint_to_big_endian, edi, con.dh_e
  98.  
  99.         DEBUGF  2, "Sending GEX init\n"
  100.         mov     ecx, dword[con.tx_buffer.message_code+1]
  101.         bswap   ecx
  102.         add     ecx, 5
  103.         stdcall ssh_send_packet, con, con.tx_buffer.message_code, ecx, 0
  104.         cmp     eax, -1
  105.         je      .socket_err
  106.  
  107. ;---------------------------------------------
  108. ; << Parse Diffie-Hellman Group Exchange Reply
  109.  
  110.         stdcall ssh_recv_packet, con, 0
  111.         cmp     eax, -1
  112.         je      .socket_err
  113.  
  114.         cmp     [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_REPLY
  115.         jne     .proto_err
  116.  
  117.         DEBUGF  2, "Received GEX Reply\n"
  118.  
  119. ;--------------------------------
  120. ; HASH: string K_S, the host key
  121.         mov     esi, con.rx_buffer+sizeof.ssh_packet_header
  122.         mov     edx, [esi]
  123.         bswap   edx
  124.         add     edx, 4
  125.         lea     ebx, [esi+edx]
  126.         mov     [dh_f_big], ebx
  127.         invoke  sha256_update, con.temp_ctx, esi, edx
  128.  
  129. ;--------------------------------------------------------------------------
  130. ; HASH: uint32 min, minimal size in bits of an acceptable group
  131. ;       uint32 n, preferred size in bits of the group the server will send
  132. ;       uint32 max, maximal size in bits of an acceptable group
  133.         invoke  sha256_update, con.temp_ctx, ssh_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12
  134.  
  135. ;----------------------------
  136. ; HASH: mpint p, safe prime
  137.         stdcall mpint_shrink, con.dh_p
  138.         stdcall mpint_to_big_endian, con.mpint_tmp, con.dh_p
  139.         lea     edx, [eax+4]
  140.         invoke  sha256_update, con.temp_ctx, con.mpint_tmp, edx
  141.  
  142. ;----------------------------------------
  143. ; HASH: mpint g, generator for subgroup
  144.         stdcall mpint_shrink, con.dh_g
  145.         stdcall mpint_to_big_endian, con.mpint_tmp, con.dh_g
  146.         lea     edx, [eax+4]
  147.         invoke  sha256_update, con.temp_ctx, con.mpint_tmp, edx
  148.  
  149. ;---------------------------------------------------
  150. ; HASH: mpint e, exchange value sent by the client
  151.         mov     esi, con.tx_buffer+sizeof.ssh_packet_header
  152.         mov     edx, [esi]
  153.         bswap   edx
  154.         add     edx, 4
  155.         invoke  sha256_update, con.temp_ctx, esi, edx
  156.  
  157. ;---------------------------------------------------
  158. ; HASH: mpint f, exchange value sent by the server
  159.         mov     esi, [dh_f_big]
  160.         mov     edx, [esi]
  161.         bswap   edx
  162.         add     edx, 4
  163.         invoke  sha256_update, con.temp_ctx, esi, edx
  164.  
  165.         stdcall mpint_to_little_endian, con.dh_f, [dh_f_big]
  166.         mov     esi, [dh_f_big]
  167.         add     esi, eax
  168.         add     esi, 4
  169.         DEBUGF  1, "DH f: "
  170.         stdcall mpint_print, con.dh_f
  171.  
  172.         stdcall mpint_to_little_endian, con.dh_signature, esi
  173.         DEBUGF  1, "DH signature: "
  174.         stdcall mpint_print, con.dh_signature
  175.  
  176. ;--------------------------------------
  177. ; Calculate shared secret K = f^x mod p
  178.         stdcall mpint_modexp, con.rx_buffer, con.dh_f, con.dh_x, con.dh_p
  179.         stdcall mpint_shrink, con.rx_buffer
  180.  
  181.         DEBUGF  1, "DH K: "
  182.         stdcall mpint_print, con.rx_buffer
  183.  
  184. ; We always need it in big endian order, so store it as such.
  185.         stdcall mpint_to_big_endian, con.dh_K, con.rx_buffer
  186.         mov     [con.dh_K_length], eax
  187.  
  188. ;-----------------------------------
  189. ; HASH: mpint K, the shared secret
  190.         mov     edx, [con.dh_K_length]
  191.         add     edx, 4
  192.         invoke  sha256_update, con.temp_ctx, con.dh_K, edx
  193.  
  194. ;-------------------------------
  195. ; Finalize the exchange hash (H)
  196.         invoke  sha256_final, con.temp_ctx
  197.         mov     esi, con.temp_ctx.hash
  198.         mov     edi, con.dh_H
  199.         mov     ecx, SHA256_HASH_SIZE/4
  200.         rep movsd
  201.  
  202.         DEBUGF  1, "Exchange hash H: "
  203.         stdcall dump_hex, con.dh_H, 8
  204.  
  205. ; TODO: skip this block when re-keying
  206.         mov     esi, con.dh_H
  207.         mov     edi, con.session_id
  208.         mov     ecx, SHA256_HASH_SIZE/4
  209.         rep movsd
  210.  
  211. ;---------------
  212. ; Calculate keys
  213.  
  214. ; First, calculate partial hash of K and H so we can re-use it for every key.
  215.  
  216.         invoke  sha256_init, con.k_h_ctx
  217.  
  218.         mov     edx, [con.dh_K_length]
  219.         add     edx, 4
  220.         invoke  sha256_update, con.k_h_ctx, con.dh_K, edx
  221.         invoke  sha256_update, con.k_h_ctx, con.dh_H, 32
  222.  
  223. ;---------------------------------------------------------------
  224. ; Initial IV client to server: HASH(K || H || "A" || session_id)
  225.  
  226.         mov     esi, con.k_h_ctx
  227.         mov     edi, con.temp_ctx
  228.         mov     ecx, sizeof.crash_ctx/4
  229.         rep movsd
  230.         mov     [con.session_id_prefix], 'A'
  231.         invoke  sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
  232.         invoke  sha256_final, con.temp_ctx.hash
  233.         mov     edi, con.tx_iv
  234.         mov     esi, con.temp_ctx
  235.         mov     ecx, SHA256_HASH_SIZE/4
  236.         rep movsd
  237.  
  238.         DEBUGF  1, "Remote IV: "
  239.         stdcall dump_hex, con.tx_iv, 8
  240.  
  241. ;---------------------------------------------------------------
  242. ; Initial IV server to client: HASH(K || H || "B" || session_id)
  243.  
  244.         mov     esi, con.k_h_ctx
  245.         mov     edi, con.temp_ctx
  246.         mov     ecx, sizeof.crash_ctx/4
  247.         rep movsd
  248.         inc     [con.session_id_prefix]
  249.         invoke  sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
  250.         invoke  sha256_final, con.temp_ctx
  251.         mov     edi, con.rx_iv
  252.         mov     esi, con.temp_ctx
  253.         mov     ecx, SHA256_HASH_SIZE/4
  254.         rep movsd
  255.  
  256.         DEBUGF  1, "Local IV: "
  257.         stdcall dump_hex, con.rx_iv, 8
  258.  
  259. ;-------------------------------------------------------------------
  260. ; Encryption key client to server: HASH(K || H || "C" || session_id)
  261.  
  262.         mov     esi, con.k_h_ctx
  263.         mov     edi, con.temp_ctx
  264.         mov     ecx, sizeof.crash_ctx/4
  265.         rep movsd
  266.         inc     [con.session_id_prefix]
  267.         invoke  sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
  268.         invoke  sha256_final, con.temp_ctx
  269.         mov     edi, con.tx_enc_key
  270.         mov     esi, con.temp_ctx
  271.         mov     ecx, SHA256_HASH_SIZE/4
  272.         rep movsd
  273.  
  274.         DEBUGF  1, "Remote key: "
  275.         stdcall dump_hex, con.tx_enc_key, 8
  276.  
  277. ;-------------------------------------------------------------------
  278. ; Encryption key server to client: HASH(K || H || "D" || session_id)
  279.  
  280.         mov     esi, con.k_h_ctx
  281.         mov     edi, con.temp_ctx
  282.         mov     ecx, sizeof.crash_ctx/4
  283.         rep movsd
  284.         inc     [con.session_id_prefix]
  285.         invoke  sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
  286.         invoke  sha256_final, con.temp_ctx
  287.         mov     edi, con.rx_enc_key
  288.         mov     esi, con.temp_ctx
  289.         mov     ecx, SHA256_HASH_SIZE/4
  290.         rep movsd
  291.  
  292.         DEBUGF  1, "Local key: "
  293.         stdcall dump_hex, con.rx_enc_key, 8
  294.  
  295. ;------------------------------------------------------------------
  296. ; Integrity key client to server: HASH(K || H || "E" || session_id)
  297.  
  298.         mov     esi, con.k_h_ctx
  299.         mov     edi, con.temp_ctx
  300.         mov     ecx, sizeof.crash_ctx/4
  301.         rep movsd
  302.         inc     [con.session_id_prefix]
  303.         invoke  sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
  304.         invoke  sha256_final, con.temp_ctx
  305.         mov     edi, con.tx_int_key
  306.         mov     esi, con.temp_ctx
  307.         mov     ecx, SHA256_HASH_SIZE/4
  308.         rep movsd
  309.  
  310.         DEBUGF  1, "Remote Integrity key: "
  311.         stdcall dump_hex, con.tx_int_key, 8
  312.  
  313. ;------------------------------------------------------------------
  314. ; Integrity key server to client: HASH(K || H || "F" || session_id)
  315.  
  316.         mov     esi, con.k_h_ctx
  317.         mov     edi, con.temp_ctx
  318.         mov     ecx, sizeof.crash_ctx/4
  319.         rep movsd
  320.         inc     [con.session_id_prefix]
  321.         invoke  sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
  322.         invoke  sha256_final, con.temp_ctx
  323.         mov     edi, con.rx_int_key
  324.         mov     esi, con.temp_ctx
  325.         mov     ecx, SHA256_HASH_SIZE/4
  326.         rep movsd
  327.  
  328.         DEBUGF  1, "Local Integrity key: "
  329.         stdcall dump_hex, con.rx_int_key, 8
  330.  
  331. ;-------------------------------------
  332. ; << Parse Diffie-Hellman New Keys MSG
  333.  
  334.         stdcall ssh_recv_packet, con, 0
  335.         cmp     eax, -1
  336.         je      .socket_err
  337.  
  338.         cmp     [con.rx_buffer.message_code], SSH_MSG_NEWKEYS
  339.         jne     .proto_err
  340.  
  341.         DEBUGF  2, "Received New Keys\n"
  342.  
  343. ;-------------------------------
  344. ; >> Reply with New Keys message
  345.  
  346.         stdcall ssh_send_packet, con, ssh_new_keys, ssh_new_keys.length, 0
  347.  
  348.         xor     eax, eax
  349.         ret
  350.  
  351.   .socket_err:
  352.         DEBUGF  3, "Socket error during key exchange!\n"
  353.         mov     eax, 1
  354.         ret
  355.  
  356.   .proto_err:
  357.         DEBUGF  3, "Protocol error during key exchange!\n"
  358.         mov     eax, 2
  359.         ret
  360.  
  361. endp
  362.