| //! Bindings to winapi's certificate-chain related APIs. |
| |
| use std::mem; |
| use std::slice; |
| use winapi::um::wincrypt; |
| |
| use crate::cert_context::CertContext; |
| use crate::Inner; |
| |
| /// A certificate chain context (consisting of multiple chains) |
| pub struct CertChainContext(pub(crate) wincrypt::PCERT_CHAIN_CONTEXT); |
| inner!(CertChainContext, wincrypt::PCERT_CHAIN_CONTEXT); |
| |
| unsafe impl Sync for CertChainContext {} |
| unsafe impl Send for CertChainContext {} |
| |
| impl Clone for CertChainContext { |
| fn clone(&self) -> Self { |
| let rced = unsafe { |
| wincrypt::CertDuplicateCertificateChain(self.0) as *mut _ |
| }; |
| CertChainContext(rced) |
| } |
| } |
| |
| impl Drop for CertChainContext { |
| fn drop(&mut self) { |
| unsafe { |
| wincrypt::CertFreeCertificateChain(self.0); |
| } |
| } |
| } |
| |
| impl CertChainContext { |
| /// Get the final (for a successful verification this means successful) certificate chain |
| /// |
| /// https://msdn.microsoft.com/de-de/library/windows/desktop/aa377182(v=vs.85).aspx |
| /// rgpChain[cChain - 1] is the final chain |
| pub fn final_chain(&self) -> Option<CertChain> { |
| if let Some(chain) = self.chains().last(){ |
| return Some(CertChain(chain.0, self.clone())); |
| } |
| None |
| } |
| |
| /// Retrieves the specified chain from the context. |
| pub fn get_chain(&self, index :usize) -> Option<CertChain> { |
| let cert_chain = unsafe { |
| let cert_chain = *self.0; |
| if index >= cert_chain.cChain as usize { |
| None |
| } else { |
| let chain_slice = slice::from_raw_parts( |
| cert_chain.rgpChain as *mut wincrypt::PCERT_SIMPLE_CHAIN, |
| cert_chain.cChain as usize); |
| Some(CertChain(chain_slice[index], self.clone())) |
| } |
| }; |
| return cert_chain; |
| } |
| |
| /// Return an iterator over all certificate chains in this context |
| pub fn chains(&self) -> CertificateChains { |
| CertificateChains { |
| context: self, |
| idx: 0 |
| } |
| } |
| } |
| |
| /// A (simple) certificate chain |
| pub struct CertChain(wincrypt::PCERT_SIMPLE_CHAIN, CertChainContext); |
| |
| impl CertChain { |
| /// Returns the number of certificates in the chain |
| pub fn len(&self) -> usize { |
| unsafe { |
| (*self.0).cElement as usize |
| } |
| } |
| |
| /// Get the n-th certificate from the current chain |
| pub fn get(&self, idx: usize) -> Option<CertContext> { |
| let elements = unsafe { |
| let cert_chain = *self.0; |
| slice::from_raw_parts( |
| cert_chain.rgpElement as *mut &mut wincrypt::CERT_CHAIN_ELEMENT, |
| cert_chain.cElement as usize) |
| }; |
| elements.get(idx).map(|el| { |
| let cert = unsafe { |
| CertContext::from_inner(el.pCertContext) |
| }; |
| let rc_cert = cert.clone(); |
| mem::forget(cert); |
| rc_cert |
| }) |
| } |
| |
| /// Return an iterator over all certificates in this chain |
| pub fn certificates(&self) -> Certificates { |
| Certificates { |
| chain: self, |
| idx: 0, |
| } |
| } |
| } |
| |
| |
| /// An iterator that iterates over all chains in a context |
| pub struct CertificateChains<'a> { |
| context: &'a CertChainContext, |
| idx: usize, |
| } |
| |
| impl<'a> Iterator for CertificateChains<'a> { |
| type Item = CertChain; |
| |
| fn next(&mut self) -> Option<CertChain> { |
| let idx = self.idx; |
| self.idx += 1; |
| self.context.get_chain(idx) |
| } |
| } |
| |
| /// An iterator that iterates over all certificates in a chain |
| pub struct Certificates<'a> { |
| chain: &'a CertChain, |
| idx: usize, |
| } |
| |
| impl<'a> Iterator for Certificates<'a> { |
| type Item = CertContext; |
| |
| fn next(&mut self) -> Option<CertContext> { |
| let idx = self.idx; |
| self.idx += 1; |
| self.chain.get(idx) |
| } |
| } |