alpm_ll/
signing.rs

1use crate::{utils::*, LIBRARY, Library};
2use crate::{free, Alpm, AlpmListMut, Db, Package, Result};
3
4use alpm_sys_ll::_alpm_sigstatus_t::*;
5use alpm_sys_ll::_alpm_sigvalidity_t::*;
6use alpm_sys_ll::*;
7
8use std::ffi::{c_void, CString};
9use std::mem::transmute;
10use std::{fmt, ptr, slice};
11
12#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
13pub struct SignatureDecodeError;
14
15impl fmt::Display for SignatureDecodeError {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        f.write_str("failed to decode signature")
18    }
19}
20
21impl std::error::Error for SignatureDecodeError {}
22
23pub fn decode_signature<S: Into<Vec<u8>>>(
24    b64: S,
25) -> std::result::Result<Vec<u8>, SignatureDecodeError> {
26    let b64 = CString::new(b64).unwrap();
27    let mut data = ptr::null_mut();
28    let mut len = 0;
29    let ret = unsafe { LIBRARY.force_load().alpm_decode_signature(b64.as_ptr(), &mut data, &mut len) };
30    if ret != 0 {
31        return Err(SignatureDecodeError);
32    }
33
34    let buff = unsafe { slice::from_raw_parts(data, len) };
35    let v = buff.to_owned();
36
37    unsafe { free(data as *mut c_void) };
38    Ok(v)
39}
40
41#[repr(u32)]
42#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
43pub enum SigStatus {
44    Valid = ALPM_SIGSTATUS_VALID as u32,
45    KeyExpired = ALPM_SIGSTATUS_KEY_EXPIRED as u32,
46    SigExpired = ALPM_SIGSTATUS_SIG_EXPIRED as u32,
47    KeyUnknown = ALPM_SIGSTATUS_KEY_UNKNOWN as u32,
48    KeyDisabled = ALPM_SIGSTATUS_KEY_DISABLED as u32,
49    Invalid = ALPM_SIGSTATUS_INVALID as u32,
50}
51
52#[repr(u32)]
53#[derive(Debug, Eq, PartialEq, Copy, Clone, Ord, PartialOrd, Hash)]
54pub enum SigValidity {
55    Full = ALPM_SIGVALIDITY_FULL as u32,
56    Marginal = ALPM_SIGVALIDITY_MARGINAL as u32,
57    Never = ALPM_SIGVALIDITY_NEVER as u32,
58    Unknown = ALPM_SIGVALIDITY_UNKNOWN as u32,
59}
60
61pub struct PgpKey {
62    pub(crate) inner: alpm_pgpkey_t,
63}
64
65impl fmt::Debug for PgpKey {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.debug_struct("PgpKey")
68            .field("name", &self.name())
69            .field("email", &self.email())
70            .field("uid", &self.uid())
71            .field("fingerprint", &self.fingerprint())
72            .field("created", &self.created())
73            .field("expires", &self.expires())
74            .field("length", &self.length())
75            .field("revoked", &self.revoked())
76            .field("pubkey_algo", &self.pubkey_algo())
77            .finish()
78    }
79}
80
81impl PgpKey {
82    pub fn fingerprint(&self) -> &str {
83        unsafe { from_cstr(self.inner.fingerprint) }
84    }
85
86    pub fn uid(&self) -> &str {
87        unsafe { from_cstr(self.inner.uid) }
88    }
89
90    pub fn name(&self) -> &str {
91        unsafe { from_cstr_optional2(self.inner.name) }
92    }
93
94    pub fn email(&self) -> &str {
95        unsafe { from_cstr_optional2(self.inner.email) }
96    }
97
98    pub fn created(&self) -> i64 {
99        self.inner.created
100    }
101
102    pub fn expires(&self) -> i64 {
103        self.inner.expires
104    }
105
106    pub fn length(&self) -> u32 {
107        self.inner.length
108    }
109
110    pub fn revoked(&self) -> u32 {
111        self.inner.revoked
112    }
113
114    pub fn pubkey_algo(&self) -> u8 {
115        self.inner.pubkey_algo as u8
116    }
117}
118
119#[repr(transparent)]
120pub struct SigResult {
121    inner: alpm_sigresult_t,
122}
123
124impl fmt::Debug for SigResult {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        f.debug_struct("SigResult")
127            .field("key", &self.key())
128            .field("status", &self.status())
129            .field("validity", &self.validity())
130            .finish()
131    }
132}
133
134impl SigResult {
135    pub fn key(&self) -> PgpKey {
136        PgpKey {
137            inner: self.inner.key,
138        }
139    }
140
141    pub fn status(&self) -> SigStatus {
142        unsafe { transmute::<alpm_sigstatus_t, SigStatus>(self.inner.status) }
143    }
144
145    pub fn validity(&self) -> SigValidity {
146        unsafe { transmute::<alpm_sigvalidity_t, SigValidity>(self.inner.validity) }
147    }
148}
149
150pub struct SigList {
151    inner: alpm_siglist_t,
152}
153
154impl fmt::Debug for SigList {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        f.debug_list().entries(self.results()).finish()
157    }
158}
159
160impl Drop for SigList {
161    fn drop(&mut self) {
162        unsafe { LIBRARY.force_load().alpm_siglist_cleanup(&mut self.inner) };
163    }
164}
165
166impl Default for SigList {
167    fn default() -> SigList {
168        Self::new()
169    }
170}
171
172impl SigList {
173    pub fn new() -> SigList {
174        SigList {
175            inner: alpm_siglist_t {
176                count: 0,
177                results: ptr::null_mut(),
178            },
179        }
180    }
181
182    pub fn results(&self) -> &[SigResult] {
183        if self.inner.results.is_null() {
184            unsafe { slice::from_raw_parts(1 as *const SigResult, 0) }
185        } else {
186            unsafe {
187                slice::from_raw_parts(self.inner.results as *const SigResult, self.inner.count)
188            }
189        }
190    }
191}
192
193impl<'a> Package<'a> {
194    pub fn check_signature(&self) -> Result<(bool, SigList)> {
195        let mut siglist = SigList::new();
196        let ret = unsafe { LIBRARY.force_load().alpm_pkg_check_pgp_signature(self.pkg.as_ptr(), &mut siglist.inner) };
197        let valid = match ret {
198            0 => true,
199            1 => false,
200            _ => return Err(self.handle.last_error()),
201        };
202
203        Ok((valid, siglist))
204    }
205}
206
207impl<'a> Db<'a> {
208    pub fn check_signature(&self) -> Result<(bool, SigList)> {
209        let mut siglist = SigList::new();
210        let ret = unsafe { LIBRARY.force_load().alpm_db_check_pgp_signature(self.as_ptr(), &mut siglist.inner) };
211        let valid = match ret {
212            0 => true,
213            1 => false,
214            _ => return Err(self.handle.last_error()),
215        };
216
217        Ok((valid, siglist))
218    }
219}
220
221impl Alpm {
222    pub fn extract_keyid<'a, S: Into<Vec<u8>>>(
223        &'a self,
224        ident: S,
225        sig: &[u8],
226    ) -> Result<AlpmListMut<'a, String>> {
227        let ident = CString::new(ident).unwrap();
228        let mut keys = ptr::null_mut();
229
230        let ret = unsafe {
231            self.lib.alpm_extract_keyid(
232                self.as_ptr(),
233                ident.as_ptr(),
234                sig.as_ptr(),
235                sig.len(),
236                &mut keys,
237            )
238        };
239
240        self.check_ret(ret)?;
241        unsafe { Ok(AlpmListMut::from_parts(self, keys)) }
242    }
243}