Subversion Repositories Kolibri OS

Rev

Rev 9216 | Rev 9990 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9106 hidnplayr 1
;    sshlib_connection.inc - SSH connection
2
;
9987 hidnplayr 3
;    Copyright (C) 2016-2024 Jeffrey Amelynck
9106 hidnplayr 4
;
5
;    This program is free software: you can redistribute it and/or modify
6
;    it under the terms of the GNU General Public License as published by
7
;    the Free Software Foundation, either version 3 of the License, or
8
;    (at your option) any later version.
9
;
10
;    This program is distributed in the hope that it will be useful,
11
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
;    GNU General Public License for more details.
14
;
15
;    You should have received a copy of the GNU General Public License
16
;    along with this program.  If not, see .
17
 
9987 hidnplayr 18
; https://www.ietf.org/rfc/rfc4253.txt
19
 
9106 hidnplayr 20
proc sshlib_connect con_ptr, hostname_sz
21
 
22
locals
23
        socketnum       dd ?
24
        sockaddr        sockaddr_in
25
        ctx_ptr         dd ?
26
endl
27
 
28
        mov     edi, [con_ptr]
29
        lea     eax, [edi + sshlib_connection.part_ex_hash_ctx]
30
        mov     [ctx_ptr], eax
31
 
32
; Set default values in sockaddr struct
33
        mov     [sockaddr.sin_family], AF_INET4
34
        mov     [sockaddr.sin_port], 22 shl 8
35
 
36
; Parse hostname_sz
37
; Verify length, extract port number if given and copy base url to sshlib_connection struct
38
; Port number, if provided, will be written in sockaddr struct.
39
; Hostname ends with any character equal to 0x20 or lower
40
 
41
        mov     esi, [hostname_sz]
42
        lea     edi, [edi + sshlib_connection.hostname_sz]
43
        mov     ecx, MAX_HOSTNAME_LENGTH
44
  @@:
45
        dec     ecx
46
        jz      .err_hostname
47
        lodsb
48
        cmp     al, ':'
49
        je      .do_port
50
        stosb
51
        cmp     al, 0x20
52
        ja      @r
53
        mov     byte[edi-1], 0
54
        jmp     .hostname_ok
55
 
56
  .do_port:
57
        xor     eax, eax
58
        xor     ebx, ebx
59
        mov     byte[edi-1], 0
60
  .portloop:
61
        lodsb
62
        cmp     al, 0x20
63
        jbe     .port_done
64
        sub     al, '0'
65
        jb      .err_hostname
66
        cmp     al, 9
67
        ja      .err_hostname
68
        lea     ebx, [ebx*4+ebx]
69
        shl     ebx, 1
70
        add     ebx, eax
71
        jmp     .portloop
72
  .port_done:
73
        xchg    bl, bh
74
        mov     [sockaddr.sin_port], bx
75
 
76
  .hostname_ok:
77
; resolve name
78
        push    esp     ; reserve stack place
79
        push    esp
80
        mov     eax, [con_ptr]
81
        lea     eax, [eax+sshlib_connection.hostname_sz]
82
        invoke  getaddrinfo, eax, 0, 0
83
        pop     esi
84
; test for error
85
        test    eax, eax
86
        jnz     .err_hostname
87
 
88
; convert IP address to decimal notation
89
        mov     eax, [esi+addrinfo.ai_addr]
90
        mov     eax, [eax+sockaddr_in.sin_addr]
91
        mov     [sockaddr.sin_addr], eax
92
        invoke  inet_ntoa, eax
93
; write result
94
        stdcall sshlib_callback_connecting, [con_ptr], eax
95
; free allocated memory
96
        invoke  freeaddrinfo, esi
97
 
98
; Create socket
99
        mcall   socket, AF_INET4, SOCK_STREAM, 0
100
        cmp     eax, -1
101
        jz      .err_sock
102
        mov     [socketnum], eax
103
        mov     ebx, [con_ptr]
104
        mov     [ebx + sshlib_connection.socketnum], eax
105
 
106
; Connect
107
        DEBUGF  2, "Connecting to server\n"
108
        lea     edx, [sockaddr]
109
        mcall   connect, [socketnum], , sizeof.sockaddr_in
110
        test    eax, eax
111
        jnz     .err_sock
112
 
113
; Start calculating hash
9216 dunkaist 114
        invoke  sha2_256_init, [ctx_ptr]
9106 hidnplayr 115
; HASH: string  V_C, the client's version string (CR and NL excluded)
9216 dunkaist 116
        invoke  sha2_256_update, [ctx_ptr], ssh_ident_ha, ssh_msg_ident.length+4-2
9106 hidnplayr 117
 
118
; >> Send our identification string
119
        DEBUGF  2, "Sending ID string\n"
120
        mcall   send, [socketnum], ssh_msg_ident, ssh_msg_ident.length, 0
121
        cmp     eax, -1
122
        je      .err_sock
123
 
124
; << Check protocol version of server
125
        mov     edx, [con_ptr]
126
        lea     edx, [edx + sshlib_connection.rx_buffer + 4]
127
        mcall   recv, [socketnum], , PACKETSIZE, 0
128
        cmp     eax, -1
129
        je      .err_sock
130
 
131
        DEBUGF  2, "Received ID string\n"
132
        cmp     dword[edx], "SSH-"
133
        jne     .err_proto
134
        cmp     dword[edx+4], "2.0-"
135
        jne     .err_proto
136
 
137
; HASH: string  V_S, the server's version string (CR and NL excluded)
138
        lea     ecx, [eax+2]
139
        sub     eax, 2
140
        bswap   eax
141
        sub     edx, 4
142
        mov     dword[edx], eax
9216 dunkaist 143
        invoke  sha2_256_update, [ctx_ptr], edx, ecx
9106 hidnplayr 144
 
145
; >> Key Exchange init
146
        mov     eax, [con_ptr]
147
        mov     [eax + sshlib_connection.status], SSHLIB_CON_STAT_INIT
148
 
149
        mov     [eax + sshlib_connection.algo_kex], SSHLIB_ALGO_NONE
150
        mov     [eax + sshlib_connection.algo_hostkey], SSHLIB_ALGO_NONE
151
        mov     [eax + sshlib_connection.algo_crypt_rx], SSHLIB_ALGO_NONE
152
        mov     [eax + sshlib_connection.algo_crypt_tx], SSHLIB_ALGO_NONE
153
        mov     [eax + sshlib_connection.algo_mac_rx], SSHLIB_ALGO_NONE
154
        mov     [eax + sshlib_connection.algo_mac_tx], SSHLIB_ALGO_NONE
155
        mov     [eax + sshlib_connection.algo_compr_rx], SSHLIB_ALGO_NONE
156
        mov     [eax + sshlib_connection.algo_compr_tx], SSHLIB_ALGO_NONE
157
 
158
        mov     [eax + sshlib_connection.rx_mac_seqnr], 0
159
        mov     [eax + sshlib_connection.tx_mac_seqnr], 0
160
        mov     [eax + sshlib_connection.rx_crypt_blocksize], 4             ; minimum blocksize
161
        mov     [eax + sshlib_connection.tx_crypt_blocksize], 4
9987 hidnplayr 162
        mov     [eax + sshlib_connection.rx_crypt_proc], 0
163
        mov     [eax + sshlib_connection.tx_crypt_proc], 0
9106 hidnplayr 164
        mov     [eax + sshlib_connection.rx_mac_proc], 0
165
        mov     [eax + sshlib_connection.tx_mac_proc], 0
166
        mov     [eax + sshlib_connection.rx_mac_length], 0
167
        mov     [eax + sshlib_connection.tx_mac_length], 0
168
        mov     [eax + sshlib_connection.tx_pad_size], 8
169
 
9987 hidnplayr 170
        mov     [eax + sshlib_connection.rx_proc], sshlib_recv_packet_clear
171
        mov     [eax + sshlib_connection.tx_proc], sshlib_send_packet_clear
172
 
9106 hidnplayr 173
        DEBUGF  2, "Sending KEX init\n"
174
        mov     edi, ssh_msg_kex.cookie
175
        call    MBRandom
176
        stosd
177
        call    MBRandom
178
        stosd
179
        call    MBRandom
180
        stosd
181
        call    MBRandom
182
        stosd
183
        stdcall sshlib_send_packet, [con_ptr], ssh_msg_kex, ssh_msg_kex.length, 0
184
        cmp     eax, -1
185
        je      .err_sock
186
 
187
; HASH: string  I_C, the payload of the client's SSH_MSG_KEXINIT
188
        mov     esi, [con_ptr]
189
        mov     eax, [esi+sshlib_connection.tx_buffer.packet_length]
190
        bswap   eax
191
        movzx   ebx, [esi+sshlib_connection.tx_buffer.padding_length]
192
        sub     eax, ebx
193
        dec     eax
194
        lea     edx, [eax+4]
195
        bswap   eax
196
        lea     esi, [esi+sshlib_connection.tx_buffer+1]
197
        mov     dword[esi], eax
9216 dunkaist 198
        invoke  sha2_256_update, [ctx_ptr], esi, edx
9106 hidnplayr 199
 
200
; << Check key exchange init of server
201
        stdcall sshlib_recv_packet, [con_ptr], 0
202
        cmp     eax, -1
203
        je      .err_sock
204
 
205
        mov     esi, [con_ptr]
206
        cmp     [esi + sshlib_connection.rx_buffer.message_code], SSH_MSG_KEXINIT
207
        jne     .err_proto
208
        DEBUGF  2, "Received KEX init\n"
209
 
210
        lea     esi, [esi + sshlib_connection.rx_buffer + sizeof.ssh_packet_header + 16]
211
        lodsd
212
        bswap   eax
213
        DEBUGF  1, "kex_algorithms: %s\n", esi
214
        add     esi, eax
215
        lodsd
216
        bswap   eax
217
        DEBUGF  1, "server_host_key_algorithms: %s\n", esi
218
        add     esi, eax
219
        lodsd
220
        bswap   eax
221
        DEBUGF  1, "encryption_algorithms_client_to_server: %s\n", esi
222
        add     esi, eax
223
        lodsd
224
        bswap   eax
225
        DEBUGF  1, "encryption_algorithms_server_to_client: %s\n", esi
226
        add     esi, eax
227
        lodsd
228
        bswap   eax
229
        DEBUGF  1, "mac_algorithms_client_to_server: %s\n", esi
230
        add     esi, eax
231
        lodsd
232
        bswap   eax
233
        DEBUGF  1, "mac_algorithms_server_to_client: %s\n", esi
234
        add     esi, eax
235
        lodsd
236
        bswap   eax
237
        DEBUGF  1, "compression_algorithms_client_to_server: %s\n", esi
238
        add     esi, eax
239
        lodsd
240
        bswap   eax
241
        DEBUGF  1, "compression_algorithms_server_to_client: %s\n", esi
242
        add     esi, eax
243
        lodsd
244
        bswap   eax
245
        DEBUGF  1, "languages_client_to_server: %s\n", esi
246
        add     esi, eax
247
        lodsd
248
        bswap   eax
249
        DEBUGF  1, "languages_server_to_client: %s\n", esi
250
        add     esi, eax
251
        lodsb
252
        DEBUGF  1, "KEX First Packet Follows: %u\n", al
253
 
254
; TODO: parse this structure and set algorithm codes accordingly
255
; FIXME: hardcoded for now
256
        mov     esi, [con_ptr]
257
        mov     [esi+sshlib_connection.algo_kex], SSHLIB_KEX_DH_SHA256
258
        mov     [esi+sshlib_connection.algo_hostkey], SSHLIB_HOSTKEY_RSA
259
        mov     [esi+sshlib_connection.algo_crypt_rx], SSHLIB_CRYPT_AES256_CTR
260
        mov     [esi+sshlib_connection.algo_crypt_tx], SSHLIB_CRYPT_AES256_CTR
261
        mov     [esi+sshlib_connection.algo_mac_rx], SSHLIB_HMAC_SHA2_256
262
        mov     [esi+sshlib_connection.algo_mac_tx], SSHLIB_HMAC_SHA2_256
263
        mov     [esi+sshlib_connection.algo_compr_rx], SSHLIB_COMPR_NONE
264
        mov     [esi+sshlib_connection.algo_compr_tx], SSHLIB_COMPR_NONE
265
 
266
; HASH: string I_S, the payload of the servers's SSH_MSG_KEXINIT
267
        mov     esi, [con_ptr]
268
        mov     eax, [esi+sshlib_connection.rx_buffer.packet_length]
269
        movzx   ebx, [esi+sshlib_connection.rx_buffer.padding_length]
270
        sub     eax, ebx
271
        dec     eax
272
        lea     edx, [eax+4]
273
        bswap   eax
274
        lea     esi, [esi+sshlib_connection.rx_buffer+1]
275
        mov     dword[esi], eax
9216 dunkaist 276
        invoke  sha2_256_update, [ctx_ptr], esi, edx
9106 hidnplayr 277
 
278
; Exchange keys with the server
279
 
280
        stdcall sshlib_dh_gex, [con_ptr]
281
        test    eax, eax
282
        jnz     .err
283
 
9987 hidnplayr 284
; Set keys and initialize transport subroutines
285
 
286
        DEBUGF  2, "SSH: Setting encryption keys\n"
287
 
288
        mov     ebx, [con_ptr]
289
 
290
;        lea     ecx, [ebx + sshlib_connection.rx_crypt_ctx]
291
;        lea     edx, [ebx + sshlib_connection.rx_enc_key]
292
;        lea     esi, [ebx + sshlib_connection.rx_iv]
293
;        invoke  aes256ctr.init, ecx, edx, esi, 0
294
;
295
;        push    [aes256ctr.update]
296
;        pop     [ebx + sshlib_connection.rx_crypt_proc]
297
;        mov     [ebx + sshlib_connection.rx_crypt_blocksize], 16        ; AES_BLOCKSIZE
298
;
299
;        push    [hmac_sha2_256.oneshot]
300
;        pop     [ebx + sshlib_connection.rx_mac_proc]
301
;        mov     [ebx + sshlib_connection.rx_mac_length], SHA2_256_LEN
302
;
303
;        lea     ecx, [ebx + sshlib_connection.tx_crypt_ctx]
304
;        lea     edx, [ebx + sshlib_connection.tx_enc_key]
305
;        lea     esi, [ebx + sshlib_connection.tx_iv]
306
;        invoke  aes256ctr.init, ecx, edx, esi, 0
307
;
308
;        push    [aes256ctr.update]
309
;        pop     [ebx + sshlib_connection.tx_crypt_proc]
310
;        mov     [ebx + sshlib_connection.tx_crypt_blocksize], 16        ; AES_BLOCKSIZE
311
;        mov     [ebx + sshlib_connection.tx_pad_size], 16               ; AES_BLOCKSIZE
312
;
313
;        push    [hmac_sha2_256.oneshot]
314
;        pop     [ebx + sshlib_connection.tx_mac_proc]
315
;        mov     [ebx + sshlib_connection.tx_mac_length], SHA2_256_LEN
316
;
317
;        mov     [ebx + sshlib_connection.rx_proc], sshlib_recv_packet_hmac
318
;        mov     [ebx + sshlib_connection.tx_proc], sshlib_send_packet_hmac
319
 
320
        mov     [ebx + sshlib_connection.rx_proc], sshlib_recv_packet_poly1305chacha20
321
        mov     [ebx + sshlib_connection.tx_proc], sshlib_send_packet_poly1305chacha20
322
 
9106 hidnplayr 323
; Re-seed RNG for padding bytes
324
 
325
        call    create_seed
326
        call    init_random
327
 
328
        xor     eax, eax
329
        ret
330
 
331
  .err_hostname:
332
        mov     eax, SSHLIB_ERR_HOSTNAME
333
        ret
334
 
335
  .err_sock:
336
        mov     eax, SSHLIB_ERR_SOCKET
337
        ret
338
 
339
  .err_proto:
340
        mov     eax, SSHLIB_ERR_PROTOCOL
341
        ret
342
 
343
  .err:
344
        ret
345
 
346
endp
347
 
348
 
349
 
350
 
351
; Handle common messages and return to caller for specific ones
352
proc sshlib_msg_handler, con_ptr, flags
353
 
354
  .recv:
355
; Send a window update if advertised window drops below half
356
        cmp     [ssh_chan.rcv_wnd], BUFFERSIZE/2
357
        ja      .no_wnd
358
        mov     eax, BUFFERSIZE
359
        bswap   eax
360
        mov     [ssh_msg_channel_window_adjust.wnd], eax
361
        stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_window_adjust, ssh_msg_channel_window_adjust.length, 0
362
        mov     [ssh_chan.rcv_wnd], BUFFERSIZE
363
  .no_wnd:
364
 
365
; Receive 1 SSH packet
366
        stdcall sshlib_recv_packet, [con_ptr], [flags]
367
        cmp     eax, 0
368
        jle     .ret
369
 
370
        mov     esi, [con_ptr]
371
        lea     esi, [esi + sshlib_connection.rx_buffer]
372
        mov     al, [esi + ssh_packet_header.message_code]
9987 hidnplayr 373
        add     esi, sizeof.ssh_packet_header
9106 hidnplayr 374
 
375
        cmp     al, SSH_MSG_DISCONNECT
376
        je      .disc
377
        cmp     al, SSH_MSG_IGNORE
378
        je      .ign
379
        cmp     al, SSH_MSG_DEBUG
380
        je      .dbg
381
        cmp     al, SSH_MSG_GLOBAL_REQUEST
382
        je      .glob_req
383
        cmp     al, SSH_MSG_CHANNEL_WINDOW_ADJUST
384
        je      .chan_win_adj
385
;        cmp     al, SSH_MSG_CHANNEL_REQUEST
386
;        je      .chan_req
387
        cmp     al, SSH_MSG_CHANNEL_EOF
388
        je      .chan_eof
389
        cmp     al, SSH_MSG_CHANNEL_CLOSE
390
        je      .chan_close
391
 
9987 hidnplayr 392
        DEBUGF  3, "SSH: Message type: %u\n", al
393
 
9106 hidnplayr 394
  .ret:
395
        ret
396
 
397
  .disc:
398
        DEBUGF  3, "SSH: Disconnect message received\n"
399
        mov     eax, SSHLIB_ERR_DISCONNECTING
400
        ret
401
 
402
  .ign:
403
        DEBUGF  3, "SSH: Ignore MSG received\n"
404
        jmp     .recv
405
 
406
  .dbg:
407
        DEBUGF  3, "SSH: Debug MSG received\n"
408
        ;TODO
409
        jmp     .recv
410
 
411
  .glob_req:
9987 hidnplayr 412
        add     esi, 4
413
        DEBUGF  3, "SSH: Global MSG received: %s\n", esi
9106 hidnplayr 414
        ;TODO
415
        jmp     .recv
416
 
417
  .chan_win_adj:
418
        mov     eax, dword[esi]
419
        bswap   eax
420
        mov     [ssh_chan.snd_wnd], eax
421
        ; TODO: validate channel number, act accordingly
422
        DEBUGF  3, "SSH: Channel %u window update received\n", eax
423
        jmp     .recv
424
 
425
  .chan_eof:
426
        mov     eax, dword[esi]
427
        bswap   eax
428
        ; TODO: validate channel number, act accordingly
429
        DEBUGF  3, "SSH: Channel %u EOF received\n", eax
430
        jmp     .recv
431
 
432
  .chan_close:
433
        mov     eax, dword[esi]
434
        bswap   eax
435
        ; TODO: validate channel number
436
        DEBUGF  3, "SSH: Channel %u close received\n", eax
437
        ; Reply with close message
438
        stdcall sshlib_send_packet, [con_ptr], ssh_msg_channel_close, ssh_msg_channel_close.length, 0
439
        xor     eax, eax
440
        ret
441
 
9216 dunkaist 442
endp