1- use std :: convert :: TryFrom ;
1+ use core :: str ;
22
33use byteorder:: { BigEndian , ByteOrder } ;
44use log:: debug;
55use russh_cryptovec:: CryptoVec ;
6+ use ssh_key:: { Algorithm , HashAlg , PrivateKey , PublicKey , Signature } ;
67use tokio;
78use tokio:: io:: { AsyncRead , AsyncReadExt , AsyncWrite , AsyncWriteExt } ;
89
910use super :: { msg, Constraint } ;
1011use crate :: encoding:: { Encoding , Reader } ;
11- use crate :: key :: { PublicKey , SignatureHash } ;
12- use crate :: { key, protocol , Error , PublicKeyBase64 } ;
12+ use crate :: helpers :: EncodedExt ;
13+ use crate :: { key, Error } ;
1314
1415pub trait AgentStream : AsyncRead + AsyncWrite { }
1516
@@ -142,7 +143,7 @@ impl<S: AgentStream + Unpin> AgentClient<S> {
142143 /// constraints to apply when using the key to sign.
143144 pub async fn add_identity (
144145 & mut self ,
145- key : & key :: KeyPair ,
146+ key : & PrivateKey ,
146147 constraints : & [ Constraint ] ,
147148 ) -> Result < ( ) , Error > {
148149 // See IETF draft-miller-ssh-agent-13, section 3.2 for format.
@@ -154,30 +155,10 @@ impl<S: AgentStream + Unpin> AgentClient<S> {
154155 } else {
155156 self . buf . push ( msg:: ADD_ID_CONSTRAINED )
156157 }
157- match * key {
158- key:: KeyPair :: Ed25519 ( ref pair) => {
159- self . buf . extend_ssh_string ( b"ssh-ed25519" ) ;
160- self . buf . extend_ssh_string ( pair. verifying_key ( ) . as_bytes ( ) ) ;
161- self . buf . push_u32_be ( 64 ) ;
162- self . buf . extend ( pair. to_bytes ( ) . as_slice ( ) ) ;
163- self . buf . extend ( pair. verifying_key ( ) . as_bytes ( ) ) ;
164- self . buf . extend_ssh_string ( b"" ) ;
165- }
166- #[ allow( clippy:: unwrap_used) ] // key is known to be private
167- key:: KeyPair :: RSA { ref key, .. } => {
168- self . buf . extend_ssh_string ( b"ssh-rsa" ) ;
169- self . buf
170- . extend_ssh ( & protocol:: RsaPrivateKey :: try_from ( key) ?) ;
171- }
172- key:: KeyPair :: EC { ref key } => {
173- self . buf . extend_ssh_string ( key. algorithm ( ) . as_bytes ( ) ) ;
174- self . buf . extend_ssh_string ( key. ident ( ) . as_bytes ( ) ) ;
175- self . buf
176- . extend_ssh_string ( & key. to_public_key ( ) . to_sec1_bytes ( ) ) ;
177- self . buf . extend_ssh_mpint ( & key. to_secret_bytes ( ) ) ;
178- self . buf . extend_ssh_string ( b"" ) ; // comment
179- }
180- }
158+
159+ self . buf . extend ( key. key_data ( ) . encoded ( ) ?. as_slice ( ) ) ;
160+ self . buf . extend_ssh_string ( & [ ] ) ; // comment field
161+
181162 if !constraints. is_empty ( ) {
182163 for cons in constraints {
183164 match * cons {
@@ -292,66 +273,54 @@ impl<S: AgentStream + Unpin> AgentClient<S> {
292273 for _ in 0 ..n {
293274 let key_blob = r. read_string ( ) ?;
294275 let _comment = r. read_string ( ) ?;
295- keys. push ( key:: parse_public_key (
296- key_blob,
297- Some ( SignatureHash :: SHA2_512 ) ,
298- ) ?) ;
276+ keys. push ( key:: parse_public_key ( key_blob) ?) ;
299277 }
300278 }
301279
302280 Ok ( keys)
303281 }
304282
305283 /// Ask the agent to sign the supplied piece of data.
306- pub fn sign_request (
307- mut self ,
308- public : & key :: PublicKey ,
284+ pub async fn sign_request (
285+ & mut self ,
286+ public : & PublicKey ,
309287 mut data : CryptoVec ,
310- ) -> impl futures :: Future < Output = ( Self , Result < CryptoVec , Error > ) > {
288+ ) -> Result < CryptoVec , Error > {
311289 debug ! ( "sign_request: {:?}" , data) ;
312- let hash = self . prepare_sign_request ( public, & data) ;
313-
314- async move {
315- if let Err ( e) = hash {
316- return ( self , Err ( e) ) ;
317- }
290+ let hash = self . prepare_sign_request ( public, & data) ?;
318291
319- let resp = self . read_response ( ) . await ;
320- debug ! ( "resp = {:?}" , & self . buf[ ..] ) ;
321- if let Err ( e) = resp {
322- return ( self , Err ( e) ) ;
323- }
292+ self . read_response ( ) . await ?;
324293
325- #[ allow( clippy:: indexing_slicing, clippy:: unwrap_used) ]
326- // length is checked, hash already checked
327- if !self . buf . is_empty ( ) && self . buf [ 0 ] == msg:: SIGN_RESPONSE {
328- let resp = self . write_signature ( hash. unwrap ( ) , & mut data) ;
329- if let Err ( e) = resp {
330- return ( self , Err ( e) ) ;
331- }
332- ( self , Ok ( data) )
333- } else if self . buf . first ( ) == Some ( & msg:: FAILURE ) {
334- ( self , Err ( Error :: AgentFailure ) )
335- } else {
336- debug ! ( "self.buf = {:?}" , & self . buf[ ..] ) ;
337- ( self , Ok ( data) )
338- }
294+ if self . buf . first ( ) == Some ( & msg:: SIGN_RESPONSE ) {
295+ self . write_signature ( hash, & mut data) ?;
296+ Ok ( data)
297+ } else if self . buf . first ( ) == Some ( & msg:: FAILURE ) {
298+ Err ( Error :: AgentFailure )
299+ } else {
300+ debug ! ( "self.buf = {:?}" , & self . buf[ ..] ) ;
301+ Ok ( data)
339302 }
340303 }
341304
342- fn prepare_sign_request ( & mut self , public : & key:: PublicKey , data : & [ u8 ] ) -> Result < u32 , Error > {
305+ fn prepare_sign_request (
306+ & mut self ,
307+ public : & ssh_key:: PublicKey ,
308+ data : & [ u8 ] ,
309+ ) -> Result < u32 , Error > {
343310 self . buf . clear ( ) ;
344311 self . buf . resize ( 4 ) ;
345312 self . buf . push ( msg:: SIGN_REQUEST ) ;
346313 key_blob ( public, & mut self . buf ) ?;
347314 self . buf . extend_ssh_string ( data) ;
348315 debug ! ( "public = {:?}" , public) ;
349- let hash = match public {
350- PublicKey :: RSA { hash, .. } => match hash {
351- SignatureHash :: SHA2_256 => 2 ,
352- SignatureHash :: SHA2_512 => 4 ,
353- SignatureHash :: SHA1 => 0 ,
354- } ,
316+ let hash = match public. algorithm ( ) {
317+ Algorithm :: Rsa {
318+ hash : Some ( HashAlg :: Sha256 ) ,
319+ } => 2 ,
320+ Algorithm :: Rsa {
321+ hash : Some ( HashAlg :: Sha512 ) ,
322+ } => 4 ,
323+ Algorithm :: Rsa { hash : None } => 0 ,
355324 _ => 0 ,
356325 } ;
357326 self . buf . push_u32_be ( hash) ;
@@ -376,7 +345,7 @@ impl<S: AgentStream + Unpin> AgentClient<S> {
376345 /// Ask the agent to sign the supplied piece of data.
377346 pub fn sign_request_base64 (
378347 mut self ,
379- public : & key :: PublicKey ,
348+ public : & ssh_key :: PublicKey ,
380349 data : & [ u8 ] ,
381350 ) -> impl futures:: Future < Output = ( Self , Result < String , Error > ) > {
382351 debug ! ( "sign_request: {:?}" , data) ;
@@ -402,67 +371,32 @@ impl<S: AgentStream + Unpin> AgentClient<S> {
402371 }
403372
404373 /// Ask the agent to sign the supplied piece of data, and return a `Signature`.
405- pub fn sign_request_signature (
406- mut self ,
407- public : & key :: PublicKey ,
374+ pub async fn sign_request_signature (
375+ & mut self ,
376+ public : & ssh_key :: PublicKey ,
408377 data : & [ u8 ] ,
409- ) -> impl futures :: Future < Output = ( Self , Result < crate :: signature :: Signature , Error > ) > {
378+ ) -> Result < Signature , Error > {
410379 debug ! ( "sign_request: {:?}" , data) ;
411380
412- let r = self . prepare_sign_request ( public, data) ;
413-
414- async move {
415- if let Err ( e) = r {
416- return ( self , Err ( e) ) ;
417- }
418-
419- if let Err ( e) = self . read_response ( ) . await {
420- return ( self , Err ( e) ) ;
421- }
381+ self . prepare_sign_request ( public, data) ?;
382+ self . read_response ( ) . await ?;
422383
423- #[ allow( clippy:: indexing_slicing) ] // length is checked
424- if !self . buf . is_empty ( ) && self . buf [ 0 ] == msg:: SIGN_RESPONSE {
425- let as_sig = |buf : & CryptoVec | -> Result < crate :: signature:: Signature , Error > {
426- let mut r = buf. reader ( 1 ) ;
427- let mut resp = r. read_string ( ) ?. reader ( 0 ) ;
428- let typ = resp. read_string ( ) ?;
429- let sig = resp. read_string ( ) ?;
430- use crate :: signature:: Signature ;
431- match typ {
432- b"ssh-rsa" => Ok ( Signature :: RSA {
433- bytes : sig. to_vec ( ) ,
434- hash : SignatureHash :: SHA1 ,
435- } ) ,
436- b"rsa-sha2-256" => Ok ( Signature :: RSA {
437- bytes : sig. to_vec ( ) ,
438- hash : SignatureHash :: SHA2_256 ,
439- } ) ,
440- b"rsa-sha2-512" => Ok ( Signature :: RSA {
441- bytes : sig. to_vec ( ) ,
442- hash : SignatureHash :: SHA2_512 ,
443- } ) ,
444- b"ssh-ed25519" => {
445- let mut sig_bytes = [ 0 ; 64 ] ;
446- sig_bytes. clone_from_slice ( sig) ;
447- Ok ( Signature :: Ed25519 ( crate :: signature:: SignatureBytes (
448- sig_bytes,
449- ) ) )
450- }
451- _ => Err ( Error :: UnknownSignatureType {
452- sig_type : std:: str:: from_utf8 ( typ) . unwrap_or ( "" ) . to_string ( ) ,
453- } ) ,
454- }
455- } ;
456- let sig = as_sig ( & self . buf ) ;
457- ( self , sig)
458- } else {
459- ( self , Err ( Error :: AgentProtocolError ) )
460- }
384+ #[ allow( clippy:: indexing_slicing) ] // length is checked
385+ if !self . buf . is_empty ( ) && self . buf [ 0 ] == msg:: SIGN_RESPONSE {
386+ let mut r = self . buf . reader ( 1 ) ;
387+ let mut resp = r. read_string ( ) ?. reader ( 0 ) ;
388+ let typ = String :: from_utf8 ( resp. read_string ( ) ?. into ( ) ) ?;
389+ let sig = resp. read_string ( ) ?;
390+ let algo = Algorithm :: new ( & typ) ?;
391+ let sig = Signature :: new ( algo, sig. to_vec ( ) ) ?;
392+ Ok ( sig)
393+ } else {
394+ Err ( Error :: AgentProtocolError )
461395 }
462396 }
463397
464398 /// Ask the agent to remove a key from its memory.
465- pub async fn remove_identity ( & mut self , public : & key :: PublicKey ) -> Result < ( ) , Error > {
399+ pub async fn remove_identity ( & mut self , public : & ssh_key :: PublicKey ) -> Result < ( ) , Error > {
466400 self . buf . clear ( ) ;
467401 self . buf . resize ( 4 ) ;
468402 self . buf . push ( msg:: REMOVE_IDENTITY ) ;
@@ -527,29 +461,7 @@ impl<S: AgentStream + Unpin> AgentClient<S> {
527461 }
528462}
529463
530- fn key_blob ( public : & key:: PublicKey , buf : & mut CryptoVec ) -> Result < ( ) , Error > {
531- match * public {
532- PublicKey :: RSA { ref key, .. } => {
533- buf. extend ( & [ 0 , 0 , 0 , 0 ] ) ;
534- let len0 = buf. len ( ) ;
535- buf. extend_ssh_string ( b"ssh-rsa" ) ;
536- buf. extend_ssh ( & protocol:: RsaPublicKey :: from ( key) ) ;
537- let len1 = buf. len ( ) ;
538- #[ allow( clippy:: indexing_slicing) ] // length is known
539- BigEndian :: write_u32 ( & mut buf[ 5 ..] , ( len1 - len0) as u32 ) ;
540- }
541- PublicKey :: Ed25519 ( ref p) => {
542- buf. extend ( & [ 0 , 0 , 0 , 0 ] ) ;
543- let len0 = buf. len ( ) ;
544- buf. extend_ssh_string ( b"ssh-ed25519" ) ;
545- buf. extend_ssh_string ( p. as_bytes ( ) ) ;
546- let len1 = buf. len ( ) ;
547- #[ allow( clippy:: indexing_slicing) ] // length is known
548- BigEndian :: write_u32 ( & mut buf[ 5 ..] , ( len1 - len0) as u32 ) ;
549- }
550- PublicKey :: EC { .. } => {
551- buf. extend_ssh_string ( & public. public_key_bytes ( ) ) ;
552- }
553- }
464+ fn key_blob ( public : & ssh_key:: PublicKey , buf : & mut CryptoVec ) -> Result < ( ) , Error > {
465+ buf. extend_ssh_string ( public. key_data ( ) . encoded ( ) ?. as_slice ( ) ) ;
554466 Ok ( ( ) )
555467}
0 commit comments