Description
I'm generating ed25519 keys using ed25519-dalek
and the rand
crates, and while I can sign and verify using public key PEM encoding, verification fails when using public key DER encoding.
Cargo.toml:
# ...
[dependencies]
ed25519-dalek = { version = "2", features = ["pkcs8", "pem", "rand_core"] }
jsonwebtoken = "9"
rand = "0.8"
Here is a test case which generates a keypair, converts it into jsonwebtoken
types, and successfully signs and verifies a signature:
tests/test_alpha.rs:
use ed25519::pkcs8::{EncodePrivateKey, EncodePublicKey};
use ed25519::pkcs8::spki::der::pem::LineEnding;
use ed25519_dalek::SigningKey as Ed25519SigningKey;
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey};
/// Tests that we can generate an ed25519 keypair via [ed25519_dalek], import it into
/// [jsonwebtoken], generate a signature, and verify that signature.
#[test]
fn test_ed25519_roundtrip() {
use jsonwebtoken::crypto::{sign, verify};
// first, generate an ed25519 private key using the thread rng
let dalek_private = Ed25519SigningKey::generate(&mut rand::thread_rng());
let dalek_public = dalek_private.verifying_key();
// next, in order for it to work with jsonwebtoken, we convert it into pkcs8
let (public_pem, private_der) = (
// FIXME this line succeeds when using pem, fails when using der
dalek_public.to_public_key_pem(LineEnding::LF).expect("unable to convert public to der"),
dalek_private.to_pkcs8_der().expect("unable to convert private to der")
);
// create the jsonwebtoken key structure
let (encoding_key, decoding_key) = (
EncodingKey::from_ed_der(private_der.as_bytes()),
// FIXME this line succeeds when using pem, fails when using der
DecodingKey::from_ed_pem(public_pem.as_bytes()).expect("unable to parse public pem"),
);
// create a signature
let message = "Hello World";
let signature = sign(message.as_bytes(), &encoding_key, Algorithm::EdDSA).unwrap();
let valid = verify(signature.as_str(), message.as_bytes(), &decoding_key, Algorithm::EdDSA)
.unwrap();
assert!(valid, "failed to verify signature");
}
The above code does pass the test, but note that I'm converting my public ed25519 key to PEM format, and creating a DecodingKey
using DecodingKey::from_ed_pem
:
let (public_pem, private_der) = (
// FIXME this line succeeds when using pem, fails when using der
dalek_public.to_public_key_pem(LineEnding::LF).expect("unable to convert public to der"),
dalek_private.to_pkcs8_der().expect("unable to convert private to der")
);
let (encoding_key, decoding_key) = (
EncodingKey::from_ed_der(private_der.as_bytes()),
DecodingKey::from_ed_pem(public_pem.as_bytes()).expect("unable to parse public pem"),
);
My private key converts just fine when using DER encoding, but the public key seems to be the problem. If I change the above code to use DER for the public key, the test fails:
let (public_der, private_der) = (
// FIXME this line succeeds when using pem, fails when using der
dalek_public.to_public_key_der().expect("unable to convert public to der"),
dalek_private.to_pkcs8_der().expect("unable to convert private to der")
);
let (encoding_key, decoding_key) = (
EncodingKey::from_ed_der(private_der.as_bytes()),
DecodingKey::from_ed_der(public_der.as_bytes()),
);
Just changing the DecodingKey
from PEM format to DER format causes the verification to fail.
Am I doing something wrong here when trying to work with DER format? Is it possible that the DER format emitted by ed25519-dalek is incompatible with this library, and if so, what can I do to determine where the incompatibility is coming from?