@@ -50,6 +50,7 @@ type t = {
50
50
user_db : Auth .db ; (* username database *)
51
51
channels : Channel .db ; (* Ssh channels *)
52
52
ignore_next_packet : bool ; (* Ignore the next packet from the wire *)
53
+ dh_group : (Mirage_crypto_pk.Dh .group * int32 * int32 * int32 ) option ; (* used for GEX (RFC 4419) *)
53
54
}
54
55
55
56
let guard_msg t msg =
@@ -70,7 +71,7 @@ let make host_key user_db =
70
71
let open Ssh in
71
72
let server_kexinit =
72
73
let algs = host_key_algs host_key in
73
- Kex. make_kexinit algs Kex. server_supported ()
74
+ Kex. make_kexinit algs Kex. supported ()
74
75
in
75
76
let banner_msg = Ssh. Msg_version version_banner in
76
77
let kex_msg = Ssh. Msg_kexinit server_kexinit in
@@ -92,7 +93,9 @@ let make host_key user_db =
92
93
auth_state = Auth. Preauth ;
93
94
user_db;
94
95
channels = Channel. empty_db;
95
- ignore_next_packet = false },
96
+ ignore_next_packet = false ;
97
+ dh_group = None ;
98
+ },
96
99
[ banner_msg; kex_msg ]
97
100
98
101
(* t with updated keys from new_keys_ctos *)
@@ -116,7 +119,7 @@ let rekey t =
116
119
| false , true -> (* can't be keying and must be keyed *)
117
120
let server_kexinit =
118
121
let algs = host_key_algs t.host_key in
119
- Kex. make_kexinit algs Kex. server_supported ()
122
+ Kex. make_kexinit algs Kex. supported ()
120
123
in
121
124
let t = { t with server_kexinit; keying = true } in
122
125
Some (t, Ssh. Msg_kexinit server_kexinit)
@@ -341,60 +344,139 @@ let input_msg t msg now =
341
344
kex.first_kex_packet_follows &&
342
345
not (Kex. guessed_right ~s: t.server_kexinit ~c: kex)
343
346
in
347
+ let expect =
348
+ Some (if Kex. is_rfc4419 neg.kex_alg then MSG_KEX_4 else MSG_KEX_0 )
349
+ in
344
350
let t = { t with client_kexinit = Some kex;
345
351
neg_kex = Some neg;
346
- expect = Some MSG_KEX_0 ; (* TODO needs fix *)
352
+ expect;
347
353
ignore_next_packet;
348
354
ext_info = kex.ext_info = Some `Ext_info_c ; }
349
355
in
350
356
(match rekey t with
351
357
| None -> make_noreply t (* either already rekeying or not keyed *)
352
358
| Some (t , kexinit ) -> make_reply t kexinit)
353
359
| Msg_kex (id , data ) ->
354
- begin
355
- let * m = Wire. dh_kexdh_of_kex id data in
356
- match m with
357
- | Msg_kexdh_init e ->
358
- let * neg = guard_some t.neg_kex " No negotiated kex" in
359
- let * client_version = guard_some t.client_version " No client version" in
360
- let * () = guard_none t.new_keys_stoc " Already got new_keys_stoc" in
361
- let * () = guard_none t.new_keys_ctos " Already got new_keys_ctos" in
362
- let * c = guard_some t.client_kexinit " No client kex" in
363
- let * f, k = Kex. (Dh. generate neg.kex_alg e) in
364
- let pub_host_key = Hostkey. pub_of_priv t.host_key in
365
- let h = Kex.Dh. compute_hash ~signed: true neg
366
- ~v_c: client_version
367
- ~v_s: t.server_version
368
- ~i_c: c.rawkex
369
- ~i_s: (Wire. blob_of_kexinit t.server_kexinit)
370
- ~k_s: pub_host_key
371
- ~e ~f ~k
360
+ let exts =
361
+ if t.ext_info then
362
+ let algs =
363
+ String. concat " ,"
364
+ (List. map Hostkey. alg_to_string (host_key_algs t.host_key));
372
365
in
373
- let signature = Hostkey. sign neg.server_host_key_alg t.host_key h in
374
- let session_id = match t.session_id with None -> h | Some x -> x in
375
- let * new_keys_ctos, new_keys_stoc, key_eol =
376
- Kex.Dh. derive_keys k h session_id neg now
366
+ let extensions =
367
+ [Extension { name = " server-sig-algs" ; value = algs; }]
377
368
in
378
- let signature = neg.server_host_key_alg, signature in
379
- make_replies { t with session_id = Some session_id;
380
- new_keys_ctos = Some new_keys_ctos;
381
- new_keys_stoc = Some new_keys_stoc;
382
- key_eol = Some key_eol;
383
- expect = Some MSG_NEWKEYS }
384
- ([ Msg_kexdh_reply (pub_host_key, f, signature); Msg_newkeys ] @ (
385
- if t.ext_info then
386
- let algs =
387
- String. concat " ,"
388
- (List. map Hostkey. alg_to_string (host_key_algs t.host_key));
389
- in
390
- let extensions =
391
- [Extension { name = " server-sig-algs" ;
392
- value = algs; }]
393
- in
394
- [ Msg_ext_info extensions ]
395
- else [] ))
396
- | _ ->
397
- Error " unexpected KEX message"
369
+ [ Msg_ext_info extensions ]
370
+ else []
371
+ in
372
+ let sign_rekey t neg ~h ~f ~k =
373
+ let signature = Hostkey. sign neg.Kex. server_host_key_alg t.host_key h in
374
+ Log. debug (fun m -> m " shared is %a signature is %a (hash %a)"
375
+ Cstruct. hexdump_pp (Mirage_crypto_pk.Z_extra. to_cstruct_be f)
376
+ Cstruct. hexdump_pp signature Cstruct. hexdump_pp h);
377
+ let session_id = match t.session_id with None -> h | Some x -> x in
378
+ let * new_keys_ctos, new_keys_stoc, key_eol =
379
+ Kex.Dh. derive_keys k h session_id neg now
380
+ in
381
+ let signature = neg.server_host_key_alg, signature in
382
+ Ok ({ t with session_id = Some session_id;
383
+ new_keys_ctos = Some new_keys_ctos;
384
+ new_keys_stoc = Some new_keys_stoc;
385
+ key_eol = Some key_eol;
386
+ expect = Some MSG_NEWKEYS },
387
+ signature,
388
+ Msg_newkeys :: exts)
389
+ in
390
+ let cv_ckex t =
391
+ let * client_version = guard_some t.client_version " No client version" in
392
+ let * () = guard_none t.new_keys_stoc " Already got new_keys_stoc" in
393
+ let * () = guard_none t.new_keys_ctos " Already got new_keys_ctos" in
394
+ let * c = guard_some t.client_kexinit " No client kex" in
395
+ Ok (client_version, c.rawkex)
396
+ in
397
+ let dh ~ec t neg ~e ~f ~k =
398
+ let * client_version, i_c = cv_ckex t in
399
+ let pub_host_key = Hostkey. pub_of_priv t.host_key in
400
+ let h = Kex.Dh. compute_hash ~signed: (not ec) neg
401
+ ~v_c: client_version
402
+ ~v_s: t.server_version
403
+ ~i_c
404
+ ~i_s: (Wire. blob_of_kexinit t.server_kexinit)
405
+ ~k_s: pub_host_key
406
+ ~e ~f ~k
407
+ in
408
+ let * t, signature, msgs = sign_rekey t neg ~h ~f ~k in
409
+ Ok (t, (pub_host_key, signature), msgs)
410
+ in
411
+ begin
412
+ match t.neg_kex with
413
+ | None -> Error " No negotiated kex"
414
+ | Some neg ->
415
+ if Kex. is_rfc4419 neg.kex_alg then
416
+ let * m = Wire. dh_kexdh_gex_of_kex id data in
417
+ match t.dh_group, m with
418
+ | None , Msg_kexdh_gex_request (min , n , max ) ->
419
+ let * group =
420
+ if max < 2048l then
421
+ Error " maximum group size too small"
422
+ else if min > 8192l then
423
+ Error " minimum group size too big"
424
+ else if min > n || n > max then
425
+ Error " group size limits wrong (min <= n <= max)"
426
+ else if n < 3072l then
427
+ Ok Mirage_crypto_pk.Dh.Group. ffdhe2048
428
+ else if n < 4096l then
429
+ Ok Mirage_crypto_pk.Dh.Group. ffdhe3072
430
+ else if n < 6144l then
431
+ Ok Mirage_crypto_pk.Dh.Group. ffdhe4096
432
+ else if n < 8192l then
433
+ Ok Mirage_crypto_pk.Dh.Group. ffdhe6144
434
+ else
435
+ Ok Mirage_crypto_pk.Dh.Group. ffdhe8192
436
+ in
437
+ make_replies { t with
438
+ dh_group = Some (group, min, n, max);
439
+ expect = Some MSG_KEX_2 }
440
+ [ Msg_kexdh_gex_group (group.p, group.gg) ]
441
+ | Some (group , min , n , max ), Msg_kexdh_gex_init theirs ->
442
+ let secret, my_share = Mirage_crypto_pk.Dh. gen_key group in
443
+ let * client_version, i_c = cv_ckex t in
444
+ let * k = Kex.Dh. shared secret theirs in
445
+ let pub_host_key = Hostkey. pub_of_priv t.host_key in
446
+ let f = Mirage_crypto_pk.Z_extra. of_cstruct_be my_share in
447
+ let h =
448
+ Kex.Dh. compute_hash_gex neg
449
+ ~v_c: client_version ~v_s: t.server_version
450
+ ~i_c ~i_s: (Wire. blob_of_kexinit t.server_kexinit)
451
+ ~k_s: pub_host_key
452
+ ~min ~n ~max
453
+ ~p: group.p ~g: group.gg
454
+ ~e: theirs ~f
455
+ ~k
456
+ in
457
+ let * t, sig_, msgs = sign_rekey t neg ~h ~f ~k in
458
+ make_replies t
459
+ (Msg_kexdh_gex_reply (pub_host_key, f, sig_) :: msgs)
460
+ | _ -> Error " unexpected KEX message"
461
+ else if Kex. is_finite_field neg.kex_alg then
462
+ let * m = Wire. dh_kexdh_of_kex id data in
463
+ match m with
464
+ | Msg_kexdh_init e ->
465
+ let * f, k = Kex. (Dh. generate neg.kex_alg e) in
466
+ let * (t, (key, sig_), msgs) = dh ~ec: false t neg ~e ~f ~k in
467
+ make_replies t
468
+ (Msg_kexdh_reply (key, f, sig_) :: msgs)
469
+ | _ -> Error " unexpected KEX message"
470
+ else (* EC *)
471
+ let * m = Wire. dh_kexecdh_of_kex id data in
472
+ match m with
473
+ | Msg_kexecdh_init e ->
474
+ let secret, f = Kex.Dh. ec_secret_pub neg.kex_alg in
475
+ let * k = Kex.Dh. ec_shared secret e in
476
+ let * (t, (key, sig_), msgs) = dh ~ec: true t neg ~e ~f ~k in
477
+ make_replies t
478
+ (Msg_kexecdh_reply (key, f, sig_) :: msgs)
479
+ | _ -> Error " unexpected KEX message"
398
480
end
399
481
| Msg_newkeys ->
400
482
(* If this is the first time we keyed, we must take a service request *)
0 commit comments