use crate::error::TLSError;
use crate::key;
use crate::msgs::enums::{SignatureAlgorithm, SignatureScheme};
use ring::{
    self,
    signature::{self, EcdsaKeyPair, Ed25519KeyPair, RsaKeyPair},
};
use webpki;
use std::mem;
use std::sync::Arc;
pub trait SigningKey: Send + Sync {
    
    
    
    
    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>>;
    
    fn algorithm(&self) -> SignatureAlgorithm;
}
pub trait Signer: Send + Sync {
    
    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, TLSError>;
    
    fn get_scheme(&self) -> SignatureScheme;
}
#[derive(Clone)]
pub struct CertifiedKey {
    
    pub cert: Vec<key::Certificate>,
    
    pub key: Arc<Box<dyn SigningKey>>,
    
    
    pub ocsp: Option<Vec<u8>>,
    
    
    
    pub sct_list: Option<Vec<u8>>,
}
impl CertifiedKey {
    
    
    
    
    pub fn new(cert: Vec<key::Certificate>, key: Arc<Box<dyn SigningKey>>) -> CertifiedKey {
        CertifiedKey {
            cert,
            key,
            ocsp: None,
            sct_list: None,
        }
    }
    
    pub fn end_entity_cert(&self) -> Result<&key::Certificate, ()> {
        self.cert.get(0).ok_or(())
    }
    
    pub fn take_cert(&mut self) -> Vec<key::Certificate> {
        mem::replace(&mut self.cert, Vec::new())
    }
    
    pub fn has_ocsp(&self) -> bool {
        self.ocsp.is_some()
    }
    
    pub fn take_ocsp(&mut self) -> Option<Vec<u8>> {
        mem::replace(&mut self.ocsp, None)
    }
    
    pub fn has_sct_list(&self) -> bool {
        self.sct_list.is_some()
    }
    
    pub fn take_sct_list(&mut self) -> Option<Vec<u8>> {
        mem::replace(&mut self.sct_list, None)
    }
    
    
    
    
    
    
    
    
    pub fn cross_check_end_entity_cert(
        &self,
        name: Option<webpki::DNSNameRef>,
    ) -> Result<(), TLSError> {
        
        let end_entity_cert = self.end_entity_cert().map_err(|()| {
            TLSError::General("No end-entity certificate in certificate chain".to_string())
        })?;
        
        let end_entity_cert =
            webpki::EndEntityCert::from(end_entity_cert.as_ref()).map_err(|_| {
                TLSError::General(
                    "End-entity certificate in certificate \
                                  chain is syntactically invalid"
                        .to_string(),
                )
            })?;
        if let Some(name) = name {
            
            
            
            
            
            if end_entity_cert
                .verify_is_valid_for_dns_name(name)
                .is_err()
            {
                return Err(TLSError::General(
                    "The server certificate is not \
                                             valid for the given name"
                        .to_string(),
                ));
            }
        }
        Ok(())
    }
}
pub fn any_supported_type(der: &key::PrivateKey) -> Result<Box<dyn SigningKey>, ()> {
    if let Ok(rsa) = RSASigningKey::new(der) {
        Ok(Box::new(rsa))
    } else if let Ok(ecdsa) = any_ecdsa_type(der) {
        Ok(ecdsa)
    } else {
        any_eddsa_type(der)
    }
}
pub fn any_ecdsa_type(der: &key::PrivateKey) -> Result<Box<dyn SigningKey>, ()> {
    if let Ok(ecdsa_p256) = ECDSASigningKey::new(
        der,
        SignatureScheme::ECDSA_NISTP256_SHA256,
        &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
    ) {
        return Ok(Box::new(ecdsa_p256));
    }
    if let Ok(ecdsa_p384) = ECDSASigningKey::new(
        der,
        SignatureScheme::ECDSA_NISTP384_SHA384,
        &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
    ) {
        return Ok(Box::new(ecdsa_p384));
    }
    Err(())
}
pub fn any_eddsa_type(der: &key::PrivateKey) -> Result<Box<dyn SigningKey>, ()> {
    if let Ok(ed25519) = Ed25519SigningKey::new(der, SignatureScheme::ED25519) {
        return Ok(Box::new(ed25519));
    }
    
    Err(())
}
pub struct RSASigningKey {
    key: Arc<RsaKeyPair>,
}
static ALL_RSA_SCHEMES: &[SignatureScheme] = &[
    SignatureScheme::RSA_PSS_SHA512,
    SignatureScheme::RSA_PSS_SHA384,
    SignatureScheme::RSA_PSS_SHA256,
    SignatureScheme::RSA_PKCS1_SHA512,
    SignatureScheme::RSA_PKCS1_SHA384,
    SignatureScheme::RSA_PKCS1_SHA256,
];
impl RSASigningKey {
    
    
    pub fn new(der: &key::PrivateKey) -> Result<RSASigningKey, ()> {
        RsaKeyPair::from_der(&der.0)
            .or_else(|_| RsaKeyPair::from_pkcs8(&der.0))
            .map(|s| RSASigningKey { key: Arc::new(s) })
            .map_err(|_| ())
    }
}
impl SigningKey for RSASigningKey {
    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
        ALL_RSA_SCHEMES
            .iter()
            .filter(|scheme| offered.contains(scheme))
            .nth(0)
            .map(|scheme| RSASigner::new(self.key.clone(), *scheme))
    }
    fn algorithm(&self) -> SignatureAlgorithm {
        SignatureAlgorithm::RSA
    }
}
struct RSASigner {
    key: Arc<RsaKeyPair>,
    scheme: SignatureScheme,
    encoding: &'static dyn signature::RsaEncoding,
}
impl RSASigner {
    fn new(key: Arc<RsaKeyPair>, scheme: SignatureScheme) -> Box<dyn Signer> {
        let encoding: &dyn signature::RsaEncoding = match scheme {
            SignatureScheme::RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_SHA256,
            SignatureScheme::RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_SHA384,
            SignatureScheme::RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_SHA512,
            SignatureScheme::RSA_PSS_SHA256 => &signature::RSA_PSS_SHA256,
            SignatureScheme::RSA_PSS_SHA384 => &signature::RSA_PSS_SHA384,
            SignatureScheme::RSA_PSS_SHA512 => &signature::RSA_PSS_SHA512,
            _ => unreachable!(),
        };
        Box::new(RSASigner {
            key,
            scheme,
            encoding,
        })
    }
}
impl Signer for RSASigner {
    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, TLSError> {
        let mut sig = vec![0; self.key.public_modulus_len()];
        let rng = ring::rand::SystemRandom::new();
        self.key
            .sign(self.encoding, &rng, message, &mut sig)
            .map(|_| sig)
            .map_err(|_| TLSError::General("signing failed".to_string()))
    }
    fn get_scheme(&self) -> SignatureScheme {
        self.scheme
    }
}
struct ECDSASigningKey {
    key: Arc<EcdsaKeyPair>,
    scheme: SignatureScheme,
}
impl ECDSASigningKey {
    
    
    pub fn new(
        der: &key::PrivateKey,
        scheme: SignatureScheme,
        sigalg: &'static signature::EcdsaSigningAlgorithm,
    ) -> Result<ECDSASigningKey, ()> {
        EcdsaKeyPair::from_pkcs8(sigalg, &der.0)
            .map(|kp| ECDSASigningKey {
                key: Arc::new(kp),
                scheme,
            })
            .map_err(|_| ())
    }
}
impl SigningKey for ECDSASigningKey {
    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
        if offered.contains(&self.scheme) {
            Some(Box::new(ECDSASigner {
                key: self.key.clone(),
                scheme: self.scheme,
            }))
        } else {
            None
        }
    }
    fn algorithm(&self) -> SignatureAlgorithm {
        use crate::msgs::handshake::DecomposedSignatureScheme;
        self.scheme.sign()
    }
}
struct ECDSASigner {
    key: Arc<EcdsaKeyPair>,
    scheme: SignatureScheme,
}
impl Signer for ECDSASigner {
    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, TLSError> {
        let rng = ring::rand::SystemRandom::new();
        self.key
            .sign(&rng, message)
            .map_err(|_| TLSError::General("signing failed".into()))
            .map(|sig| sig.as_ref().into())
    }
    fn get_scheme(&self) -> SignatureScheme {
        self.scheme
    }
}
struct Ed25519SigningKey {
    key: Arc<Ed25519KeyPair>,
    scheme: SignatureScheme,
}
impl Ed25519SigningKey {
    
    
    pub fn new(der: &key::PrivateKey, scheme: SignatureScheme) -> Result<Ed25519SigningKey, ()> {
        Ed25519KeyPair::from_pkcs8_maybe_unchecked(&der.0)
            .map(|kp| Ed25519SigningKey {
                key: Arc::new(kp),
                scheme,
            })
            .map_err(|_| ())
    }
}
impl SigningKey for Ed25519SigningKey {
    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
        if offered.contains(&self.scheme) {
            Some(Box::new(Ed25519Signer {
                key: self.key.clone(),
                scheme: self.scheme,
            }))
        } else {
            None
        }
    }
    fn algorithm(&self) -> SignatureAlgorithm {
        use crate::msgs::handshake::DecomposedSignatureScheme;
        self.scheme.sign()
    }
}
struct Ed25519Signer {
    key: Arc<Ed25519KeyPair>,
    scheme: SignatureScheme,
}
impl Signer for Ed25519Signer {
    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, TLSError> {
        Ok(self.key.sign(message).as_ref().into())
    }
    fn get_scheme(&self) -> SignatureScheme {
        self.scheme
    }
}
pub fn supported_sign_tls13() -> &'static [SignatureScheme] {
    &[
        SignatureScheme::ECDSA_NISTP384_SHA384,
        SignatureScheme::ECDSA_NISTP256_SHA256,
        SignatureScheme::RSA_PSS_SHA512,
        SignatureScheme::RSA_PSS_SHA384,
        SignatureScheme::RSA_PSS_SHA256,
        SignatureScheme::ED25519,
    ]
}