Skip to content

Commit

Permalink
The NEWKEYS activation is independent of direction.
Browse files Browse the repository at this point in the history
Basically when we send our NEWKEYS, it means we will use it to transmit and the
peer should use it as the receiving keys (obviously).

Before this, I assumed that NEWKEYS installed both ways, since both sides can
calculate the keys at that point. That's wrong.
  • Loading branch information
haesbaert committed Feb 14, 2017
1 parent 56809aa commit b834e4a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 21 deletions.
24 changes: 12 additions & 12 deletions lib/kex.ml
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,9 @@ let make_pkt () =
first_kex_packet_follows = false }

type keys = {
iiv_ctos : Cstruct.t; (* Initial IV client to server *)
iiv_stoc : Cstruct.t; (* Initial IV server to client *)
enc_ctos : Cstruct.t; (* Encryption key client to server *)
enc_stoc : Cstruct.t; (* Encryption key server to client *)
int_ctos : Cstruct.t; (* Integrity key client to server *)
int_stoc : Cstruct.t; (* Integrity key server to client *)
iiv : Cstruct.t; (* Initial IV *)
enc : Cstruct.t; (* Encryption key *)
mac : Cstruct.t; (* Integrity key *)
}

let derive_keys digestv k h session_id need =
Expand All @@ -75,12 +72,15 @@ let derive_keys digestv k h session_id need =
Cstruct.set_char x 0 ch;
expand (digestv [k; h; x; session_id])
in
{ iiv_ctos = hash 'A';
iiv_stoc = hash 'B';
enc_ctos = hash 'C';
enc_stoc = hash 'D';
int_ctos = hash 'E';
int_stoc = hash 'F'; }
let ctos = { iiv = hash 'A';
enc = hash 'C';
mac = hash 'E'; }
in
let stoc = { iiv = hash 'B';
enc = hash 'D';
mac = hash 'F'; }
in
(ctos, stoc)

type negotiation = {
kex_algorithm : algorithm;
Expand Down
33 changes: 24 additions & 9 deletions lib/server.ml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ type t = {
neg_kex : Kex.negotiation option; (* Negotiated KEX *)
host_key : Nocrypto.Rsa.priv; (* Server host key *)
session_id : Cstruct.t option; (* First calculated H *)
keys : Kex.keys option; (* Derived keys *)
new_keys : Kex.keys option; (* Keys to be used after SSH_MSG_NEWKEYS *)
keys_ctos : Kex.keys option; (* Client to server (input) keys *)
keys_stoc : Kex.keys option; (* Server to cleint (output) keys *)
new_keys_ctos : Kex.keys option; (* Install when we received NEWKEYS *)
new_keys_stoc : Kex.keys option; (* Install after we send NEWKEYS *)
}

let make host_key =
Expand All @@ -43,8 +45,10 @@ let make host_key =
neg_kex = None;
host_key;
session_id = None;
keys = None;
new_keys = None; }
keys_ctos = None;
keys_stoc = None;
new_keys_ctos = None;
new_keys_stoc = None; }
in
t, Cstruct.append banner_buf (Ssh.encode_plain_pkt server_kex)

Expand All @@ -61,7 +65,8 @@ let input_msg t msgbuf =
| Ssh_msg_kexdh_init e ->
guard_some t.neg_kex "No negotiated kex" >>= fun neg ->
guard_some t.client_version "No client version" >>= fun v_c ->
guard_none t.new_keys "Already got new_keys" >>= fun () ->
guard_none t.new_keys_stoc "Already got new_keys_stoc" >>= fun () ->
guard_none t.new_keys_ctos "Already got new_keys_ctos" >>= fun () ->
guard_some t.client_kex "No client kex" >>= fun i_c ->
let v_c = Cstruct.of_string v_c in
let v_s = Cstruct.of_string t.server_version in
Expand All @@ -72,19 +77,29 @@ let input_msg t msgbuf =
Kex.Dh.compute_hash ~v_c ~v_s ~i_c ~i_s ~k_s ~e ~f ~k >>= fun h ->
let signature = Rsa.PKCS1.sig_encode t.host_key h in
let session_id = match t.session_id with None -> h | Some x -> x in
let new_keys = Kex.Dh.derive_keys k h session_id (Kex.keylen_needed neg) in
let new_keys_ctos, new_keys_stoc =
Kex.Dh.derive_keys k h session_id (Kex.keylen_needed neg)
in
ok ({t with session_id = Some session_id;
new_keys = Some new_keys; },
new_keys_ctos = Some new_keys_ctos;
new_keys_stoc = Some new_keys_stoc; },
[ Ssh_msg_kexdh_reply (pub_host_key, f, signature);
Ssh_msg_newkeys ])

| Ssh_msg_newkeys ->
guard_some t.new_keys_ctos "No new_keys_ctos" >>= fun new_keys_ctos ->
ok ({ t with keys_ctos = Some new_keys_ctos;
new_keys_ctos = None },
[])

| _ -> error "unhandled stuff"

let output_msg t msg =
let open Ssh in
match msg with
| Ssh_msg_newkeys ->
guard_some t.new_keys "Expected new keys" >>= fun _ ->
ok { t with keys = t.new_keys; new_keys = None }
guard_some t.new_keys_stoc "Expected new keys" >>= fun new_keys_stoc ->
ok { t with keys_stoc = Some new_keys_stoc;
new_keys_stoc = None }

| _ -> ok t

0 comments on commit b834e4a

Please sign in to comment.