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