//! Certificate types which are passed to `CertificateCheck` in //! `RemoteCallbacks`. use std::marker; use std::mem; use std::slice; use crate::raw; use crate::util::Binding; /// A certificate for a remote connection, viewable as one of `CertHostkey` or /// `CertX509` currently. pub struct Cert<'a> { raw: *mut raw::git_cert, _marker: marker::PhantomData<&'a raw::git_cert>, } /// Hostkey information taken from libssh2 pub struct CertHostkey<'a> { raw: *mut raw::git_cert_hostkey, _marker: marker::PhantomData<&'a raw::git_cert>, } /// X.509 certificate information pub struct CertX509<'a> { raw: *mut raw::git_cert_x509, _marker: marker::PhantomData<&'a raw::git_cert>, } /// The SSH host key type. #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub enum SshHostKeyType { /// Unknown key type Unknown = raw::GIT_CERT_SSH_RAW_TYPE_UNKNOWN as isize, /// RSA key type Rsa = raw::GIT_CERT_SSH_RAW_TYPE_RSA as isize, /// DSS key type Dss = raw::GIT_CERT_SSH_RAW_TYPE_DSS as isize, /// ECDSA 256 key type Ecdsa256 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256 as isize, /// ECDSA 384 key type Ecdsa384 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384 as isize, /// ECDSA 521 key type Ecdsa521 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521 as isize, /// ED25519 key type Ed255219 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ED25519 as isize, } impl SshHostKeyType { /// The name of the key type as encoded in the known_hosts file. pub fn name(&self) -> &'static str { match self { SshHostKeyType::Unknown => "unknown", SshHostKeyType::Rsa => "ssh-rsa", SshHostKeyType::Dss => "ssh-dss", SshHostKeyType::Ecdsa256 => "ecdsa-sha2-nistp256", SshHostKeyType::Ecdsa384 => "ecdsa-sha2-nistp384", SshHostKeyType::Ecdsa521 => "ecdsa-sha2-nistp521", SshHostKeyType::Ed255219 => "ssh-ed25519", } } /// A short name of the key type, the colloquial form used as a human-readable description. pub fn short_name(&self) -> &'static str { match self { SshHostKeyType::Unknown => "Unknown", SshHostKeyType::Rsa => "RSA", SshHostKeyType::Dss => "DSA", SshHostKeyType::Ecdsa256 => "ECDSA", SshHostKeyType::Ecdsa384 => "ECDSA", SshHostKeyType::Ecdsa521 => "ECDSA", SshHostKeyType::Ed255219 => "ED25519", } } } impl<'a> Cert<'a> { /// Attempt to view this certificate as an SSH hostkey. /// /// Returns `None` if this is not actually an SSH hostkey. pub fn as_hostkey(&self) -> Option<&CertHostkey<'a>> { self.cast(raw::GIT_CERT_HOSTKEY_LIBSSH2) } /// Attempt to view this certificate as an X.509 certificate. /// /// Returns `None` if this is not actually an X.509 certificate. pub fn as_x509(&self) -> Option<&CertX509<'a>> { self.cast(raw::GIT_CERT_X509) } fn cast(&self, kind: raw::git_cert_t) -> Option<&T> { assert_eq!(mem::size_of::>(), mem::size_of::()); unsafe { if kind == (*self.raw).cert_type { Some(&*(self as *const Cert<'a> as *const T)) } else { None } } } } impl<'a> CertHostkey<'a> { /// Returns the md5 hash of the hostkey, if available. pub fn hash_md5(&self) -> Option<&[u8; 16]> { unsafe { if (*self.raw).kind as u32 & raw::GIT_CERT_SSH_MD5 as u32 == 0 { None } else { Some(&(*self.raw).hash_md5) } } } /// Returns the SHA-1 hash of the hostkey, if available. pub fn hash_sha1(&self) -> Option<&[u8; 20]> { unsafe { if (*self.raw).kind as u32 & raw::GIT_CERT_SSH_SHA1 as u32 == 0 { None } else { Some(&(*self.raw).hash_sha1) } } } /// Returns the SHA-256 hash of the hostkey, if available. pub fn hash_sha256(&self) -> Option<&[u8; 32]> { unsafe { if (*self.raw).kind as u32 & raw::GIT_CERT_SSH_SHA256 as u32 == 0 { None } else { Some(&(*self.raw).hash_sha256) } } } /// Returns the raw host key. pub fn hostkey(&self) -> Option<&[u8]> { unsafe { if (*self.raw).kind & raw::GIT_CERT_SSH_RAW == 0 { return None; } Some(slice::from_raw_parts( (*self.raw).hostkey as *const u8, (*self.raw).hostkey_len as usize, )) } } /// Returns the type of the host key. pub fn hostkey_type(&self) -> Option { unsafe { if (*self.raw).kind & raw::GIT_CERT_SSH_RAW == 0 { return None; } let t = match (*self.raw).raw_type { raw::GIT_CERT_SSH_RAW_TYPE_UNKNOWN => SshHostKeyType::Unknown, raw::GIT_CERT_SSH_RAW_TYPE_RSA => SshHostKeyType::Rsa, raw::GIT_CERT_SSH_RAW_TYPE_DSS => SshHostKeyType::Dss, raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256 => SshHostKeyType::Ecdsa256, raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384 => SshHostKeyType::Ecdsa384, raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521 => SshHostKeyType::Ecdsa521, raw::GIT_CERT_SSH_RAW_TYPE_KEY_ED25519 => SshHostKeyType::Ed255219, t => panic!("unexpected host key type {:?}", t), }; Some(t) } } } impl<'a> CertX509<'a> { /// Return the X.509 certificate data as a byte slice pub fn data(&self) -> &[u8] { unsafe { slice::from_raw_parts((*self.raw).data as *const u8, (*self.raw).len as usize) } } } impl<'a> Binding for Cert<'a> { type Raw = *mut raw::git_cert; unsafe fn from_raw(raw: *mut raw::git_cert) -> Cert<'a> { Cert { raw, _marker: marker::PhantomData, } } fn raw(&self) -> *mut raw::git_cert { self.raw } }