diff --git a/Cargo.lock b/Cargo.lock index 80f025e7b..3fa5ddb74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2152,6 +2152,7 @@ dependencies = [ "console", "lazy_static", "linked-hash-map", + "serde", "similar", "yaml-rust", ] @@ -2699,6 +2700,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "generic-array", + "insta", "k256", "mas-iana", "mas-jose", @@ -2708,6 +2710,7 @@ dependencies = [ "pkcs1", "pkcs8", "rand", + "rand_chacha", "rsa", "sec1", "spki", diff --git a/Cargo.toml b/Cargo.toml index 20704f876..5c1ac8112 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,6 @@ [workspace] - default-members = ["crates/cli"] members = ["crates/*"] + +[profile.dev.package.num-bigint-dig] +opt-level = 3 diff --git a/crates/keystore/Cargo.toml b/crates/keystore/Cargo.toml index 9822f20a8..375715d39 100644 --- a/crates/keystore/Cargo.toml +++ b/crates/keystore/Cargo.toml @@ -30,3 +30,7 @@ base64ct = "1.5.2" mas-iana = { path = "../iana" } mas-jose = { path = "../jose" } + +[dev-dependencies] +insta = { version = "1.21.0", features = ["yaml"] } +rand_chacha = "0.3.1" diff --git a/crates/keystore/tests/keystore.rs b/crates/keystore/tests/keystore.rs index c089fe9e3..57df2d416 100644 --- a/crates/keystore/tests/keystore.rs +++ b/crates/keystore/tests/keystore.rs @@ -12,11 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +use der::pem::LineEnding; +use mas_iana::jose::JsonWebSignatureAlg; use mas_jose::{ jwk::ParametersInfo, jwt::{JsonWebSignatureHeader, Jwt}, }; -use mas_keystore::PrivateKey; +use mas_keystore::{JsonWebKey, JsonWebKeySet, Keystore, PrivateKey}; +use rand::SeedableRng; static PASSWORD: &str = "hunter2"; @@ -166,3 +169,56 @@ fn load_unencrypted_as_encrypted_error() { .unwrap_err() .is_unencrypted()); } + +#[test] +fn generate_sign_and_verify() { + // Use a seeded RNG to keep the snapshot stable + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(42); + + let rsa = PrivateKey::generate_rsa(&mut rng).expect("Failed to generate RSA key"); + insta::assert_snapshot!(rsa.to_pem(LineEnding::LF).unwrap()); + + let ec_p256 = PrivateKey::generate_ec_p256(&mut rng); + insta::assert_snapshot!(ec_p256.to_pem(LineEnding::LF).unwrap()); + + let ec_p384 = PrivateKey::generate_ec_p384(&mut rng); + insta::assert_snapshot!(ec_p384.to_pem(LineEnding::LF).unwrap()); + + let ec_k256 = PrivateKey::generate_ec_k256(&mut rng); + insta::assert_snapshot!(ec_k256.to_pem(LineEnding::LF).unwrap()); + + // Create a keystore out of the keys + let keyset = Keystore::new(JsonWebKeySet::new(vec![ + JsonWebKey::new(rsa), + JsonWebKey::new(ec_p256), + JsonWebKey::new(ec_p384), + JsonWebKey::new(ec_k256), + ])); + + // And extract the public JWKS + let jwks = keyset.public_jwks(); + insta::assert_yaml_snapshot!(jwks); + + // Try signing for each supported algorithm + for alg in [ + JsonWebSignatureAlg::Rs256, + JsonWebSignatureAlg::Rs384, + JsonWebSignatureAlg::Rs512, + JsonWebSignatureAlg::Ps256, + JsonWebSignatureAlg::Ps384, + JsonWebSignatureAlg::Ps512, + JsonWebSignatureAlg::Es256, + JsonWebSignatureAlg::Es384, + JsonWebSignatureAlg::Es256K, + ] { + // Find a matching key and sign with it + let key = keyset.signing_key_for_algorithm(&alg).unwrap(); + let signer = key.params().signing_key_for_alg(&alg).unwrap(); + let header = JsonWebSignatureHeader::new(alg.clone()); + let token = Jwt::sign_with_rng(&mut rng, header, "", &signer).unwrap(); + insta::assert_snapshot!(format!("jwt_{alg}"), token.as_str()); + + // Then try to verify from the public JWKS + token.verify_with_jwks(&jwks).unwrap(); + } +} diff --git a/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-2.snap b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-2.snap new file mode 100644 index 000000000..42a2f0945 --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-2.snap @@ -0,0 +1,10 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: "ec_p256.to_pem(LineEnding::LF).unwrap()" +--- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIH3L+ZYgfEaJtclP07qPQBrmkHEhYkyYooxvU8AlSW+CoAoGCCqGSM49 +AwEHoUQDQgAEXcA+X+lhDCmmzaUQFh7i7gkT7mwdrRUsMl9RSfyWh93n+xq3O4/m +vMmUnlvy7tBoHkcAdTJ+Zkv+loLw+mkcBA== +-----END EC PRIVATE KEY----- + diff --git a/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-3.snap b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-3.snap new file mode 100644 index 000000000..b71a5dcad --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-3.snap @@ -0,0 +1,11 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: "ec_p384.to_pem(LineEnding::LF).unwrap()" +--- +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDAl3R97SR8hWLuMH6737YdvXVb7P7T9pKSIhQozmzN+r+V5Ncvjn+DQ +Q/QxYr9nLwOgBwYFK4EEACKhZANiAASa86XQW7CDF9GhvcBY53sJ4lP0z9rfrjwo +nwixQJIWBROjlpsm5hdIwLfj46IUPYCNEoD8VP8eR2s/uzlgEv1hnz/2wmLlMqU0 +2R5QcY7Gc9CyDTO1bh5V2FFYjks4xfs= +-----END EC PRIVATE KEY----- + diff --git a/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-4.snap b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-4.snap new file mode 100644 index 000000000..850ca57cf --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-4.snap @@ -0,0 +1,10 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: "ec_k256.to_pem(LineEnding::LF).unwrap()" +--- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIBcikq9QkV39T8VFZWD4j5wO9xm0FWxhuAmvDRpix8XUoAcGBSuBBAAK +oUQDQgAEf4htTtPsdxlZn1htWE3ueHT4JB/4n4lxVOQdT/3RFuCS5aKQ04oS9pKM +QAHAn1bjbLRQ88Yxi3CgHuCitS+RrA== +-----END EC PRIVATE KEY----- + diff --git a/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-5.snap b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-5.snap new file mode 100644 index 000000000..a38f81bbd --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify-5.snap @@ -0,0 +1,21 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: jwks +--- +keys: + - kty: RSA + n: vClyfM076hWBZonjThx_PX46UQUWb2LfOpUV1655ZGoKMKgqanLMMfLBPjW9ouY6UtrZ7BxEgl01xLZ1dLdD2Ggb2IpwW56PUuZD2w9hJMungjR0ImymFBwjA9j2ucr0eIHdVQoOakEsrB0dqEC-3R7ax7piGCj9YB6uGZbDVfIJUv40o1pb-hvmmyQHwpoU4jR1y_V-OhrdFMPtwCXov2nlrqDb_e-T7TQlu4FN0URI6VxLNcSkgZfJH50PdJPr7AHqtnWhOGBfLaC9jDpGxfbjmC1iSMSzOt6WyVdcnqHv_JpzXu0SzFqpUSm3OI_l2DUjwTJBL1TOIRTVsjQN1w + e: AQAB + - kty: EC + crv: P-256 + x: XcA-X-lhDCmmzaUQFh7i7gkT7mwdrRUsMl9RSfyWh90 + y: 5_satzuP5rzJlJ5b8u7QaB5HAHUyfmZL_paC8PppHAQ + - kty: EC + crv: P-384 + x: mvOl0FuwgxfRob3AWOd7CeJT9M_a3648KJ8IsUCSFgUTo5abJuYXSMC34-OiFD2A + y: jRKA_FT_HkdrP7s5YBL9YZ8_9sJi5TKlNNkeUHGOxnPQsg0ztW4eVdhRWI5LOMX7 + - kty: EC + crv: secp256k1 + x: f4htTtPsdxlZn1htWE3ueHT4JB_4n4lxVOQdT_3RFuA + y: kuWikNOKEvaSjEABwJ9W42y0UPPGMYtwoB7gorUvkaw + diff --git a/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify.snap b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify.snap new file mode 100644 index 000000000..13523757a --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__generate_sign_and_verify.snap @@ -0,0 +1,32 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: "rsa.to_pem(LineEnding::LF).unwrap()" +--- +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAvClyfM076hWBZonjThx/PX46UQUWb2LfOpUV1655ZGoKMKgq +anLMMfLBPjW9ouY6UtrZ7BxEgl01xLZ1dLdD2Ggb2IpwW56PUuZD2w9hJMungjR0 +ImymFBwjA9j2ucr0eIHdVQoOakEsrB0dqEC+3R7ax7piGCj9YB6uGZbDVfIJUv40 +o1pb+hvmmyQHwpoU4jR1y/V+OhrdFMPtwCXov2nlrqDb/e+T7TQlu4FN0URI6VxL +NcSkgZfJH50PdJPr7AHqtnWhOGBfLaC9jDpGxfbjmC1iSMSzOt6WyVdcnqHv/Jpz +Xu0SzFqpUSm3OI/l2DUjwTJBL1TOIRTVsjQN1wIDAQABAoIBAD4bcC7Bj4U0lAHE +gcLGpTkm8RjNFRqvB//ONed7L5Z1aeelmlqIid3ywtZF5tJeK+ItWsEUk4h0O8sy +bpKX600DEC3phCy5qZUzbDJiYS5ECoZvyeWS9z6sCuK6OrYYx5j/RI9NQnTQDm7B +LYjb1iQmixBh9P8EiJ2xgsXvfYpgSDv2nUBVywp8HUmadAqE89cBsyurvMpR6eY4 +HI0Wge+vIbh0KHj5h7sJ7C8mWBcnjkJ9hWSCumMth3wufEpfs4lCUjhojTkr6ioT +9Mok8VpZvsxzDw3Ubnut1lX7II2EYwNEfgm/Tcw4/NC2eLc1AjoshxLVLg5JWy85 +RGj7FAECgYEAyLTpdQjD0PrQBi6O5HWQnVMVvJQz6bihdKUrjwJOfWvqgKVpAVVQ +IbLUT3J6ooe4Tei6xc7viNA7JZ+KyRvaQuZT4nWW2AkOCOnaxH3NKI4cDpWsdNdC +jNBHnIUUvDU4c4CkgIc8f1Gezm9epDVsgb1+wxwSbB8Je4S7M8is1WUCgYEA7//M +f1UPl32yaXH7ag8DbWHMzeNRw5T+F3zTagp93mCM0mPYyjggMfwPFr7167ISWrG4 +6DfHHABqhjnAkKfrrFMN5Xm8oup60XXIox1FB4Ew4K0VzyMTnSMPMMEGJZx6VQJP +TlGpexs4t+1N/gWgcGv1OgZ+fw7hjcaFtTMAcIsCgYBY/W3tyF8aT7rgotAUl9Px +DZ+7p3KFFKnx0DJKDFnE3o5xT+YJA0yuRF5Cg53AZrDfSmtVvXUTklBHVD/y/3h8 +5ScYZ87kJs+kQBwRtz2515i1FsQKYk9NpCO8UH1rHaXUAJvvqQa35PamzVaHNHDR +7bVAyTeZ3QEVVTqzsSyAyQKBgQDDIcL+QIW10VBPJYqZ9+z8cUkYmVuwXqKdLDOk +gzVFqlC0+tOXzzx2B4+pGchPQ3Bi5x8FR9yOqtPxoGEt/CnE6Z5h1rIF8Am95jsk +TDcE3AiGlJQn30giOhAuvrIlwG1CUudyMTlQS5i5Cquf/qks3sn6zK7q1YmUQTYT +Vo1j8wKBgQCgSISkWgRrQhEdZKBBzcxkWyUXUMieZa+pPTooZGY1VAqyTSXHUlLi +mrWtJ4temNK6OE7xAWJMWL6cVAxQUrs8C11DS//IGMxlMF/7uMU6pOFmMqq52G3D +k3NkZSJmC1liFiu3Q6Q2UqGHRX8CS5MeLncReuNUnFOiX8X2fcjoRw== +-----END RSA PRIVATE KEY----- + diff --git a/crates/keystore/tests/snapshots/keystore__jwt_ES256.snap b/crates/keystore/tests/snapshots/keystore__jwt_ES256.snap new file mode 100644 index 000000000..562a72caf --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_ES256.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJFUzI1NiJ9.IiI.Yvudbc_oPln_H02H9woFZurQrgzsuWGnRK2kZzat_rp2HYFZtYobvMw9LqPDgeqq9a1HiL_Hx796SqyobiTXJg diff --git a/crates/keystore/tests/snapshots/keystore__jwt_ES256K.snap b/crates/keystore/tests/snapshots/keystore__jwt_ES256K.snap new file mode 100644 index 000000000..9b937afdf --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_ES256K.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJFUzI1NksifQ.IiI.4q4ua7R-we5m58rKtLQDHJmQJb15dEUhj7A_H5kh591mrScXFmCYXVQI5iKKXGFHBV_AFISrJF4YjWCHDnLPeQ diff --git a/crates/keystore/tests/snapshots/keystore__jwt_ES384.snap b/crates/keystore/tests/snapshots/keystore__jwt_ES384.snap new file mode 100644 index 000000000..5297e8c2f --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_ES384.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJFUzM4NCJ9.IiI.p9Otttjs3JOxZCeuIKwkql3YM-nfdxo__EVt84sex_PcokYjY47sa0qsvCqUUhpUoLSBihdchynuYqc5lOFuAM3Pi2pjg-ZrTqrzI23UlzFonlr4Zag9Qo3IYD10HKFq diff --git a/crates/keystore/tests/snapshots/keystore__jwt_PS256.snap b/crates/keystore/tests/snapshots/keystore__jwt_PS256.snap new file mode 100644 index 000000000..1d7c18db3 --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_PS256.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJQUzI1NiJ9.IiI.HlJaOfS2PMi4mWzE8-0EgXt06-MeqzaLRy_04gs4HTS7FugbSJ0rJiwUwhss6O1KWT9TvDqo6AQBO_2hV1DKDiBIIh5Z6M92uC4MJNVLbAVQo6dSBt2DfSzioBI5MoDOBvgbIwSZAIFMqKTbYDa9rQ3XRAaClpqrIN-ACa3gz99ds5mYvUyiYsL5uuEBuWrp8DRk6WKjduhpOi4sMvylZbnfop1uHbvg6_dk5lzXt-1MKIW1QJW_63cFn7vdap5T9U4DBsEkCzYtuwgU-UCmsC8W07QEfcrJhHIlYoPQPHePKF0A4dVHKrgRmf1ik2p6e-VNw129JMvx0KO6v_JBww diff --git a/crates/keystore/tests/snapshots/keystore__jwt_PS384.snap b/crates/keystore/tests/snapshots/keystore__jwt_PS384.snap new file mode 100644 index 000000000..058db0ed5 --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_PS384.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJQUzM4NCJ9.IiI.AHBo1kZW72IQfs7NvjfrD_WpDa9avLdKyf_rqcCp0mJtGID60cgOG5RDTmI6K7TwzykW6l6LjEuYXDR8hemri6mQrtpQ6rMVTJwqJ6D8M92vH4b2gDBwSwbKz427bGdd_fnqm5K2ntwZGC7pceYg1zbcUQ6NJXs3vqKI6YSKustmm9yA1iMfugFG4eLAPrpfTtLmT1sSWYTYWHVT-6G5q7Bfk7Yu5aHiGDQTo427-Y9YF2fabIuDyCGG48UrBp0ajlm1MHKCBuOvK6NI5Jojd9IWDIf7tvAArsrKVR8QRvDXqqPInJEEZ5x7H1YEEZ5Qrh4XKVhRh9b3O-grDMxMng diff --git a/crates/keystore/tests/snapshots/keystore__jwt_PS512.snap b/crates/keystore/tests/snapshots/keystore__jwt_PS512.snap new file mode 100644 index 000000000..1736ec046 --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_PS512.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJQUzUxMiJ9.IiI.o_-UDhc26qYAstuaFJQUz8OKw3UeMc4N7b3U4qcLM-84dxRdw-wBw1rf94jX71vsrFQ2bEh6J5fc4_VtYgKBb2P6QvoL55c7Gqr-5JBw8BkoiiCzlvKIsi_j41FH5Gb4ZBE5Nf9vZD7DnD9BhYXadxaiksx20oNRKIKQ3oMiJxH1w0c-miCSoIR0jnS1QLlKoHYVb7wnkCiR2SOYQ42Je8B8REVzWm2GrqS2cRWnpi3nHihrapruL_BA161Ip1uH4lUFdZLXeG-R6pAlg1OJ_QXSZlP16nzT6MAW_-IFXfioR1QKT8AFNBodY8zlQCGglMyppZi5Y9i7YaMxFgnM4A diff --git a/crates/keystore/tests/snapshots/keystore__jwt_RS256.snap b/crates/keystore/tests/snapshots/keystore__jwt_RS256.snap new file mode 100644 index 000000000..43d4230ea --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_RS256.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJSUzI1NiJ9.IiI.H_iz_ry505dPMNxQIi4raU88i3wu7DS0Rre6Qm_LJz0Ee_gd5C_t92fBcrFkber1XL_p8AvlXx4DT2Zr_PMBL_2IblJ7t0Od5wnGC__twarj0v1t6KfUkLXcJ3Jy-StnHNbFTmdFnLuGGWIO7xG9h6xgKIvTroVoLJekMzYCc0wSFiyCfaow4yuKesQHUO-N9VDDPoYhkCPqbhVI_d0y6u7KmQy97FbCdCIxvPGHWrwxWcmYbTh4K9xhGDspDUUEubjYTg3t-oaMc2TJqWvu2FE8jyD02A8OCgca6bCU3NmV_Qr6LSUpFNsL4c-0sIp3-L9ndEWzGnN-ZeeGKur-FQ diff --git a/crates/keystore/tests/snapshots/keystore__jwt_RS384.snap b/crates/keystore/tests/snapshots/keystore__jwt_RS384.snap new file mode 100644 index 000000000..1ba885663 --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_RS384.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJSUzM4NCJ9.IiI.bxKYTQQ4RlxOUvxbU_kuwJKGXXiuIPeRgO78a_3zHjvxIzDNKDvQK3w4DUVTlibR-iTVOASRSycWifBJZx_tsU7-BSqrBcjMtgP7mW-HwZ6pANO071iPkkiQU7gqMzbc2tz4uqGI0Z0izkX0_9dOOFSb7jKIUMzzW1O14fBPhZ4kPqkj07A9S9LW9lauQUTXrFgyEaT6G372cyNxi3-T55u9lkjjiiVN4TAhkaXUSN79IE2rNstU8DtKKs725WNUFy30f1-Ftc-J2uGEOsMZ9CQvEVPwOKbvFY2Uh1S8-FT4ahhwj1fxrmUwDH2lSmz6Rj5zf9-FF-IzivSVq4Z4ig diff --git a/crates/keystore/tests/snapshots/keystore__jwt_RS512.snap b/crates/keystore/tests/snapshots/keystore__jwt_RS512.snap new file mode 100644 index 000000000..7312fefc3 --- /dev/null +++ b/crates/keystore/tests/snapshots/keystore__jwt_RS512.snap @@ -0,0 +1,5 @@ +--- +source: crates/keystore/tests/keystore.rs +expression: token.as_str() +--- +eyJhbGciOiJSUzUxMiJ9.IiI.nFsZ3X8GCgpPEojuEktc9a4C-YGQYx8XpbzhOkgnMVrw_wpqIQgWI--4r6BYV6TYAH8NBdQ8Dkdw6POh1Ni-vAtE2rAzjU19ySth5mfP7WEJXRxA1oEV3-dOqCgUI2JJEM13DuLlWFsUaOCbc1_kCkiziTcLtNap__EPGp5koRy-ZyVa1p_mQSQ4NlhJ3hZfHMGnQ0k3RWnpBn3AqERWllQllLniWGQ4l7rZStsD8PRr-rg7P7W7CRIyjrDqy_3bNJyKQCzs_oUrxO-Z7CU6-KfAeyM2U80TQvhZb-Z8_1dJ8e9WsfudQMLtHgO4tlD678Ywezjvr5ackZdn4QEEEA