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/>.
|
||||
|
||||
struct aes256_ctr_context aes256_context
|
||||
|
||||
counter rb AES256_BLOCKSIZE
|
||||
output rb AES256_BLOCKSIZE ; counter after aes_crypt
|
||||
|
||||
ends
|
||||
|
||||
|
||||
proc aes256_ctr_init _counter
|
||||
|
||||
push ebx esi edi
|
||||
|
||||
mcall 68, 12, sizeof.aes256_ctr_context
|
||||
@ -34,6 +37,7 @@ proc aes256_ctr_init _counter
|
||||
|
||||
pop edi esi ebx
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
|
||||
@ -84,7 +88,7 @@ proc aes256_ctr_crypt _ctx, _in, _out
|
||||
bswap ecx
|
||||
bswap edx
|
||||
|
||||
inc edx
|
||||
adc edx, 1
|
||||
adc ecx, 0
|
||||
adc ebx, 0
|
||||
adc eax, 0
|
||||
|
@ -84,7 +84,7 @@ proc blowfish_ctr_crypt _ctx, _in, _out
|
||||
bswap ecx
|
||||
bswap edx
|
||||
|
||||
inc edx
|
||||
adc edx, 1
|
||||
adc ecx, 0
|
||||
adc ebx, 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_SUCCESS = 52
|
||||
SSH_MSG_USERAUTH_BANNER = 53
|
||||
SSH_MSG_USERAUTH_PASSWD_CHANGEREQ = 60
|
||||
SSH_MSG_GLOBAL_REQUEST = 80
|
||||
SSH_MSG_REQUEST_SUCCESS = 81
|
||||
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