jwtk 0.5.0

JWT signing (JWS) and verification, with first class JWK and JWK Set (JWKS) support.
Documentation
//! Enum of EC / RSA / Ed keys.

#[cfg(feature = "openssl")]
use crate::ecdsa::{EcdsaPrivateKey, EcdsaPublicKey};
#[cfg(feature = "openssl")]
use crate::eddsa::{Ed25519PrivateKey, Ed25519PublicKey};
#[cfg(feature = "openssl")]
use crate::rsa::RsaPrivateKey;
#[cfg(any(feature = "openssl", feature = "aws-lc"))]
use crate::rsa::RsaPublicKey;

#[cfg(feature = "openssl")]
use crate::Error;
use crate::{jwk::Jwk, PrivateKeyToJwk, PublicKeyToJwk, Result, SigningKey, VerificationKey};

/// An RSA, EC or Ed25519 private key.
///
/// Use this if you just want to load SOME private key from an external pem
/// file.
#[non_exhaustive]
#[derive(Debug)]
pub enum SomePrivateKey {
    #[cfg(feature = "openssl")]
    Ed25519(Ed25519PrivateKey),
    #[cfg(feature = "openssl")]
    Ecdsa(EcdsaPrivateKey),
    #[cfg(feature = "openssl")]
    Rsa(RsaPrivateKey),
}

/// An RSA, EC or Ed25519 public key.
///
/// Use this if you just want to load SOME public key from an external pem file
/// or JWK.
#[non_exhaustive]
#[derive(Debug)]
pub enum SomePublicKey {
    #[cfg(feature = "openssl")]
    Ed25519(Ed25519PublicKey),
    #[cfg(feature = "openssl")]
    Ecdsa(EcdsaPublicKey),
    #[cfg(any(feature = "openssl", feature = "aws-lc"))]
    Rsa(RsaPublicKey),
}

#[cfg(feature = "openssl")]
impl From<Ed25519PrivateKey> for SomePrivateKey {
    #[inline]
    fn from(k: Ed25519PrivateKey) -> SomePrivateKey {
        SomePrivateKey::Ed25519(k)
    }
}

#[cfg(feature = "openssl")]
impl From<EcdsaPrivateKey> for SomePrivateKey {
    #[inline]
    fn from(k: EcdsaPrivateKey) -> SomePrivateKey {
        SomePrivateKey::Ecdsa(k)
    }
}

#[cfg(feature = "openssl")]
impl From<RsaPrivateKey> for SomePrivateKey {
    #[inline]
    fn from(k: RsaPrivateKey) -> SomePrivateKey {
        SomePrivateKey::Rsa(k)
    }
}

#[cfg(feature = "openssl")]
impl From<Ed25519PublicKey> for SomePublicKey {
    #[inline]
    fn from(k: Ed25519PublicKey) -> SomePublicKey {
        SomePublicKey::Ed25519(k)
    }
}

#[cfg(feature = "openssl")]
impl From<EcdsaPublicKey> for SomePublicKey {
    #[inline]
    fn from(k: EcdsaPublicKey) -> SomePublicKey {
        SomePublicKey::Ecdsa(k)
    }
}

#[cfg(any(feature = "openssl", feature = "aws-lc"))]
impl From<RsaPublicKey> for SomePublicKey {
    #[inline]
    fn from(k: RsaPublicKey) -> SomePublicKey {
        SomePublicKey::Rsa(k)
    }
}

#[cfg(feature = "openssl")]
impl SomePrivateKey {
    /// Read an RSA/EC/Ed25519 private key from PEM.
    ///
    /// For an EC/Ed25519 private key, algorithm is deduced from the curve, e.g.
    /// P-256 -> ES256.
    ///
    /// For an RSA private key, `if_rsa_algorithm` is used.
    pub fn from_pem(pem: &[u8], if_rsa_algorithm: crate::rsa::RsaAlgorithm) -> Result<Self> {
        use openssl::pkey::{Id, PKey};

        let pk = PKey::private_key_from_pem(pem)?;

        match pk.id() {
            Id::RSA => Ok(Self::Rsa(RsaPrivateKey::from_pkey(pk, if_rsa_algorithm)?)),
            Id::EC => {
                let k = EcdsaPrivateKey::from_pkey(pk)?;
                Ok(Self::Ecdsa(k))
            }
            Id::ED25519 => {
                let k = Ed25519PrivateKey::from_pkey(pk)?;
                Ok(Self::Ed25519(k))
            }
            _ => Err(Error::UnsupportedOrInvalidKey),
        }
    }

    pub fn private_key_to_pem_pkcs8(&self) -> Result<String> {
        match self {
            SomePrivateKey::Ed25519(ed) => ed.private_key_to_pem_pkcs8(),
            SomePrivateKey::Ecdsa(ec) => ec.private_key_to_pem_pkcs8(),
            SomePrivateKey::Rsa(rsa) => rsa.private_key_to_pem_pkcs8(),
        }
    }

    pub fn public_key_to_pem(&self) -> Result<String> {
        match self {
            SomePrivateKey::Ed25519(ed) => ed.public_key_to_pem(),
            SomePrivateKey::Ecdsa(ec) => ec.public_key_to_pem(),
            SomePrivateKey::Rsa(rsa) => rsa.public_key_to_pem(),
        }
    }
}

#[cfg(feature = "openssl")]
impl SomePublicKey {
    /// Read an RSA/EC/Ed25519 public key from PEM.
    ///
    /// For an EC/Ed25519 public key, algorithm is deduced from the curve, e.g.
    /// P-256 -> ES256.
    ///
    /// For an RSA public key, signatures generated by any RSA algorithms can be
    /// verified.
    pub fn from_pem(pem: &[u8]) -> Result<Self> {
        use openssl::pkey::{Id, PKey};

        let pk = PKey::public_key_from_pem(pem)?;
        match pk.id() {
            Id::RSA => Ok(Self::Rsa(RsaPublicKey::from_pkey(pk, None)?)),
            Id::EC => {
                let k = EcdsaPublicKey::from_pkey(pk)?;
                Ok(Self::Ecdsa(k))
            }
            Id::ED25519 => {
                let k = Ed25519PublicKey::from_pkey(pk)?;
                Ok(Self::Ed25519(k))
            }
            _ => Err(Error::UnsupportedOrInvalidKey),
        }
    }

    pub fn to_pem(&self) -> Result<String> {
        match self {
            SomePublicKey::Ed25519(ed) => ed.to_pem(),
            SomePublicKey::Ecdsa(ec) => ec.to_pem(),
            SomePublicKey::Rsa(rsa) => rsa.to_pem(),
        }
    }
}

impl PublicKeyToJwk for SomePrivateKey {
    fn public_key_to_jwk(&self) -> Result<Jwk> {
        match self {
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ed25519(ed) => ed.public_key_to_jwk(),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ecdsa(ec) => ec.public_key_to_jwk(),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Rsa(rsa) => rsa.public_key_to_jwk(),
            #[cfg(not(feature = "openssl"))]
            _ => unreachable!(),
        }
    }
}

impl PrivateKeyToJwk for SomePrivateKey {
    fn private_key_to_jwk(&self) -> Result<Jwk> {
        match self {
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ed25519(ed) => ed.private_key_to_jwk(),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ecdsa(ec) => ec.private_key_to_jwk(),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Rsa(rsa) => rsa.private_key_to_jwk(),
            #[cfg(not(feature = "openssl"))]
            _ => unreachable!(),
        }
    }
}

impl SigningKey for SomePrivateKey {
    fn alg(&self) -> &'static str {
        match self {
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ed25519(ed) => ed.alg(),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ecdsa(ec) => ec.alg(),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Rsa(rsa) => rsa.alg(),
            #[cfg(not(feature = "openssl"))]
            _ => unreachable!(),
        }
    }

    fn sign(&self, _v: &[u8]) -> crate::Result<smallvec::SmallVec<[u8; 64]>> {
        match self {
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ed25519(ed) => ed.sign(_v),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ecdsa(ec) => ec.sign(_v),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Rsa(rsa) => rsa.sign(_v),
            #[cfg(not(feature = "openssl"))]
            _ => unreachable!(),
        }
    }
}

impl VerificationKey for SomePrivateKey {
    fn verify(&self, _v: &[u8], _sig: &[u8], _alg: &str) -> crate::Result<()> {
        match self {
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ed25519(ed) => ed.verify(_v, _sig, _alg),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Ecdsa(ec) => ec.verify(_v, _sig, _alg),
            #[cfg(feature = "openssl")]
            SomePrivateKey::Rsa(rsa) => rsa.verify(_v, _sig, _alg),
            #[cfg(not(feature = "openssl"))]
            _ => unreachable!(),
        }
    }
}

impl VerificationKey for SomePublicKey {
    fn verify(&self, _v: &[u8], _sig: &[u8], _alg: &str) -> crate::Result<()> {
        match self {
            #[cfg(feature = "openssl")]
            SomePublicKey::Ed25519(ed) => ed.verify(_v, _sig, _alg),
            #[cfg(feature = "openssl")]
            SomePublicKey::Ecdsa(ec) => ec.verify(_v, _sig, _alg),
            #[cfg(any(feature = "openssl", feature = "aws-lc"))]
            SomePublicKey::Rsa(rsa) => rsa.verify(_v, _sig, _alg),
            #[cfg(not(any(feature = "openssl", feature = "aws-lc")))]
            _ => unreachable!(),
        }
    }
}

impl PublicKeyToJwk for SomePublicKey {
    fn public_key_to_jwk(&self) -> Result<Jwk> {
        match self {
            #[cfg(feature = "openssl")]
            SomePublicKey::Ed25519(ed) => ed.public_key_to_jwk(),
            #[cfg(feature = "openssl")]
            SomePublicKey::Ecdsa(ec) => ec.public_key_to_jwk(),
            #[cfg(any(feature = "openssl", feature = "aws-lc"))]
            SomePublicKey::Rsa(rsa) => rsa.public_key_to_jwk(),
            #[cfg(not(any(feature = "openssl", feature = "aws-lc")))]
            _ => unreachable!(),
        }
    }
}