Subversion Repositories Kolibri OS

Rev

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

  1. ;    sshlib_host.inc - SSH remote host authentication
  2. ;
  3. ;    Copyright (C) 2021-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://datatracker.ietf.org/doc/html/rfc4253#section-6.6
  19. ; https://datatracker.ietf.org/doc/html/rfc3447
  20. ; https://datatracker.ietf.org/doc/html/rfc4716
  21. ; https://datatracker.ietf.org/doc/html/rfc8017
  22.  
  23. proc sshlib_host_verify  con_ptr, str_host_key, str_signature, message, message_len
  24.  
  25. locals
  26.         current_hkb64           rb MAX_PUBLIC_KEY_SIZE*4        ; Current Host key in Base64
  27.         cached_hkb64            rb MAX_PUBLIC_KEY_SIZE*4        ; Cached Host key in Base64
  28.         key_name_sz             dd ?
  29.         hostname_sz             dd ?
  30.         current_hk64_end        dd ?
  31. endl
  32.  
  33.         DEBUGF  2, "Verifying host key\n"
  34.  
  35.         mov     eax, [con_ptr]
  36.         lea     ebx, [eax + sshlib_connection.hostname_sz]
  37.         mov     [hostname_sz], ebx
  38.         cmp     [eax+sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA_SHA1
  39.         je      .rsa
  40.         cmp     [eax+sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA_SHA2_256
  41.         je      .rsa
  42.         cmp     [eax+sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA_SHA2_512
  43.         je      .rsa
  44.         mov     eax, SSHLIB_ERR_HKEY_NO_ALGO
  45.         ret
  46.  
  47.   .rsa:
  48.         stdcall sshlib_host_verify_rsa, [con_ptr], [str_host_key], [str_signature], [message], [message_len]
  49.         test    eax, eax
  50.         jnz     .err
  51.         mov     [key_name_sz], ssh_rsa_sz
  52.  
  53.   .lookup:
  54. ; Convert the current host key to base64
  55.         mov     esi, [str_host_key]
  56.         mov     ecx, [esi]
  57.         bswap   ecx
  58.         add     esi, 4
  59.         lea     edi, [current_hkb64]
  60.         call    base64_encode
  61.         mov     [current_hk64_end], edi
  62.  
  63. ; Try to read the cached key for this host and key type
  64.         lea     edi, [cached_hkb64]
  65.         invoke  ini_get_str, known_hostsfile, [hostname_sz], [key_name_sz], edi, MAX_PUBLIC_KEY_SIZE*4, 0
  66.         test    eax, eax
  67.         jnz     .unknown
  68. ; If the cached key is empty, return SSHLIB_HOSTKEY_PROBLEM_UNKNOWN
  69.         lea     esi, [cached_hkb64]
  70.         cmp     byte[esi], 0
  71.         je      .unknown
  72. ; Else, compare it to the current one
  73.         lea     edi, [current_hkb64]
  74.         mov     ecx, MAX_PUBLIC_KEY_SIZE*4
  75.   .cmploop:
  76.         lodsb
  77.         scasb
  78.         jne     .mismatch
  79.         test    al, al
  80.         jz      .match
  81.         dec     ecx
  82.         jnz     .cmploop
  83.         jmp     .mismatch
  84.  
  85.   .match:
  86.         xor     eax, eax
  87.         ret
  88.  
  89.   .mismatch:
  90.         lea     eax, [current_hkb64]
  91.         stdcall sshlib_callback_hostkey_problem, [con_ptr], SSHLIB_HOSTKEY_PROBLEM_MISMATCH, eax
  92.         cmp     eax, SSHLIB_HOSTKEY_ACCEPT
  93.         je      .store
  94.         ret
  95.  
  96.   .unknown:
  97.         lea     eax, [current_hkb64]
  98.         stdcall sshlib_callback_hostkey_problem, [con_ptr], SSHLIB_HOSTKEY_PROBLEM_UNKNOWN, eax
  99.         cmp     eax, SSHLIB_HOSTKEY_ACCEPT
  100.         je      .store
  101.         ret
  102.  
  103.   .store:
  104.         lea     esi, [current_hkb64]
  105.         mov     ecx, [current_hk64_end]
  106.         sub     ecx, esi
  107.         invoke  ini_set_str, known_hostsfile, [hostname_sz], [key_name_sz], esi, ecx
  108.         xor     eax, eax
  109.         ret
  110.  
  111.   .err:
  112.         ret
  113.  
  114. endp
  115.  
  116.  
  117. ; https://datatracker.ietf.org/doc/html/rfc3447#section-8.2.2
  118. ; RSASSA-PKCS1-V1_5-VERIFY
  119. proc sshlib_host_verify_rsa con_ptr, str_host_key, str_signature, M, message_len
  120.  
  121. locals
  122.         h_ctx                   dd ?
  123.  
  124. ; Signer's RSA public key
  125.         mpint_e                 dd ?    ; public exponent
  126.         mpint_n                 dd ?    ; modulus
  127.  
  128.         mpint_m                 dd ?
  129.  
  130.         EM                      dd ?
  131.         EM_accent               dd ?
  132.  
  133.         mpint_s                 dd ?    ; rsa_signature_blob
  134.  
  135.         k                       dd ?    ; Key length
  136.  
  137. endl
  138.  
  139.         DEBUGF  3, "SSH: Performing RSA verification\n"
  140.  
  141.         mcall   68, 12, LIBCRASH_CTX_LEN + 5*(MAX_BITS/8+4)
  142.         test    eax, eax
  143.         jz      .err_nomem
  144.         mov     [h_ctx], eax
  145.         add     eax, LIBCRASH_CTX_LEN
  146.         mov     [mpint_e], eax
  147.         add     eax, MAX_BITS/8+4
  148.         mov     [mpint_n], eax
  149.         add     eax, MAX_BITS/8+4
  150.         mov     [mpint_m], eax
  151.         add     eax, MAX_BITS/8+4
  152.         mov     [EM], eax
  153.         add     eax, MAX_BITS/8+4
  154.         mov     [EM_accent], eax
  155.         add     eax, MAX_BITS/8+4
  156.         mov     [mpint_s], eax
  157. ;        add     eax, MAX_BITS/8+4
  158.  
  159. ; Host key
  160.         mov     esi, [str_host_key]
  161.         mov     ecx, [esi]
  162.         bswap   ecx
  163.         cmp     ecx, MAX_PUBLIC_KEY_SIZE
  164.         ja      .err_key
  165. ; Host key type (string)
  166.         cmp     dword[esi+4], 0x07000000
  167.         jne     .err_key
  168.         cmp     dword[esi+8], 'ssh-'
  169.         jne     .err_key
  170.         cmp     dword[esi+11], '-rsa'
  171.         jne     .err_key
  172.         add     esi, 4+4+7
  173. ; mpint e
  174.         stdcall mpint_to_little_endian, [mpint_e], esi
  175.         add     esi, eax
  176.         add     esi, 4
  177. ; mpint n
  178.         stdcall mpint_to_little_endian, [mpint_n], esi
  179.         and     eax, not (32-1)         ; CHECKME
  180.         mov     [k], eax
  181.  
  182. ; Signature
  183.         mov     esi, [str_signature]
  184.         mov     ecx, [esi]
  185.         bswap   ecx                     ; TODO: check length
  186.  
  187. ; Host key type (string)
  188.         cmp     dword[esi+4], 0x07000000
  189.         jne     .not_ssh_rsa
  190.         cmp     dword[esi+8], 'ssh-'
  191.         jne     .not_ssh_rsa
  192.         cmp     dword[esi+11], '-rsa'
  193.         je      .sha1
  194.  
  195.   .not_ssh_rsa:
  196.         cmp     dword[esi+4], 0x0c000000
  197.         jne     .not_sha2
  198.         cmp     dword[esi+8], 'rsa-'
  199.         jne     .not_sha2
  200.         cmp     dword[esi+12], 'sha2'
  201.         jne     .not_sha2
  202.         cmp     dword[esi+16], '-256'
  203.         je      .sha2_256
  204.         cmp     dword[esi+16], '-512'
  205.         je      .sha2_512
  206.  
  207.   .not_sha2:
  208.         jmp     .err_signature
  209.  
  210.   .sha1:
  211.         mov     eax, [con_ptr]
  212.         cmp     [eax + sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA_SHA1
  213.         jne     .err_signature
  214.  
  215.         DEBUGF  3, "SSH: Using RSA with SHA1 hash\n"
  216.         add     esi, 4+4+7
  217.         push    esi
  218.  
  219. ; EMSA-PKCS1-v1_5
  220.         invoke  sha1.init, [h_ctx]
  221.         invoke  sha1.update, [h_ctx], [M], [message_len]
  222.         invoke  sha1.finish, [h_ctx]
  223.  
  224.         mov     edi, [EM_accent]
  225.         mov     al, 0x00
  226.         stosb
  227.         mov     al, 0x01
  228.         stosb
  229.         mov     ecx, [k]
  230.         sub     ecx, (rsa_sha1_T.len + 3 + SHA1_LEN)
  231.         jl      .err_key
  232.         jz      @f
  233.         mov     al, 0xff
  234.         rep stosb
  235.   @@:
  236.         mov     al, 0x00
  237.         stosb
  238.         mov     esi, rsa_sha1_T
  239.         mov     ecx, rsa_sha1_T.len
  240.         rep movsb
  241.         mov     esi, [h_ctx]
  242.         mov     ecx, SHA1_LEN
  243.         rep movsb
  244.  
  245.         pop     esi
  246.         jmp     .rsa
  247.  
  248.   .sha2_256:
  249.         mov     eax, [con_ptr]
  250.         cmp     [eax + sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA_SHA2_256
  251.         jne     .err_signature
  252.         DEBUGF  3, "SSH: Using RSA with SHA2-256 hash\n"
  253.         add     esi, 4+4+12
  254.         push    esi
  255.  
  256. ; EMSA-PKCS1-v1_5
  257.         invoke  sha2_256.init, [h_ctx]
  258.         invoke  sha2_256.update, [h_ctx], [M], [message_len]
  259.         invoke  sha2_256.finish, [h_ctx]
  260.  
  261.         mov     edi, [EM_accent]
  262.         mov     al, 0x00
  263.         stosb
  264.         mov     al, 0x01
  265.         stosb
  266.         mov     ecx, [k]
  267.         sub     ecx, (rsa_sha256_T.len + 3 + SHA2_256_LEN)
  268.         jl      .err_key
  269.         jz      @f
  270.         mov     al, 0xff
  271.         rep stosb
  272.   @@:
  273.         mov     al, 0x00
  274.         stosb
  275.         mov     esi, rsa_sha256_T
  276.         mov     ecx, rsa_sha256_T.len
  277.         rep movsb
  278.         mov     esi, [h_ctx]
  279.         mov     ecx, SHA2_256_LEN
  280.         rep movsb
  281.  
  282.         pop     esi
  283.         jmp     .rsa
  284.  
  285.   .sha2_512:
  286.         mov     eax, [con_ptr]
  287.         cmp     [eax + sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA_SHA2_512
  288.         jne     .err_signature
  289.         DEBUGF  3, "SSH: Using RSA with SHA2-512 hash\n"
  290.         add     esi, 4+4+12
  291.         push    esi
  292.  
  293. ; EMSA-PKCS1-v1_5
  294.         invoke  sha2_512.init, [h_ctx]
  295.         invoke  sha2_512.update, [h_ctx], [M], [message_len]
  296.         invoke  sha2_512.finish, [h_ctx]
  297.  
  298.         mov     edi, [EM_accent]
  299.         mov     al, 0x00
  300.         stosb
  301.         mov     al, 0x01
  302.         stosb
  303.         mov     ecx, [k]
  304.         sub     ecx, (rsa_sha512_T.len + 3 + SHA2_512_LEN)
  305.         jl      .err_key
  306.         jz      @f
  307.         mov     al, 0xff
  308.         rep stosb
  309.   @@:
  310.         mov     al, 0x00
  311.         stosb
  312.         mov     esi, rsa_sha512_T
  313.         mov     ecx, rsa_sha512_T.len
  314.         rep movsb
  315.         mov     esi, [h_ctx]
  316.         mov     ecx, SHA2_512_LEN
  317.         rep movsb
  318.  
  319.         pop     esi
  320.         jmp     .rsa
  321.  
  322.   .rsa:
  323. ; RSA signature blob
  324.         stdcall mpint_to_little_endian, [mpint_s], esi
  325. ;        cmp     eax, [k]
  326. ;        jne     .err_signature
  327.  
  328. ; RSAVP1
  329.         stdcall mpint_modexp, [mpint_m], [mpint_s], [mpint_e], [mpint_n]
  330. ; I2OSP
  331.         stdcall mpint_shrink, [mpint_m]
  332.         stdcall mpint_grow, [mpint_m], [k]
  333.         stdcall mpint_to_big_endian, [EM], [mpint_m]
  334.  
  335. ; Compare EM with EM_accent
  336.         mov     esi, [EM]
  337.         add     esi, 4
  338.         mov     edi, [EM_accent]
  339.         mov     ecx, [k]
  340.         shr     ecx, 2
  341.         xor     eax, eax
  342.   .ct_cmp_loop:
  343.         mov     ebx, [esi]
  344.         xor     ebx, [edi]
  345.         or      eax, ebx
  346.         lea     esi, [esi+4]
  347.         lea     edi, [edi+4]
  348.         dec     ecx
  349.         jnz     .ct_cmp_loop
  350.  
  351.         push    eax
  352.         mcall   68, 13, [h_ctx]
  353.         pop     eax
  354.  
  355.         test    eax, eax
  356.         jnz     .fail
  357.  
  358.         DEBUGF  3, "SSH: RSA verification OK!\n"
  359.  
  360.         ret
  361.  
  362.   .fail:
  363.         DEBUGF  3, "SSH: RSA verification failed!\n"
  364.         mov     eax, SSHLIB_ERR_HKEY_VERIFY_FAIL
  365.         ret
  366.  
  367.   .err_nomem:
  368.         mov     eax, SSHLIB_ERR_NOMEM
  369.         ret
  370.  
  371.   .err_signature:
  372.         mov     eax, SSHLIB_ERR_HKEY_SIGNATURE
  373.         ret
  374.  
  375.   .err_key:
  376.         mov     eax, SSHLIB_ERR_HKEY_PUBLIC_KEY
  377.         ret
  378.  
  379. endp
  380.  
  381.  
  382. base64_encode:
  383.  
  384.         xor     ebx, ebx
  385.   .loop:
  386.         lodsb
  387.         call    .byte
  388.         dec     ecx
  389.         jnz     .loop
  390.  
  391.   .final:
  392.         mov     al, 0
  393.         test    ebx, ebx
  394.         jz      .f000
  395.         call    .byte
  396.         test    ebx, ebx
  397.         jz      .f001
  398.         call    .byte
  399.         mov     byte[edi-2], '='
  400.  
  401.   .f001:
  402.         mov     byte[edi-1], '='
  403.  
  404.   .f000:
  405.         mov     byte[edi], 0
  406.         ret
  407.  
  408.   .byte:
  409.         inc     ebx
  410.         shl     edx, 8
  411.         mov     dl, al
  412.         cmp     ebx, 3
  413.         je      .b001
  414.         ret
  415.  
  416.   .b001:
  417.         shl     edx, 8
  418.         inc     ebx
  419.  
  420.   .b002:
  421.         rol     edx, 6
  422.         xor     eax, eax
  423.         xchg    al, dl
  424.         mov     al, [base64_table+eax]
  425.         stosb
  426.         dec     ebx
  427.         jnz     .b002
  428.         ret
  429.  
  430.  
  431.  
  432.  
  433. iglobal
  434.  
  435.         known_hostsfile db '/sys/settings/known_hosts.ini', 0
  436.         base64_table    db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  437.         rsa_sha1_T      db 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14
  438.         .len = $ - rsa_sha1_T
  439.         rsa_sha256_T    db 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
  440.         .len = $ - rsa_sha256_T
  441.         rsa_sha512_T    db 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40
  442.         .len = $ - rsa_sha512_T
  443.         ssh_rsa_sz      db 'ssh-rsa', 0
  444.  
  445. endg
  446.  
  447.