dat 2.2.0

DAT - Distributed Access Token
Documentation
use crate::signature_algorithm::DatSignatureAlgorithm;
use crate::error::DatError;
use aws_lc_rs::signature::{EcdsaKeyPair, KeyPair, UnparsedPublicKey, ECDSA_P256_SHA256_FIXED, ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED, ECDSA_P384_SHA384_FIXED_SIGNING, ECDSA_P521_SHA512_FIXED, ECDSA_P521_SHA512_FIXED_SIGNING};
use strum_macros::{Display, EnumString};

#[repr(u8)]
#[derive(Debug, Display, EnumString, Clone, Copy, Eq, PartialEq)]
pub enum DatSignatureKeyOutOption {
    FULL,
    SIGNING,
    VERIFYING,
}

pub struct DatSignatureKey {
    algorithm: DatSignatureAlgorithm,
    signing_key: Option<EcdsaKeyPair>,
    signing_key_bytes: Vec<u8>,
    verifying_key: UnparsedPublicKey<Vec<u8>>,
}

impl DatSignatureKey {
    pub fn generate(algorithm: DatSignatureAlgorithm) -> Result<Self, DatError> {
        Self::from_or_new(true, algorithm, &[], &[])
    }

    pub fn from_bytes(algorithm: DatSignatureAlgorithm, signing_key_bytes: &[u8], verifying_key_bytes: &[u8]) -> Result<DatSignatureKey, DatError> {
        Self::from_or_new(false, algorithm, signing_key_bytes, verifying_key_bytes)
    }
    fn from_or_new(new: bool, algorithm: DatSignatureAlgorithm, signing_key_bytes: &[u8], verifying_key_bytes: &[u8]) -> Result<DatSignatureKey, DatError> {
        let (sa, va) = match algorithm {
            DatSignatureAlgorithm::P256 => &(ECDSA_P256_SHA256_FIXED_SIGNING, ECDSA_P256_SHA256_FIXED),
            DatSignatureAlgorithm::P384 => &(ECDSA_P384_SHA384_FIXED_SIGNING, ECDSA_P384_SHA384_FIXED),
            DatSignatureAlgorithm::P521 => &(ECDSA_P521_SHA512_FIXED_SIGNING, ECDSA_P521_SHA512_FIXED),
        };
        let rng = aws_lc_rs::rand::SystemRandom::new();

        let mut signing_key_bytes = Vec::from(signing_key_bytes);
        let mut verifying_key_bytes = Vec::from(verifying_key_bytes);
        let pkcs8_private_key = if new {
            let pkcs8_private_key = Vec::from(EcdsaKeyPair::generate_pkcs8(sa, &rng).map_err(|_| DatError::CreateDatSigningKeyError)?.as_ref());
            signing_key_bytes = to_raw(algorithm, &pkcs8_private_key)?;
            pkcs8_private_key
        } else {
            to_pkcs8_der(algorithm, &signing_key_bytes)?
        };

        let signing_key: Option<EcdsaKeyPair> = if pkcs8_private_key.is_empty() {
            None
        } else {
            let sk = EcdsaKeyPair::from_pkcs8(sa, &*pkcs8_private_key)
                .map_err(|_| { DatError::ParseDatSigningKeyError })?;
            if verifying_key_bytes.is_empty() {
                verifying_key_bytes = Vec::from(sk.public_key().as_ref());
            }
            Some(sk)
        };

        if verifying_key_bytes.is_empty() {
            return Err(DatError::ParseDatVerifyingKeyError);
        }

        let verifying_key = UnparsedPublicKey::new(va, verifying_key_bytes);

        Ok(DatSignatureKey {
            algorithm,
            signing_key,
            signing_key_bytes,
            verifying_key,
        })
    }

    pub fn algorithm(&self) -> DatSignatureAlgorithm {
        self.algorithm
    }

    pub fn signature_size(&self) -> usize {
        match self.algorithm {
            DatSignatureAlgorithm::P256 => 64,
            DatSignatureAlgorithm::P384 => 96,
            DatSignatureAlgorithm::P521 => 132,
        }
    }

    pub fn raw_signing_key_size(&self) -> usize {
        match self.algorithm {
            DatSignatureAlgorithm::P256 => 32,
            DatSignatureAlgorithm::P384 => 48,
            DatSignatureAlgorithm::P521 => 66,
        }
    }

    pub fn to_bytes(&self) -> (Box<[u8]>, Box<[u8]>) {
        (Box::from(&*self.signing_key_bytes), Box::from(&*self.verifying_key.as_ref()))
    }

    pub fn sign(&self, data: &[u8]) -> Result<Box<[u8]>, DatError> {
        self.signing_key.as_ref().ok_or_else(|| DatError::VerifyOnlyKey)?
            .sign(&aws_lc_rs::rand::SystemRandom::new(), data)
            .map(|x| Box::from(x.as_ref()))
            .map_err(|_| DatError::DatSignatureError)
    }

    pub fn verify(&self, body: &[u8], sign: &[u8]) -> Result<(), DatError> {
        self.verifying_key.verify(body, sign).map_err(|_| DatError::InvalidDat)
    }

    pub fn has_signing_key(&self) -> bool {
        self.signing_key.is_some()
    }
}

impl Clone for DatSignatureKey {
    fn clone(&self) -> Self {
        let (k, v) = self.to_bytes();
        DatSignatureKey::from_bytes(self.algorithm(), &*k, &*v).unwrap()
    }
}

pub fn to_pkcs8_der(algorithm: DatSignatureAlgorithm, signing_key: &[u8]) -> Result<Vec<u8>, DatError> {
    if signing_key.is_empty() {
        return Ok(Vec::new());
    }

    Ok(match algorithm {
        DatSignatureAlgorithm::P256 => {
            let k = p256::ecdsa::SigningKey::from_slice(signing_key).map_err(|_| DatError::ParseDatSigningKeyError)?;
            p256::pkcs8::EncodePrivateKey::to_pkcs8_der(&k).map_err(|_| DatError::ParseDatSigningKeyError)?.as_bytes().to_vec()
        },
        DatSignatureAlgorithm::P384 => {
            let k = p384::ecdsa::SigningKey::from_slice(signing_key).map_err(|_| DatError::ParseDatSigningKeyError)?;
            p384::pkcs8::EncodePrivateKey::to_pkcs8_der(&k).map_err(|_| DatError::ParseDatSigningKeyError)?.as_bytes().to_vec()
        },
        DatSignatureAlgorithm::P521 => {
            let k = p521::ecdsa::SigningKey::from_slice(signing_key).map_err(|_| DatError::ParseDatSigningKeyError)?;
            p521::pkcs8::EncodePrivateKey::to_pkcs8_der(&k).map_err(|_| DatError::ParseDatSigningKeyError)?.as_bytes().to_vec()
        },
    })
}

pub fn to_raw(algorithm: DatSignatureAlgorithm, pkcs8_der: &[u8]) -> Result<Vec<u8>, DatError> {
    if pkcs8_der.is_empty() {
        return Ok(Vec::new());
    }

    Ok(match algorithm {
        DatSignatureAlgorithm::P256 => {
            let k: p256::ecdsa::SigningKey = p256::pkcs8::DecodePrivateKey::from_pkcs8_der(pkcs8_der).map_err(|_| DatError::ParseDatSigningKeyError)?;
            k.to_bytes().to_vec()
        },
        DatSignatureAlgorithm::P384 => {
            let k: p384::ecdsa::SigningKey = p384::pkcs8::DecodePrivateKey::from_pkcs8_der(pkcs8_der).map_err(|_| DatError::ParseDatSigningKeyError)?;
            k.to_bytes().to_vec()
        },
        DatSignatureAlgorithm::P521 => {
            let k: p521::ecdsa::SigningKey = p521::pkcs8::DecodePrivateKey::from_pkcs8_der(pkcs8_der).map_err(|_| DatError::ParseDatSigningKeyError)?;
            k.to_bytes().to_vec()
        },
    })
}