Subversion Repositories Kolibri OS

Rev

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

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