diff --git a/async/src/async_door.rs b/async/src/async_door.rs index df4419f381571ff7308883d12f327263c2220206..c3bc33f8eb8367bc1bfab757feec39e1b71b9ea1 100644 --- a/async/src/async_door.rs +++ b/async/src/async_door.rs @@ -59,6 +59,9 @@ impl<'a> AsyncDoor<'a> { AsyncDoorSocket::new(self) } + /// The `f` closure should return `Some` if the result should be returned + /// from `progress()`, or `None` to not do that. + /// XXX better docs, perhaps it won't take a closure anyway pub async fn progress<F, R>(&mut self, b: &mut Behaviour<'_>, f: F) diff --git a/sshproto/src/conn.rs b/sshproto/src/conn.rs index da464d5b8ccd934e83c2df40bf2683b63e71b80d..556f8e969811d5e22b55a30ad7056ac5723dafdc 100644 --- a/sshproto/src/conn.rs +++ b/sshproto/src/conn.rs @@ -242,7 +242,7 @@ impl<'a> Conn<'a> { let kex = core::mem::replace(&mut self.kex, kex::Kex::new()?); *output = Some(kex.handle_kexdhinit(&p, &self.sess_id)?); - let reply = output.as_ref().trap()?.make_kexdhreply(&b.server()?)?; + let reply = output.as_mut().trap()?.make_kexdhreply(&mut b.server()?).await?; resp.push(reply.into()).trap()?; } } diff --git a/sshproto/src/kex.rs b/sshproto/src/kex.rs index 59b9e18b72092b6e3e6d565ba113128137a00b48..cc6db093cfecf7afa82fe7304718694ffd33d584 100644 --- a/sshproto/src/kex.rs +++ b/sshproto/src/kex.rs @@ -445,7 +445,7 @@ impl SharedSecret { SharedSecret::KexCurve25519(ref k) => { let pubkey: salty::agreement::PublicKey = k.ours.as_ref().trap()?.into(); let mut kex_out = KexCurve25519::secret(&mut algos, p.q_c.0, kex_hash, sess_id)?; - kex_out.pubkey = Some(pubkey.to_bytes()); + kex_out.kex_pub = Some(pubkey.to_bytes()); kex_out } }; @@ -467,14 +467,17 @@ pub(crate) struct KexOutput { // storage for kex packet reply content that outlives Kex // in make_kexdhreply(). - // TODO: this should become generic for other kex methods - pubkey: Option<[u8; 32]>, + /// ephemeral public key octet string + kex_pub: Option<[u8; 32]>, + // the negotiated signature type + sig_type: SigType, + sig: Option<sign::OwnedSig>, } impl fmt::Debug for KexOutput { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("KexOutput") - .field("pubkey", &self.pubkey.is_some()) + .field("kex_pub", &self.kex_pub.is_some()) .finish_non_exhaustive() } } @@ -488,15 +491,19 @@ impl<'a> KexOutput { let sess_id = sess_id.as_ref().unwrap_or(&h); let keys = Keys::new_from(k, &h, &sess_id, algos)?; - Ok(KexOutput { h, keys, pubkey: None }) + Ok(KexOutput { h, keys, kex_pub: None, sig_type: algos.hostsig, sig: None }) } // server only - pub fn make_kexdhreply(&'a self, b: &ServBehaviour) -> Result<Packet<'a>> { - let q_s = BinString(self.pubkey.as_ref().trap()?); - // TODO real signature - let k_s = Blob(PubKey::Ed25519(packets::Ed25519PubKey{ key: BinString(&[]) })); - let sig = Blob(Signature::Ed25519(packets::Ed25519Sig{ sig: BinString(&[]) })); + pub async fn make_kexdhreply<'b>(&'a mut self, b: &'a mut ServBehaviour<'_>) -> Result<Packet<'a>> { + let q_s = BinString(self.kex_pub.as_ref().trap()?); + + // hostkeys list must contain the signature type + let key = b.hostkeys().await?.iter().find(|k| k.can_sign(&self.sig_type)).trap()?; + let k_s = Blob(key.pubkey()); + self.sig = Some(key.sign(&self.h.as_slice(), None)?); + let sig: Signature = self.sig.as_ref().unwrap().into(); + let sig = Blob(sig); Ok(packets::KexDHReply { k_s, q_s, sig }.into()) } } diff --git a/sshproto/src/sign.rs b/sshproto/src/sign.rs index 638499fd7e107a3d8367e25d0bc41b9a1da73cbc..7ec846c9962492089a5e00dc34aaf84d79d99622 100644 --- a/sshproto/src/sign.rs +++ b/sshproto/src/sign.rs @@ -20,7 +20,7 @@ use core::mem::discriminant; // RSA requires alloc. -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum SigType { Ed25519, RSA256, @@ -137,7 +137,14 @@ impl SignKey { k.try_into() } - pub(crate) fn sign_encode<'s>(&self, msg: &'s impl SSHEncode, parse_ctx: Option<&ParseContext>) -> Result<OwnedSig> { + /// Returns whether this `SignKey` can create a given signature type + pub(crate) fn can_sign(&self, sig_type: &SigType) -> bool { + match self { + SignKey::Ed25519(_) => matches!(sig_type, SigType::Ed25519), + } + } + + pub(crate) fn sign<'s>(&self, msg: &'s impl SSHEncode, parse_ctx: Option<&ParseContext>) -> Result<OwnedSig> { match self { SignKey::Ed25519(k) => { k.sign_parts(|h| {