From d550c5f3188e726dcd212565fe4ed96db68b11c9 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Fri, 15 Nov 2019 20:16:38 +0100 Subject: [PATCH] Add more tests and document SEC1 lack of support --- README.md | 8 ++++++++ src/pem/decoder.rs | 2 ++ tests/ecdsa/mod.rs | 23 +++++++++++++++++++---- tests/ecdsa/private_jwtio.pem | 6 ++++++ tests/ecdsa/private_jwtio_pkcs8.pem | 6 ++++++ tests/ecdsa/public_jwtio.pem | 5 +++++ tests/rsa/mod.rs | 19 +++++++++++++++++++ tests/rsa/private_jwtio.pem | 27 +++++++++++++++++++++++++++ tests/rsa/public_jwtio.pem | 9 +++++++++ 9 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 tests/ecdsa/private_jwtio.pem create mode 100644 tests/ecdsa/private_jwtio_pkcs8.pem create mode 100644 tests/ecdsa/public_jwtio.pem create mode 100644 tests/rsa/private_jwtio.pem create mode 100644 tests/rsa/public_jwtio.pem diff --git a/README.md b/README.md index cd78b9d..a1cbce6 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,14 @@ You can use openssl for that: openssl rsa -inform DER -outform PEM -in mykey.der -out mykey.pem ``` +### Convert SEC1 private key to PKCS8 +`jsonwebtoken` currently only supports PKCS8 format for private EC keys. If your key has `BEGIN EC PRIVATE KEY` at the top, +this is a SEC1 type and can be converted to PKCS8 like so: + +```bash +openssl pkcs8 -topk8 -nocrypt -in sec1.pem -out pkcs8.pem +``` + ## Validation This library validates automatically the `exp` claim and `nbf` is validated if present. You can also validate the `sub`, `iss` and `aud` but diff --git a/src/pem/decoder.rs b/src/pem/decoder.rs index db41156..ded5ac5 100644 --- a/src/pem/decoder.rs +++ b/src/pem/decoder.rs @@ -13,7 +13,9 @@ enum PemType { #[derive(Debug, PartialEq)] enum Standard { + // Only for RSA Pkcs1, + // RSA/EC Pkcs8, } diff --git a/tests/ecdsa/mod.rs b/tests/ecdsa/mod.rs index b9754c1..d90242e 100644 --- a/tests/ecdsa/mod.rs +++ b/tests/ecdsa/mod.rs @@ -25,23 +25,38 @@ pub struct Claims { #[test] fn round_trip_sign_verification_pem() { let privkey = include_bytes!("private_ecdsa_key.pem"); - let encrypted = sign("hello world", privkey, Algorithm::ES256).unwrap(); let pubkey = include_bytes!("public_ecdsa_key.pem"); + let encrypted = sign("hello world", privkey, Algorithm::ES256).unwrap(); let is_valid = verify(&encrypted, "hello world", pubkey, Algorithm::ES256).unwrap(); assert!(is_valid); } #[test] fn round_trip_claim() { + let privkey = include_bytes!("private_ecdsa_key.pem"); + let pubkey = include_bytes!("public_ecdsa_key.pem"); let my_claims = Claims { sub: "b@b.com".to_string(), company: "ACME".to_string(), exp: Utc::now().timestamp() + 10000, }; - let privkey = include_bytes!("private_ecdsa_key.pem"); let token = encode(&Header::new(Algorithm::ES256), &my_claims, privkey).unwrap(); - let pubkey = include_bytes!("public_ecdsa_key.pem"); let token_data = decode::(&token, pubkey, &Validation::new(Algorithm::ES256)).unwrap(); assert_eq!(my_claims, token_data.claims); - assert!(token_data.header.kid.is_none()); +} + +// https://jwt.io/ is often used for examples so ensure their example works with jsonwebtoken +#[test] +fn roundtrip_with_jwtio_example() { + // We currently do not support SEC1 so we use the converted PKCS8 formatted + let privkey = include_bytes!("private_jwtio_pkcs8.pem"); + let pubkey = include_bytes!("public_jwtio.pem"); + let my_claims = Claims { + sub: "b@b.com".to_string(), + company: "ACME".to_string(), + exp: Utc::now().timestamp() + 10000, + }; + let token = encode(&Header::new(Algorithm::ES384), &my_claims, privkey).unwrap(); + let token_data = decode::(&token, pubkey, &Validation::new(Algorithm::ES384)).unwrap(); + assert_eq!(my_claims, token_data.claims); } diff --git a/tests/ecdsa/private_jwtio.pem b/tests/ecdsa/private_jwtio.pem new file mode 100644 index 0000000..6e8b0cc --- /dev/null +++ b/tests/ecdsa/private_jwtio.pem @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDCAHpFQ62QnGCEvYh/pE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhske +enT+rAyyPhGgBwYFK4EEACKhZANiAAQLW5ZJePZzMIPAxMtZXkEWbDF0zo9f2n4+ +T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw8lE5IPUWpgu553SteKigiKLU +PeNpbqmYZUkWGh3MLfVzLmx85ii2vMU= +-----END EC PRIVATE KEY----- diff --git a/tests/ecdsa/private_jwtio_pkcs8.pem b/tests/ecdsa/private_jwtio_pkcs8.pem new file mode 100644 index 0000000..893d58e --- /dev/null +++ b/tests/ecdsa/private_jwtio_pkcs8.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCAHpFQ62QnGCEvYh/p +E9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGhZANiAAQLW5ZJePZz +MIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw +8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU= +-----END PRIVATE KEY----- diff --git a/tests/ecdsa/public_jwtio.pem b/tests/ecdsa/public_jwtio.pem new file mode 100644 index 0000000..81eac4e --- /dev/null +++ b/tests/ecdsa/public_jwtio.pem @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+ +Pk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii +1D3jaW6pmGVJFhodzC31cy5sfOYotrzF +-----END PUBLIC KEY----- diff --git a/tests/rsa/mod.rs b/tests/rsa/mod.rs index f93ed96..9b3301e 100644 --- a/tests/rsa/mod.rs +++ b/tests/rsa/mod.rs @@ -89,3 +89,22 @@ fn fails_with_non_pkcs8_key_format() { let _encrypted = sign("hello world", include_bytes!("private_rsa_key_pkcs1.pem"), Algorithm::ES256).unwrap(); } + +// https://jwt.io/ is often used for examples so ensure their example works with jsonwebtoken +#[test] +fn roundtrip_with_jwtio_example_jey() { + let privkey_pem = include_bytes!("private_jwtio.pem"); + let pubkey_pem = include_bytes!("public_jwtio.pem"); + + let my_claims = Claims { + sub: "b@b.com".to_string(), + company: "ACME".to_string(), + exp: Utc::now().timestamp() + 10000, + }; + + for &alg in RSA_ALGORITHMS { + let token = encode(&Header::new(alg), &my_claims, privkey_pem).unwrap(); + let token_data = decode::(&token, pubkey_pem, &Validation::new(alg)).unwrap(); + assert_eq!(my_claims, token_data.claims); + } +} diff --git a/tests/rsa/private_jwtio.pem b/tests/rsa/private_jwtio.pem new file mode 100644 index 0000000..61056a5 --- /dev/null +++ b/tests/rsa/private_jwtio.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWw +kWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mr +m/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEi +NQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV +3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2 +QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjs +kFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0go +amMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM ++bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9 +D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC +0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5Y +lSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+ +hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNp +bU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X ++jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9B +BwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC +2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjx +QYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz +5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9 +Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0 +NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j +8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma +3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5K +y18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrB +jg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE= +-----END RSA PRIVATE KEY----- diff --git a/tests/rsa/public_jwtio.pem b/tests/rsa/public_jwtio.pem new file mode 100644 index 0000000..12301e0 --- /dev/null +++ b/tests/rsa/public_jwtio.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv +vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc +aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy +tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0 +e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb +V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9 +MwIDAQAB +-----END PUBLIC KEY-----