11use aws_lc_rs:: {
22 digest:: { Digest , SHA256 , digest} ,
3+ encoding:: { AsDer , Pkcs8V1Der } ,
34 pkcs8:: Document ,
45 rand:: SystemRandom ,
6+ rsa:: KeySize ,
57 signature:: {
68 self , ECDSA_P256_SHA256_FIXED_SIGNING , EcdsaKeyPair , EcdsaSigningAlgorithm ,
7- EcdsaVerificationAlgorithm , KeyPair , Signature ,
9+ EcdsaVerificationAlgorithm , KeyPair , RsaKeyPair , Signature ,
810 } ,
911} ;
1012use base64:: { Engine as _, prelude:: BASE64_URL_SAFE_NO_PAD } ;
1113use rama_core:: error:: { ErrorContext , OpaqueError } ;
1214use serde:: { Deserialize , Serialize , Serializer , ser:: SerializeStruct } ;
1315
14- use crate :: jose:: { JWA , Signer } ;
16+ use crate :: jose:: { JWA , Signer , jwk_utils :: create_subject_public_key_info } ;
1517
1618#[ derive( Clone , Debug , Serialize , Deserialize , PartialEq , Eq ) ]
1719/// [`JWK`] or JSON Web Key as defined in [`rfc7517`]
@@ -157,7 +159,21 @@ impl JWK {
157159 & self ,
158160 ) -> Result < signature:: UnparsedPublicKey < Vec < u8 > > , OpaqueError > {
159161 match & self . key_type {
160- JWKType :: RSA { .. } => Err ( OpaqueError :: from_display ( "currently not supported" ) ) ,
162+ JWKType :: RSA { n, e } => {
163+ let n_bytes = BASE64_URL_SAFE_NO_PAD
164+ . decode ( n)
165+ . context ( "decode RSA modulus (n)" ) ?;
166+ let e_bytes = BASE64_URL_SAFE_NO_PAD
167+ . decode ( e)
168+ . context ( "decode RSA exponent (e)" ) ?;
169+
170+ let rsa_public_key_sequence = create_subject_public_key_info ( n_bytes, e_bytes) ;
171+
172+ Ok ( signature:: UnparsedPublicKey :: new (
173+ self . alg . try_into ( ) ?,
174+ rsa_public_key_sequence,
175+ ) )
176+ }
161177 JWKType :: OCT { .. } => Err ( OpaqueError :: from_display (
162178 "Symmetric key cannot be converted to public key" ,
163179 ) ) ,
@@ -181,6 +197,25 @@ impl JWK {
181197 }
182198 }
183199 }
200+
201+ /// Creates a new [`JWK`] from a given [`RSAKeyPair`]
202+ #[ must_use]
203+ pub fn new_from_rsa_key_pair ( rsa_key_pair : & RsaKeyPair , alg : JWA ) -> Self {
204+ let n = rsa_key_pair. public_key ( ) . modulus ( ) ;
205+ let e = rsa_key_pair. public_key ( ) . exponent ( ) ;
206+ Self {
207+ alg,
208+ key_type : JWKType :: RSA {
209+ n : BASE64_URL_SAFE_NO_PAD . encode ( n. big_endian_without_leading_zero ( ) ) ,
210+ e : BASE64_URL_SAFE_NO_PAD . encode ( e. big_endian_without_leading_zero ( ) ) ,
211+ } ,
212+ r#use : Some ( JWKUse :: Signature ) ,
213+ key_ops : None ,
214+ x5c : None ,
215+ x5t : None ,
216+ x5t_sha256 : None ,
217+ }
218+ }
184219}
185220
186221#[ derive( Debug ) ]
@@ -257,7 +292,7 @@ impl EcdsaKey {
257292}
258293
259294#[ derive( Serialize ) ]
260- struct EcdsaKeySigningHeaders < ' a > {
295+ struct SigningHeaders < ' a > {
261296 alg : JWA ,
262297 jwk : & ' a JWK ,
263298}
@@ -272,7 +307,7 @@ impl Signer for EcdsaKey {
272307 _unprotected_headers : & mut super :: jws:: Headers ,
273308 ) -> Result < ( ) , Self :: Error > {
274309 let jwk = self . create_jwk ( ) ;
275- protected_headers. try_set_headers ( EcdsaKeySigningHeaders {
310+ protected_headers. try_set_headers ( SigningHeaders {
276311 alg : jwk. alg ,
277312 jwk : & jwk,
278313 } ) ?;
@@ -289,9 +324,91 @@ impl Signer for EcdsaKey {
289324 }
290325}
291326
327+ pub struct RsaKey {
328+ rng : SystemRandom ,
329+ alg : JWA ,
330+ inner : RsaKeyPair ,
331+ }
332+
333+ impl RsaKey {
334+ /// Create a new [`RsaKey`] from the given [`RsaKeyPair`]
335+ pub fn new ( key_pair : RsaKeyPair , alg : JWA , rng : SystemRandom ) -> Result < Self , OpaqueError > {
336+ Ok ( Self {
337+ rng,
338+ alg,
339+ inner : key_pair,
340+ } )
341+ }
342+
343+ /// Generate a new [`RsaKey`] from a newly generated [`RsaKeyPair`]
344+ pub fn generate ( key_size : KeySize ) -> Result < Self , OpaqueError > {
345+ let key_pair = RsaKeyPair :: generate ( key_size) . context ( "error generating rsa key pair" ) ?;
346+
347+ Self :: new ( key_pair, JWA :: RS256 , SystemRandom :: new ( ) )
348+ }
349+
350+ /// Generate a new [`RsaKey`] from the given pkcs8 der
351+ pub fn from_pkcs8_der (
352+ pkcs8_der : & [ u8 ] ,
353+ alg : JWA ,
354+ rng : SystemRandom ,
355+ ) -> Result < Self , OpaqueError > {
356+ let key_pair = RsaKeyPair :: from_pkcs8 ( pkcs8_der) . context ( "create RSAKeyPair from pkcs8" ) ?;
357+
358+ Self :: new ( key_pair, alg, rng)
359+ }
360+
361+ /// Create pkcs8 der for the current [`RsaKeyPair`]
362+ pub fn pkcs8_der ( & self ) -> Result < ( JWA , Pkcs8V1Der < ' static > ) , OpaqueError > {
363+ let doc = self
364+ . inner
365+ . as_der ( )
366+ . context ( "error creating pkcs8 der from rsa keypair" ) ?;
367+ Ok ( ( self . alg , doc) )
368+ }
369+
370+ /// Create a [`JWK`] for this [`RsaKey`]
371+ #[ must_use]
372+ pub fn create_jwk ( & self ) -> JWK {
373+ JWK :: new_from_rsa_key_pair ( & self . inner , self . alg )
374+ }
375+
376+ #[ must_use]
377+ pub fn rng ( & self ) -> & SystemRandom {
378+ & self . rng
379+ }
380+ }
381+
382+ impl Signer for RsaKey {
383+ type Signature = Vec < u8 > ;
384+ type Error = OpaqueError ;
385+
386+ fn set_headers (
387+ & self ,
388+ protected_headers : & mut super :: jws:: Headers ,
389+ _unprotected_headers : & mut super :: jws:: Headers ,
390+ ) -> Result < ( ) , Self :: Error > {
391+ let jwk = self . create_jwk ( ) ;
392+ protected_headers. try_set_headers ( SigningHeaders {
393+ alg : jwk. alg ,
394+ jwk : & jwk,
395+ } ) ?;
396+ Ok ( ( ) )
397+ }
398+
399+ fn sign ( & self , data : & str ) -> Result < Self :: Signature , Self :: Error > {
400+ let mut sig = vec ! [ 0 ; self . inner. public_modulus_len( ) ] ;
401+ self . inner
402+ . sign ( self . alg . try_into ( ) ?, self . rng ( ) , data. as_bytes ( ) , & mut sig)
403+ . context ( "sign protected data" ) ?;
404+ Ok ( sig)
405+ }
406+ }
407+
292408#[ cfg( test) ]
293409mod tests {
294410 use super :: * ;
411+ use crate :: jose:: JWKType :: RSA ;
295412
296413 #[ test]
297414 fn jwk_thumb_order_is_correct ( ) {
@@ -328,4 +445,60 @@ mod tests {
328445
329446 assert_eq ! ( key. create_jwk( ) , recreated_key. create_jwk( ) )
330447 }
448+
449+ #[ test]
450+ fn test_n_and_e_are_base64_encoded ( ) {
451+ let rsa_key_pair = RsaKey :: generate ( KeySize :: Rsa4096 ) . unwrap ( ) ;
452+ let jwk = JWK :: new_from_rsa_key_pair ( & rsa_key_pair. inner , JWA :: PS512 ) ;
453+ let JWKType :: RSA { n, e } = jwk. key_type else {
454+ panic ! ( "JWK type not RSA" )
455+ } ;
456+ assert ! ( BASE64_URL_SAFE_NO_PAD . decode( n) . is_ok( ) ) ;
457+ assert ! ( BASE64_URL_SAFE_NO_PAD . decode( e) . is_ok( ) ) ;
458+ }
459+
460+ /// This example is taken from the [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517#appendix-A.1)
461+ /// Appendix A.1.
462+ #[ test]
463+ fn test_unparsed_public_key ( ) {
464+ let jwk_rsa = JWK {
465+ alg : JWA :: RS256 ,
466+ key_type : RSA {
467+ n : "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK\
468+ 7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl9\
469+ 3lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHz\
470+ u6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksIN\
471+ HaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
472+ . to_owned ( ) ,
473+ e : "AQAB" . to_owned ( ) ,
474+ } ,
475+ r#use : None ,
476+ key_ops : None ,
477+ x5c : None ,
478+ x5t : None ,
479+ x5t_sha256 : None ,
480+ } ;
481+ // This is the known byte sequence of the unparsed public key generated from the above JWK
482+ // using the python `cryptography` library.
483+ let expected_unparsed_bytes = [
484+ 48 , 130 , 1 , 34 , 48 , 13 , 6 , 9 , 42 , 134 , 72 , 134 , 247 , 13 , 1 , 1 , 1 , 5 , 0 , 3 , 130 , 1 , 15 ,
485+ 0 , 48 , 130 , 1 , 10 , 2 , 130 , 1 , 1 , 0 , 210 , 252 , 123 , 106 , 10 , 30 , 108 , 103 , 16 , 74 , 235 ,
486+ 143 , 136 , 178 , 87 , 102 , 155 , 77 , 246 , 121 , 221 , 173 , 9 , 155 , 92 , 74 , 108 , 217 , 168 ,
487+ 128 , 21 , 181 , 161 , 51 , 191 , 11 , 133 , 108 , 120 , 113 , 182 , 223 , 0 , 11 , 85 , 79 , 206 , 179 ,
488+ 194 , 237 , 81 , 43 , 182 , 143 , 20 , 92 , 110 , 132 , 52 , 117 , 47 , 171 , 82 , 161 , 207 , 193 , 36 ,
489+ 64 , 143 , 121 , 181 , 138 , 69 , 120 , 193 , 100 , 40 , 133 , 87 , 137 , 247 , 162 , 73 , 227 , 132 ,
490+ 203 , 45 , 159 , 174 , 45 , 103 , 253 , 150 , 251 , 146 , 108 , 25 , 142 , 7 , 115 , 153 , 253 , 200 ,
491+ 21 , 192 , 175 , 9 , 125 , 222 , 90 , 173 , 239 , 244 , 77 , 231 , 14 , 130 , 127 , 72 , 120 , 67 , 36 ,
492+ 57 , 191 , 238 , 185 , 96 , 104 , 208 , 71 , 79 , 197 , 13 , 109 , 144 , 191 , 58 , 152 , 223 , 175 , 16 ,
493+ 64 , 200 , 156 , 2 , 214 , 146 , 171 , 59 , 60 , 40 , 150 , 96 , 157 , 134 , 253 , 115 , 183 , 116 , 206 ,
494+ 7 , 64 , 100 , 124 , 238 , 234 , 163 , 16 , 189 , 18 , 249 , 133 , 168 , 235 , 159 , 89 , 253 , 212 , 38 ,
495+ 206 , 165 , 178 , 18 , 15 , 79 , 42 , 52 , 188 , 171 , 118 , 75 , 126 , 108 , 84 , 214 , 132 , 2 , 56 ,
496+ 188 , 196 , 5 , 135 , 165 , 158 , 102 , 237 , 31 , 51 , 137 , 69 , 119 , 99 , 92 , 71 , 10 , 247 , 92 ,
497+ 249 , 44 , 32 , 209 , 218 , 67 , 225 , 191 , 196 , 25 , 226 , 34 , 166 , 240 , 208 , 187 , 53 , 140 , 94 ,
498+ 56 , 249 , 203 , 5 , 10 , 234 , 254 , 144 , 72 , 20 , 241 , 172 , 26 , 164 , 156 , 202 , 158 , 160 , 202 ,
499+ 131 , 2 , 3 , 1 , 0 , 1 ,
500+ ] ;
501+ let unparsed_key = jwk_rsa. unparsed_public_key ( ) . unwrap ( ) ;
502+ assert_eq ! ( expected_unparsed_bytes, unparsed_key. as_ref( ) ) ;
503+ }
331504}
0 commit comments