jwtk 0.5.0

JWT signing (JWS) and verification, with first class JWK and JWK Set (JWKS) support.
Documentation
use crate::{
    jwk::Jwk, Error, PrivateKeyToJwk, PublicKeyToJwk, Result, SigningKey, VerificationKey,
    URL_SAFE_TRAILING_BITS,
};
use base64::Engine as _;
use foreign_types::ForeignType;
use openssl::{
    error::ErrorStack,
    pkey::{PKey, Private, Public},
    sign::{Signer, Verifier},
};
use smallvec::SmallVec;
use std::ptr;

#[derive(Debug, Clone)]
pub struct Ed25519PrivateKey {
    private_key: PKey<Private>,
}

impl Ed25519PrivateKey {
    pub fn generate() -> Result<Self> {
        let pkey = PKey::generate_ed25519()?;
        Ok(Self { private_key: pkey })
    }

    pub fn from_bytes(b: &[u8]) -> Result<Self> {
        let pkey = unsafe {
            openssl_sys::EVP_PKEY_new_raw_private_key(
                openssl_sys::EVP_PKEY_ED25519,
                ptr::null_mut(),
                b.as_ptr(),
                b.len(),
            )
        };
        if pkey.is_null() {
            return Err(ErrorStack::get().into());
        }
        Ok(Self {
            private_key: unsafe { PKey::from_ptr(pkey) },
        })
    }

    pub(crate) fn from_pkey(pk: PKey<Private>) -> Result<Self> {
        if pk.id() != openssl::pkey::Id::ED25519 {
            return Err(Error::UnsupportedOrInvalidKey);
        }
        Ok(Self { private_key: pk })
    }

    pub fn from_pem(pem: &[u8]) -> Result<Self> {
        let pk = PKey::private_key_from_pem(pem)?;
        Self::from_pkey(pk)
    }

    pub fn private_key_bytes(&self) -> Result<[u8; 32]> {
        let mut out = [0u8; 32];
        let r = unsafe {
            openssl_sys::EVP_PKEY_get_raw_private_key(
                self.private_key.as_ptr(),
                out.as_mut_ptr(),
                &mut out.len(),
            )
        };
        if r == 0 {
            return Err(ErrorStack::get().into());
        }
        Ok(out)
    }

    pub fn public_key_bytes(&self) -> Result<[u8; 32]> {
        let mut out = [0u8; 32];
        let r = unsafe {
            openssl_sys::EVP_PKEY_get_raw_public_key(
                self.private_key.as_ptr(),
                out.as_mut_ptr(),
                &mut out.len(),
            )
        };
        if r == 0 {
            return Err(ErrorStack::get().into());
        }
        Ok(out)
    }

    pub fn private_key_to_pem_pkcs8(&self) -> Result<String> {
        Ok(String::from_utf8(
            self.private_key.private_key_to_pem_pkcs8()?,
        )?)
    }

    pub fn public_key_to_pem(&self) -> Result<String> {
        Ok(String::from_utf8(self.private_key.public_key_to_pem()?)?)
    }
}

impl PublicKeyToJwk for Ed25519PrivateKey {
    fn public_key_to_jwk(&self) -> Result<Jwk> {
        let bytes: [u8; 32] = self.public_key_bytes()?;
        Ok(Jwk {
            kty: "OKP".into(),
            crv: Some("Ed25519".into()),
            x: Some(URL_SAFE_TRAILING_BITS.encode(bytes)),
            ..Jwk::default()
        })
    }
}

impl PrivateKeyToJwk for Ed25519PrivateKey {
    fn private_key_to_jwk(&self) -> Result<Jwk> {
        let d = self.private_key_bytes()?;
        let x: [u8; 32] = self.public_key_bytes()?;
        Ok(Jwk {
            kty: "OKP".into(),
            crv: Some("Ed25519".into()),
            d: Some(URL_SAFE_TRAILING_BITS.encode(d)),
            x: Some(URL_SAFE_TRAILING_BITS.encode(x)),
            ..Jwk::default()
        })
    }
}

#[derive(Debug)]
pub struct Ed25519PublicKey {
    public_key: PKey<Public>,
}

impl Ed25519PublicKey {
    pub(crate) fn from_pkey(pkey: PKey<Public>) -> Result<Self> {
        if pkey.id() != openssl::pkey::Id::ED25519 {
            return Err(Error::UnsupportedOrInvalidKey);
        }
        Ok(Self { public_key: pkey })
    }

    pub fn from_pem(pem: &[u8]) -> Result<Self> {
        let pk = PKey::public_key_from_pem(pem)?;
        Self::from_pkey(pk)
    }

    pub fn from_bytes(b: &[u8]) -> Result<Self> {
        let pkey = unsafe {
            openssl_sys::EVP_PKEY_new_raw_public_key(
                openssl_sys::EVP_PKEY_ED25519,
                ptr::null_mut(),
                b.as_ptr(),
                b.len(),
            )
        };
        if pkey.is_null() {
            return Err(ErrorStack::get().into());
        }
        Ok(Self {
            public_key: unsafe { PKey::from_ptr(pkey) },
        })
    }

    pub fn to_pem(&self) -> Result<String> {
        Ok(String::from_utf8(self.public_key.public_key_to_pem()?)?)
    }

    pub fn to_bytes(&self) -> Result<[u8; 32]> {
        let mut out = [0u8; 32];
        let r = unsafe {
            openssl_sys::EVP_PKEY_get_raw_public_key(
                self.public_key.as_ptr(),
                out.as_mut_ptr(),
                &mut out.len(),
            )
        };
        if r == 0 {
            return Err(ErrorStack::get().into());
        }
        Ok(out)
    }
}

impl PublicKeyToJwk for Ed25519PublicKey {
    fn public_key_to_jwk(&self) -> Result<Jwk> {
        let bytes: [u8; 32] = self.to_bytes()?;
        Ok(Jwk {
            kty: "OKP".into(),
            crv: Some("Ed25519".into()),
            x: Some(URL_SAFE_TRAILING_BITS.encode(bytes)),
            ..Jwk::default()
        })
    }
}

impl SigningKey for Ed25519PrivateKey {
    fn sign(&self, v: &[u8]) -> Result<SmallVec<[u8; 64]>> {
        let mut signer = Signer::new_without_digest(self.private_key.as_ref())?;

        let mut out = [0u8; 64];

        signer.sign_oneshot(&mut out, v)?;

        Ok(out.into())
    }

    fn alg(&self) -> &'static str {
        "EdDSA"
    }
}

impl VerificationKey for Ed25519PrivateKey {
    fn verify(&self, v: &[u8], sig: &[u8], alg: &str) -> Result<()> {
        if alg != "EdDSA" {
            return Err(Error::VerificationError);
        }

        let mut verifier = Verifier::new_without_digest(self.private_key.as_ref())?;
        if verifier.verify_oneshot(sig, v)? {
            Ok(())
        } else {
            Err(Error::VerificationError)
        }
    }
}

impl VerificationKey for Ed25519PublicKey {
    fn verify(&self, v: &[u8], sig: &[u8], alg: &str) -> Result<()> {
        if alg != "EdDSA" {
            return Err(Error::VerificationError);
        }

        let mut verifier = Verifier::new_without_digest(self.public_key.as_ref())?;
        if verifier.verify_oneshot(sig, v)? {
            Ok(())
        } else {
            Err(Error::VerificationError)
        }
    }
}

#[cfg(test)]
mod tests {
    use openssl::{
        ec::{EcGroup, EcKey},
        nid::Nid,
    };

    use crate::{rsa::RsaAlgorithm, SomePrivateKey};

    use super::*;

    #[test]
    fn conversion() -> Result<()> {
        let k = Ed25519PrivateKey::generate()?;

        {
            let bytes = k.private_key_bytes()?;
            let k1 = Ed25519PrivateKey::from_bytes(&bytes)?;
            let bytes1 = k1.private_key_bytes()?;
            assert_eq!(bytes, bytes1);
        }

        let pem = k.private_key_to_pem_pkcs8()?;
        Ed25519PrivateKey::from_pem(pem.as_bytes())?;

        let secp256k1_k = EcKey::generate(EcGroup::from_curve_name(Nid::SECP256K1)?.as_ref())?;
        let secp256k1_k_pem = secp256k1_k.private_key_to_pem()?;
        let secp256k1_k_pub_pem = secp256k1_k.public_key_to_pem()?;
        assert!(Ed25519PrivateKey::from_pem(&secp256k1_k_pem).is_err());
        assert!(Ed25519PublicKey::from_pem(&secp256k1_k_pub_pem).is_err());

        let pk_pem = k.public_key_to_pem()?;

        let pk = Ed25519PublicKey::from_pem(pk_pem.as_bytes())?;

        println!("k: {:?}, pk: {:?}", k, pk);

        let pk_pem1 = pk.to_pem()?;

        assert_eq!(pk_pem, pk_pem1);

        if let SomePrivateKey::Ed25519(k1) = k
            .private_key_to_jwk()?
            .to_signing_key(RsaAlgorithm::PS256)?
        {
            assert!(k.private_key.public_eq(k1.private_key.as_ref()));
        } else {
            panic!("expected ed25519 private key");
        }

        k.public_key_to_jwk()?.to_verification_key()?;
        pk.public_key_to_jwk()?.to_verification_key()?;

        Ok(())
    }

    #[test]
    fn sign_verify() -> Result<()> {
        let k = Ed25519PrivateKey::generate()?;
        let pk = Ed25519PublicKey::from_pem(k.public_key_to_pem()?.as_bytes())?;
        let sig = k.sign(b"...")?;
        assert!(k.verify(b"...", &sig, "EdDSA").is_ok());
        assert!(pk.verify(b"...", &sig, "EdDSA").is_ok());
        assert!(pk.verify(b"....", &sig, "EdDSA").is_err());
        assert!(pk.verify(b"...", &sig, "WRONG ALG").is_err());
        assert!(pk.verify(b"...", &sig[..63], "EdDSA").is_err());
        Ok(())
    }
}