mirror of
https://github.com/Noratrieb/cluelessh.git
synced 2026-01-14 16:35:06 +01:00
fix sign
This commit is contained in:
parent
53bd98f2b3
commit
157d6081b8
3 changed files with 39 additions and 8 deletions
|
|
@ -2,8 +2,9 @@ use std::{io::Write, path::PathBuf};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use eyre::{bail, Context};
|
use eyre::{bail, Context};
|
||||||
|
use sha2::Digest;
|
||||||
use ssh_agent_client::{IdentityAnswer, SocketAgentConnection};
|
use ssh_agent_client::{IdentityAnswer, SocketAgentConnection};
|
||||||
use ssh_transport::key::PublicKey;
|
use ssh_transport::{key::PublicKey, parse::Writer};
|
||||||
|
|
||||||
#[derive(clap::Parser, Debug)]
|
#[derive(clap::Parser, Debug)]
|
||||||
struct Args {
|
struct Args {
|
||||||
|
|
@ -28,8 +29,11 @@ enum Subcommand {
|
||||||
/// Sign a blob, SSH_AGENTC_SIGN_REQUEST
|
/// Sign a blob, SSH_AGENTC_SIGN_REQUEST
|
||||||
Sign {
|
Sign {
|
||||||
/// The key-id of the key, obtained with list-identities --key-id
|
/// The key-id of the key, obtained with list-identities --key-id
|
||||||
#[arg(short, long = "key")]
|
#[arg(short, long)]
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
|
/// The domain of the signature, for example 'file'
|
||||||
|
#[arg(short, long)]
|
||||||
|
namespace: String,
|
||||||
file: PathBuf,
|
file: PathBuf,
|
||||||
},
|
},
|
||||||
/// Temporarily lock the agent with a passphrase, SSH_AGENTC_LOCK
|
/// Temporarily lock the agent with a passphrase, SSH_AGENTC_LOCK
|
||||||
|
|
@ -64,7 +68,15 @@ async fn main() -> eyre::Result<()> {
|
||||||
Subcommand::ListIdentities { key_id } => {
|
Subcommand::ListIdentities { key_id } => {
|
||||||
list_ids(&mut agent, key_id).await?;
|
list_ids(&mut agent, key_id).await?;
|
||||||
}
|
}
|
||||||
Subcommand::Sign { file, key } => {
|
Subcommand::Sign {
|
||||||
|
file,
|
||||||
|
key,
|
||||||
|
namespace,
|
||||||
|
} => {
|
||||||
|
if namespace.is_empty() {
|
||||||
|
bail!("namespace must not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
let file = std::fs::read(&file)
|
let file = std::fs::read(&file)
|
||||||
.wrap_err_with(|| format!("reading file {}", file.display()))?;
|
.wrap_err_with(|| format!("reading file {}", file.display()))?;
|
||||||
|
|
||||||
|
|
@ -107,10 +119,27 @@ async fn main() -> eyre::Result<()> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let signature = agent.sign(&key.key_blob, &file, 0).await?;
|
// <https://github.com/openssh/openssh-portable/blob/a76a6b85108e3032c8175611ecc5746e7131f876/PROTOCOL.sshsig>
|
||||||
|
|
||||||
// TODO: https://github.com/openssh/openssh-portable/blob/a76a6b85108e3032c8175611ecc5746e7131f876/PROTOCOL.sshsig
|
let mut sign_data = Writer::new();
|
||||||
let signature = pem::encode(&pem::Pem::new("SSH SIGNATURE", signature));
|
sign_data.raw(b"SSHSIG");
|
||||||
|
sign_data.string(&namespace);
|
||||||
|
sign_data.string([]);
|
||||||
|
sign_data.string(b"sha512");
|
||||||
|
sign_data.string(sha2::Sha512::digest(file));
|
||||||
|
|
||||||
|
let signature = agent.sign(&key.key_blob, &sign_data.finish(), 0).await?;
|
||||||
|
|
||||||
|
let mut sig = Writer::new();
|
||||||
|
sig.raw(b"SSHSIG");
|
||||||
|
sig.u32(1); // version
|
||||||
|
sig.string(&key.key_blob); // publickey
|
||||||
|
sig.string(namespace.as_bytes());
|
||||||
|
sig.string(b""); // reserved
|
||||||
|
sig.string(b"sha512"); // hash algorithm
|
||||||
|
sig.string(&signature);
|
||||||
|
|
||||||
|
let signature = pem::encode(&pem::Pem::new("SSH SIGNATURE", sig.finish()));
|
||||||
std::io::stdout().write_all(signature.as_bytes())?;
|
std::io::stdout().write_all(signature.as_bytes())?;
|
||||||
}
|
}
|
||||||
Subcommand::Lock => {
|
Subcommand::Lock => {
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ pub enum ExtensionResponse {
|
||||||
/// A single identity in SSH_AGENT_IDENTITIES_ANSWER.
|
/// A single identity in SSH_AGENT_IDENTITIES_ANSWER.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IdentityAnswer {
|
pub struct IdentityAnswer {
|
||||||
|
/// The public key in the SSH wire encoding.
|
||||||
pub key_blob: Vec<u8>,
|
pub key_blob: Vec<u8>,
|
||||||
pub comment: String,
|
pub comment: String,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simplified `byteorder` clone that emits client errors when the data is too short.
|
/// A writer for the SSH wire format.
|
||||||
pub struct Writer(Vec<u8>);
|
pub struct Writer(Vec<u8>);
|
||||||
|
|
||||||
impl Writer {
|
impl Writer {
|
||||||
|
|
@ -149,7 +149,8 @@ impl Writer {
|
||||||
self.raw(bytes);
|
self.raw(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string(&mut self, data: &[u8]) {
|
pub fn string(&mut self, data: impl AsRef<[u8]>) {
|
||||||
|
let data = data.as_ref();
|
||||||
self.u32(data.len() as u32);
|
self.u32(data.len() as u32);
|
||||||
self.raw(data);
|
self.raw(data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue