├── Cargo.toml ├── README.md └── src ├── agent.rs ├── error.rs ├── handler.rs ├── lib.rs └── protocol.rs /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ssh_agent" 3 | version = "0.1.0" 4 | authors = ["Nicolas Trippar "] 5 | 6 | [lib] 7 | name = "ssh_agent" 8 | path = "src/lib.rs" 9 | 10 | 11 | [dependencies] 12 | log = "0.3.8" 13 | env_logger = "0.4.3" 14 | byteorder = "1.1.0" 15 | 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ssh-agent 2 | rust ssh agent library 3 | this code is mostly a port of @jonas-schievink work, i needed as a library and added multithreading. 4 | -------------------------------------------------------------------------------- /src/agent.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use std::sync::Arc; 3 | use std::sync::Mutex; 4 | 5 | use std::os::unix::net::{UnixListener, UnixStream}; 6 | 7 | use protocol::Request; 8 | 9 | use handler::SSHAgentHandler; 10 | 11 | use error::HandleResult; 12 | pub struct Agent; 13 | 14 | impl Agent { 15 | 16 | fn handle_client(handler: Arc>, mut stream: UnixStream) -> HandleResult<()> { 17 | debug!("handling new connection"); 18 | loop { 19 | let req = Request::read(&mut stream)?; 20 | debug!("request: {:?}", req); 21 | let response = handler.lock().unwrap().handle_request(req)?; 22 | debug!("handler: {:?}", response); 23 | response.write(&mut stream)?; 24 | } 25 | 26 | } 27 | 28 | pub fn run(handler: T, listener: UnixListener) { 29 | let arc_handler = Arc::new(Mutex::new(handler)); 30 | // accept the connections and spawn a new thread for each one 31 | for stream in listener.incoming() { 32 | match stream { 33 | Ok(stream) => { 34 | // connection succeded 35 | let ref_handler = arc_handler.clone(); 36 | thread::spawn( ||{ 37 | match Agent::handle_client(ref_handler, stream){ 38 | Ok(_) => {}, 39 | Err(e) => debug!("handler: {:?}", e), 40 | } 41 | }); 42 | } 43 | Err(_) => { 44 | // connection failed 45 | break; 46 | } 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{io}; 2 | 3 | pub type ParsingError = Result; 4 | pub type WrittingError = Result; 5 | pub type HandleResult = Result; 6 | 7 | 8 | #[derive(Debug)] 9 | pub struct Error { 10 | pub details: String, 11 | } 12 | 13 | impl Error { 14 | fn new>(details: T) -> Error { 15 | Error { 16 | details: String::from(details.as_ref()), 17 | } 18 | } 19 | } 20 | 21 | 22 | impl From for Error { 23 | fn from(err: io::Error) -> Error { 24 | match err { 25 | _ => Error::new("IOError") 26 | } 27 | } 28 | } 29 | 30 | 31 | impl<'a> From<&'a str> for Error { 32 | fn from(err: &'a str) -> Error { 33 | match err { 34 | _ => Error::new(err) 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/handler.rs: -------------------------------------------------------------------------------- 1 | use protocol::Request; 2 | use protocol::Response; 3 | 4 | use error::HandleResult; 5 | 6 | pub trait SSHAgentHandler: Send + Sync { 7 | fn new() -> Self; 8 | fn identities(&mut self) -> HandleResult; 9 | fn sign_request(&mut self, pubkey: Vec, data: Vec, flags: u32) -> HandleResult; 10 | 11 | fn handle_request(&mut self, request: Request) -> HandleResult { 12 | match request { 13 | Request::RequestIdentities => { 14 | self.identities() 15 | } 16 | Request::SignRequest {ref pubkey_blob, ref data, ref flags} => { 17 | self.sign_request(pubkey_blob.clone(), data.clone(), flags.clone()) 18 | } 19 | Request::Unknown => { 20 | Ok(Response::Failure) 21 | } 22 | 23 | } 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate log; 2 | extern crate byteorder; 3 | 4 | mod agent; 5 | mod protocol; 6 | mod handler; 7 | pub mod error; 8 | 9 | pub use handler::SSHAgentHandler; 10 | pub use agent::Agent; 11 | pub use protocol::Response; 12 | pub use protocol::Identity; -------------------------------------------------------------------------------- /src/protocol.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::os::unix::net::{UnixStream}; 3 | 4 | use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; 5 | use std::io::{Read, Write}; 6 | 7 | use error::{ParsingError, WrittingError}; 8 | 9 | #[derive(Debug)] 10 | #[derive(Copy, Clone)] 11 | enum MessageRequest { 12 | RequestIdentities, 13 | SignRequest, 14 | AddIdentity, 15 | RemoveIdentity, 16 | RemoveAllIdentities, 17 | AddIdConstrained, 18 | AddSmartcardKey, 19 | RemoveSmartcardKey, 20 | Lock, 21 | Unlock, 22 | AddSmartcardKeyConstrained, 23 | Extension, 24 | Unknown, 25 | } 26 | 27 | impl MessageRequest { 28 | fn from_u8(value: u8) -> MessageRequest { 29 | match value { 30 | 11 => MessageRequest::RequestIdentities, 31 | 13 => MessageRequest::SignRequest, 32 | 17 => MessageRequest::AddIdentity, 33 | 18 => MessageRequest::RemoveIdentity, 34 | 19 => MessageRequest::RemoveAllIdentities, 35 | 25 => MessageRequest::AddIdConstrained, 36 | 20 => MessageRequest::AddSmartcardKey, 37 | 21 => MessageRequest::RemoveSmartcardKey, 38 | 22 => MessageRequest::Lock, 39 | 23 => MessageRequest::Unlock, 40 | 26 => MessageRequest::AddSmartcardKeyConstrained, 41 | 27 => MessageRequest::Extension, 42 | _ => MessageRequest::Unknown, 43 | } 44 | } 45 | } 46 | 47 | 48 | 49 | fn read_message(stream: &mut R) -> ParsingError> { 50 | let len = stream.read_u32::()?; 51 | 52 | let mut buf = vec![0; len as usize]; 53 | stream.read_exact(&mut buf)?; 54 | 55 | Ok(buf) 56 | } 57 | 58 | fn write_message(w: &mut W, string: &[u8]) -> WrittingError<()> { 59 | w.write_u32::(string.len() as u32)?; 60 | w.write_all(string)?; 61 | Ok(()) 62 | } 63 | 64 | #[derive(Debug)] 65 | pub enum Request { 66 | RequestIdentities, 67 | SignRequest { 68 | // Blob of the public key 69 | // (encoded as per RFC4253 "6.6. Public Key Algorithms"). 70 | pubkey_blob: Vec, 71 | // The data to sign. 72 | data: Vec, 73 | // Request flags. 74 | flags: u32, 75 | }, 76 | Unknown, 77 | } 78 | impl Request { 79 | 80 | pub fn read(stream: &mut UnixStream) -> ParsingError{ 81 | 82 | debug!("reading request"); 83 | let raw_msg = read_message(stream)?; 84 | let mut buf = raw_msg.as_slice(); 85 | 86 | let msg = buf.read_u8()?; 87 | match MessageRequest::from_u8(msg) { 88 | MessageRequest::RequestIdentities => { 89 | Ok(Request::RequestIdentities) 90 | } 91 | MessageRequest::SignRequest => { 92 | Ok(Request::SignRequest { 93 | pubkey_blob: read_message(&mut buf)?, 94 | data: read_message(&mut buf)?, 95 | flags: buf.read_u32::()?, 96 | }) 97 | } 98 | MessageRequest::AddIdentity => { 99 | Ok(Request::Unknown) 100 | } 101 | MessageRequest::RemoveIdentity => { 102 | Ok(Request::Unknown) 103 | } 104 | MessageRequest::RemoveAllIdentities => { 105 | Ok(Request::Unknown) 106 | } 107 | MessageRequest::AddIdConstrained => { 108 | Ok(Request::Unknown) 109 | } 110 | MessageRequest::AddSmartcardKey => { 111 | Ok(Request::Unknown) 112 | } 113 | MessageRequest::RemoveSmartcardKey => { 114 | Ok(Request::Unknown) 115 | } 116 | MessageRequest::Lock => { 117 | Ok(Request::Unknown) 118 | } 119 | MessageRequest::Unlock => { 120 | Ok(Request::Unknown) 121 | } 122 | MessageRequest::AddSmartcardKeyConstrained => { 123 | Ok(Request::Unknown) 124 | } 125 | MessageRequest::Extension => { 126 | Ok(Request::Unknown) 127 | } 128 | MessageRequest::Unknown => { 129 | debug!("Unknown request {}", msg); 130 | Ok(Request::Unknown) 131 | } 132 | 133 | } 134 | } 135 | } 136 | 137 | enum MessageResponse { 138 | AgentFailure = 5, 139 | AgentSuccess = 6, 140 | AgentIdentitiesAnswer = 12, 141 | AgentSignResponse = 14, 142 | } 143 | 144 | #[derive(Debug)] 145 | pub struct Identity { 146 | pub key_blob: Vec, 147 | pub key_comment: String, 148 | } 149 | 150 | #[derive(Debug)] 151 | pub enum Response { 152 | Success, 153 | Failure, 154 | Identities(Vec), 155 | SignResponse { 156 | algo_name: String, 157 | signature: Vec, 158 | }, 159 | } 160 | 161 | impl Response { 162 | 163 | pub fn write(&self, stream: &mut UnixStream) -> WrittingError<()>{ 164 | let mut buf = Vec::new(); 165 | match *self { 166 | Response::Success => buf.write_u8(MessageResponse::AgentSuccess as u8)?, 167 | Response::Failure => buf.write_u8(MessageResponse::AgentFailure as u8)?, 168 | Response::Identities(ref identities) => { 169 | buf.write_u8(MessageResponse::AgentIdentitiesAnswer as u8)?; 170 | buf.write_u32::(identities.len() as u32)?; 171 | 172 | for identity in identities { 173 | write_message(&mut buf, &identity.key_blob)?; 174 | write_message(&mut buf, &identity.key_comment.as_bytes())?; 175 | } 176 | } 177 | Response::SignResponse { ref algo_name, ref signature } => { 178 | buf.write_u8(MessageResponse::AgentSignResponse as u8)?; 179 | 180 | let mut full_sig = Vec::new(); 181 | write_message(&mut full_sig, algo_name.as_bytes())?; 182 | write_message(&mut full_sig, signature)?; 183 | 184 | write_message(&mut buf, full_sig.as_slice())?; 185 | } 186 | } 187 | stream.write_u32::(buf.len() as u32)?; 188 | stream.write_all(&buf)?; 189 | Ok(()) 190 | } 191 | } --------------------------------------------------------------------------------