@@ -36,11 +36,6 @@ pub mod messages;
3636pub enum AttestDataError {
3737 #[ cfg_attr( feature = "std" , error( "Deserialization failed" ) ) ]
3838 Deserialize ,
39- #[ cfg_attr(
40- feature = "std" ,
41- error( "Failed to get random Nonce from the platform" )
42- ) ]
43- GetRandom ,
4439 #[ cfg_attr( feature = "std" , error( "Slice is the wrong length" ) ) ]
4540 TryFromSliceError ,
4641 #[ cfg_attr(
@@ -52,6 +47,18 @@ pub enum AttestDataError {
5247 TaggedDigest ,
5348}
5449
50+ #[ cfg_attr( feature = "std" , derive( Error ) ) ]
51+ #[ derive( Debug , PartialEq ) ]
52+ pub enum NonceError {
53+ #[ cfg_attr( feature = "std" , error( "unsupported Nonce length ({0})" ) ) ]
54+ UnsupportedLen ( usize ) ,
55+ #[ cfg_attr(
56+ feature = "std" ,
57+ error( "Failed to get random Nonce from the platform" )
58+ ) ]
59+ GetRandom ,
60+ }
61+
5562/// Array is the type we use as a base for types that are constant sized byte
5663/// buffers.
5764#[ serde_as]
@@ -117,40 +124,105 @@ impl<const N: usize> AsRef<[u8]> for Array<N> {
117124const SHA3_256_DIGEST_SIZE : usize =
118125 <Sha3_256Core as OutputSizeUser >:: OutputSize :: USIZE ;
119126
120- const NONCE_SIZE : usize = SHA3_256_DIGEST_SIZE ;
121-
122127/// An array of bytes sized appropriately for a sha3-256 digest.
123128pub type Sha3_256Digest = Array < SHA3_256_DIGEST_SIZE > ;
124129
125130/// An array of bytes sized appropriately for a sha3-256 digest.
126131pub type Ed25519Signature = Array < SIGNATURE_SERIALIZED_LENGTH > ;
127132
128- /// Nonce is a newtype around an appropriately sized byte array.
129- pub type Nonce = Array < NONCE_SIZE > ;
133+ pub type Nonce32 = Array < SHA3_256_DIGEST_SIZE > ;
134+
135+ /// A Nonce is supplied as part of the attestation challenge to guarantee
136+ /// freshness. Callers are expected to use a random Nonce with a length that's
137+ /// appropriate for the specific digest and signing algorithms in use. We may
138+ /// in the future extend this to accept arbitrarily sized values.
139+ #[ derive(
140+ Copy ,
141+ Clone ,
142+ Debug ,
143+ Deserialize ,
144+ PartialEq ,
145+ // The current RoT Attest API takes the nonce bytes directly (i.e. a
146+ // `Nonce32`/`Array<32>`) rather than this more generic `Nonce` type.
147+ // To prevent accidentally accepting this type where it currently shouldn't
148+ // be accepted, we omit these for now until hubris#2375 is fixed.
149+ // Serialize, SerializedSize,
150+ ) ]
151+ pub enum Nonce {
152+ /// A 32-byte Nonce value.
153+ N32 ( Nonce32 ) ,
154+ }
130155
131156#[ cfg( feature = "std" ) ]
132157impl fmt:: Display for Nonce {
133158 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
134- let mut out: Vec < String > = Vec :: new ( ) ;
159+ write ! ( f, "Nonce({})" , hex:: encode( self . as_ref( ) ) )
160+ }
161+ }
162+
163+ impl Nonce {
164+ #[ cfg( feature = "std" ) ]
165+ pub fn from_platform_rng ( len : usize ) -> Result < Self , NonceError > {
166+ // We currently only support 32-byte Nonce's
167+ if len != Nonce32 :: LENGTH {
168+ return Err ( NonceError :: UnsupportedLen ( len) ) ;
169+ }
170+ let mut nonce = Array ( [ 0u8 ; Nonce32 :: LENGTH ] ) ;
171+ getrandom:: fill ( nonce. 0 . as_mut_slice ( ) )
172+ . map_err ( |_| NonceError :: GetRandom ) ?;
173+ Ok ( Nonce :: N32 ( nonce) )
174+ }
175+ }
176+
177+ #[ cfg( feature = "std" ) ]
178+ impl AsRef < [ u8 ] > for Nonce {
179+ fn as_ref ( & self ) -> & [ u8 ] {
180+ match self {
181+ Nonce :: N32 ( n) => n. as_ref ( ) ,
182+ }
183+ }
184+ }
135185
136- for byte in self . 0 {
137- out. push ( format ! ( "{byte}" ) ) ;
186+ impl TryFrom < & [ u8 ] > for Nonce {
187+ type Error = NonceError ;
188+
189+ fn try_from ( item : & [ u8 ] ) -> Result < Self , Self :: Error > {
190+ match item. len ( ) {
191+ Nonce32 :: LENGTH => {
192+ // SAFETY: We've already checked the length is correct.
193+ Ok ( Nonce :: N32 ( item. try_into ( ) . unwrap ( ) ) )
194+ }
195+ len => Err ( NonceError :: UnsupportedLen ( len) ) ,
138196 }
139- let out = out. join ( " " ) ;
197+ }
198+ }
199+
200+ #[ cfg( feature = "std" ) ]
201+ impl TryFrom < Vec < u8 > > for Nonce {
202+ type Error = NonceError ;
140203
141- write ! ( f, "[{out}]" )
204+ fn try_from ( item : Vec < u8 > ) -> Result < Self , Self :: Error > {
205+ item[ ..] . try_into ( )
142206 }
143207}
144208
145- impl Nonce {
146- #[ cfg( feature = "std" ) ]
147- pub fn from_platform_rng ( ) -> Result < Self , AttestDataError > {
148- let mut nonce = [ 0u8 ; NONCE_SIZE ] ;
149- getrandom:: fill ( & mut nonce[ ..] )
150- . map_err ( |_| AttestDataError :: GetRandom ) ?;
151- let nonce = nonce;
209+ impl TryFrom < Nonce > for Nonce32 {
210+ type Error = NonceError ;
211+
212+ fn try_from ( item : Nonce ) -> Result < Nonce32 , Self :: Error > {
213+ match item {
214+ Nonce :: N32 ( n) => Ok ( n) ,
215+ }
216+ }
217+ }
218+
219+ impl < ' a > TryFrom < & ' a Nonce > for & ' a Nonce32 {
220+ type Error = NonceError ;
152221
153- Ok ( Self ( nonce) )
222+ fn try_from ( item : & Nonce ) -> Result < & Nonce32 , Self :: Error > {
223+ match item {
224+ Nonce :: N32 ( n) => Ok ( n) ,
225+ }
154226 }
155227}
156228
@@ -437,4 +509,24 @@ mod tests {
437509 }
438510 assert_eq ! ( count, 1 ) ;
439511 }
512+
513+ #[ cfg( feature = "std" ) ]
514+ #[ test]
515+ fn nonce_from_bytes ( ) {
516+ let empty_nonce = Nonce :: try_from ( [ ] . as_ref ( ) ) ;
517+ assert_eq ! ( empty_nonce, Err ( NonceError :: UnsupportedLen ( 0 ) ) ) ;
518+
519+ let short_nonce = Nonce :: try_from ( [ 1 ] . as_ref ( ) ) ;
520+ assert_eq ! ( short_nonce, Err ( NonceError :: UnsupportedLen ( 1 ) ) ) ;
521+
522+ let n32 = [ 0 ; 32 ] ;
523+ let nonce = Nonce :: try_from ( n32. as_ref ( ) ) . expect ( "32-byte Nonce" ) ;
524+ assert_eq ! ( nonce, Nonce :: N32 ( Array ( n32) ) ) ;
525+
526+ let nonce32 = Nonce32 :: try_from ( nonce) ;
527+ assert_eq ! ( nonce32, Ok ( Array ( n32) ) ) ;
528+
529+ let _ = Nonce :: from_platform_rng ( Nonce32 :: LENGTH )
530+ . expect ( "random 32-byte Nonce" ) ;
531+ }
440532}
0 commit comments