1 //! Bindings to winapi's certificate-chain related APIs. 2 3 use std::mem; 4 use std::slice; 5 use winapi::um::wincrypt; 6 7 use crate::cert_context::CertContext; 8 use crate::Inner; 9 10 /// A certificate chain context (consisting of multiple chains) 11 pub struct CertChainContext(pub(crate) wincrypt::PCERT_CHAIN_CONTEXT); 12 inner!(CertChainContext, wincrypt::PCERT_CHAIN_CONTEXT); 13 14 unsafe impl Sync for CertChainContext {} 15 unsafe impl Send for CertChainContext {} 16 17 impl Clone for CertChainContext { clone(&self) -> Self18 fn clone(&self) -> Self { 19 let rced = unsafe { 20 wincrypt::CertDuplicateCertificateChain(self.0) as *mut _ 21 }; 22 CertChainContext(rced) 23 } 24 } 25 26 impl Drop for CertChainContext { drop(&mut self)27 fn drop(&mut self) { 28 unsafe { 29 wincrypt::CertFreeCertificateChain(self.0); 30 } 31 } 32 } 33 34 impl CertChainContext { 35 /// Get the final (for a successful verification this means successful) certificate chain 36 /// 37 /// https://msdn.microsoft.com/de-de/library/windows/desktop/aa377182(v=vs.85).aspx 38 /// rgpChain[cChain - 1] is the final chain final_chain(&self) -> Option<CertChain>39 pub fn final_chain(&self) -> Option<CertChain> { 40 if let Some(chain) = self.chains().last(){ 41 return Some(CertChain(chain.0, self.clone())); 42 } 43 None 44 } 45 46 /// Retrieves the specified chain from the context. get_chain(&self, index :usize) -> Option<CertChain>47 pub fn get_chain(&self, index :usize) -> Option<CertChain> { 48 let cert_chain = unsafe { 49 let cert_chain = *self.0; 50 if index >= cert_chain.cChain as usize { 51 None 52 } else { 53 let chain_slice = slice::from_raw_parts( 54 cert_chain.rgpChain as *mut wincrypt::PCERT_SIMPLE_CHAIN, 55 cert_chain.cChain as usize); 56 Some(CertChain(chain_slice[index], self.clone())) 57 } 58 }; 59 return cert_chain; 60 } 61 62 /// Return an iterator over all certificate chains in this context chains(&self) -> CertificateChains63 pub fn chains(&self) -> CertificateChains { 64 CertificateChains { 65 context: self, 66 idx: 0 67 } 68 } 69 } 70 71 /// A (simple) certificate chain 72 pub struct CertChain(wincrypt::PCERT_SIMPLE_CHAIN, CertChainContext); 73 74 impl CertChain { 75 /// Returns the number of certificates in the chain len(&self) -> usize76 pub fn len(&self) -> usize { 77 unsafe { 78 (*self.0).cElement as usize 79 } 80 } 81 82 /// Get the n-th certificate from the current chain get(&self, idx: usize) -> Option<CertContext>83 pub fn get(&self, idx: usize) -> Option<CertContext> { 84 let elements = unsafe { 85 let cert_chain = *self.0; 86 slice::from_raw_parts( 87 cert_chain.rgpElement as *mut &mut wincrypt::CERT_CHAIN_ELEMENT, 88 cert_chain.cElement as usize) 89 }; 90 elements.get(idx).map(|el| { 91 let cert = unsafe { 92 CertContext::from_inner(el.pCertContext) 93 }; 94 let rc_cert = cert.clone(); 95 mem::forget(cert); 96 rc_cert 97 }) 98 } 99 100 /// Return an iterator over all certificates in this chain certificates(&self) -> Certificates101 pub fn certificates(&self) -> Certificates { 102 Certificates { 103 chain: self, 104 idx: 0, 105 } 106 } 107 } 108 109 110 /// An iterator that iterates over all chains in a context 111 pub struct CertificateChains<'a> { 112 context: &'a CertChainContext, 113 idx: usize, 114 } 115 116 impl<'a> Iterator for CertificateChains<'a> { 117 type Item = CertChain; 118 next(&mut self) -> Option<CertChain>119 fn next(&mut self) -> Option<CertChain> { 120 let idx = self.idx; 121 self.idx += 1; 122 self.context.get_chain(idx) 123 } 124 } 125 126 /// An iterator that iterates over all certificates in a chain 127 pub struct Certificates<'a> { 128 chain: &'a CertChain, 129 idx: usize, 130 } 131 132 impl<'a> Iterator for Certificates<'a> { 133 type Item = CertContext; 134 next(&mut self) -> Option<CertContext>135 fn next(&mut self) -> Option<CertContext> { 136 let idx = self.idx; 137 self.idx += 1; 138 self.chain.get(idx) 139 } 140 } 141