schannel/
cert_chain.rs

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