forked from KolibriOS/kolibrios
Big refactor: separate backend from frontend. Prepare for dynamically negotiated algorithms etc.
New: RSA host authentication, use new con_get_input from console.lib to get escape codes from special keys, UTF8 to CP866 decoder, .. Bugfix: CTR counters. git-svn-id: svn://kolibrios.org@9106 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
ec273ce904
commit
67b03ef814
@ -16,12 +16,15 @@
|
|||||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
struct aes256_ctr_context aes256_context
|
struct aes256_ctr_context aes256_context
|
||||||
|
|
||||||
counter rb AES256_BLOCKSIZE
|
counter rb AES256_BLOCKSIZE
|
||||||
output rb AES256_BLOCKSIZE ; counter after aes_crypt
|
output rb AES256_BLOCKSIZE ; counter after aes_crypt
|
||||||
|
|
||||||
ends
|
ends
|
||||||
|
|
||||||
|
|
||||||
proc aes256_ctr_init _counter
|
proc aes256_ctr_init _counter
|
||||||
|
|
||||||
push ebx esi edi
|
push ebx esi edi
|
||||||
|
|
||||||
mcall 68, 12, sizeof.aes256_ctr_context
|
mcall 68, 12, sizeof.aes256_ctr_context
|
||||||
@ -34,6 +37,7 @@ proc aes256_ctr_init _counter
|
|||||||
|
|
||||||
pop edi esi ebx
|
pop edi esi ebx
|
||||||
ret
|
ret
|
||||||
|
|
||||||
endp
|
endp
|
||||||
|
|
||||||
|
|
||||||
@ -84,7 +88,7 @@ proc aes256_ctr_crypt _ctx, _in, _out
|
|||||||
bswap ecx
|
bswap ecx
|
||||||
bswap edx
|
bswap edx
|
||||||
|
|
||||||
inc edx
|
adc edx, 1
|
||||||
adc ecx, 0
|
adc ecx, 0
|
||||||
adc ebx, 0
|
adc ebx, 0
|
||||||
adc eax, 0
|
adc eax, 0
|
||||||
|
@ -84,7 +84,7 @@ proc blowfish_ctr_crypt _ctx, _in, _out
|
|||||||
bswap ecx
|
bswap ecx
|
||||||
bswap edx
|
bswap edx
|
||||||
|
|
||||||
inc edx
|
adc edx, 1
|
||||||
adc ecx, 0
|
adc ecx, 0
|
||||||
adc ebx, 0
|
adc ebx, 0
|
||||||
adc eax, 0
|
adc eax, 0
|
||||||
|
@ -1,361 +0,0 @@
|
|||||||
; dh_gex.inc - Diffie Hellman Group exchange
|
|
||||||
;
|
|
||||||
; Copyright (C) 2015-2021 Jeffrey Amelynck
|
|
||||||
;
|
|
||||||
; This program is free software: you can redistribute it and/or modify
|
|
||||||
; it under the terms of the GNU General Public License as published by
|
|
||||||
; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
; (at your option) any later version.
|
|
||||||
;
|
|
||||||
; This program is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
; https://www.ietf.org/rfc/rfc4419.txt
|
|
||||||
|
|
||||||
; TODO: dont convert mpints to little endian immediately.
|
|
||||||
; Or maybe even better, not at all.
|
|
||||||
|
|
||||||
proc dh_gex
|
|
||||||
|
|
||||||
locals
|
|
||||||
dh_f_big dd ?
|
|
||||||
endl
|
|
||||||
|
|
||||||
;----------------------------------------------
|
|
||||||
; >> Send Diffie-Hellman Group Exchange Request
|
|
||||||
|
|
||||||
DEBUGF 2, "Sending GEX\n"
|
|
||||||
stdcall ssh_send_packet, con, ssh_gex_req, ssh_gex_req.length, 0
|
|
||||||
cmp eax, -1
|
|
||||||
je .socket_err
|
|
||||||
|
|
||||||
;---------------------------------------------
|
|
||||||
; << Parse Diffie-Hellman Group Exchange Group
|
|
||||||
|
|
||||||
stdcall ssh_recv_packet, con, 0
|
|
||||||
cmp eax, -1
|
|
||||||
je .socket_err
|
|
||||||
|
|
||||||
cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_GROUP
|
|
||||||
jne proto_err
|
|
||||||
DEBUGF 2, "Received GEX group\n"
|
|
||||||
|
|
||||||
mov esi, con.rx_buffer+sizeof.ssh_packet_header
|
|
||||||
DEBUGF 1, "DH modulus (p): "
|
|
||||||
stdcall mpint_to_little_endian, con.dh_p, esi
|
|
||||||
add esi, 4
|
|
||||||
add esi, eax
|
|
||||||
stdcall mpint_print, con.dh_p
|
|
||||||
|
|
||||||
DEBUGF 1, "DH base (g): "
|
|
||||||
stdcall mpint_to_little_endian, con.dh_g, esi
|
|
||||||
add esi, 4
|
|
||||||
add esi, eax
|
|
||||||
stdcall mpint_print, con.dh_g
|
|
||||||
|
|
||||||
;-------------------------------------------
|
|
||||||
; >> Send Diffie-Hellman Group Exchange Init
|
|
||||||
|
|
||||||
; generate a random number x, where 1 < x < (p-1)/2
|
|
||||||
mov edi, con.dh_x+4
|
|
||||||
mov [con.dh_x], DH_PRIVATE_KEY_SIZE/8
|
|
||||||
mov ecx, DH_PRIVATE_KEY_SIZE/8/4
|
|
||||||
@@:
|
|
||||||
push ecx
|
|
||||||
call MBRandom
|
|
||||||
pop ecx
|
|
||||||
stosd
|
|
||||||
dec ecx
|
|
||||||
jnz @r
|
|
||||||
|
|
||||||
; If the highest bit is set, add a zero byte
|
|
||||||
shl eax, 1
|
|
||||||
jnc @f
|
|
||||||
mov byte[edi], 0
|
|
||||||
inc dword[con.dh_x]
|
|
||||||
@@:
|
|
||||||
|
|
||||||
DEBUGF 1, "DH x: "
|
|
||||||
stdcall mpint_print, con.dh_x
|
|
||||||
|
|
||||||
; Compute e = g^x mod p
|
|
||||||
stdcall mpint_modexp, con.dh_e, con.dh_g, con.dh_x, con.dh_p
|
|
||||||
stdcall mpint_shrink, con.dh_e
|
|
||||||
|
|
||||||
DEBUGF 1, "DH e: "
|
|
||||||
stdcall mpint_print, con.dh_e
|
|
||||||
|
|
||||||
; Create group exchange init packet
|
|
||||||
mov edi, con.tx_buffer.message_code
|
|
||||||
mov al, SSH_MSG_KEX_DH_GEX_INIT
|
|
||||||
stosb
|
|
||||||
stdcall mpint_to_big_endian, edi, con.dh_e
|
|
||||||
|
|
||||||
DEBUGF 2, "Sending GEX init\n"
|
|
||||||
mov ecx, dword[con.tx_buffer.message_code+1]
|
|
||||||
bswap ecx
|
|
||||||
add ecx, 5
|
|
||||||
stdcall ssh_send_packet, con, con.tx_buffer.message_code, ecx, 0
|
|
||||||
cmp eax, -1
|
|
||||||
je .socket_err
|
|
||||||
|
|
||||||
;---------------------------------------------
|
|
||||||
; << Parse Diffie-Hellman Group Exchange Reply
|
|
||||||
|
|
||||||
stdcall ssh_recv_packet, con, 0
|
|
||||||
cmp eax, -1
|
|
||||||
je .socket_err
|
|
||||||
|
|
||||||
cmp [con.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_REPLY
|
|
||||||
jne .proto_err
|
|
||||||
|
|
||||||
DEBUGF 2, "Received GEX Reply\n"
|
|
||||||
|
|
||||||
;--------------------------------
|
|
||||||
; HASH: string K_S, the host key
|
|
||||||
mov esi, con.rx_buffer+sizeof.ssh_packet_header
|
|
||||||
mov edx, [esi]
|
|
||||||
bswap edx
|
|
||||||
add edx, 4
|
|
||||||
lea ebx, [esi+edx]
|
|
||||||
mov [dh_f_big], ebx
|
|
||||||
invoke sha256_update, con.temp_ctx, esi, edx
|
|
||||||
|
|
||||||
;--------------------------------------------------------------------------
|
|
||||||
; HASH: uint32 min, minimal size in bits of an acceptable group
|
|
||||||
; uint32 n, preferred size in bits of the group the server will send
|
|
||||||
; uint32 max, maximal size in bits of an acceptable group
|
|
||||||
invoke sha256_update, con.temp_ctx, ssh_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12
|
|
||||||
|
|
||||||
;----------------------------
|
|
||||||
; HASH: mpint p, safe prime
|
|
||||||
stdcall mpint_shrink, con.dh_p
|
|
||||||
stdcall mpint_to_big_endian, con.mpint_tmp, con.dh_p
|
|
||||||
lea edx, [eax+4]
|
|
||||||
invoke sha256_update, con.temp_ctx, con.mpint_tmp, edx
|
|
||||||
|
|
||||||
;----------------------------------------
|
|
||||||
; HASH: mpint g, generator for subgroup
|
|
||||||
stdcall mpint_shrink, con.dh_g
|
|
||||||
stdcall mpint_to_big_endian, con.mpint_tmp, con.dh_g
|
|
||||||
lea edx, [eax+4]
|
|
||||||
invoke sha256_update, con.temp_ctx, con.mpint_tmp, edx
|
|
||||||
|
|
||||||
;---------------------------------------------------
|
|
||||||
; HASH: mpint e, exchange value sent by the client
|
|
||||||
mov esi, con.tx_buffer+sizeof.ssh_packet_header
|
|
||||||
mov edx, [esi]
|
|
||||||
bswap edx
|
|
||||||
add edx, 4
|
|
||||||
invoke sha256_update, con.temp_ctx, esi, edx
|
|
||||||
|
|
||||||
;---------------------------------------------------
|
|
||||||
; HASH: mpint f, exchange value sent by the server
|
|
||||||
mov esi, [dh_f_big]
|
|
||||||
mov edx, [esi]
|
|
||||||
bswap edx
|
|
||||||
add edx, 4
|
|
||||||
invoke sha256_update, con.temp_ctx, esi, edx
|
|
||||||
|
|
||||||
stdcall mpint_to_little_endian, con.dh_f, [dh_f_big]
|
|
||||||
mov esi, [dh_f_big]
|
|
||||||
add esi, eax
|
|
||||||
add esi, 4
|
|
||||||
DEBUGF 1, "DH f: "
|
|
||||||
stdcall mpint_print, con.dh_f
|
|
||||||
|
|
||||||
stdcall mpint_to_little_endian, con.dh_signature, esi
|
|
||||||
DEBUGF 1, "DH signature: "
|
|
||||||
stdcall mpint_print, con.dh_signature
|
|
||||||
|
|
||||||
;--------------------------------------
|
|
||||||
; Calculate shared secret K = f^x mod p
|
|
||||||
stdcall mpint_modexp, con.rx_buffer, con.dh_f, con.dh_x, con.dh_p
|
|
||||||
stdcall mpint_shrink, con.rx_buffer
|
|
||||||
|
|
||||||
DEBUGF 1, "DH K: "
|
|
||||||
stdcall mpint_print, con.rx_buffer
|
|
||||||
|
|
||||||
; We always need it in big endian order, so store it as such.
|
|
||||||
stdcall mpint_to_big_endian, con.dh_K, con.rx_buffer
|
|
||||||
mov [con.dh_K_length], eax
|
|
||||||
|
|
||||||
;-----------------------------------
|
|
||||||
; HASH: mpint K, the shared secret
|
|
||||||
mov edx, [con.dh_K_length]
|
|
||||||
add edx, 4
|
|
||||||
invoke sha256_update, con.temp_ctx, con.dh_K, edx
|
|
||||||
|
|
||||||
;-------------------------------
|
|
||||||
; Finalize the exchange hash (H)
|
|
||||||
invoke sha256_final, con.temp_ctx
|
|
||||||
mov esi, con.temp_ctx.hash
|
|
||||||
mov edi, con.dh_H
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
DEBUGF 1, "Exchange hash H: "
|
|
||||||
stdcall dump_hex, con.dh_H, 8
|
|
||||||
|
|
||||||
; TODO: skip this block when re-keying
|
|
||||||
mov esi, con.dh_H
|
|
||||||
mov edi, con.session_id
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
;---------------
|
|
||||||
; Calculate keys
|
|
||||||
|
|
||||||
; First, calculate partial hash of K and H so we can re-use it for every key.
|
|
||||||
|
|
||||||
invoke sha256_init, con.k_h_ctx
|
|
||||||
|
|
||||||
mov edx, [con.dh_K_length]
|
|
||||||
add edx, 4
|
|
||||||
invoke sha256_update, con.k_h_ctx, con.dh_K, edx
|
|
||||||
invoke sha256_update, con.k_h_ctx, con.dh_H, 32
|
|
||||||
|
|
||||||
;---------------------------------------------------------------
|
|
||||||
; Initial IV client to server: HASH(K || H || "A" || session_id)
|
|
||||||
|
|
||||||
mov esi, con.k_h_ctx
|
|
||||||
mov edi, con.temp_ctx
|
|
||||||
mov ecx, sizeof.crash_ctx/4
|
|
||||||
rep movsd
|
|
||||||
mov [con.session_id_prefix], 'A'
|
|
||||||
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
|
|
||||||
invoke sha256_final, con.temp_ctx.hash
|
|
||||||
mov edi, con.tx_iv
|
|
||||||
mov esi, con.temp_ctx
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
DEBUGF 1, "Remote IV: "
|
|
||||||
stdcall dump_hex, con.tx_iv, 8
|
|
||||||
|
|
||||||
;---------------------------------------------------------------
|
|
||||||
; Initial IV server to client: HASH(K || H || "B" || session_id)
|
|
||||||
|
|
||||||
mov esi, con.k_h_ctx
|
|
||||||
mov edi, con.temp_ctx
|
|
||||||
mov ecx, sizeof.crash_ctx/4
|
|
||||||
rep movsd
|
|
||||||
inc [con.session_id_prefix]
|
|
||||||
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
|
|
||||||
invoke sha256_final, con.temp_ctx
|
|
||||||
mov edi, con.rx_iv
|
|
||||||
mov esi, con.temp_ctx
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
DEBUGF 1, "Local IV: "
|
|
||||||
stdcall dump_hex, con.rx_iv, 8
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------
|
|
||||||
; Encryption key client to server: HASH(K || H || "C" || session_id)
|
|
||||||
|
|
||||||
mov esi, con.k_h_ctx
|
|
||||||
mov edi, con.temp_ctx
|
|
||||||
mov ecx, sizeof.crash_ctx/4
|
|
||||||
rep movsd
|
|
||||||
inc [con.session_id_prefix]
|
|
||||||
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
|
|
||||||
invoke sha256_final, con.temp_ctx
|
|
||||||
mov edi, con.tx_enc_key
|
|
||||||
mov esi, con.temp_ctx
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
DEBUGF 1, "Remote key: "
|
|
||||||
stdcall dump_hex, con.tx_enc_key, 8
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------
|
|
||||||
; Encryption key server to client: HASH(K || H || "D" || session_id)
|
|
||||||
|
|
||||||
mov esi, con.k_h_ctx
|
|
||||||
mov edi, con.temp_ctx
|
|
||||||
mov ecx, sizeof.crash_ctx/4
|
|
||||||
rep movsd
|
|
||||||
inc [con.session_id_prefix]
|
|
||||||
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
|
|
||||||
invoke sha256_final, con.temp_ctx
|
|
||||||
mov edi, con.rx_enc_key
|
|
||||||
mov esi, con.temp_ctx
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
DEBUGF 1, "Local key: "
|
|
||||||
stdcall dump_hex, con.rx_enc_key, 8
|
|
||||||
|
|
||||||
;------------------------------------------------------------------
|
|
||||||
; Integrity key client to server: HASH(K || H || "E" || session_id)
|
|
||||||
|
|
||||||
mov esi, con.k_h_ctx
|
|
||||||
mov edi, con.temp_ctx
|
|
||||||
mov ecx, sizeof.crash_ctx/4
|
|
||||||
rep movsd
|
|
||||||
inc [con.session_id_prefix]
|
|
||||||
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
|
|
||||||
invoke sha256_final, con.temp_ctx
|
|
||||||
mov edi, con.tx_int_key
|
|
||||||
mov esi, con.temp_ctx
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
DEBUGF 1, "Remote Integrity key: "
|
|
||||||
stdcall dump_hex, con.tx_int_key, 8
|
|
||||||
|
|
||||||
;------------------------------------------------------------------
|
|
||||||
; Integrity key server to client: HASH(K || H || "F" || session_id)
|
|
||||||
|
|
||||||
mov esi, con.k_h_ctx
|
|
||||||
mov edi, con.temp_ctx
|
|
||||||
mov ecx, sizeof.crash_ctx/4
|
|
||||||
rep movsd
|
|
||||||
inc [con.session_id_prefix]
|
|
||||||
invoke sha256_update, con.temp_ctx, con.session_id_prefix, 32+1
|
|
||||||
invoke sha256_final, con.temp_ctx
|
|
||||||
mov edi, con.rx_int_key
|
|
||||||
mov esi, con.temp_ctx
|
|
||||||
mov ecx, SHA256_HASH_SIZE/4
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
DEBUGF 1, "Local Integrity key: "
|
|
||||||
stdcall dump_hex, con.rx_int_key, 8
|
|
||||||
|
|
||||||
;-------------------------------------
|
|
||||||
; << Parse Diffie-Hellman New Keys MSG
|
|
||||||
|
|
||||||
stdcall ssh_recv_packet, con, 0
|
|
||||||
cmp eax, -1
|
|
||||||
je .socket_err
|
|
||||||
|
|
||||||
cmp [con.rx_buffer.message_code], SSH_MSG_NEWKEYS
|
|
||||||
jne .proto_err
|
|
||||||
|
|
||||||
DEBUGF 2, "Received New Keys\n"
|
|
||||||
|
|
||||||
;-------------------------------
|
|
||||||
; >> Reply with New Keys message
|
|
||||||
|
|
||||||
stdcall ssh_send_packet, con, ssh_new_keys, ssh_new_keys.length, 0
|
|
||||||
|
|
||||||
xor eax, eax
|
|
||||||
ret
|
|
||||||
|
|
||||||
.socket_err:
|
|
||||||
DEBUGF 3, "Socket error during key exchange!\n"
|
|
||||||
mov eax, 1
|
|
||||||
ret
|
|
||||||
|
|
||||||
.proto_err:
|
|
||||||
DEBUGF 3, "Protocol error during key exchange!\n"
|
|
||||||
mov eax, 2
|
|
||||||
ret
|
|
||||||
|
|
||||||
endp
|
|
292
programs/network/ssh/encodings.inc
Normal file
292
programs/network/ssh/encodings.inc
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; ;;
|
||||||
|
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
|
||||||
|
;; Distributed under terms of the GNU General Public License ;;
|
||||||
|
;; ;;
|
||||||
|
;; Written by CleverMouse ;;
|
||||||
|
;; ;;
|
||||||
|
;; GNU GENERAL PUBLIC LICENSE ;;
|
||||||
|
;; Version 2, June 1991 ;;
|
||||||
|
;; ;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
uglobal
|
||||||
|
|
||||||
|
utf8_bytes_rest dd ? ; bytes rest in current UTF8 sequence
|
||||||
|
utf8_char dd ? ; first bits of current UTF8 character
|
||||||
|
|
||||||
|
endg
|
||||||
|
|
||||||
|
|
||||||
|
;get_next_byte:
|
||||||
|
;; Load next byte from the packet, translating to cp866 if necessary
|
||||||
|
;; At input esi = pointer to data, edx = limit of data
|
||||||
|
;; Output is either (translated) byte in al with CF set or CF cleared.
|
||||||
|
; mov eax, [encoding]
|
||||||
|
; jmp [get_byte_table+eax*4]
|
||||||
|
;
|
||||||
|
;get_byte_cp866:
|
||||||
|
; cmp esi, edx
|
||||||
|
; jae .nothing
|
||||||
|
; lodsb
|
||||||
|
;.nothing:
|
||||||
|
; ret
|
||||||
|
;
|
||||||
|
;get_byte_cp1251:
|
||||||
|
; cmp esi, edx
|
||||||
|
; jae .nothing
|
||||||
|
; lodsb
|
||||||
|
; cmp al, 0x80
|
||||||
|
; jb @f
|
||||||
|
; and eax, 0x7F
|
||||||
|
; mov al, [cp1251_table+eax]
|
||||||
|
;@@:
|
||||||
|
; stc
|
||||||
|
;.nothing:
|
||||||
|
; ret
|
||||||
|
|
||||||
|
get_byte_utf8:
|
||||||
|
; UTF8 decoding is slightly complicated.
|
||||||
|
; One character can occupy one or more bytes.
|
||||||
|
; The boundary in packets theoretically can be anywhere in data,
|
||||||
|
; so this procedure keeps internal state between calls and handles
|
||||||
|
; one byte at a time, looping until character is read or packet is over.
|
||||||
|
; Globally, there are two distinct tasks: decode byte sequence to unicode char
|
||||||
|
; and convert this unicode char to our base encoding (that is cp866).
|
||||||
|
; 1. Check that there are data.
|
||||||
|
cmp esi, edx
|
||||||
|
jae .nothing
|
||||||
|
; 2. Load byte.
|
||||||
|
lodsb
|
||||||
|
movzx ecx, al
|
||||||
|
; 3. Bytes in an UTF8 sequence can be of any of three types.
|
||||||
|
; If most significant bit is cleared, sequence is one byte and usual ASCII char.
|
||||||
|
; First byte of a sequence must be 11xxxxxx, other bytes are 10yyyyyy.
|
||||||
|
and al, 0xC0
|
||||||
|
jns .single_byte
|
||||||
|
jp .first_byte
|
||||||
|
; 4. This byte is not first in UTF8 sequence.
|
||||||
|
; 4a. Check that the sequence was started. If no, it is invalid byte
|
||||||
|
; and we simply ignore it.
|
||||||
|
cmp [utf8_bytes_rest], 0
|
||||||
|
jz get_byte_utf8
|
||||||
|
; 4b. Otherwise, it is really next byte and it gives some more bits of char.
|
||||||
|
mov eax, [utf8_char]
|
||||||
|
shl eax, 6
|
||||||
|
lea eax, [eax+ecx-0x80]
|
||||||
|
; 4c. Decrement number of bytes rest in the sequence.
|
||||||
|
; If it goes to zero, character is read, so return it.
|
||||||
|
dec [utf8_bytes_rest]
|
||||||
|
jz .got_char
|
||||||
|
mov [utf8_char], eax
|
||||||
|
jmp get_byte_utf8
|
||||||
|
; 5. If the byte is first in UTF8 sequence, calculate the number of leading 1s
|
||||||
|
; - it equals total number of bytes in the sequence; some other bits rest for
|
||||||
|
; leading bits in the character.
|
||||||
|
.first_byte:
|
||||||
|
mov eax, -1
|
||||||
|
@@:
|
||||||
|
inc eax
|
||||||
|
add cl, cl
|
||||||
|
js @b
|
||||||
|
mov [utf8_bytes_rest], eax
|
||||||
|
xchg eax, ecx
|
||||||
|
inc ecx
|
||||||
|
shr al, cl
|
||||||
|
mov [utf8_char], eax
|
||||||
|
jmp get_byte_utf8
|
||||||
|
; 6. If the byte is ASCII char, it is the character.
|
||||||
|
.single_byte:
|
||||||
|
xchg eax, ecx
|
||||||
|
.got_char:
|
||||||
|
; We got the character, now abandon a possible sequence in progress.
|
||||||
|
and [utf8_bytes_rest], 0
|
||||||
|
; Now second task. The unicode character is in eax, and now we shall convert it
|
||||||
|
; to cp866.
|
||||||
|
cmp eax, 0x80
|
||||||
|
jb .done
|
||||||
|
; 0x410-0x43F -> 0x80-0xAF, 0x440-0x44F -> 0xE0-0xEF, 0x401 -> 0xF0, 0x451 -> 0xF1
|
||||||
|
cmp eax, 0x401
|
||||||
|
jz .YO
|
||||||
|
cmp eax, 0x451
|
||||||
|
jz .yo
|
||||||
|
cmp eax, 0x410
|
||||||
|
jb .unrecognized
|
||||||
|
cmp eax, 0x440
|
||||||
|
jb .part1
|
||||||
|
cmp eax, 0x450
|
||||||
|
jb .part2
|
||||||
|
cmp eax, 0x25a0
|
||||||
|
jae .unrecognized
|
||||||
|
sub eax, 0x2500
|
||||||
|
jb .unrecognized
|
||||||
|
mov al, [cp866_boxes+eax]
|
||||||
|
ret
|
||||||
|
.part1:
|
||||||
|
sub al, 0x10-0x80
|
||||||
|
.nothing:
|
||||||
|
.done:
|
||||||
|
ret
|
||||||
|
.part2:
|
||||||
|
sub al, (0x40-0xE0) and 0xFF
|
||||||
|
ret
|
||||||
|
.unrecognized:
|
||||||
|
mov al, '?'
|
||||||
|
stc
|
||||||
|
ret
|
||||||
|
.YO:
|
||||||
|
mov al, 0xF0
|
||||||
|
stc
|
||||||
|
ret
|
||||||
|
.yo:
|
||||||
|
mov al, 0xF1
|
||||||
|
stc
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;recode_to_cp866:
|
||||||
|
; rep movsb
|
||||||
|
; ret
|
||||||
|
;
|
||||||
|
;recode_to_cp1251:
|
||||||
|
; xor eax, eax
|
||||||
|
; jecxz .nothing
|
||||||
|
; .loop:
|
||||||
|
; lodsb
|
||||||
|
; cmp al,0x80
|
||||||
|
; jb @f
|
||||||
|
; mov al, [cp866_table-0x80+eax]
|
||||||
|
; @@: stosb
|
||||||
|
; loop .loop
|
||||||
|
; .nothing:
|
||||||
|
; ret
|
||||||
|
|
||||||
|
recode_to_utf8:
|
||||||
|
jecxz .nothing
|
||||||
|
.loop:
|
||||||
|
lodsb
|
||||||
|
cmp al, 0x80
|
||||||
|
jb .single_byte
|
||||||
|
and eax, 0x7F
|
||||||
|
mov ax, [utf8_table+eax*2]
|
||||||
|
stosw
|
||||||
|
loop .loop
|
||||||
|
ret
|
||||||
|
.single_byte:
|
||||||
|
stosb
|
||||||
|
loop .loop
|
||||||
|
.nothing:
|
||||||
|
ret
|
||||||
|
|
||||||
|
;recode:
|
||||||
|
; mov eax, [encoding]
|
||||||
|
; jmp [recode_proc+eax*4]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;encoding dd UTF8
|
||||||
|
;recode_proc dd recode_to_cp866, recode_to_cp1251, recode_to_utf8
|
||||||
|
;get_byte_table dd get_byte_cp866, get_byte_cp1251, get_byte_utf8
|
||||||
|
|
||||||
|
|
||||||
|
;cp1251_table:
|
||||||
|
; db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; 8
|
||||||
|
; db '?','?','?','?','?',$F9,'?','?' , '?','?','?','?','?','?','?','?' ; 9
|
||||||
|
; db '?',$F6,$F7,'?',$FD,'?','?','?' , $F0,'?',$F2,'?','?','?','?',$F4 ; A
|
||||||
|
; db $F8,'?','?','?','?','?','?',$FA , $F1,$FC,$F3,'?','?','?','?',$F5 ; B
|
||||||
|
; db $80,$81,$82,$83,$84,$85,$86,$87 , $88,$89,$8A,$8B,$8C,$8D,$8E,$8F ; C
|
||||||
|
; db $90,$91,$92,$93,$94,$95,$96,$97 , $98,$99,$9A,$9B,$9C,$9D,$9E,$9F ; D
|
||||||
|
; db $A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7 , $A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF ; E
|
||||||
|
; db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; F
|
||||||
|
|
||||||
|
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
|
||||||
|
utf8_table:
|
||||||
|
times 80h dw 0x98C3 ; default placeholder
|
||||||
|
|
||||||
|
; 0x80-0xAF -> 0x90D0-0xBFD0
|
||||||
|
repeat 0x30
|
||||||
|
store byte 0xD0 at utf8_table+2*(%-1)
|
||||||
|
store byte 0x90+%-1 at utf8_table+2*%-1
|
||||||
|
end repeat
|
||||||
|
|
||||||
|
; 0xE0-0xEF -> 0x80D1-0x8FD1
|
||||||
|
repeat 0x10
|
||||||
|
store byte 0xD1 at utf8_table+2*(0xE0-0x80+%-1)
|
||||||
|
store byte 0x80+%-1 at utf8_table+2*(0xE0-0x80+%)-1
|
||||||
|
end repeat
|
||||||
|
|
||||||
|
; 0xF0 -> 0x81D0, 0xF1 -> 0x91D1
|
||||||
|
store dword 0x91D181D0 at utf8_table+2*(0xF0-0x80)
|
||||||
|
|
||||||
|
;cp866_table:
|
||||||
|
; db $C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7 , $C8,$C9,$CA,$CB,$CC,$CD,$CE,$CF ; 8
|
||||||
|
; db $D0,$D1,$D2,$D3,$D4,$D5,$D6,$D7 , $D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF ; 9
|
||||||
|
; db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; A
|
||||||
|
; db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; B
|
||||||
|
; db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; C
|
||||||
|
; db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; D
|
||||||
|
; db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7 , $F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF ; E
|
||||||
|
; db $A8,$B8,$AA,$BA,$AF,$BF,$A1,$A2 , $B0,$95,$B7,'?',$B9,$A4,'?','?' ; F
|
||||||
|
|
||||||
|
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
|
||||||
|
|
||||||
|
; Codepoints for 0xB0-0xDF, unicode offset 0x2500
|
||||||
|
cp866_boxes:
|
||||||
|
times 0xA0 db '?'
|
||||||
|
|
||||||
|
store byte 0xB0 at cp866_boxes+0x91
|
||||||
|
store byte 0xB1 at cp866_boxes+0x92
|
||||||
|
store byte 0xB2 at cp866_boxes+0x93
|
||||||
|
store byte 0xB3 at cp866_boxes+0x02
|
||||||
|
store byte 0xB4 at cp866_boxes+0x24
|
||||||
|
store byte 0xB5 at cp866_boxes+0x61
|
||||||
|
store byte 0xB6 at cp866_boxes+0x62
|
||||||
|
store byte 0xB7 at cp866_boxes+0x56
|
||||||
|
|
||||||
|
store byte 0xB8 at cp866_boxes+0x55
|
||||||
|
store byte 0xB9 at cp866_boxes+0x63
|
||||||
|
store byte 0xBA at cp866_boxes+0x51
|
||||||
|
store byte 0xBB at cp866_boxes+0x57
|
||||||
|
store byte 0xBC at cp866_boxes+0x5D
|
||||||
|
store byte 0xBD at cp866_boxes+0x5C
|
||||||
|
store byte 0xBE at cp866_boxes+0x5B
|
||||||
|
store byte 0xBF at cp866_boxes+0x10
|
||||||
|
|
||||||
|
store byte 0xC0 at cp866_boxes+0x14
|
||||||
|
store byte 0xC1 at cp866_boxes+0x34
|
||||||
|
store byte 0xC2 at cp866_boxes+0x2C
|
||||||
|
store byte 0xC3 at cp866_boxes+0x1C
|
||||||
|
store byte 0xC4 at cp866_boxes+0x00
|
||||||
|
store byte 0xC5 at cp866_boxes+0x3C
|
||||||
|
store byte 0xC6 at cp866_boxes+0x5E
|
||||||
|
store byte 0xC7 at cp866_boxes+0x5F
|
||||||
|
|
||||||
|
store byte 0xC8 at cp866_boxes+0x5A
|
||||||
|
store byte 0xC9 at cp866_boxes+0x54
|
||||||
|
store byte 0xCA at cp866_boxes+0x69
|
||||||
|
store byte 0xCB at cp866_boxes+0x66
|
||||||
|
store byte 0xCC at cp866_boxes+0x60
|
||||||
|
store byte 0xCD at cp866_boxes+0x50
|
||||||
|
store byte 0xCE at cp866_boxes+0x6C
|
||||||
|
store byte 0xCF at cp866_boxes+0x67
|
||||||
|
|
||||||
|
store byte 0xD0 at cp866_boxes+0x68
|
||||||
|
store byte 0xD1 at cp866_boxes+0x64
|
||||||
|
store byte 0xD2 at cp866_boxes+0x65
|
||||||
|
store byte 0xD3 at cp866_boxes+0x59
|
||||||
|
store byte 0xD4 at cp866_boxes+0x58
|
||||||
|
store byte 0xD5 at cp866_boxes+0x52
|
||||||
|
store byte 0xD6 at cp866_boxes+0x53
|
||||||
|
store byte 0xD7 at cp866_boxes+0x6B
|
||||||
|
|
||||||
|
store byte 0xD8 at cp866_boxes+0x6A
|
||||||
|
store byte 0xD9 at cp866_boxes+0x18
|
||||||
|
store byte 0xDA at cp866_boxes+0x0C
|
||||||
|
store byte 0xDB at cp866_boxes+0x88
|
||||||
|
store byte 0xDC at cp866_boxes+0x84
|
||||||
|
store byte 0xDD at cp866_boxes+0x8C
|
||||||
|
store byte 0xDE at cp866_boxes+0x90
|
||||||
|
store byte 0xDF at cp866_boxes+0x80
|
File diff suppressed because it is too large
Load Diff
@ -1,274 +0,0 @@
|
|||||||
; ssh_transport.inc - SSH transport layer
|
|
||||||
;
|
|
||||||
; Copyright (C) 2016-2021 Jeffrey Amelynck
|
|
||||||
;
|
|
||||||
; This program is free software: you can redistribute it and/or modify
|
|
||||||
; it under the terms of the GNU General Public License as published by
|
|
||||||
; the Free Software Foundation, either version 3 of the License, or
|
|
||||||
; (at your option) any later version.
|
|
||||||
;
|
|
||||||
; This program is distributed in the hope that it will be useful,
|
|
||||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
; GNU General Public License for more details.
|
|
||||||
;
|
|
||||||
; You should have received a copy of the GNU General Public License
|
|
||||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
struct ssh_packet_header
|
|
||||||
packet_length dd ? ; The length of the packet in bytes, not including 'mac' or the
|
|
||||||
; 'packet_length' field itself.
|
|
||||||
padding_length db ? ; Length of 'random padding' (bytes).
|
|
||||||
|
|
||||||
message_code db ? ; First byte of payload
|
|
||||||
ends
|
|
||||||
|
|
||||||
proc padding_zero
|
|
||||||
|
|
||||||
xor eax, eax
|
|
||||||
ret
|
|
||||||
|
|
||||||
endp
|
|
||||||
|
|
||||||
proc ssh_recv_packet connection, flags
|
|
||||||
|
|
||||||
locals
|
|
||||||
data_length dd ? ; Total length of packet without MAC
|
|
||||||
socket_error dd ?
|
|
||||||
endl
|
|
||||||
|
|
||||||
DEBUGF 2, "> "
|
|
||||||
; Receive first block (Read length, padding length, message code)
|
|
||||||
mov ebx, [connection]
|
|
||||||
mov ecx, [ebx+ssh_connection.socketnum]
|
|
||||||
mov esi, [ebx+ssh_connection.rx_crypt_blocksize]
|
|
||||||
lea edx, [ebx+ssh_connection.rx_buffer]
|
|
||||||
mov edi, [flags]
|
|
||||||
mcall recv
|
|
||||||
mov [socket_error], ebx
|
|
||||||
DEBUGF 1, "chunk = %u ", eax
|
|
||||||
mov ebx, [connection]
|
|
||||||
cmp eax, [ebx+ssh_connection.rx_crypt_blocksize]
|
|
||||||
jne .fail
|
|
||||||
|
|
||||||
; Decrypt first block
|
|
||||||
cmp [ebx+ssh_connection.rx_crypt_proc], 0
|
|
||||||
je @f
|
|
||||||
pusha
|
|
||||||
lea esi, [ebx+ssh_connection.rx_buffer]
|
|
||||||
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
|
|
||||||
popa
|
|
||||||
@@:
|
|
||||||
|
|
||||||
; Check data length
|
|
||||||
mov esi, [ebx+ssh_connection.rx_buffer.packet_length]
|
|
||||||
bswap esi ; convert length to little endian
|
|
||||||
mov [ebx+ssh_connection.rx_buffer.packet_length], esi
|
|
||||||
DEBUGF 1, "packet length=%u ", esi
|
|
||||||
cmp esi, BUFFERSIZE
|
|
||||||
ja .fail ; packet is too large
|
|
||||||
|
|
||||||
; Calculate amount of remaining data
|
|
||||||
add esi, 4 ; Packet length field itself is not included in the count
|
|
||||||
sub esi, [ebx+ssh_connection.rx_crypt_blocksize] ; Already received this amount of data
|
|
||||||
add esi, [ebx+ssh_connection.rx_mac_length]
|
|
||||||
jz .got_all_data
|
|
||||||
|
|
||||||
; Receive remaining data
|
|
||||||
lea edx, [ebx+ssh_connection.rx_buffer]
|
|
||||||
add edx, [ebx+ssh_connection.rx_crypt_blocksize]
|
|
||||||
mov ecx, [ebx+ssh_connection.socketnum]
|
|
||||||
mov edi, [flags]
|
|
||||||
.receive_loop:
|
|
||||||
mcall recv
|
|
||||||
DEBUGF 1, "chunk = %u ", eax
|
|
||||||
cmp eax, 0
|
|
||||||
jbe .fail
|
|
||||||
add edx, eax
|
|
||||||
sub esi, eax
|
|
||||||
jnz .receive_loop
|
|
||||||
|
|
||||||
; Decrypt data
|
|
||||||
mov ebx, [connection]
|
|
||||||
cmp [ebx+ssh_connection.rx_crypt_proc], 0
|
|
||||||
je .decrypt_complete
|
|
||||||
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length]
|
|
||||||
add ecx, 4 ; Packet_length field itself
|
|
||||||
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize] ; Already decrypted this amount of data
|
|
||||||
jz .decrypt_complete
|
|
||||||
|
|
||||||
lea esi, [ebx+ssh_connection.rx_buffer]
|
|
||||||
add esi, [ebx+ssh_connection.rx_crypt_blocksize]
|
|
||||||
.decrypt_loop:
|
|
||||||
pusha
|
|
||||||
stdcall [ebx+ssh_connection.rx_crypt_proc], [ebx+ssh_connection.rx_crypt_ctx_ptr], esi, esi
|
|
||||||
popa
|
|
||||||
add esi, [ebx+ssh_connection.rx_crypt_blocksize]
|
|
||||||
sub ecx, [ebx+ssh_connection.rx_crypt_blocksize]
|
|
||||||
jnz .decrypt_loop
|
|
||||||
.decrypt_complete:
|
|
||||||
|
|
||||||
; Authenticate message
|
|
||||||
cmp [ebx+ssh_connection.rx_mac_proc], 0
|
|
||||||
je .mac_complete
|
|
||||||
lea esi, [ebx+ssh_connection.rx_seq]
|
|
||||||
mov ecx, [ebx+ssh_connection.rx_buffer.packet_length]
|
|
||||||
add ecx, 8 ; packet_length field itself + sequence number
|
|
||||||
lea eax, [ebx+ssh_connection.rx_mac_ctx]
|
|
||||||
mov edx, [ebx+ssh_connection.rx_buffer.packet_length]
|
|
||||||
bswap edx ; convert length to big endian
|
|
||||||
mov [ebx+ssh_connection.rx_buffer.packet_length], edx
|
|
||||||
stdcall [ebx+ssh_connection.rx_mac_proc], eax, esi, ecx
|
|
||||||
mov edx, [ebx+ssh_connection.rx_buffer.packet_length]
|
|
||||||
bswap edx ; convert length to little endian
|
|
||||||
mov [ebx+ssh_connection.rx_buffer.packet_length], edx
|
|
||||||
|
|
||||||
lea esi, [ebx+ssh_connection.rx_mac_ctx]
|
|
||||||
lea edi, [ebx+ssh_connection.rx_buffer]
|
|
||||||
add edi, [ebx+ssh_connection.rx_buffer.packet_length]
|
|
||||||
add edi, 4
|
|
||||||
mov ecx, [ebx+ssh_connection.rx_mac_length]
|
|
||||||
shr ecx, 2
|
|
||||||
repe cmpsd
|
|
||||||
jne .mac_failed
|
|
||||||
.mac_complete:
|
|
||||||
add byte[ebx+ssh_connection.rx_seq+3], 1 ; Update sequence counter
|
|
||||||
adc byte[ebx+ssh_connection.rx_seq+2], 0
|
|
||||||
adc byte[ebx+ssh_connection.rx_seq+1], 0
|
|
||||||
adc byte[ebx+ssh_connection.rx_seq+0], 0
|
|
||||||
|
|
||||||
; Return useful data length to the caller via eax register
|
|
||||||
.got_all_data:
|
|
||||||
mov eax, [ebx+ssh_connection.rx_buffer.packet_length]
|
|
||||||
movzx ebx, [ebx+ssh_connection.rx_buffer.padding_length]
|
|
||||||
sub eax, ebx
|
|
||||||
DEBUGF 1, "useful data length=%u\n", eax
|
|
||||||
ret
|
|
||||||
|
|
||||||
.fail:
|
|
||||||
DEBUGF 3, "ssh_recv_packet failed!\n"
|
|
||||||
mov eax, -1
|
|
||||||
mov ebx, [socket_error]
|
|
||||||
ret
|
|
||||||
|
|
||||||
.mac_failed:
|
|
||||||
DEBUGF 3, "ssh_recv_packet MAC failed!\n"
|
|
||||||
mov eax, -2
|
|
||||||
mov ebx, [socket_error]
|
|
||||||
ret
|
|
||||||
|
|
||||||
endp
|
|
||||||
|
|
||||||
|
|
||||||
proc ssh_send_packet connection, buf, payload_size, flags
|
|
||||||
|
|
||||||
locals
|
|
||||||
packet_size dd ?
|
|
||||||
endl
|
|
||||||
DEBUGF 2, "< "
|
|
||||||
|
|
||||||
; Check how many bytes we should pad
|
|
||||||
mov eax, [payload_size]
|
|
||||||
inc eax ; padding length byte
|
|
||||||
lea edx, [eax+4] ; total packet size (without padding and MAC)
|
|
||||||
mov [packet_size], edx
|
|
||||||
|
|
||||||
mov ecx, [connection]
|
|
||||||
mov ebx, [ecx+ssh_connection.tx_pad_size]
|
|
||||||
dec ebx
|
|
||||||
and edx, ebx
|
|
||||||
neg edx
|
|
||||||
add edx, [ecx+ssh_connection.tx_pad_size]
|
|
||||||
add edx, [ecx+ssh_connection.tx_pad_size]
|
|
||||||
DEBUGF 1, "padding %u bytes ", edx
|
|
||||||
add [packet_size], edx ; total packet size with padding
|
|
||||||
|
|
||||||
; Start building the packet
|
|
||||||
; First comes the packet length, in network byte order ofcourse.
|
|
||||||
add eax, edx
|
|
||||||
DEBUGF 1, "total size: %u ", eax
|
|
||||||
bswap eax
|
|
||||||
lea edi, [ecx+ssh_connection.tx_buffer]
|
|
||||||
stosd
|
|
||||||
; Then the padding length
|
|
||||||
mov al, dl
|
|
||||||
stosb
|
|
||||||
; And the actual payload bytes
|
|
||||||
mov esi, [buf]
|
|
||||||
mov ecx, [payload_size]
|
|
||||||
rep movsb
|
|
||||||
|
|
||||||
; Append the packet with #edx padding bytes.
|
|
||||||
; Since we must pad at least 8 bytes, we can always use DWORD writes.
|
|
||||||
; First do an (unaligned) write exactly following the data
|
|
||||||
dec edx
|
|
||||||
mov esi, edx
|
|
||||||
shr esi, 2 ; number dwords
|
|
||||||
mov ebx, edx
|
|
||||||
and ebx, 3
|
|
||||||
inc ebx ; number bytes in first write (1-4)
|
|
||||||
mov edx, [connection]
|
|
||||||
call [edx+ssh_connection.tx_pad_proc]
|
|
||||||
mov dword[edi], eax
|
|
||||||
add edi, ebx
|
|
||||||
; Then, do as many aligned writes as nescessary
|
|
||||||
mov ebx, [connection]
|
|
||||||
@@:
|
|
||||||
call [ebx+ssh_connection.tx_pad_proc]
|
|
||||||
stosd
|
|
||||||
dec esi
|
|
||||||
jnz @r
|
|
||||||
|
|
||||||
; Append the packet with Message Authentication Code
|
|
||||||
mov edx, [connection]
|
|
||||||
cmp [edx+ssh_connection.tx_mac_proc], 0
|
|
||||||
je .mac_complete
|
|
||||||
DEBUGF 1, "MAC sequence number: 0x%x\n", [edx+ssh_connection.tx_seq]
|
|
||||||
lea esi, [edx+ssh_connection.tx_seq]
|
|
||||||
mov ecx, [packet_size]
|
|
||||||
add ecx, 4 ; Sequence number length
|
|
||||||
lea eax, [edx+ssh_connection.tx_mac_ctx]
|
|
||||||
stdcall [edx+ssh_connection.tx_mac_proc], eax, esi, ecx
|
|
||||||
|
|
||||||
lea esi, [edx+ssh_connection.tx_mac_ctx]
|
|
||||||
lea edi, [edx+ssh_connection.tx_buffer]
|
|
||||||
add edi, [packet_size]
|
|
||||||
mov ecx, [edx+ssh_connection.tx_mac_length]
|
|
||||||
shr ecx, 2
|
|
||||||
rep movsd
|
|
||||||
.mac_complete:
|
|
||||||
add byte[edx+ssh_connection.tx_seq+3], 1 ; Update sequence counter
|
|
||||||
adc byte[edx+ssh_connection.tx_seq+2], 0
|
|
||||||
adc byte[edx+ssh_connection.tx_seq+1], 0
|
|
||||||
adc byte[edx+ssh_connection.tx_seq+0], 0
|
|
||||||
|
|
||||||
; Now, encrypt everything but MAC
|
|
||||||
cmp [edx+ssh_connection.tx_crypt_proc], 0
|
|
||||||
je .encrypt_complete
|
|
||||||
lea esi, [edx+ssh_connection.tx_buffer]
|
|
||||||
mov ecx, [packet_size]
|
|
||||||
.encrypt_loop:
|
|
||||||
pusha
|
|
||||||
stdcall [edx+ssh_connection.tx_crypt_proc], [edx+ssh_connection.tx_crypt_ctx_ptr], esi, esi
|
|
||||||
popa
|
|
||||||
add esi, [edx+ssh_connection.tx_crypt_blocksize]
|
|
||||||
sub ecx, [edx+ssh_connection.tx_crypt_blocksize]
|
|
||||||
jnz .encrypt_loop
|
|
||||||
.encrypt_complete:
|
|
||||||
|
|
||||||
; Send the packet
|
|
||||||
mov ebx, [connection]
|
|
||||||
mov ecx, [ebx+ssh_connection.socketnum]
|
|
||||||
lea edx, [ebx+ssh_connection.tx_buffer]
|
|
||||||
mov esi, [packet_size]
|
|
||||||
add esi, [ebx+ssh_connection.tx_mac_length]
|
|
||||||
mov edi, [flags]
|
|
||||||
mcall send
|
|
||||||
|
|
||||||
DEBUGF 1, "\n"
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
endp
|
|
||||||
|
|
155
programs/network/ssh/sshlib.inc
Normal file
155
programs/network/ssh/sshlib.inc
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
; sshlib.inc - SSHlib constants
|
||||||
|
;
|
||||||
|
; Copyright (C) 2016-2021 Jeffrey Amelynck
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
; Error codes
|
||||||
|
|
||||||
|
SSHLIB_ERR_NOMEM = -1
|
||||||
|
SSHLIB_ERR_SOCKET = -2
|
||||||
|
SSHLIB_ERR_PROTOCOL = -3
|
||||||
|
SSHLIB_ERR_HOSTNAME = -4
|
||||||
|
SSHLIB_ERR_DISCONNECTING = -5
|
||||||
|
SSHLIB_ERR_MAC_VERIFY_FAIL = -6
|
||||||
|
SSHLIB_ERR_HKEY_NO_ALGO = -7
|
||||||
|
SSHLIB_ERR_HKEY_VERIFY_FAIL = -8
|
||||||
|
SSHLIB_ERR_HKEY_SIGNATURE = -9
|
||||||
|
SSHLIB_ERR_HKEY_PUBLIC_KEY = -10
|
||||||
|
|
||||||
|
; Channel status codes
|
||||||
|
|
||||||
|
SSHLIB_CHAN_STAT_CONNECTING = 0
|
||||||
|
SSHLIB_CHAN_STAT_CONNECTED = 1
|
||||||
|
SSHLIB_CHAN_STAT_EOF_RECEIVED = 2
|
||||||
|
SSHLIB_CHAN_STAT_CLOSING = 3
|
||||||
|
SSHLIB_CHAN_STAT_CLOSED = 3
|
||||||
|
|
||||||
|
; Connection status codes
|
||||||
|
|
||||||
|
SSHLIB_CON_STAT_INIT = 0
|
||||||
|
SSHLIB_CON_STAT_KEX_DONE = 1
|
||||||
|
|
||||||
|
; Algorithm identifier codes
|
||||||
|
|
||||||
|
SSHLIB_ALGO_NONE = 0
|
||||||
|
|
||||||
|
SSHLIB_KEX_DH_SHA1 = 1
|
||||||
|
SSHLIB_KEX_DH_SHA256 = 2
|
||||||
|
|
||||||
|
SSHLIB_HOSTKEY_DSS = 1
|
||||||
|
SSHLIB_HOSTKEY_RSA = 2
|
||||||
|
SSHLIB_HOSTKEY_RSA_SHA2_256 = 3
|
||||||
|
SSHLIB_HOSTKEY_RSA_SHA2_512 = 4
|
||||||
|
|
||||||
|
SSHLIB_CRYPT_BLOWFISH_CTR = 1
|
||||||
|
SSHLIB_CRYPT_BLOWFISH_CBC = 2
|
||||||
|
SSHLIB_CRYPT_AES128_CTR = 3
|
||||||
|
SSHLIB_CRYPT_AES128_CBC = 4
|
||||||
|
SSHLIB_CRYPT_AES192_CTR = 5
|
||||||
|
SSHLIB_CRYPT_AES192_CBC = 6
|
||||||
|
SSHLIB_CRYPT_AES256_CTR = 7
|
||||||
|
SSHLIB_CRYPT_AES256_CBC = 8
|
||||||
|
|
||||||
|
SSHLIB_HMAC_MD5 = 1
|
||||||
|
SSHLIB_HMAC_SHA1 = 2
|
||||||
|
SSHLIB_HMAC_SHA1_96 = 3
|
||||||
|
SSHLIB_HMAC_SHA2_256 = 4
|
||||||
|
|
||||||
|
SSHLIB_COMPR_NONE = 1
|
||||||
|
SSHLIB_COMPR_ZLIB = 2
|
||||||
|
|
||||||
|
; Hostkey
|
||||||
|
|
||||||
|
SSHLIB_HOSTKEY_PROBLEM_UNKNOWN = 0
|
||||||
|
SSHLIB_HOSTKEY_PROBLEM_MISMATCH = 1
|
||||||
|
|
||||||
|
SSHLIB_HOSTKEY_REFUSE = -1
|
||||||
|
SSHLIB_HOSTKEY_ACCEPT = 0
|
||||||
|
SSHLIB_HOSTKEY_ONCE = 1
|
||||||
|
|
||||||
|
; SSH network packet header
|
||||||
|
|
||||||
|
struct ssh_packet_header
|
||||||
|
|
||||||
|
packet_length dd ? ; The length of the packet in bytes, not including 'mac' or the
|
||||||
|
; 'packet_length' field itself.
|
||||||
|
padding_length db ? ; Length of 'random padding' (bytes).
|
||||||
|
|
||||||
|
message_code db ? ; First byte of payload
|
||||||
|
|
||||||
|
ends
|
||||||
|
|
||||||
|
; SSH connection structure
|
||||||
|
|
||||||
|
struct sshlib_connection
|
||||||
|
|
||||||
|
status dd ?
|
||||||
|
|
||||||
|
socketnum dd ?
|
||||||
|
|
||||||
|
rx_crypt_proc dd ?
|
||||||
|
tx_crypt_proc dd ?
|
||||||
|
rx_crypt_ctx_ptr dd ?
|
||||||
|
tx_crypt_ctx_ptr dd ?
|
||||||
|
rx_crypt_blocksize dd ?
|
||||||
|
tx_crypt_blocksize dd ?
|
||||||
|
|
||||||
|
tx_pad_size dd ? ; = Max(8, tx_crypt_blocksize)
|
||||||
|
tx_pad_proc dd ?
|
||||||
|
|
||||||
|
rx_mac_proc dd ?
|
||||||
|
tx_mac_proc dd ?
|
||||||
|
rx_mac_ctx hmac_sha256_context
|
||||||
|
tx_mac_ctx hmac_sha256_context
|
||||||
|
rx_mac_length dd ?
|
||||||
|
tx_mac_length dd ?
|
||||||
|
|
||||||
|
rx_mac_seqnr dd ? ; DO NOT MOVE
|
||||||
|
rx_buffer ssh_packet_header
|
||||||
|
rb BUFFERSIZE-sizeof.ssh_packet_header
|
||||||
|
|
||||||
|
tx_mac_seqnr dd ? ; DO NOT MOVE
|
||||||
|
tx_buffer ssh_packet_header
|
||||||
|
rb PACKETSIZE-sizeof.ssh_packet_header
|
||||||
|
|
||||||
|
part_ex_hash_ctx crash_ctx
|
||||||
|
session_id rb SHA256_HASH_SIZE
|
||||||
|
|
||||||
|
algo_kex dd ?
|
||||||
|
algo_hostkey dd ?
|
||||||
|
algo_crypt_rx dd ?
|
||||||
|
algo_crypt_tx dd ?
|
||||||
|
algo_mac_rx dd ?
|
||||||
|
algo_mac_tx dd ?
|
||||||
|
algo_compr_rx dd ?
|
||||||
|
algo_compr_tx dd ?
|
||||||
|
|
||||||
|
hostname_sz rb MAX_HOSTNAME_LENGTH
|
||||||
|
|
||||||
|
ends
|
||||||
|
|
||||||
|
; SSH channel structure
|
||||||
|
|
||||||
|
struct sshlib_channel
|
||||||
|
|
||||||
|
id dd ? ; Channel ID (big endian)
|
||||||
|
status dd ? ; Channel status
|
||||||
|
rcv_wnd dd ? ; Receive window
|
||||||
|
snd_wnd dd ? ; Send window
|
||||||
|
|
||||||
|
; rcv_callb dd ? ; TODO
|
||||||
|
|
||||||
|
ends
|
87
programs/network/ssh/sshlib_channel.inc
Normal file
87
programs/network/ssh/sshlib_channel.inc
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
; sshlib_channel.inc - SSH channel
|
||||||
|
;
|
||||||
|
; Copyright (C) 2016-2021 Jeffrey Amelynck
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
proc sshlib_chan_open con_ptr; Channel struct ptr?!
|
||||||
|
|
||||||
|
; >> Open channel
|
||||||
|
|
||||||
|
DEBUGF 2, "SSH: Open channel\n"
|
||||||
|
|
||||||
|
mov [ssh_chan.rcv_wnd], BUFFERSIZE
|
||||||
|
mov [ssh_chan.snd_wnd], 0
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_open, ssh_msg_channel_open.length, 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
; << Check for channel open confirmation
|
||||||
|
|
||||||
|
stdcall sshlib_msg_handler, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
cmp [esi + sshlib_connection.rx_buffer.message_code], SSH_MSG_CHANNEL_OPEN_CONFIRMATION
|
||||||
|
jne .err_proto
|
||||||
|
|
||||||
|
; >> Channel request: pty
|
||||||
|
|
||||||
|
DEBUGF 2, "SSH: Request pty\n"
|
||||||
|
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_request, ssh_msg_channel_request.length, 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
; << Check for channel request confirmation
|
||||||
|
|
||||||
|
stdcall sshlib_msg_handler, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
cmp [esi + sshlib_connection.rx_buffer.message_code], SSH_MSG_CHANNEL_SUCCESS
|
||||||
|
jne .err_proto
|
||||||
|
|
||||||
|
; >> Channel request: shell
|
||||||
|
|
||||||
|
DEBUGF 2, "SSH: Request shell\n"
|
||||||
|
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_shell_request, ssh_msg_shell_request.length, 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
; << Check for channel request confirmation
|
||||||
|
|
||||||
|
; TODO: timeout
|
||||||
|
.wait_success:
|
||||||
|
stdcall sshlib_msg_handler, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
cmp [esi + sshlib_connection.rx_buffer.message_code], SSH_MSG_CHANNEL_SUCCESS
|
||||||
|
jne .wait_success
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
.err:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_proto:
|
||||||
|
mov eax, SSHLIB_ERR_PROTOCOL
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
396
programs/network/ssh/sshlib_connection.inc
Normal file
396
programs/network/ssh/sshlib_connection.inc
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
; sshlib_connection.inc - SSH connection
|
||||||
|
;
|
||||||
|
; Copyright (C) 2016-2021 Jeffrey Amelynck
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
proc sshlib_connect con_ptr, hostname_sz
|
||||||
|
|
||||||
|
locals
|
||||||
|
socketnum dd ?
|
||||||
|
sockaddr sockaddr_in
|
||||||
|
ctx_ptr dd ?
|
||||||
|
endl
|
||||||
|
|
||||||
|
mov edi, [con_ptr]
|
||||||
|
lea eax, [edi + sshlib_connection.part_ex_hash_ctx]
|
||||||
|
mov [ctx_ptr], eax
|
||||||
|
|
||||||
|
; Set default values in sockaddr struct
|
||||||
|
mov [sockaddr.sin_family], AF_INET4
|
||||||
|
mov [sockaddr.sin_port], 22 shl 8
|
||||||
|
|
||||||
|
; Parse hostname_sz
|
||||||
|
; Verify length, extract port number if given and copy base url to sshlib_connection struct
|
||||||
|
; Port number, if provided, will be written in sockaddr struct.
|
||||||
|
; Hostname ends with any character equal to 0x20 or lower
|
||||||
|
|
||||||
|
mov esi, [hostname_sz]
|
||||||
|
lea edi, [edi + sshlib_connection.hostname_sz]
|
||||||
|
mov ecx, MAX_HOSTNAME_LENGTH
|
||||||
|
@@:
|
||||||
|
dec ecx
|
||||||
|
jz .err_hostname
|
||||||
|
lodsb
|
||||||
|
cmp al, ':'
|
||||||
|
je .do_port
|
||||||
|
stosb
|
||||||
|
cmp al, 0x20
|
||||||
|
ja @r
|
||||||
|
mov byte[edi-1], 0
|
||||||
|
jmp .hostname_ok
|
||||||
|
|
||||||
|
.do_port:
|
||||||
|
xor eax, eax
|
||||||
|
xor ebx, ebx
|
||||||
|
mov byte[edi-1], 0
|
||||||
|
.portloop:
|
||||||
|
lodsb
|
||||||
|
cmp al, 0x20
|
||||||
|
jbe .port_done
|
||||||
|
sub al, '0'
|
||||||
|
jb .err_hostname
|
||||||
|
cmp al, 9
|
||||||
|
ja .err_hostname
|
||||||
|
lea ebx, [ebx*4+ebx]
|
||||||
|
shl ebx, 1
|
||||||
|
add ebx, eax
|
||||||
|
jmp .portloop
|
||||||
|
.port_done:
|
||||||
|
xchg bl, bh
|
||||||
|
mov [sockaddr.sin_port], bx
|
||||||
|
|
||||||
|
.hostname_ok:
|
||||||
|
; resolve name
|
||||||
|
push esp ; reserve stack place
|
||||||
|
push esp
|
||||||
|
mov eax, [con_ptr]
|
||||||
|
lea eax, [eax+sshlib_connection.hostname_sz]
|
||||||
|
invoke getaddrinfo, eax, 0, 0
|
||||||
|
pop esi
|
||||||
|
; test for error
|
||||||
|
test eax, eax
|
||||||
|
jnz .err_hostname
|
||||||
|
|
||||||
|
; convert IP address to decimal notation
|
||||||
|
mov eax, [esi+addrinfo.ai_addr]
|
||||||
|
mov eax, [eax+sockaddr_in.sin_addr]
|
||||||
|
mov [sockaddr.sin_addr], eax
|
||||||
|
invoke inet_ntoa, eax
|
||||||
|
; write result
|
||||||
|
stdcall sshlib_callback_connecting, [con_ptr], eax
|
||||||
|
; free allocated memory
|
||||||
|
invoke freeaddrinfo, esi
|
||||||
|
|
||||||
|
; Create socket
|
||||||
|
mcall socket, AF_INET4, SOCK_STREAM, 0
|
||||||
|
cmp eax, -1
|
||||||
|
jz .err_sock
|
||||||
|
mov [socketnum], eax
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
mov [ebx + sshlib_connection.socketnum], eax
|
||||||
|
|
||||||
|
; Connect
|
||||||
|
DEBUGF 2, "Connecting to server\n"
|
||||||
|
lea edx, [sockaddr]
|
||||||
|
mcall connect, [socketnum], , sizeof.sockaddr_in
|
||||||
|
test eax, eax
|
||||||
|
jnz .err_sock
|
||||||
|
|
||||||
|
; Start calculating hash
|
||||||
|
invoke sha256_init, [ctx_ptr]
|
||||||
|
; HASH: string V_C, the client's version string (CR and NL excluded)
|
||||||
|
invoke sha256_update, [ctx_ptr], ssh_ident_ha, ssh_msg_ident.length+4-2
|
||||||
|
|
||||||
|
; >> Send our identification string
|
||||||
|
DEBUGF 2, "Sending ID string\n"
|
||||||
|
mcall send, [socketnum], ssh_msg_ident, ssh_msg_ident.length, 0
|
||||||
|
cmp eax, -1
|
||||||
|
je .err_sock
|
||||||
|
|
||||||
|
; << Check protocol version of server
|
||||||
|
mov edx, [con_ptr]
|
||||||
|
lea edx, [edx + sshlib_connection.rx_buffer + 4]
|
||||||
|
mcall recv, [socketnum], , PACKETSIZE, 0
|
||||||
|
cmp eax, -1
|
||||||
|
je .err_sock
|
||||||
|
|
||||||
|
DEBUGF 2, "Received ID string\n"
|
||||||
|
cmp dword[edx], "SSH-"
|
||||||
|
jne .err_proto
|
||||||
|
cmp dword[edx+4], "2.0-"
|
||||||
|
jne .err_proto
|
||||||
|
|
||||||
|
; HASH: string V_S, the server's version string (CR and NL excluded)
|
||||||
|
lea ecx, [eax+2]
|
||||||
|
sub eax, 2
|
||||||
|
bswap eax
|
||||||
|
sub edx, 4
|
||||||
|
mov dword[edx], eax
|
||||||
|
invoke sha256_update, [ctx_ptr], edx, ecx
|
||||||
|
|
||||||
|
; >> Key Exchange init
|
||||||
|
mov eax, [con_ptr]
|
||||||
|
mov [eax + sshlib_connection.status], SSHLIB_CON_STAT_INIT
|
||||||
|
|
||||||
|
mov [eax + sshlib_connection.algo_kex], SSHLIB_ALGO_NONE
|
||||||
|
mov [eax + sshlib_connection.algo_hostkey], SSHLIB_ALGO_NONE
|
||||||
|
mov [eax + sshlib_connection.algo_crypt_rx], SSHLIB_ALGO_NONE
|
||||||
|
mov [eax + sshlib_connection.algo_crypt_tx], SSHLIB_ALGO_NONE
|
||||||
|
mov [eax + sshlib_connection.algo_mac_rx], SSHLIB_ALGO_NONE
|
||||||
|
mov [eax + sshlib_connection.algo_mac_tx], SSHLIB_ALGO_NONE
|
||||||
|
mov [eax + sshlib_connection.algo_compr_rx], SSHLIB_ALGO_NONE
|
||||||
|
mov [eax + sshlib_connection.algo_compr_tx], SSHLIB_ALGO_NONE
|
||||||
|
|
||||||
|
mov [eax + sshlib_connection.rx_mac_seqnr], 0
|
||||||
|
mov [eax + sshlib_connection.tx_mac_seqnr], 0
|
||||||
|
mov [eax + sshlib_connection.rx_crypt_blocksize], 4 ; minimum blocksize
|
||||||
|
mov [eax + sshlib_connection.tx_crypt_blocksize], 4
|
||||||
|
mov [eax + sshlib_connection.rx_crypt_proc], sshlib_crypt_null
|
||||||
|
mov [eax + sshlib_connection.tx_crypt_proc], sshlib_crypt_null
|
||||||
|
mov [eax + sshlib_connection.rx_mac_proc], 0
|
||||||
|
mov [eax + sshlib_connection.tx_mac_proc], 0
|
||||||
|
mov [eax + sshlib_connection.rx_mac_length], 0
|
||||||
|
mov [eax + sshlib_connection.tx_mac_length], 0
|
||||||
|
mov [eax + sshlib_connection.tx_pad_size], 8
|
||||||
|
mov [eax + sshlib_connection.tx_pad_proc], sshlib_padd_null
|
||||||
|
|
||||||
|
DEBUGF 2, "Sending KEX init\n"
|
||||||
|
mov edi, ssh_msg_kex.cookie
|
||||||
|
call MBRandom
|
||||||
|
stosd
|
||||||
|
call MBRandom
|
||||||
|
stosd
|
||||||
|
call MBRandom
|
||||||
|
stosd
|
||||||
|
call MBRandom
|
||||||
|
stosd
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_kex, ssh_msg_kex.length, 0
|
||||||
|
cmp eax, -1
|
||||||
|
je .err_sock
|
||||||
|
|
||||||
|
; HASH: string I_C, the payload of the client's SSH_MSG_KEXINIT
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
mov eax, [esi+sshlib_connection.tx_buffer.packet_length]
|
||||||
|
bswap eax
|
||||||
|
movzx ebx, [esi+sshlib_connection.tx_buffer.padding_length]
|
||||||
|
sub eax, ebx
|
||||||
|
dec eax
|
||||||
|
lea edx, [eax+4]
|
||||||
|
bswap eax
|
||||||
|
lea esi, [esi+sshlib_connection.tx_buffer+1]
|
||||||
|
mov dword[esi], eax
|
||||||
|
invoke sha256_update, [ctx_ptr], esi, edx
|
||||||
|
|
||||||
|
; << Check key exchange init of server
|
||||||
|
stdcall sshlib_recv_packet, [con_ptr], 0
|
||||||
|
cmp eax, -1
|
||||||
|
je .err_sock
|
||||||
|
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
cmp [esi + sshlib_connection.rx_buffer.message_code], SSH_MSG_KEXINIT
|
||||||
|
jne .err_proto
|
||||||
|
DEBUGF 2, "Received KEX init\n"
|
||||||
|
|
||||||
|
lea esi, [esi + sshlib_connection.rx_buffer + sizeof.ssh_packet_header + 16]
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "kex_algorithms: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "server_host_key_algorithms: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "encryption_algorithms_client_to_server: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "encryption_algorithms_server_to_client: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "mac_algorithms_client_to_server: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "mac_algorithms_server_to_client: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "compression_algorithms_client_to_server: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "compression_algorithms_server_to_client: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "languages_client_to_server: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsd
|
||||||
|
bswap eax
|
||||||
|
DEBUGF 1, "languages_server_to_client: %s\n", esi
|
||||||
|
add esi, eax
|
||||||
|
lodsb
|
||||||
|
DEBUGF 1, "KEX First Packet Follows: %u\n", al
|
||||||
|
|
||||||
|
; TODO: parse this structure and set algorithm codes accordingly
|
||||||
|
; FIXME: hardcoded for now
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
mov [esi+sshlib_connection.algo_kex], SSHLIB_KEX_DH_SHA256
|
||||||
|
mov [esi+sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA
|
||||||
|
mov [esi+sshlib_connection.algo_crypt_rx], SSHLIB_CRYPT_AES256_CTR
|
||||||
|
mov [esi+sshlib_connection.algo_crypt_tx], SSHLIB_CRYPT_AES256_CTR
|
||||||
|
mov [esi+sshlib_connection.algo_mac_rx], SSHLIB_HMAC_SHA2_256
|
||||||
|
mov [esi+sshlib_connection.algo_mac_tx], SSHLIB_HMAC_SHA2_256
|
||||||
|
mov [esi+sshlib_connection.algo_compr_rx], SSHLIB_COMPR_NONE
|
||||||
|
mov [esi+sshlib_connection.algo_compr_tx], SSHLIB_COMPR_NONE
|
||||||
|
|
||||||
|
; HASH: string I_S, the payload of the servers's SSH_MSG_KEXINIT
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
mov eax, [esi+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
movzx ebx, [esi+sshlib_connection.rx_buffer.padding_length]
|
||||||
|
sub eax, ebx
|
||||||
|
dec eax
|
||||||
|
lea edx, [eax+4]
|
||||||
|
bswap eax
|
||||||
|
lea esi, [esi+sshlib_connection.rx_buffer+1]
|
||||||
|
mov dword[esi], eax
|
||||||
|
invoke sha256_update, [ctx_ptr], esi, edx
|
||||||
|
|
||||||
|
; Exchange keys with the server
|
||||||
|
|
||||||
|
stdcall sshlib_dh_gex, [con_ptr]
|
||||||
|
test eax, eax
|
||||||
|
jnz .err
|
||||||
|
|
||||||
|
; Re-seed RNG for padding bytes
|
||||||
|
|
||||||
|
call create_seed
|
||||||
|
call init_random
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_hostname:
|
||||||
|
mov eax, SSHLIB_ERR_HOSTNAME
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_sock:
|
||||||
|
mov eax, SSHLIB_ERR_SOCKET
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_proto:
|
||||||
|
mov eax, SSHLIB_ERR_PROTOCOL
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err:
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; Handle common messages and return to caller for specific ones
|
||||||
|
proc sshlib_msg_handler, con_ptr, flags
|
||||||
|
|
||||||
|
.recv:
|
||||||
|
; Send a window update if advertised window drops below half
|
||||||
|
cmp [ssh_chan.rcv_wnd], BUFFERSIZE/2
|
||||||
|
ja .no_wnd
|
||||||
|
mov eax, BUFFERSIZE
|
||||||
|
bswap eax
|
||||||
|
mov [ssh_msg_channel_window_adjust.wnd], eax
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_window_adjust, ssh_msg_channel_window_adjust.length, 0
|
||||||
|
mov [ssh_chan.rcv_wnd], BUFFERSIZE
|
||||||
|
.no_wnd:
|
||||||
|
|
||||||
|
; Receive 1 SSH packet
|
||||||
|
stdcall sshlib_recv_packet, [con_ptr], [flags]
|
||||||
|
cmp eax, 0
|
||||||
|
jle .ret
|
||||||
|
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
lea esi, [esi + sshlib_connection.rx_buffer]
|
||||||
|
mov al, [esi + ssh_packet_header.message_code]
|
||||||
|
inc esi
|
||||||
|
|
||||||
|
cmp al, SSH_MSG_DISCONNECT
|
||||||
|
je .disc
|
||||||
|
cmp al, SSH_MSG_IGNORE
|
||||||
|
je .ign
|
||||||
|
cmp al, SSH_MSG_DEBUG
|
||||||
|
je .dbg
|
||||||
|
cmp al, SSH_MSG_GLOBAL_REQUEST
|
||||||
|
je .glob_req
|
||||||
|
cmp al, SSH_MSG_CHANNEL_WINDOW_ADJUST
|
||||||
|
je .chan_win_adj
|
||||||
|
; cmp al, SSH_MSG_CHANNEL_REQUEST
|
||||||
|
; je .chan_req
|
||||||
|
cmp al, SSH_MSG_CHANNEL_EOF
|
||||||
|
je .chan_eof
|
||||||
|
cmp al, SSH_MSG_CHANNEL_CLOSE
|
||||||
|
je .chan_close
|
||||||
|
|
||||||
|
.ret:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.disc:
|
||||||
|
DEBUGF 3, "SSH: Disconnect message received\n"
|
||||||
|
mov eax, SSHLIB_ERR_DISCONNECTING
|
||||||
|
ret
|
||||||
|
|
||||||
|
.ign:
|
||||||
|
DEBUGF 3, "SSH: Ignore MSG received\n"
|
||||||
|
jmp .recv
|
||||||
|
|
||||||
|
.dbg:
|
||||||
|
DEBUGF 3, "SSH: Debug MSG received\n"
|
||||||
|
;TODO
|
||||||
|
jmp .recv
|
||||||
|
|
||||||
|
.glob_req:
|
||||||
|
DEBUGF 3, "SSH: Global MSG received\n"
|
||||||
|
;TODO
|
||||||
|
jmp .recv
|
||||||
|
|
||||||
|
.chan_win_adj:
|
||||||
|
mov eax, dword[esi]
|
||||||
|
bswap eax
|
||||||
|
mov [ssh_chan.snd_wnd], eax
|
||||||
|
; TODO: validate channel number, act accordingly
|
||||||
|
DEBUGF 3, "SSH: Channel %u window update received\n", eax
|
||||||
|
jmp .recv
|
||||||
|
|
||||||
|
.chan_eof:
|
||||||
|
mov eax, dword[esi]
|
||||||
|
bswap eax
|
||||||
|
; TODO: validate channel number, act accordingly
|
||||||
|
DEBUGF 3, "SSH: Channel %u EOF received\n", eax
|
||||||
|
jmp .recv
|
||||||
|
|
||||||
|
.chan_close:
|
||||||
|
mov eax, dword[esi]
|
||||||
|
bswap eax
|
||||||
|
; TODO: validate channel number
|
||||||
|
DEBUGF 3, "SSH: Channel %u close received\n", eax
|
||||||
|
; Reply with close message
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_close, ssh_msg_channel_close.length, 0
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
507
programs/network/ssh/sshlib_dh_gex.inc
Normal file
507
programs/network/ssh/sshlib_dh_gex.inc
Normal file
@ -0,0 +1,507 @@
|
|||||||
|
; sshlib_dh_gex.inc - Diffie Hellman Group exchange
|
||||||
|
;
|
||||||
|
; Copyright (C) 2015-2021 Jeffrey Amelynck
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
; https://www.ietf.org/rfc/rfc4419.txt
|
||||||
|
|
||||||
|
proc sshlib_dh_gex con_ptr
|
||||||
|
|
||||||
|
locals
|
||||||
|
|
||||||
|
mpint_tmp dd ?
|
||||||
|
|
||||||
|
mpint_p dd ?
|
||||||
|
mpint_g dd ?
|
||||||
|
mpint_x dd ?
|
||||||
|
mpint_e dd ?
|
||||||
|
mpint_f dd ?
|
||||||
|
mpint_K_big dd ?
|
||||||
|
|
||||||
|
k_h_ctx dd ?
|
||||||
|
temp_ctx dd ?
|
||||||
|
|
||||||
|
H dd ? ; exchange hash
|
||||||
|
|
||||||
|
rx_iv dd ? ; Rx initialisation vector
|
||||||
|
tx_iv dd ? ; Tx initialisation vector
|
||||||
|
rx_enc_key dd ? ; Rx encryption key
|
||||||
|
tx_enc_key dd ? ; Tx encryption key
|
||||||
|
rx_int_key dd ? ; Rx integrity key
|
||||||
|
tx_int_key dd ? ; Tx integrity key
|
||||||
|
|
||||||
|
K_length dd ?
|
||||||
|
|
||||||
|
session_id_x rb SHA256_HASH_SIZE+1
|
||||||
|
|
||||||
|
str_K_S dd ? ; server public host key and certificates (K_S)
|
||||||
|
mpint_f_big dd ? ; pointer to original
|
||||||
|
str_s_of_H dd ? ; signature of H
|
||||||
|
|
||||||
|
endl
|
||||||
|
|
||||||
|
; Allocate memory for temp variables
|
||||||
|
|
||||||
|
mov ecx, 7*(MAX_BITS/8+4) + 7*SHA256_HASH_SIZE + 2*sizeof.crash_ctx
|
||||||
|
mcall 68, 12
|
||||||
|
test eax, eax
|
||||||
|
jz .err_nomem
|
||||||
|
|
||||||
|
; Init pointers for temp variables
|
||||||
|
|
||||||
|
mov [mpint_tmp], eax
|
||||||
|
add eax, (MAX_BITS/8+4)
|
||||||
|
mov [mpint_p], eax
|
||||||
|
add eax, (MAX_BITS/8+4)
|
||||||
|
mov [mpint_g], eax
|
||||||
|
add eax, (MAX_BITS/8+4)
|
||||||
|
mov [mpint_x], eax
|
||||||
|
add eax, (MAX_BITS/8+4)
|
||||||
|
mov [mpint_e], eax
|
||||||
|
add eax, (MAX_BITS/8+4)
|
||||||
|
mov [mpint_f], eax
|
||||||
|
add eax, (MAX_BITS/8+4)
|
||||||
|
mov [mpint_K_big], eax
|
||||||
|
add eax, (MAX_BITS/8+4)
|
||||||
|
|
||||||
|
mov [k_h_ctx], eax
|
||||||
|
add eax, sizeof.crash_ctx
|
||||||
|
mov [temp_ctx], eax
|
||||||
|
add eax, sizeof.crash_ctx
|
||||||
|
|
||||||
|
mov [H], eax
|
||||||
|
add eax, SHA256_HASH_SIZE
|
||||||
|
mov [rx_iv], eax
|
||||||
|
add eax, SHA256_HASH_SIZE
|
||||||
|
mov [tx_iv], eax
|
||||||
|
add eax, SHA256_HASH_SIZE
|
||||||
|
mov [rx_enc_key], eax
|
||||||
|
add eax, SHA256_HASH_SIZE
|
||||||
|
mov [tx_enc_key], eax
|
||||||
|
add eax, SHA256_HASH_SIZE
|
||||||
|
mov [rx_int_key], eax
|
||||||
|
add eax, SHA256_HASH_SIZE
|
||||||
|
mov [tx_int_key], eax
|
||||||
|
; add eax, SHA256_HASH_SIZE
|
||||||
|
|
||||||
|
; Copy the partial exchange hash to our temporary one
|
||||||
|
|
||||||
|
mov esi, [con_ptr]
|
||||||
|
lea esi, [esi+sshlib_connection.part_ex_hash_ctx]
|
||||||
|
mov edi, [temp_ctx]
|
||||||
|
mov ecx, sizeof.crash_ctx/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
;----------------------------------------------
|
||||||
|
; >> Send Diffie-Hellman Group Exchange Request
|
||||||
|
|
||||||
|
DEBUGF 2, "Sending GEX\n"
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_gex_req, ssh_msg_gex_req.length, 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
;---------------------------------------------
|
||||||
|
; << Parse Diffie-Hellman Group Exchange Group
|
||||||
|
|
||||||
|
stdcall sshlib_recv_packet, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
cmp [ebx + sshlib_connection.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_GROUP
|
||||||
|
jne .err_proto
|
||||||
|
DEBUGF 2, "Received GEX group\n"
|
||||||
|
|
||||||
|
lea esi, [ebx + sshlib_connection.rx_buffer + sizeof.ssh_packet_header]
|
||||||
|
stdcall mpint_to_little_endian, [mpint_p], esi
|
||||||
|
add esi, 4
|
||||||
|
add esi, eax
|
||||||
|
DEBUGM 1, "DH modulus (p): ", [mpint_p]
|
||||||
|
|
||||||
|
stdcall mpint_to_little_endian, [mpint_g], esi
|
||||||
|
add esi, 4
|
||||||
|
add esi, eax
|
||||||
|
DEBUGM 1, "DH base (g): ", [mpint_g]
|
||||||
|
|
||||||
|
;-------------------------------------------
|
||||||
|
; >> Send Diffie-Hellman Group Exchange Init
|
||||||
|
|
||||||
|
; generate a random number x, where 1 < x < (p-1)/2
|
||||||
|
mov edi, [mpint_x]
|
||||||
|
mov dword[edi], DH_PRIVATE_KEY_SIZE/8
|
||||||
|
add edi, 4
|
||||||
|
mov ecx, DH_PRIVATE_KEY_SIZE/8/4
|
||||||
|
@@:
|
||||||
|
push ecx
|
||||||
|
call MBRandom
|
||||||
|
pop ecx
|
||||||
|
stosd
|
||||||
|
dec ecx
|
||||||
|
jnz @r
|
||||||
|
|
||||||
|
; If the highest bit is set, add a zero byte
|
||||||
|
shl eax, 1
|
||||||
|
jnc @f
|
||||||
|
mov byte[edi], 0
|
||||||
|
mov eax, [mpint_x]
|
||||||
|
inc dword[eax]
|
||||||
|
@@:
|
||||||
|
DEBUGM 1, "DH private key (x): ", [mpint_x]
|
||||||
|
|
||||||
|
; Compute e = g^x mod p
|
||||||
|
stdcall mpint_modexp, [mpint_e], [mpint_g], [mpint_x], [mpint_p]
|
||||||
|
stdcall mpint_shrink, [mpint_e]
|
||||||
|
DEBUGM 1, "DH public key (e): ", [mpint_e]
|
||||||
|
|
||||||
|
; Create group exchange init packet
|
||||||
|
mov byte[ebx + sshlib_connection.tx_buffer.message_code], SSH_MSG_KEX_DH_GEX_INIT
|
||||||
|
lea edi, [ebx + sshlib_connection.tx_buffer.message_code+1]
|
||||||
|
stdcall mpint_to_big_endian, edi, [mpint_e]
|
||||||
|
|
||||||
|
DEBUGF 2, "Sending GEX init\n"
|
||||||
|
mov ecx, dword[ebx + sshlib_connection.tx_buffer.message_code+1] ;;;; dword[edi]
|
||||||
|
bswap ecx
|
||||||
|
add ecx, 5
|
||||||
|
lea esi, [ebx + sshlib_connection.tx_buffer.message_code]
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], esi, ecx, 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
;---------------------------------------------
|
||||||
|
; << Parse Diffie-Hellman Group Exchange Reply
|
||||||
|
|
||||||
|
stdcall sshlib_recv_packet, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
cmp [ebx + sshlib_connection.rx_buffer.message_code], SSH_MSG_KEX_DH_GEX_REPLY
|
||||||
|
jne .err_proto
|
||||||
|
|
||||||
|
DEBUGF 2, "Received GEX Reply\n"
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
; HASH: string K_S, the host key
|
||||||
|
lea esi, [ebx + sshlib_connection.rx_buffer + sizeof.ssh_packet_header]
|
||||||
|
mov [str_K_S], esi
|
||||||
|
mov edx, [esi]
|
||||||
|
bswap edx
|
||||||
|
add edx, 4
|
||||||
|
lea eax, [esi+edx]
|
||||||
|
mov [mpint_f_big], eax
|
||||||
|
invoke sha256_update, [temp_ctx], esi, edx
|
||||||
|
|
||||||
|
;--------------------------------------------------------------------------
|
||||||
|
; HASH: uint32 min, minimal size in bits of an acceptable group
|
||||||
|
; uint32 n, preferred size in bits of the group the server will send
|
||||||
|
; uint32 max, maximal size in bits of an acceptable group
|
||||||
|
invoke sha256_update, [temp_ctx], ssh_msg_gex_req+sizeof.ssh_packet_header-ssh_packet_header.message_code, 12
|
||||||
|
|
||||||
|
;----------------------------
|
||||||
|
; HASH: mpint p, safe prime
|
||||||
|
stdcall mpint_shrink, [mpint_p]
|
||||||
|
stdcall mpint_to_big_endian, [mpint_tmp], [mpint_p]
|
||||||
|
add eax, 4
|
||||||
|
invoke sha256_update, [temp_ctx], [mpint_tmp], eax
|
||||||
|
|
||||||
|
;----------------------------------------
|
||||||
|
; HASH: mpint g, generator for subgroup
|
||||||
|
stdcall mpint_shrink, [mpint_g]
|
||||||
|
stdcall mpint_to_big_endian, [mpint_tmp], [mpint_g]
|
||||||
|
add eax, 4
|
||||||
|
invoke sha256_update, [temp_ctx], [mpint_tmp], eax
|
||||||
|
|
||||||
|
;---------------------------------------------------
|
||||||
|
; HASH: mpint e, exchange value sent by the client
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
lea esi, [ebx + sshlib_connection.tx_buffer + sizeof.ssh_packet_header]
|
||||||
|
mov edx, [esi]
|
||||||
|
bswap edx
|
||||||
|
add edx, 4
|
||||||
|
invoke sha256_update, [temp_ctx], esi, edx
|
||||||
|
|
||||||
|
;---------------------------------------------------
|
||||||
|
; HASH: mpint f, exchange value sent by the server
|
||||||
|
mov esi, [mpint_f_big]
|
||||||
|
mov edx, [esi]
|
||||||
|
bswap edx
|
||||||
|
add edx, 4
|
||||||
|
invoke sha256_update, [temp_ctx], esi, edx
|
||||||
|
|
||||||
|
stdcall mpint_to_little_endian, [mpint_f], [mpint_f_big]
|
||||||
|
mov esi, [mpint_f_big]
|
||||||
|
add esi, eax
|
||||||
|
add esi, 4
|
||||||
|
mov [str_s_of_H], esi
|
||||||
|
DEBUGM 1, "DH exchange value (f): ", [mpint_f]
|
||||||
|
|
||||||
|
;--------------------------------------
|
||||||
|
; Calculate shared secret K = f^x mod p
|
||||||
|
stdcall mpint_modexp, [mpint_tmp], [mpint_f], [mpint_x], [mpint_p]
|
||||||
|
stdcall mpint_shrink, [mpint_tmp]
|
||||||
|
DEBUGM 1, "DH shared secret (K): ", [mpint_tmp]
|
||||||
|
|
||||||
|
; We always need it in big endian order, so store it as such.
|
||||||
|
stdcall mpint_to_big_endian, [mpint_K_big], [mpint_tmp]
|
||||||
|
mov [K_length], eax
|
||||||
|
|
||||||
|
;-----------------------------------
|
||||||
|
; HASH: mpint K, the shared secret
|
||||||
|
add eax, 4
|
||||||
|
invoke sha256_update, [temp_ctx], [mpint_K_big], eax
|
||||||
|
|
||||||
|
;-------------------------------
|
||||||
|
; Finalize the exchange hash (H)
|
||||||
|
invoke sha256_final, [temp_ctx]
|
||||||
|
mov esi, [temp_ctx]
|
||||||
|
add esi, crash_ctx.hash
|
||||||
|
mov edi, [H]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
DEBUGF 1, "Exchange hash H: "
|
||||||
|
stdcall dump_hex, [H], SHA256_HASH_SIZE/4
|
||||||
|
|
||||||
|
;--------------------------
|
||||||
|
; Set or get the session id
|
||||||
|
|
||||||
|
mov eax, [con_ptr]
|
||||||
|
cmp [eax + sshlib_connection.status], SSHLIB_CON_STAT_KEX_DONE
|
||||||
|
jae @f
|
||||||
|
|
||||||
|
; If first KEX, verify host public key
|
||||||
|
stdcall sshlib_host_verify, [con_ptr], [str_K_S], [str_s_of_H], [H], SHA256_HASH_SIZE
|
||||||
|
test eax, eax
|
||||||
|
jnz .err
|
||||||
|
|
||||||
|
mov eax, [con_ptr]
|
||||||
|
mov esi, [H]
|
||||||
|
lea edi, [eax + sshlib_connection.session_id]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
@@:
|
||||||
|
|
||||||
|
lea esi, [eax + sshlib_connection.session_id]
|
||||||
|
lea edi, [session_id_x+1]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
|
||||||
|
;---------------
|
||||||
|
; Calculate keys
|
||||||
|
|
||||||
|
; First, calculate partial hash of K and H so we can re-use it for every key.
|
||||||
|
|
||||||
|
invoke sha256_init, [k_h_ctx]
|
||||||
|
|
||||||
|
mov ecx, [K_length]
|
||||||
|
add ecx, 4
|
||||||
|
invoke sha256_update, [k_h_ctx], [mpint_K_big], ecx
|
||||||
|
invoke sha256_update, [k_h_ctx], [H], SHA256_HASH_SIZE
|
||||||
|
|
||||||
|
;---------------------------------------------------------------
|
||||||
|
; Initial IV client to server: HASH(K || H || "A" || session_id)
|
||||||
|
|
||||||
|
mov esi, [k_h_ctx]
|
||||||
|
mov edi, [temp_ctx]
|
||||||
|
mov ecx, sizeof.crash_ctx/4
|
||||||
|
rep movsd
|
||||||
|
lea edx, [session_id_x]
|
||||||
|
mov byte[edx], 'A'
|
||||||
|
invoke sha256_update, [temp_ctx], edx, SHA256_HASH_SIZE+1
|
||||||
|
invoke sha256_final, [temp_ctx]
|
||||||
|
mov edi, [tx_iv]
|
||||||
|
mov esi, [temp_ctx]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
DEBUGF 1, "Remote IV: "
|
||||||
|
stdcall dump_hex, [tx_iv], SHA256_HASH_SIZE/4
|
||||||
|
|
||||||
|
;---------------------------------------------------------------
|
||||||
|
; Initial IV server to client: HASH(K || H || "B" || session_id)
|
||||||
|
|
||||||
|
mov esi, [k_h_ctx]
|
||||||
|
mov edi, [temp_ctx]
|
||||||
|
mov ecx, sizeof.crash_ctx/4
|
||||||
|
rep movsd
|
||||||
|
lea edx, [session_id_x]
|
||||||
|
mov byte[edx], 'B'
|
||||||
|
invoke sha256_update, [temp_ctx], edx, SHA256_HASH_SIZE+1
|
||||||
|
invoke sha256_final, [temp_ctx]
|
||||||
|
mov edi, [rx_iv]
|
||||||
|
mov esi, [temp_ctx]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
DEBUGF 1, "Local IV: "
|
||||||
|
stdcall dump_hex, [rx_iv], SHA256_HASH_SIZE/4
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------
|
||||||
|
; Encryption key client to server: HASH(K || H || "C" || session_id)
|
||||||
|
|
||||||
|
mov esi, [k_h_ctx]
|
||||||
|
mov edi, [temp_ctx]
|
||||||
|
mov ecx, sizeof.crash_ctx/4
|
||||||
|
rep movsd
|
||||||
|
lea edx, [session_id_x]
|
||||||
|
mov byte[edx], 'C'
|
||||||
|
invoke sha256_update, [temp_ctx], edx, SHA256_HASH_SIZE+1
|
||||||
|
invoke sha256_final, [temp_ctx]
|
||||||
|
mov edi, [tx_enc_key]
|
||||||
|
mov esi, [temp_ctx]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
DEBUGF 1, "Remote key: "
|
||||||
|
stdcall dump_hex, [tx_enc_key], SHA256_HASH_SIZE/4
|
||||||
|
|
||||||
|
;-------------------------------------------------------------------
|
||||||
|
; Encryption key server to client: HASH(K || H || "D" || session_id)
|
||||||
|
|
||||||
|
mov esi, [k_h_ctx]
|
||||||
|
mov edi, [temp_ctx]
|
||||||
|
mov ecx, sizeof.crash_ctx/4
|
||||||
|
rep movsd
|
||||||
|
lea edx, [session_id_x]
|
||||||
|
mov byte[edx], 'D'
|
||||||
|
invoke sha256_update, [temp_ctx], edx, SHA256_HASH_SIZE+1
|
||||||
|
invoke sha256_final, [temp_ctx]
|
||||||
|
mov edi, [rx_enc_key]
|
||||||
|
mov esi, [temp_ctx]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
DEBUGF 1, "Local key: "
|
||||||
|
stdcall dump_hex, [rx_enc_key], SHA256_HASH_SIZE/4
|
||||||
|
|
||||||
|
;------------------------------------------------------------------
|
||||||
|
; Integrity key client to server: HASH(K || H || "E" || session_id)
|
||||||
|
|
||||||
|
mov esi, [k_h_ctx]
|
||||||
|
mov edi, [temp_ctx]
|
||||||
|
mov ecx, sizeof.crash_ctx/4
|
||||||
|
rep movsd
|
||||||
|
lea edx, [session_id_x]
|
||||||
|
mov byte[edx], 'E'
|
||||||
|
invoke sha256_update, [temp_ctx], edx, SHA256_HASH_SIZE+1
|
||||||
|
invoke sha256_final, [temp_ctx]
|
||||||
|
mov edi, [tx_int_key]
|
||||||
|
mov esi, [temp_ctx]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
DEBUGF 1, "Remote Integrity key: "
|
||||||
|
stdcall dump_hex, [tx_int_key], SHA256_HASH_SIZE/4
|
||||||
|
|
||||||
|
;------------------------------------------------------------------
|
||||||
|
; Integrity key server to client: HASH(K || H || "F" || session_id)
|
||||||
|
|
||||||
|
mov esi, [k_h_ctx]
|
||||||
|
mov edi, [temp_ctx]
|
||||||
|
mov ecx, sizeof.crash_ctx/4
|
||||||
|
rep movsd
|
||||||
|
lea edx, [session_id_x]
|
||||||
|
mov byte[edx], 'F'
|
||||||
|
invoke sha256_update, [temp_ctx], edx, SHA256_HASH_SIZE+1
|
||||||
|
invoke sha256_final, [temp_ctx]
|
||||||
|
mov edi, [rx_int_key]
|
||||||
|
mov esi, [temp_ctx]
|
||||||
|
mov ecx, SHA256_HASH_SIZE/4
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
DEBUGF 1, "Local Integrity key: "
|
||||||
|
stdcall dump_hex, [rx_int_key] , SHA256_HASH_SIZE/4
|
||||||
|
|
||||||
|
;-------------------------------------
|
||||||
|
; << Parse Diffie-Hellman New Keys MSG
|
||||||
|
|
||||||
|
stdcall sshlib_recv_packet, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
cmp [ebx + sshlib_connection.rx_buffer.message_code], SSH_MSG_NEWKEYS
|
||||||
|
jne .err_proto
|
||||||
|
|
||||||
|
DEBUGF 2, "Received New Keys\n"
|
||||||
|
|
||||||
|
;-------------------------------
|
||||||
|
; >> Reply with New Keys message
|
||||||
|
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_new_keys, ssh_msg_new_keys.length, 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
;----------------------------------------------
|
||||||
|
; Set keys and initialize transport subroutines
|
||||||
|
|
||||||
|
DEBUGF 2, "SSH: Setting encryption keys\n"
|
||||||
|
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
stdcall aes256_ctr_init, [rx_iv]
|
||||||
|
test eax, eax
|
||||||
|
jz .err_nomem
|
||||||
|
mov [ebx + sshlib_connection.rx_crypt_ctx_ptr], eax
|
||||||
|
stdcall aes256_set_encrypt_key, eax, [rx_enc_key]
|
||||||
|
mov [ebx + sshlib_connection.rx_crypt_proc], aes256_ctr_crypt
|
||||||
|
mov [ebx + sshlib_connection.rx_crypt_blocksize], AES256_BLOCKSIZE
|
||||||
|
|
||||||
|
stdcall aes256_ctr_init, [tx_iv]
|
||||||
|
test eax, eax
|
||||||
|
jz .err_nomem
|
||||||
|
mov [ebx + sshlib_connection.tx_crypt_ctx_ptr], eax
|
||||||
|
stdcall aes256_set_encrypt_key, eax, [tx_enc_key]
|
||||||
|
mov [ebx + sshlib_connection.tx_crypt_proc], aes256_ctr_crypt
|
||||||
|
mov [ebx + sshlib_connection.tx_crypt_blocksize], AES256_BLOCKSIZE
|
||||||
|
|
||||||
|
mov [ebx + sshlib_connection.tx_pad_size], AES256_BLOCKSIZE
|
||||||
|
mov [ebx + sshlib_connection.tx_pad_proc], MBRandom
|
||||||
|
|
||||||
|
lea ecx, [ebx + sshlib_connection.rx_mac_ctx]
|
||||||
|
stdcall hmac_sha256_setkey, ecx, [rx_int_key], SHA256_HASH_SIZE
|
||||||
|
mov [ebx + sshlib_connection.rx_mac_proc], hmac_sha256
|
||||||
|
mov [ebx + sshlib_connection.rx_mac_length], SHA256_HASH_SIZE
|
||||||
|
|
||||||
|
lea ecx, [ebx + sshlib_connection.tx_mac_ctx]
|
||||||
|
stdcall hmac_sha256_setkey, ecx, [tx_int_key], SHA256_HASH_SIZE
|
||||||
|
mov [ebx + sshlib_connection.tx_mac_proc], hmac_sha256
|
||||||
|
mov [ebx + sshlib_connection.tx_mac_length], SHA256_HASH_SIZE
|
||||||
|
|
||||||
|
mov [ebx + sshlib_connection.status], SSHLIB_CON_STAT_KEX_DONE
|
||||||
|
xor eax, eax
|
||||||
|
|
||||||
|
.err:
|
||||||
|
push eax
|
||||||
|
xor eax, eax
|
||||||
|
mov ecx, (7*(MAX_BITS/8+4) + 7*SHA256_HASH_SIZE + 2*sizeof.crash_ctx)/4
|
||||||
|
mov edi, [mpint_tmp]
|
||||||
|
rep stosd
|
||||||
|
|
||||||
|
mcall 68, 13, [mpint_tmp]
|
||||||
|
pop eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_nomem:
|
||||||
|
DEBUGF 3, "Out of memory during key exchange!\n"
|
||||||
|
mov eax, SSHLIB_ERR_NOMEM
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_proto:
|
||||||
|
DEBUGF 3, "Protocol error during key exchange!\n"
|
||||||
|
mov eax, SSHLIB_ERR_PROTOCOL
|
||||||
|
jmp .err
|
||||||
|
|
||||||
|
endp
|
243
programs/network/ssh/sshlib_host.inc
Normal file
243
programs/network/ssh/sshlib_host.inc
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
; sshlib_host.inc - SSH remote host authentication
|
||||||
|
;
|
||||||
|
; Copyright (C) 2021 Jeffrey Amelynck
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
; https://datatracker.ietf.org/doc/html/rfc4253#section-6.6
|
||||||
|
; https://datatracker.ietf.org/doc/html/rfc3447
|
||||||
|
|
||||||
|
proc sshlib_host_verify con_ptr, str_host_key, str_signature, message, message_len
|
||||||
|
|
||||||
|
locals
|
||||||
|
known_key_sz rb MAX_PUBLIC_KEY_SIZE
|
||||||
|
endl
|
||||||
|
|
||||||
|
mov eax, [con_ptr]
|
||||||
|
cmp [eax+sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA
|
||||||
|
je .rsa
|
||||||
|
; ..add more here
|
||||||
|
mov eax, SSHLIB_ERR_HKEY_NO_ALGO
|
||||||
|
ret
|
||||||
|
|
||||||
|
.rsa:
|
||||||
|
stdcall sshlib_host_verify_rsa, [str_host_key], [str_signature], [message], [message_len]
|
||||||
|
test eax, eax
|
||||||
|
jnz .err
|
||||||
|
|
||||||
|
.lookup:
|
||||||
|
; lea eax, [known_key_sz]
|
||||||
|
; mov ebx, [con_ptr]
|
||||||
|
; lea ebx, [ebx + sshlib_connection.hostname_sz]
|
||||||
|
; invoke ini_get_str, known_hosts_file, ebx, ssh_rsa_sz, eax, MAX_PUBLIC_KEY_SIZE, null_sz
|
||||||
|
; test eax, eax
|
||||||
|
; jnz .unknown
|
||||||
|
|
||||||
|
; TODO: verify cached host key
|
||||||
|
; jne .mismatch
|
||||||
|
|
||||||
|
jmp .unknown ; FIXME
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.mismatch:
|
||||||
|
lea eax, [known_key_sz]
|
||||||
|
stdcall sshlib_callback_hostkey_problem, [con_ptr], SSHLIB_HOSTKEY_PROBLEM_MISMATCH, eax
|
||||||
|
cmp eax, SSHLIB_HOSTKEY_ACCEPT
|
||||||
|
je .store
|
||||||
|
ret
|
||||||
|
|
||||||
|
.unknown:
|
||||||
|
lea eax, [known_key_sz]
|
||||||
|
stdcall sshlib_callback_hostkey_problem, [con_ptr], SSHLIB_HOSTKEY_PROBLEM_UNKNOWN, eax
|
||||||
|
cmp eax, SSHLIB_HOSTKEY_ACCEPT
|
||||||
|
je .store
|
||||||
|
ret
|
||||||
|
|
||||||
|
.store:
|
||||||
|
; TODO: write to know_hosts file and fall-through
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err:
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
||||||
|
|
||||||
|
; https://datatracker.ietf.org/doc/html/rfc3447#section-8.2.2
|
||||||
|
; RSASSA-PKCS1-V1_5-VERIFY
|
||||||
|
proc sshlib_host_verify_rsa str_host_key, str_signature, M, message_len
|
||||||
|
|
||||||
|
locals
|
||||||
|
h_ctx dd ?
|
||||||
|
|
||||||
|
; Signer's RSA public key
|
||||||
|
mpint_e dd ? ; public exponent
|
||||||
|
mpint_n dd ? ; modulus
|
||||||
|
|
||||||
|
mpint_m dd ?
|
||||||
|
|
||||||
|
EM dd ?
|
||||||
|
EM_accent dd ?
|
||||||
|
|
||||||
|
mpint_s dd ? ; rsa_signature_blob
|
||||||
|
|
||||||
|
|
||||||
|
; k dd ? ; length of RSA modulus n
|
||||||
|
|
||||||
|
endl
|
||||||
|
|
||||||
|
DEBUGF 3, "SSH: Performing RSA verification\n"
|
||||||
|
|
||||||
|
mcall 68, 12, sizeof.crash_ctx + 5*(MAX_BITS/8+4)
|
||||||
|
test eax, eax
|
||||||
|
jz .err_nomem
|
||||||
|
mov [h_ctx], eax
|
||||||
|
add eax, sizeof.crash_ctx
|
||||||
|
mov [mpint_e], eax
|
||||||
|
add eax, MAX_BITS/8+4
|
||||||
|
mov [mpint_n], eax
|
||||||
|
add eax, MAX_BITS/8+4
|
||||||
|
mov [mpint_m], eax
|
||||||
|
add eax, MAX_BITS/8+4
|
||||||
|
mov [EM], eax
|
||||||
|
add eax, MAX_BITS/8+4
|
||||||
|
mov [EM_accent], eax
|
||||||
|
add eax, MAX_BITS/8+4
|
||||||
|
mov [mpint_s], eax
|
||||||
|
; add eax, MAX_BITS/8+4
|
||||||
|
|
||||||
|
; Host key
|
||||||
|
mov esi, [str_host_key]
|
||||||
|
mov ecx, [esi]
|
||||||
|
bswap ecx
|
||||||
|
cmp ecx, MAX_PUBLIC_KEY_SIZE
|
||||||
|
ja .err_key
|
||||||
|
; Host key type (string)
|
||||||
|
cmp dword[esi+4], 0x07000000
|
||||||
|
jne .err_key
|
||||||
|
cmp dword[esi+8], 'ssh-'
|
||||||
|
jne .err_key
|
||||||
|
cmp dword[esi+11], '-rsa'
|
||||||
|
jne .err_key
|
||||||
|
add esi, 4+4+7
|
||||||
|
; mpint e
|
||||||
|
stdcall mpint_to_little_endian, [mpint_e], esi
|
||||||
|
add esi, eax
|
||||||
|
add esi, 4
|
||||||
|
; mpint n
|
||||||
|
stdcall mpint_to_little_endian, [mpint_n], esi
|
||||||
|
; mov [k], eax ;; HMMMM FIXME, 0-byte..
|
||||||
|
|
||||||
|
; Signature
|
||||||
|
mov esi, [str_signature]
|
||||||
|
mov ecx, [esi]
|
||||||
|
bswap ecx ; TODO: check length
|
||||||
|
; Host key type (string)
|
||||||
|
cmp dword[esi+4], 0x07000000
|
||||||
|
jne .err_signature
|
||||||
|
cmp dword[esi+8], 'ssh-'
|
||||||
|
jne .err_signature
|
||||||
|
cmp dword[esi+11], '-rsa'
|
||||||
|
jne .err_signature
|
||||||
|
add esi, 4+4+7
|
||||||
|
; RSA signature blob
|
||||||
|
stdcall mpint_to_little_endian, [mpint_s], esi
|
||||||
|
; cmp eax, [k]
|
||||||
|
;;; jne .err_signature
|
||||||
|
|
||||||
|
; RSAVP1
|
||||||
|
stdcall mpint_modexp, [mpint_m], [mpint_s], [mpint_e], [mpint_n]
|
||||||
|
; I2OSP
|
||||||
|
stdcall mpint_shrink, [mpint_m]
|
||||||
|
stdcall mpint_grow, [mpint_m], 256
|
||||||
|
stdcall mpint_to_big_endian, [EM], [mpint_m]
|
||||||
|
|
||||||
|
; EMSA-PKCS1-v1_5
|
||||||
|
invoke sha1_init, [h_ctx]
|
||||||
|
invoke sha1_update, [h_ctx], [M], [message_len]
|
||||||
|
invoke sha1_final, [h_ctx]
|
||||||
|
|
||||||
|
mov edi, [EM_accent]
|
||||||
|
mov al, 0x00
|
||||||
|
stosb
|
||||||
|
mov al, 0x01
|
||||||
|
stosb
|
||||||
|
mov ecx, 256 - (rsa_sha1_t.len + 3 + SHA1_HASH_SIZE)
|
||||||
|
mov al, 0xff
|
||||||
|
rep stosb
|
||||||
|
mov al, 0x00
|
||||||
|
stosb
|
||||||
|
mov esi, rsa_sha1_t
|
||||||
|
mov ecx, rsa_sha1_t.len
|
||||||
|
rep movsb
|
||||||
|
mov esi, [h_ctx]
|
||||||
|
mov ecx, SHA1_HASH_SIZE
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
; Compare EM with EM_accent
|
||||||
|
mov esi, [EM]
|
||||||
|
add esi, 4
|
||||||
|
mov edi, [EM_accent]
|
||||||
|
mov ecx, 256/4
|
||||||
|
xor eax, eax
|
||||||
|
.ct_cmp_loop:
|
||||||
|
mov ebx, [esi]
|
||||||
|
xor ebx, [edi]
|
||||||
|
or eax, ebx
|
||||||
|
lea esi, [esi+4]
|
||||||
|
lea edi, [edi+4]
|
||||||
|
dec ecx
|
||||||
|
jnz .ct_cmp_loop
|
||||||
|
|
||||||
|
push eax
|
||||||
|
mcall 68, 13, [h_ctx]
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
test eax, eax
|
||||||
|
jnz .fail
|
||||||
|
|
||||||
|
DEBUGF 3, "SSH: RSA verification OK!\n"
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.fail:
|
||||||
|
DEBUGF 3, "SSH: RSA verification failed!\n"
|
||||||
|
mov eax, SSHLIB_ERR_HKEY_VERIFY_FAIL
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_nomem:
|
||||||
|
mov eax, SSHLIB_ERR_NOMEM
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_signature:
|
||||||
|
mov eax, SSHLIB_ERR_HKEY_SIGNATURE
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_key:
|
||||||
|
mov eax, SSHLIB_ERR_HKEY_PUBLIC_KEY
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
||||||
|
|
||||||
|
iglobal
|
||||||
|
|
||||||
|
rsa_sha1_t db 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14
|
||||||
|
.len = $ - rsa_sha1_t
|
||||||
|
|
||||||
|
endg
|
||||||
|
|
@ -16,6 +16,7 @@ SSH_MSG_USERAUTH_REQUEST = 50
|
|||||||
SSH_MSG_USERAUTH_FAILURE = 51
|
SSH_MSG_USERAUTH_FAILURE = 51
|
||||||
SSH_MSG_USERAUTH_SUCCESS = 52
|
SSH_MSG_USERAUTH_SUCCESS = 52
|
||||||
SSH_MSG_USERAUTH_BANNER = 53
|
SSH_MSG_USERAUTH_BANNER = 53
|
||||||
|
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60
|
||||||
SSH_MSG_GLOBAL_REQUEST = 80
|
SSH_MSG_GLOBAL_REQUEST = 80
|
||||||
SSH_MSG_REQUEST_SUCCESS = 81
|
SSH_MSG_REQUEST_SUCCESS = 81
|
||||||
SSH_MSG_REQUEST_FAILURE = 82
|
SSH_MSG_REQUEST_FAILURE = 82
|
275
programs/network/ssh/sshlib_transport.inc
Normal file
275
programs/network/ssh/sshlib_transport.inc
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
; sshlib_transport.inc - SSH transport layer
|
||||||
|
;
|
||||||
|
; Copyright (C) 2016-2021 Jeffrey Amelynck
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
proc sshlib_padd_null
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc sshlib_crypt_null ctx, src, dst
|
||||||
|
|
||||||
|
; Assume src == dst !
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc sshlib_recv_packet con_ptr, flags
|
||||||
|
|
||||||
|
locals
|
||||||
|
data_length dd ? ; Total length of packet without MAC
|
||||||
|
endl
|
||||||
|
|
||||||
|
DEBUGF 3, "> "
|
||||||
|
; Receive first block (Read length, padding length, message code)
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
mov ecx, [ebx+sshlib_connection.socketnum]
|
||||||
|
mov esi, [ebx+sshlib_connection.rx_crypt_blocksize]
|
||||||
|
lea edx, [ebx+sshlib_connection.rx_buffer]
|
||||||
|
mov edi, [flags]
|
||||||
|
mcall recv
|
||||||
|
cmp eax, 0
|
||||||
|
jle .sock_fail
|
||||||
|
sub [ssh_chan.rcv_wnd], eax ;;; FIXME
|
||||||
|
DEBUGF 1, "chunk = %u ", eax
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
cmp eax, [ebx+sshlib_connection.rx_crypt_blocksize]
|
||||||
|
jne .proto_fail ; TODO: handle receives of 1, 2, and 3 bytes correctly
|
||||||
|
|
||||||
|
; Decrypt first block
|
||||||
|
pusha
|
||||||
|
lea esi, [ebx+sshlib_connection.rx_buffer]
|
||||||
|
stdcall [ebx+sshlib_connection.rx_crypt_proc], [ebx+sshlib_connection.rx_crypt_ctx_ptr], esi, esi
|
||||||
|
popa
|
||||||
|
|
||||||
|
; Check data length
|
||||||
|
mov esi, [ebx + sshlib_connection.rx_buffer.packet_length]
|
||||||
|
bswap esi ; convert length to little endian
|
||||||
|
mov [ebx+sshlib_connection.rx_buffer.packet_length], esi
|
||||||
|
DEBUGF 1, "packet length=%u ", esi
|
||||||
|
cmp esi, BUFFERSIZE
|
||||||
|
ja .proto_fail ; packet is too large
|
||||||
|
|
||||||
|
; Calculate amount of remaining data
|
||||||
|
add esi, 4 ; Packet length field itself is not included in the count
|
||||||
|
sub esi, [ebx+sshlib_connection.rx_crypt_blocksize] ; Already received this amount of data
|
||||||
|
add esi, [ebx+sshlib_connection.rx_mac_length]
|
||||||
|
jz .packet_complete
|
||||||
|
|
||||||
|
; Receive remaining data
|
||||||
|
lea edx, [ebx+sshlib_connection.rx_buffer]
|
||||||
|
add edx, [ebx+sshlib_connection.rx_crypt_blocksize]
|
||||||
|
mov ecx, [ebx+sshlib_connection.socketnum]
|
||||||
|
mov edi, [flags]
|
||||||
|
.receive_loop:
|
||||||
|
DEBUGF 3, "want %d bytes.. ", esi
|
||||||
|
mcall recv
|
||||||
|
cmp eax, 0
|
||||||
|
jle .sock_fail
|
||||||
|
sub [ssh_chan.rcv_wnd], eax ;;; FIXME
|
||||||
|
DEBUGF 3, "got %d bytes\n", eax
|
||||||
|
add edx, eax
|
||||||
|
sub esi, eax
|
||||||
|
jnz .receive_loop
|
||||||
|
|
||||||
|
; Decrypt data
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
mov ecx, [ebx + sshlib_connection.rx_buffer.packet_length]
|
||||||
|
add ecx, 4 ; Packet_length field itself
|
||||||
|
sub ecx, [ebx+sshlib_connection.rx_crypt_blocksize] ; Already decrypted this amount of data
|
||||||
|
jz .decrypt_complete
|
||||||
|
|
||||||
|
lea esi, [ebx+sshlib_connection.rx_buffer]
|
||||||
|
add esi, [ebx+sshlib_connection.rx_crypt_blocksize]
|
||||||
|
.decrypt_loop:
|
||||||
|
pusha
|
||||||
|
stdcall [ebx+sshlib_connection.rx_crypt_proc], [ebx+sshlib_connection.rx_crypt_ctx_ptr], esi, esi
|
||||||
|
popa
|
||||||
|
add esi, [ebx+sshlib_connection.rx_crypt_blocksize]
|
||||||
|
sub ecx, [ebx+sshlib_connection.rx_crypt_blocksize]
|
||||||
|
jnz .decrypt_loop
|
||||||
|
.decrypt_complete:
|
||||||
|
|
||||||
|
; Authenticate message
|
||||||
|
cmp [ebx+sshlib_connection.rx_mac_proc], 0
|
||||||
|
je .mac_complete
|
||||||
|
lea esi, [ebx+sshlib_connection.rx_mac_seqnr]
|
||||||
|
mov ecx, [ebx+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
add ecx, 8 ; packet_length field itself + sequence number
|
||||||
|
lea eax, [ebx+sshlib_connection.rx_mac_ctx]
|
||||||
|
; push [ebx+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
mov edx, [ebx+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
bswap edx ; convert length to big endian
|
||||||
|
mov [ebx+sshlib_connection.rx_buffer.packet_length], edx
|
||||||
|
stdcall [ebx+sshlib_connection.rx_mac_proc], eax, esi, ecx
|
||||||
|
; pop [ebx+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
mov edx, [ebx+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
bswap edx ; convert length to little endian
|
||||||
|
mov [ebx+sshlib_connection.rx_buffer.packet_length], edx
|
||||||
|
|
||||||
|
lea esi, [ebx+sshlib_connection.rx_mac_ctx]
|
||||||
|
lea edi, [ebx+sshlib_connection.rx_buffer+4]
|
||||||
|
add edi, [ebx+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
mov ecx, [ebx+sshlib_connection.rx_mac_length]
|
||||||
|
shr ecx, 2
|
||||||
|
repe cmpsd
|
||||||
|
jne .mac_fail
|
||||||
|
.mac_complete:
|
||||||
|
add byte[ebx+sshlib_connection.rx_mac_seqnr+3], 1 ; Update sequence counter
|
||||||
|
adc byte[ebx+sshlib_connection.rx_mac_seqnr+2], 0
|
||||||
|
adc byte[ebx+sshlib_connection.rx_mac_seqnr+1], 0
|
||||||
|
adc byte[ebx+sshlib_connection.rx_mac_seqnr+0], 0
|
||||||
|
|
||||||
|
; Return useful data length to the caller via eax register
|
||||||
|
.packet_complete:
|
||||||
|
mov eax, [ebx+sshlib_connection.rx_buffer.packet_length]
|
||||||
|
movzx ebx, [ebx+sshlib_connection.rx_buffer.padding_length]
|
||||||
|
sub eax, ebx
|
||||||
|
DEBUGF 1, "useful data length=%u\n", eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.sock_fail:
|
||||||
|
DEBUGF 3, "ssh_recv_packet failed!\n"
|
||||||
|
mov eax, SSHLIB_ERR_SOCKET
|
||||||
|
ret
|
||||||
|
|
||||||
|
.mac_fail:
|
||||||
|
DEBUGF 3, "ssh_recv_packet message authentication failed!\n"
|
||||||
|
mov eax, SSHLIB_ERR_MAC_VERIFY_FAIL
|
||||||
|
xor ebx, ebx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.proto_fail:
|
||||||
|
DEBUGF 3, "ssh_recv_packet protocol failure!\n"
|
||||||
|
mov eax, SSHLIB_ERR_PROTOCOL
|
||||||
|
xor ebx, ebx
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
||||||
|
|
||||||
|
proc sshlib_send_packet con_ptr, buf, payload_size, flags
|
||||||
|
|
||||||
|
locals
|
||||||
|
packet_size dd ?
|
||||||
|
endl
|
||||||
|
DEBUGF 2, "< "
|
||||||
|
|
||||||
|
; Check how many bytes we should pad
|
||||||
|
mov eax, [payload_size]
|
||||||
|
inc eax ; padding length byte
|
||||||
|
lea edx, [eax+4] ; total packet size (without padding and MAC)
|
||||||
|
mov [packet_size], edx
|
||||||
|
|
||||||
|
mov ecx, [con_ptr]
|
||||||
|
mov ebx, [ecx+sshlib_connection.tx_pad_size]
|
||||||
|
dec ebx
|
||||||
|
and edx, ebx
|
||||||
|
neg edx
|
||||||
|
add edx, [ecx+sshlib_connection.tx_pad_size]
|
||||||
|
add edx, [ecx+sshlib_connection.tx_pad_size]
|
||||||
|
DEBUGF 1, "padding %u bytes ", edx
|
||||||
|
add [packet_size], edx ; total packet size with padding
|
||||||
|
|
||||||
|
; Start building the packet
|
||||||
|
; First comes the packet length, in network byte order ofcourse.
|
||||||
|
add eax, edx
|
||||||
|
DEBUGF 1, "total size: %u ", eax
|
||||||
|
bswap eax
|
||||||
|
lea edi, [ecx+sshlib_connection.tx_buffer]
|
||||||
|
stosd
|
||||||
|
; Then the padding length
|
||||||
|
mov al, dl
|
||||||
|
stosb
|
||||||
|
; And the actual payload bytes
|
||||||
|
mov esi, [buf]
|
||||||
|
mov ecx, [payload_size]
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
; Append the packet with #edx padding bytes.
|
||||||
|
; Since we must pad at least 8 bytes, we can always use DWORD writes.
|
||||||
|
; First do an (unaligned) write exactly following the data
|
||||||
|
dec edx
|
||||||
|
mov esi, edx
|
||||||
|
shr esi, 2 ; number dwords
|
||||||
|
mov ebx, edx
|
||||||
|
and ebx, 3
|
||||||
|
inc ebx ; number bytes in first write (1-4)
|
||||||
|
mov edx, [con_ptr]
|
||||||
|
call [edx+sshlib_connection.tx_pad_proc]
|
||||||
|
mov dword[edi], eax
|
||||||
|
add edi, ebx
|
||||||
|
; Then, do as many aligned writes as nescessary
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
@@:
|
||||||
|
call [ebx+sshlib_connection.tx_pad_proc]
|
||||||
|
stosd
|
||||||
|
dec esi
|
||||||
|
jnz @r
|
||||||
|
|
||||||
|
; Append the packet with Message Authentication Code
|
||||||
|
mov edx, [con_ptr]
|
||||||
|
cmp [edx+sshlib_connection.tx_mac_proc], 0
|
||||||
|
je .mac_complete
|
||||||
|
DEBUGF 1, "MAC sequence number: 0x%x\n", [edx+sshlib_connection.tx_mac_seqnr]
|
||||||
|
lea esi, [edx+sshlib_connection.tx_mac_seqnr]
|
||||||
|
mov ecx, [packet_size]
|
||||||
|
add ecx, 4 ; Sequence number length
|
||||||
|
lea eax, [edx+sshlib_connection.tx_mac_ctx]
|
||||||
|
stdcall [edx+sshlib_connection.tx_mac_proc], eax, esi, ecx
|
||||||
|
|
||||||
|
lea esi, [edx+sshlib_connection.tx_mac_ctx]
|
||||||
|
lea edi, [edx+sshlib_connection.tx_buffer]
|
||||||
|
add edi, [packet_size]
|
||||||
|
mov ecx, [edx+sshlib_connection.tx_mac_length]
|
||||||
|
shr ecx, 2
|
||||||
|
rep movsd
|
||||||
|
.mac_complete:
|
||||||
|
add byte[edx+sshlib_connection.tx_mac_seqnr+3], 1 ; Update sequence counter
|
||||||
|
adc byte[edx+sshlib_connection.tx_mac_seqnr+2], 0
|
||||||
|
adc byte[edx+sshlib_connection.tx_mac_seqnr+1], 0
|
||||||
|
adc byte[edx+sshlib_connection.tx_mac_seqnr+0], 0
|
||||||
|
|
||||||
|
; Now, encrypt everything but MAC
|
||||||
|
lea esi, [edx+sshlib_connection.tx_buffer]
|
||||||
|
mov ecx, [packet_size]
|
||||||
|
.encrypt_loop:
|
||||||
|
pusha
|
||||||
|
stdcall [edx+sshlib_connection.tx_crypt_proc], [edx+sshlib_connection.tx_crypt_ctx_ptr], esi, esi
|
||||||
|
popa
|
||||||
|
add esi, [edx+sshlib_connection.tx_crypt_blocksize]
|
||||||
|
sub ecx, [edx+sshlib_connection.tx_crypt_blocksize]
|
||||||
|
jnz .encrypt_loop
|
||||||
|
|
||||||
|
; Send the packet
|
||||||
|
mov ebx, [con_ptr]
|
||||||
|
mov ecx, [ebx+sshlib_connection.socketnum]
|
||||||
|
lea edx, [ebx+sshlib_connection.tx_buffer]
|
||||||
|
mov esi, [packet_size]
|
||||||
|
add esi, [ebx+sshlib_connection.tx_mac_length]
|
||||||
|
mov edi, [flags]
|
||||||
|
mcall send
|
||||||
|
|
||||||
|
DEBUGF 1, "\n"
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
149
programs/network/ssh/sshlib_userauth.inc
Normal file
149
programs/network/ssh/sshlib_userauth.inc
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
; ssh_userauth.inc - SSH user authentication
|
||||||
|
;
|
||||||
|
; Copyright (C) 2021 Jeffrey Amelynck
|
||||||
|
;
|
||||||
|
; This program is free software: you can redistribute it and/or modify
|
||||||
|
; it under the terms of the GNU General Public License as published by
|
||||||
|
; the Free Software Foundation, either version 3 of the License, or
|
||||||
|
; (at your option) any later version.
|
||||||
|
;
|
||||||
|
; This program is distributed in the hope that it will be useful,
|
||||||
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
; GNU General Public License for more details.
|
||||||
|
;
|
||||||
|
; You should have received a copy of the GNU General Public License
|
||||||
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
proc sshlib_userauth_password con_ptr, username_sz, password_sz
|
||||||
|
|
||||||
|
; >> Request service (user-auth)
|
||||||
|
|
||||||
|
DEBUGF 2, "SSH: Requesting service\n"
|
||||||
|
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ssh_msg_request_service, ssh_msg_request_service.length, 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
; << Check for service acceptance
|
||||||
|
|
||||||
|
stdcall sshlib_msg_handler, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov eax, [con_ptr]
|
||||||
|
cmp [eax + sshlib_connection.rx_buffer.message_code], SSH_MSG_SERVICE_ACCEPT
|
||||||
|
jne .err_proto
|
||||||
|
|
||||||
|
; >> Request user authentication
|
||||||
|
|
||||||
|
DEBUGF 2, "SSH: User authentication\n"
|
||||||
|
|
||||||
|
mcall 68, 12, 1024 ; FIXME: hardcoded size
|
||||||
|
test eax, eax
|
||||||
|
jz .err_nomem
|
||||||
|
mov edi, eax
|
||||||
|
mov ebx, eax
|
||||||
|
mov byte[edi], SSH_MSG_USERAUTH_REQUEST
|
||||||
|
inc edi
|
||||||
|
|
||||||
|
; Insert username
|
||||||
|
stdcall sz_len, [username_sz]
|
||||||
|
mov ecx, eax
|
||||||
|
mov esi, [username_sz]
|
||||||
|
bswap eax
|
||||||
|
stosd
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
mov dword[edi], 0x0e000000 ; 14 Bswapped
|
||||||
|
mov dword[edi+4], "ssh-"
|
||||||
|
mov dword[edi+8], "conn"
|
||||||
|
mov dword[edi+12], "ecti"
|
||||||
|
mov word[edi+16], "on"
|
||||||
|
add edi, 18
|
||||||
|
|
||||||
|
mov dword[edi], 0x08000000 ; 8 Bswapped
|
||||||
|
mov dword[edi+4], "pass"
|
||||||
|
mov dword[edi+8], "word"
|
||||||
|
|
||||||
|
mov byte[edi+12], 0 ; bool
|
||||||
|
add edi, 13
|
||||||
|
|
||||||
|
; Insert password
|
||||||
|
stdcall sz_len, [password_sz]
|
||||||
|
mov ecx, eax
|
||||||
|
mov esi, [password_sz]
|
||||||
|
bswap eax
|
||||||
|
stosd
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
sub edi, ebx
|
||||||
|
push ebx
|
||||||
|
stdcall sshlib_send_packet, [con_ptr], ebx, edi, 0
|
||||||
|
|
||||||
|
; Clear used buffer and free
|
||||||
|
pop edx
|
||||||
|
mov edi, edx
|
||||||
|
push eax
|
||||||
|
mov ecx, 1024/4 ; FIXME
|
||||||
|
xor eax, eax
|
||||||
|
rep stosd
|
||||||
|
mcall 68, 13, edx
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
; << Check for userauth acceptance
|
||||||
|
@@:
|
||||||
|
stdcall sshlib_msg_handler, [con_ptr], 0
|
||||||
|
cmp eax, 0
|
||||||
|
jl .err
|
||||||
|
|
||||||
|
mov eax, [con_ptr]
|
||||||
|
mov al, [eax + sshlib_connection.rx_buffer.message_code]
|
||||||
|
|
||||||
|
cmp al, SSH_MSG_USERAUTH_BANNER
|
||||||
|
je @r ; TODO
|
||||||
|
|
||||||
|
cmp al, SSH_MSG_USERAUTH_FAILURE
|
||||||
|
je .fail
|
||||||
|
|
||||||
|
cmp al, SSH_MSG_USERAUTH_SUCCESS
|
||||||
|
jne .err_proto
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
.err:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.fail:
|
||||||
|
xor eax, eax
|
||||||
|
inc eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_proto:
|
||||||
|
mov eax, SSHLIB_ERR_PROTOCOL
|
||||||
|
ret
|
||||||
|
|
||||||
|
.err_nomem:
|
||||||
|
mov eax, SSHLIB_ERR_NOMEM
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
endp
|
||||||
|
|
||||||
|
|
||||||
|
; Actually, string is \n and/or \0 terminated 0_o
|
||||||
|
proc sz_len uses ecx edi, string
|
||||||
|
|
||||||
|
mov edi, [string]
|
||||||
|
mov ecx, 256 ;;;;
|
||||||
|
mov al, 10
|
||||||
|
repne scasb
|
||||||
|
dec edi
|
||||||
|
sub edi, [string]
|
||||||
|
mov eax, edi
|
||||||
|
ret
|
||||||
|
|
||||||
|
endp
|
Loading…
Reference in New Issue
Block a user