@@ -86,6 +86,7 @@ pub struct Signature([u8; 64]);
8686/// `Signed<T>` is a "proof" that the signature `sig` on a [`Signable`] struct
8787/// `T` was actually signed by `signer`.
8888#[ derive( Debug , PartialEq , Eq ) ]
89+ #[ must_use]
8990pub struct Signed < T : Signable > {
9091 signer : PublicKey ,
9192 sig : Signature ,
@@ -435,7 +436,7 @@ impl PublicKey {
435436
436437 /// Like [`ed25519::verify_signed_struct`](verify_signed_struct) but only
437438 /// allows signatures produced by this `ed25519::PublicKey`.
438- pub fn verify_signed_struct < ' msg , T : Signable + Deserialize < ' msg > > (
439+ pub fn verify_self_signed_struct < ' msg , T : Signable + Deserialize < ' msg > > (
439440 & self ,
440441 serialized : & ' msg [ u8 ] ,
441442 ) -> Result < Signed < T > , Error > {
@@ -702,19 +703,36 @@ fn deserialize_pkcs8(bytes: &[u8]) -> Option<(&[u8; 32], &[u8; 32])> {
702703#[ cfg( test) ]
703704mod test {
704705 use proptest:: arbitrary:: any;
705- use proptest:: proptest;
706706 use proptest:: strategy:: Strategy ;
707+ use proptest:: { prop_assume, proptest} ;
708+ use proptest_derive:: Arbitrary ;
707709
708710 use super :: * ;
709711
710712 fn arb_seed ( ) -> impl Strategy < Value = [ u8 ; 32 ] > {
711- any :: < [ u8 ; 32 ] > ( )
713+ any :: < [ u8 ; 32 ] > ( ) . no_shrink ( )
712714 }
713715
714716 fn arb_key_pair ( ) -> impl Strategy < Value = KeyPair > {
715717 arb_seed ( ) . prop_map ( |seed| KeyPair :: from_seed ( & seed) )
716718 }
717719
720+ #[ derive( Arbitrary , Deserialize , Serialize ) ]
721+ struct SignableBytes ( Vec < u8 > ) ;
722+
723+ impl Signable for SignableBytes {
724+ const DOMAIN_SEPARATOR_STR : & ' static [ u8 ] =
725+ b"LEXE-REALM::SignableBytes" ;
726+ }
727+
728+ impl fmt:: Debug for SignableBytes {
729+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
730+ f. debug_tuple ( "SignableBytes" )
731+ . field ( & hex:: display ( & self . 0 ) )
732+ . finish ( )
733+ }
734+ }
735+
718736 #[ test]
719737 fn test_serde_pkcs8_roundtrip ( ) {
720738 proptest ! ( |( seed in arb_seed( ) ) | {
@@ -765,6 +783,103 @@ mod test {
765783 pubkey. verify_raw ( & msg, & sig2) . unwrap ( ) ;
766784 }
767785
786+ // truncating the signed struct should cause the verification to fail.
787+ #[ test]
788+ fn test_reject_truncated_sig ( ) {
789+ proptest ! ( |( key_pair in arb_key_pair( ) , msg in any:: <SignableBytes >( ) ) | {
790+ let pubkey = key_pair. public_key( ) ;
791+
792+ let ( sig, _) = key_pair. sign_struct( & msg) . unwrap( ) ;
793+ let _ = pubkey
794+ . verify_self_signed_struct:: <SignableBytes >( & sig)
795+ . unwrap( ) ;
796+
797+ for trunc_len in 0 ..SIGNED_STRUCT_OVERHEAD {
798+ pubkey
799+ . verify_self_signed_struct:: <SignableBytes >( & sig[ ..trunc_len] )
800+ . unwrap_err( ) ;
801+ pubkey
802+ . verify_self_signed_struct:: <SignableBytes >( & sig[ ( trunc_len+1 ) ..] )
803+ . unwrap_err( ) ;
804+ }
805+ } ) ;
806+ }
807+
808+ // inserting some random bytes into the signed struct should cause the
809+ // sig verification to fail
810+ #[ test]
811+ fn test_reject_pad_sig ( ) {
812+ let cfg = proptest:: test_runner:: Config :: with_cases ( 50 ) ;
813+ proptest ! ( cfg, |(
814+ key_pair in arb_key_pair( ) ,
815+ msg in any:: <SignableBytes >( ) ,
816+ padding in any:: <Vec <u8 >>( ) ,
817+ ) | {
818+ prop_assume!( !padding. is_empty( ) ) ;
819+
820+ let pubkey = key_pair. public_key( ) ;
821+
822+ let ( sig, _) = key_pair. sign_struct( & msg) . unwrap( ) ;
823+ let _ = pubkey
824+ . verify_self_signed_struct:: <SignableBytes >( & sig)
825+ . unwrap( ) ;
826+
827+ let mut sig2: Vec <u8 > = Vec :: with_capacity( sig. len( ) + padding. len( ) ) ;
828+
829+ for idx in 0 ..=sig. len( ) {
830+ let ( left, right) = sig. split_at( idx) ;
831+
832+ // sig2 := left || padding || right
833+
834+ sig2. clear( ) ;
835+ sig2. extend_from_slice( left) ;
836+ sig2. extend_from_slice( & padding) ;
837+ sig2. extend_from_slice( right) ;
838+
839+ pubkey
840+ . verify_self_signed_struct:: <SignableBytes >( & sig2)
841+ . unwrap_err( ) ;
842+ }
843+ } ) ;
844+ }
845+
846+ // flipping some random bits in the signed struct should cause the
847+ // verification to fail.
848+ #[ test]
849+ fn test_reject_modified_sig ( ) {
850+ let arb_mutation = any :: < Vec < u8 > > ( )
851+ . prop_filter ( "can't be empty or all zeroes" , |m| {
852+ !m. is_empty ( ) && !m. iter ( ) . all ( |x| x == & 0u8 )
853+ } ) ;
854+
855+ proptest ! ( |(
856+ key_pair in arb_key_pair( ) ,
857+ msg in any:: <SignableBytes >( ) ,
858+ mut_offset in any:: <usize >( ) ,
859+ mut mutation in arb_mutation,
860+ ) | {
861+ let pubkey = key_pair. public_key( ) ;
862+
863+ let ( mut sig, _) = key_pair. sign_struct( & msg) . unwrap( ) ;
864+
865+ mutation. truncate( sig. len( ) ) ;
866+ prop_assume!( !mutation. is_empty( ) && !mutation. iter( ) . all( |x| x == & 0 ) ) ;
867+
868+ let _ = pubkey
869+ . verify_self_signed_struct:: <SignableBytes >( & sig)
870+ . unwrap( ) ;
871+
872+ // xor in the mutation bytes to the signature to modify it. any
873+ // modified bit should cause the verification to fail.
874+ for ( idx_mut, m) in mutation. into_iter( ) . enumerate( ) {
875+ let idx_sig = idx_mut. wrapping_add( mut_offset) % sig. len( ) ;
876+ sig[ idx_sig] ^= m;
877+ }
878+
879+ pubkey. verify_self_signed_struct:: <SignableBytes >( & sig) . unwrap_err( ) ;
880+ } ) ;
881+ }
882+
768883 #[ test]
769884 fn test_sign_verify ( ) {
770885 proptest ! ( |( key_pair in arb_key_pair( ) , msg in any:: <Vec <u8 >>( ) ) | {
@@ -797,15 +912,17 @@ mod test {
797912
798913 proptest ! ( |( key_pair in arb_key_pair( ) , foo in arb_foo( ) ) | {
799914 let signer = key_pair. public_key( ) ;
800- let ( serialized, signed_foo) = key_pair. sign_struct:: <Foo >( & foo) . unwrap( ) ;
915+ let ( serialized, signed_foo) =
916+ key_pair. sign_struct:: <Foo >( & foo) . unwrap( ) ;
801917
802- let signed_foo2 = signer. verify_signed_struct:: <Foo >( & serialized) . unwrap( ) ;
918+ let signed_foo2 =
919+ signer. verify_self_signed_struct:: <Foo >( & serialized) . unwrap( ) ;
803920 assert_eq!( signed_foo, signed_foo2. as_ref( ) ) ;
804921
805- // trying to verify as another struct with the same serialization
806- // should be prevented by domain separation
922+ // trying to verify signature as another type with a valid
923+ // serialization is prevented by domain separation.
807924
808- signer. verify_signed_struct :: <Bar >( & serialized) . unwrap_err( ) ;
925+ signer. verify_self_signed_struct :: <Bar >( & serialized) . unwrap_err( ) ;
809926 } ) ;
810927 }
811928}
0 commit comments