-
-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathrandom-key.rs
More file actions
114 lines (102 loc) · 3.85 KB
/
Copy pathrandom-key.rs
File metadata and controls
114 lines (102 loc) · 3.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use async_trait::async_trait;
use rsa::pkcs1v15::SigningKey;
use rsa::sha2::{Sha256, Sha512};
use rsa::signature::{RandomizedSigner, SignatureEncoding};
use sha1::Sha1;
#[cfg(windows)]
use ssh_agent_lib::agent::NamedPipeListener as Listener;
use ssh_agent_lib::agent::{listen, Session};
use ssh_agent_lib::error::AgentError;
use ssh_agent_lib::proto::{signature, Identity, PublicCredential, SignRequest};
use ssh_key::private::RsaKeypair;
use ssh_key::HashAlg;
use ssh_key::{
private::{KeypairData, PrivateKey},
public::PublicKey,
Algorithm, Signature,
};
#[cfg(not(windows))]
use tokio::net::UnixListener as Listener;
#[derive(Clone)]
struct RandomKey {
private_key: Arc<Mutex<PrivateKey>>,
}
impl RandomKey {
pub fn new() -> Result<Self, AgentError> {
let rsa = RsaKeypair::random(&mut rand::thread_rng(), 2048).map_err(AgentError::other)?;
let privkey = PrivateKey::new(KeypairData::Rsa(rsa), "automatically generated RSA key")
.map_err(AgentError::other)?;
Ok(Self {
private_key: Arc::new(Mutex::new(privkey)),
})
}
}
#[crate::async_trait]
impl Session for RandomKey {
async fn sign(&mut self, sign_request: SignRequest) -> Result<Signature, AgentError> {
let private_key = self.private_key.lock().unwrap();
let PublicCredential::Key(pubkey) = sign_request.credential else {
return Err(std::io::Error::other("Key not found").into());
};
if PublicKey::from(private_key.deref()).key_data() != &pubkey {
return Err(std::io::Error::other("Key not found").into());
}
if let KeypairData::Rsa(ref key) = private_key.key_data() {
let private_key: rsa::RsaPrivateKey = key.try_into().map_err(AgentError::other)?;
let mut rng = rand::thread_rng();
let data = &sign_request.data;
Ok(if sign_request.flags & signature::RSA_SHA2_512 != 0 {
Signature::new(
Algorithm::Rsa {
hash: Some(HashAlg::Sha512),
},
SigningKey::<Sha512>::new(private_key)
.sign_with_rng(&mut rng, data)
.to_bytes(),
)
} else if sign_request.flags & signature::RSA_SHA2_256 != 0 {
Signature::new(
Algorithm::Rsa {
hash: Some(HashAlg::Sha256),
},
SigningKey::<Sha256>::new(private_key)
.sign_with_rng(&mut rng, data)
.to_bytes(),
)
} else {
Signature::new(
Algorithm::Rsa { hash: None },
SigningKey::<Sha1>::new(private_key)
.sign_with_rng(&mut rng, data)
.to_bytes(),
)
}
.map_err(AgentError::other)?)
} else {
Err(std::io::Error::other("Signature for key type not implemented").into())
}
}
async fn request_identities(&mut self) -> Result<Vec<Identity>, AgentError> {
let identity = self.private_key.lock().unwrap();
Ok(vec![Identity {
credential: PublicCredential::Key(PublicKey::from(identity.deref()).into()),
comment: identity.comment().into(),
}])
}
}
#[tokio::main]
async fn main() -> Result<(), AgentError> {
env_logger::init();
#[cfg(not(windows))]
let socket = "ssh-agent.sock";
#[cfg(windows)]
let socket = r"\\.\pipe\agent";
let _ = std::fs::remove_file(socket); // remove the socket if exists
// This is only used for integration tests on Windows:
#[cfg(windows)]
std::fs::File::create("server-started")?;
listen(Listener::bind(socket)?, RandomKey::new()?).await?;
Ok(())
}