mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-14 16:35:06 +01:00
ECDSA!
This commit is contained in:
parent
982de53668
commit
a8d25d856f
6 changed files with 49 additions and 84 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -928,6 +928,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"aes-gcm",
|
||||
"chacha20",
|
||||
"crypto-bigint",
|
||||
"ed25519-dalek",
|
||||
"eyre",
|
||||
"hex-literal",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
aes-gcm = "0.10.3"
|
||||
chacha20 = "0.9.1"
|
||||
crypto-bigint = "0.5.5"
|
||||
ed25519-dalek = { version = "2.1.1" }
|
||||
eyre = "0.6.12"
|
||||
p256 = { version = "0.13.2", features = ["ecdh", "ecdsa"] }
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use subtle::ConstantTimeEq;
|
|||
use crate::{
|
||||
client_error,
|
||||
packet::{EncryptedPacket, MsgKind, Packet, RawPacket},
|
||||
parse::Writer,
|
||||
parse::{self, Writer},
|
||||
Msg, Result, SshRng,
|
||||
};
|
||||
|
||||
|
|
@ -187,17 +187,30 @@ pub fn hostkey_ecdsa_sha2_p256(hostkey_private: Vec<u8>) -> HostKeySigningAlgori
|
|||
hostkey_private,
|
||||
public_key: |key| {
|
||||
let key = p256::ecdsa::SigningKey::from_slice(key).unwrap();
|
||||
key.verifying_key()
|
||||
.to_encoded_point(true)
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
todo!()
|
||||
let public_key = key.verifying_key();
|
||||
let mut data = Writer::new();
|
||||
|
||||
// <https://datatracker.ietf.org/doc/html/rfc5656#section-3.1>
|
||||
data.string(b"ecdsa-sha2-nistp256");
|
||||
data.string(b"nistp256");
|
||||
// > point compression MAY be used.
|
||||
// But OpenSSH does not appear to support that, so let's NOT use it.
|
||||
data.string(public_key.to_encoded_point(false).as_bytes());
|
||||
EncodedSshPublicHostKey(data.finish())
|
||||
},
|
||||
sign: |key, data| {
|
||||
let key = p256::ecdsa::SigningKey::from_slice(key).unwrap();
|
||||
let signature: p256::ecdsa::Signature = key.sign(data);
|
||||
signature.to_vec();
|
||||
todo!()
|
||||
let (r, s) = signature.split_scalars();
|
||||
|
||||
// <https://datatracker.ietf.org/doc/html/rfc5656#section-3.1.2>
|
||||
let mut data = Writer::new();
|
||||
data.string(b"ecdsa-sha2-nistp256");
|
||||
let mut signature_blob = Writer::new();
|
||||
signature_blob.mpint(p256::U256::from(r.as_ref()));
|
||||
signature_blob.mpint(p256::U256::from(s.as_ref()));
|
||||
data.string(&signature_blob.finish());
|
||||
EncodedSshSignature(data.finish())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -404,12 +417,8 @@ fn derive_key(
|
|||
output
|
||||
}
|
||||
|
||||
pub(crate) fn encode_mpint_for_hash(mut key: &[u8], mut add_to_hash: impl FnMut(&[u8])) {
|
||||
while key[0] == 0 {
|
||||
key = &key[1..];
|
||||
}
|
||||
// If the first high bit is set, pad it with a zero.
|
||||
let pad_zero = (key[0] & 0b10000000) > 1;
|
||||
pub(crate) fn encode_mpint_for_hash(key: &[u8], mut add_to_hash: impl FnMut(&[u8])) {
|
||||
let (key, pad_zero) = parse::fixup_mpint(key);
|
||||
add_to_hash(&u32::to_be_bytes((key.len() + (pad_zero as usize)) as u32));
|
||||
if pad_zero {
|
||||
add_to_hash(&[0]);
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@ use core::str;
|
|||
use std::{collections::VecDeque, mem::take};
|
||||
|
||||
use crypto::{AlgorithmName, AlgorithmNegotiation, EncryptionAlgorithm, HostKeySigningAlgorithm};
|
||||
use packet::{
|
||||
KeyExchangeEcDhInitPacket, KeyExchangeInitPacket, Packet, PacketTransport, SshPublicKey,
|
||||
SshSignature,
|
||||
};
|
||||
use packet::{KeyExchangeEcDhInitPacket, KeyExchangeInitPacket, Packet, PacketTransport};
|
||||
use parse::{NameList, Parser, Writer};
|
||||
use rand::RngCore;
|
||||
use sha2::Digest;
|
||||
|
|
@ -199,7 +196,7 @@ impl ServerConnection {
|
|||
|
||||
let hostkey_algorithms = AlgorithmNegotiation {
|
||||
supported: vec![
|
||||
//crypto::hostkey_ed25519(ED25519_PRIVKEY_BYTES.to_vec()),
|
||||
crypto::hostkey_ed25519(ED25519_PRIVKEY_BYTES.to_vec()),
|
||||
crypto::hostkey_ecdsa_sha2_p256(ECDSA_P256_PRIVKEY_BYTES.to_vec()),
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -318,69 +318,6 @@ impl<'a> KeyExchangeEcDhInitPacket<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SshPublicKey<'a> {
|
||||
pub(crate) format: &'a [u8],
|
||||
pub(crate) data: &'a [u8],
|
||||
}
|
||||
impl SshPublicKey<'_> {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut data = Writer::new();
|
||||
// ed25519-specific!
|
||||
// <https://datatracker.ietf.org/doc/html/rfc8709#section-4>
|
||||
data.string(self.format);
|
||||
data.string(self.data);
|
||||
data.finish()
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SshPublicKeyEcdsa<'a> {
|
||||
pub(crate) format: &'a [u8],
|
||||
pub(crate) ident: &'a [u8],
|
||||
pub(crate) data: &'a [u8],
|
||||
}
|
||||
impl SshPublicKeyEcdsa<'_> {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut data = Writer::new();
|
||||
// ECDSA-specific!
|
||||
// <https://datatracker.ietf.org/doc/html/rfc5656#section-3.1>
|
||||
data.string(self.format);
|
||||
data.string(self.ident);
|
||||
data.string(self.data);
|
||||
data.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SshSignature<'a> {
|
||||
pub(crate) format: &'a [u8],
|
||||
pub(crate) data: &'a [u8],
|
||||
}
|
||||
|
||||
impl SshSignature<'_> {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut data = Writer::new();
|
||||
// <https://datatracker.ietf.org/doc/html/rfc8709#section-6>
|
||||
data.string(self.format);
|
||||
data.string(self.data);
|
||||
data.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SshSignatureEcdsa<'a> {
|
||||
pub(crate) format: &'a [u8],
|
||||
pub(crate) data: &'a [u8],
|
||||
}
|
||||
|
||||
impl SshSignatureEcdsa<'_> {
|
||||
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut data = Writer::new();
|
||||
// <https://datatracker.ietf.org/doc/html/rfc5656#section-3.1.2>
|
||||
data.string(self.format);
|
||||
data.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RawPacket {
|
||||
pub mac_len: usize,
|
||||
pub raw: Vec<u8>,
|
||||
|
|
|
|||
|
|
@ -104,8 +104,18 @@ impl Writer {
|
|||
self.string(list.0.as_bytes());
|
||||
}
|
||||
|
||||
pub fn mpint(&mut self, _mpint: MpInt<'_>) {
|
||||
todo!("implement correctly?")
|
||||
pub fn mpint<const LIMBS: usize>(&mut self, uint: crypto_bigint::Uint<LIMBS>)
|
||||
where
|
||||
crypto_bigint::Uint<LIMBS>: crypto_bigint::ArrayEncoding,
|
||||
{
|
||||
let bytes = crypto_bigint::ArrayEncoding::to_be_byte_array(&uint);
|
||||
let (bytes, pad_zero) = fixup_mpint(&bytes);
|
||||
let len = bytes.len() + (pad_zero as usize);
|
||||
self.u32(len as u32);
|
||||
if pad_zero {
|
||||
self.u8(0);
|
||||
}
|
||||
self.write(bytes);
|
||||
}
|
||||
|
||||
pub fn string(&mut self, data: &[u8]) {
|
||||
|
|
@ -122,6 +132,16 @@ impl Writer {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns an array of significant bits for the mpint,
|
||||
/// and whether a leading 0 needs to be added for padding.
|
||||
pub fn fixup_mpint(mut int_encoded: &[u8]) -> (&[u8], bool) {
|
||||
while int_encoded[0] == 0 {
|
||||
int_encoded = &int_encoded[1..];
|
||||
}
|
||||
// If the first high bit is set, pad it with a zero.
|
||||
(int_encoded, (int_encoded[0] & 0b10000000) > 1)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct NameList<'a>(pub &'a str);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue